Merge "Fix timer bug in TrustManagerService." into udc-dev
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index f779b4d..b0b3b1f 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -319,6 +319,8 @@
private SensorManager mSensorManager;
private final boolean mUseMotionSensor;
private Sensor mMotionSensor;
+ private final boolean mIsLocationPrefetchEnabled;
+ @Nullable
private LocationRequest mLocationRequest;
private Intent mIdleIntent;
private Bundle mIdleIntentOptions;
@@ -2460,6 +2462,11 @@
return null;
}
+ boolean isLocationPrefetchEnabled() {
+ return mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_autoPowerModePrefetchLocation);
+ }
+
boolean useMotionSensor() {
return mContext.getResources().getBoolean(
com.android.internal.R.bool.config_autoPowerModeUseMotionSensor);
@@ -2489,6 +2496,7 @@
mAppStateTracker = mInjector.getAppStateTracker(context,
AppSchedulingModuleThread.get().getLooper());
LocalServices.addService(AppStateTracker.class, mAppStateTracker);
+ mIsLocationPrefetchEnabled = mInjector.isLocationPrefetchEnabled();
mUseMotionSensor = mInjector.useMotionSensor();
}
@@ -2602,8 +2610,7 @@
mMotionSensor = mInjector.getMotionSensor();
}
- if (getContext().getResources().getBoolean(
- com.android.internal.R.bool.config_autoPowerModePrefetchLocation)) {
+ if (mIsLocationPrefetchEnabled) {
mLocationRequest = new LocationRequest.Builder(/*intervalMillis=*/ 0)
.setQuality(LocationRequest.QUALITY_HIGH_ACCURACY)
.setMaxUpdates(1)
@@ -3779,34 +3786,40 @@
case STATE_SENSING:
cancelSensingTimeoutAlarmLocked();
moveToStateLocked(STATE_LOCATING, reason);
- scheduleAlarmLocked(mConstants.LOCATING_TIMEOUT);
- LocationManager locationManager = mInjector.getLocationManager();
- if (locationManager != null
- && locationManager.getProvider(LocationManager.FUSED_PROVIDER) != null) {
- locationManager.requestLocationUpdates(LocationManager.FUSED_PROVIDER,
- mLocationRequest,
- AppSchedulingModuleThread.getExecutor(),
- mGenericLocationListener);
- mLocating = true;
+ if (mIsLocationPrefetchEnabled) {
+ scheduleAlarmLocked(mConstants.LOCATING_TIMEOUT);
+ LocationManager locationManager = mInjector.getLocationManager();
+ if (locationManager != null
+ && locationManager.getProvider(LocationManager.FUSED_PROVIDER)
+ != null) {
+ locationManager.requestLocationUpdates(LocationManager.FUSED_PROVIDER,
+ mLocationRequest,
+ AppSchedulingModuleThread.getExecutor(),
+ mGenericLocationListener);
+ mLocating = true;
+ } else {
+ mHasFusedLocation = false;
+ }
+ if (locationManager != null
+ && locationManager.getProvider(LocationManager.GPS_PROVIDER) != null) {
+ mHasGps = true;
+ locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
+ 1000, 5, mGpsLocationListener, mHandler.getLooper());
+ mLocating = true;
+ } else {
+ mHasGps = false;
+ }
+ // If we have a location provider, we're all set, the listeners will move state
+ // forward.
+ if (mLocating) {
+ break;
+ }
+ // Otherwise, we have to move from locating into idle maintenance.
} else {
- mHasFusedLocation = false;
- }
- if (locationManager != null
- && locationManager.getProvider(LocationManager.GPS_PROVIDER) != null) {
- mHasGps = true;
- locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 5,
- mGpsLocationListener, mHandler.getLooper());
- mLocating = true;
- } else {
- mHasGps = false;
- }
- // If we have a location provider, we're all set, the listeners will move state
- // forward.
- if (mLocating) {
- break;
+ mLocating = false;
}
- // Otherwise, we have to move from locating into idle maintenance.
+ // We're not doing any locating work, so move on to the next state.
case STATE_LOCATING:
cancelAlarmLocked();
cancelLocatingLocked();
@@ -5303,15 +5316,19 @@
pw.print(" "); pw.print(mStationaryListeners.size());
pw.println(" stationary listeners registered");
}
- pw.print(" mLocating="); pw.print(mLocating);
- pw.print(" mHasGps="); pw.print(mHasGps);
- pw.print(" mHasFused="); pw.print(mHasFusedLocation);
- pw.print(" mLocated="); pw.println(mLocated);
- if (mLastGenericLocation != null) {
- pw.print(" mLastGenericLocation="); pw.println(mLastGenericLocation);
- }
- if (mLastGpsLocation != null) {
- pw.print(" mLastGpsLocation="); pw.println(mLastGpsLocation);
+ if (mIsLocationPrefetchEnabled) {
+ pw.print(" mLocating="); pw.print(mLocating);
+ pw.print(" mHasGps="); pw.print(mHasGps);
+ pw.print(" mHasFused="); pw.print(mHasFusedLocation);
+ pw.print(" mLocated="); pw.println(mLocated);
+ if (mLastGenericLocation != null) {
+ pw.print(" mLastGenericLocation="); pw.println(mLastGenericLocation);
+ }
+ if (mLastGpsLocation != null) {
+ pw.print(" mLastGpsLocation="); pw.println(mLastGpsLocation);
+ }
+ } else {
+ pw.println(" Location prefetching disabled");
}
pw.print(" mState="); pw.print(stateToString(mState));
pw.print(" mLightState=");
diff --git a/config/dirty-image-objects b/config/dirty-image-objects
index dfd091c..2584610e 100644
--- a/config/dirty-image-objects
+++ b/config/dirty-image-objects
@@ -28,359 +28,270 @@
# Then, grep for lines containing "Private dirty object" from the output.
# This particular file was generated by dumping systemserver and systemui.
#
-Landroid/accounts/Account;
-Landroid/accounts/OnAccountsUpdateListener;
Landroid/animation/LayoutTransition;
Landroid/app/ActivityManager;
-Landroid/app/ActivityManager$OnUidImportanceListener;
Landroid/app/ActivityTaskManager;
Landroid/app/ActivityThread;
-Landroid/app/admin/DevicePolicyManager;
Landroid/app/AlarmManager;
-Landroid/app/Application;
Landroid/app/AppOpsManager;
-Landroid/app/backup/BackupManager;
Landroid/app/ContextImpl;
-Landroid/app/INotificationManager;
-Landroid/app/Notification$BigPictureStyle;
-Landroid/app/Notification$BigTextStyle;
-Landroid/app/Notification$InboxStyle;
-Landroid/app/NotificationChannel;
-Landroid/app/NotificationChannelGroup;
+Landroid/app/Notification;
Landroid/app/NotificationManager;
-Landroid/app/PendingIntent;
-Landroid/app/PendingIntent$OnFinished;
+Landroid/app/PendingIntent$FinishedDispatcher;
+Landroid/app/PropertyInvalidatedCache$NoPreloadHolder;
Landroid/app/QueuedWork;
Landroid/app/ResourcesManager;
+Landroid/app/SystemServiceRegistry;
Landroid/app/WallpaperManager;
-Landroid/app/WindowConfiguration;
-Landroid/bluetooth/BluetoothAdapter;
-Landroid/bluetooth/BluetoothDevice;
-Landroid/bluetooth/BluetoothProfile;
-Landroid/bluetooth/IBluetoothA2dp;
-Landroid/bluetooth/IBluetoothHeadsetPhone;
-Landroid/bluetooth/IBluetoothHidDevice;
-Landroid/bluetooth/IBluetoothHidHost;
-Landroid/bluetooth/IBluetoothMap;
-Landroid/bluetooth/IBluetoothPan;
-Landroid/bluetooth/IBluetoothPbap;
-Landroid/bluetooth/IBluetoothSap;
-Landroid/content/ClipboardManager$OnPrimaryClipChangedListener;
-Landroid/content/ComponentName;
-Landroid/content/ContentProvider$PipeDataWriter;
+Landroid/app/backup/BackupManager;
+Landroid/compat/Compatibility;
+Landroid/content/AsyncQueryHandler;
+Landroid/content/ContentProviderClient;
Landroid/content/ContentResolver;
Landroid/content/Context;
-Landroid/content/Intent;
-Landroid/content/pm/PackageManager$OnPermissionsChangedListener;
-Landroid/content/pm/VersionedPackage;
-Landroid/content/res/Configuration;
-Landroid/content/SharedPreferences$OnSharedPreferenceChangeListener;
+Landroid/content/pm/PackageItemInfo;
+Landroid/content/pm/UserPackage;
+Landroid/content/res/ResourceTimer;
Landroid/database/CursorWindow;
Landroid/database/sqlite/SQLiteCompatibilityWalFlags;
-Landroid/database/sqlite/SQLiteDatabase$CursorFactory;
+Landroid/database/sqlite/SQLiteDebug$NoPreloadHolder;
Landroid/database/sqlite/SQLiteGlobal;
-Landroid/database/sqlite/SQLiteTransactionListener;
Landroid/ddm/DdmHandleAppName;
Landroid/graphics/Bitmap;
Landroid/graphics/Canvas;
-Landroid/graphics/drawable/AdaptiveIconDrawable;
-Landroid/graphics/drawable/ColorDrawable;
-Landroid/graphics/drawable/GradientDrawable;
-Landroid/graphics/drawable/Icon;
-Landroid/graphics/drawable/InsetDrawable;
-Landroid/graphics/drawable/RippleDrawable;
-Landroid/graphics/drawable/VectorDrawable$VGroup;
-Landroid/graphics/ImageDecoder;
-Landroid/graphics/Rect;
+Landroid/graphics/Compatibility;
+Landroid/graphics/HardwareRenderer;
Landroid/graphics/TemporaryBuffer;
-Landroid/hardware/biometrics/BiometricSourceType;
-Landroid/hardware/display/ColorDisplayManager$ColorDisplayManagerInternal;
-Landroid/hardware/display/DisplayManagerGlobal;
-Landroid/hardware/display/NightDisplayListener$Callback;
-Landroid/hardware/input/InputManager;
-Landroid/hardware/input/InputManager$InputDeviceListener;
+Landroid/graphics/Typeface;
+Landroid/graphics/drawable/AdaptiveIconDrawable;
Landroid/hardware/SensorPrivacyManager;
Landroid/hardware/SystemSensorManager;
-Landroid/icu/impl/OlsonTimeZone;
-Landroid/icu/text/BreakIterator;
+Landroid/hardware/devicestate/DeviceStateManagerGlobal;
+Landroid/hardware/display/ColorDisplayManager$ColorDisplayManagerInternal;
+Landroid/hardware/display/DisplayManagerGlobal;
+Landroid/hardware/input/InputManagerGlobal;
+Landroid/hardware/location/GeofenceHardwareImpl;
+Landroid/icu/impl/number/range/StandardPluralRanges;
Landroid/icu/text/Collator;
-Landroid/icu/text/DateFormat$BooleanAttribute;
-Landroid/icu/text/DateTimePatternGenerator$DTPGflags;
-Landroid/icu/text/PluralRules$Operand;
Landroid/icu/util/TimeZone;
-Landroid/location/GpsStatus$Listener;
-Landroid/location/LocationListener;
+Landroid/location/LocationManager;
Landroid/media/AudioManager;
+Landroid/media/AudioPlaybackConfiguration;
+Landroid/media/AudioSystem;
+Landroid/media/MediaCodec;
+Landroid/media/MediaCodecList;
+Landroid/media/MediaFrameworkPlatformInitializer;
+Landroid/media/MediaRouter2Manager;
Landroid/media/MediaRouter;
Landroid/media/PlayerBase;
-Landroid/media/session/MediaSessionManager;
-Landroid/net/apf/ApfCapabilities;
-Landroid/net/ConnectivityManager;
-Landroid/net/ConnectivityManager$OnNetworkActiveListener;
-Landroid/net/ConnectivityThread$Singleton;
-Landroid/net/IpConfiguration$IpAssignment;
-Landroid/net/IpConfiguration$ProxySettings;
-Landroid/net/IpPrefix;
-Landroid/net/LinkAddress;
-Landroid/net/LinkProperties;
-Landroid/net/Network;
-Landroid/net/NetworkCapabilities;
-Landroid/net/NetworkInfo;
-Landroid/net/NetworkInfo$State;
-Landroid/net/NetworkRequest;
-Landroid/net/NetworkRequest$Type;
-Landroid/net/RouteInfo;
-Landroid/net/StringNetworkSpecifier;
-Landroid/net/TrafficStats;
-Landroid/net/UidRange;
-Landroid/net/Uri$HierarchicalUri;
-Landroid/net/Uri$StringUri;
-Landroid/net/wifi/WifiManager;
-Landroid/net/wifi/WifiManager$SoftApCallback;
-Landroid/os/AsyncResult;
+Landroid/media/audiopolicy/AudioProductStrategy;
+Landroid/media/audiopolicy/AudioVolumeGroup;
+Landroid/nfc/NfcAdapter;
+Landroid/nfc/NfcFrameworkInitializer;
+Landroid/nfc/cardemulation/CardEmulation;
Landroid/os/AsyncTask;
+Landroid/os/BaseBundle;
+Landroid/os/Binder;
Landroid/os/BinderProxy;
-Landroid/os/Bundle;
-Landroid/os/DeadObjectException;
Landroid/os/Environment;
Landroid/os/FileObserver;
Landroid/os/Handler;
-Landroid/os/IDeviceIdleController;
Landroid/os/LocaleList;
Landroid/os/Looper;
Landroid/os/Message;
-Landroid/os/ParcelUuid;
+Landroid/os/NullVibrator;
+Landroid/os/Parcel;
Landroid/os/Process;
-Landroid/os/RecoverySystem;
Landroid/os/ServiceManager;
-Landroid/os/storage/StorageManager;
Landroid/os/StrictMode;
-Landroid/os/Trace;
+Landroid/os/UEventObserver;
+Landroid/os/UserManager;
Landroid/os/WorkSource;
-Landroid/os/WorkSource$WorkChain;
+Landroid/os/storage/StorageManager;
Landroid/permission/PermissionManager;
+Landroid/provider/DeviceConfigInitializer;
Landroid/provider/FontsContract;
-Landroid/provider/Settings$SettingNotFoundException;
+Landroid/provider/Settings;
+Landroid/renderscript/RenderScript;
Landroid/renderscript/RenderScriptCacheDir;
-Landroid/security/IKeyChainService;
-Landroid/security/keystore/AndroidKeyStoreProvider;
+Landroid/security/keystore2/KeyStoreCryptoOperationUtils;
Landroid/security/net/config/ApplicationConfig;
Landroid/security/net/config/SystemCertificateSource$NoPreloadHolder;
-Landroid/telecom/PhoneAccountHandle;
+Landroid/security/net/config/UserCertificateSource$NoPreloadHolder;
+Landroid/telecom/Log;
+Landroid/telecom/TelecomManager;
Landroid/telephony/AnomalyReporter;
-Landroid/telephony/CellSignalStrengthCdma;
-Landroid/telephony/CellSignalStrengthGsm;
-Landroid/telephony/CellSignalStrengthLte;
-Landroid/telephony/CellSignalStrengthNr;
-Landroid/telephony/CellSignalStrengthTdscdma;
-Landroid/telephony/CellSignalStrengthWcdma;
-Landroid/telephony/DataSpecificRegistrationInfo;
-Landroid/telephony/emergency/EmergencyNumber;
-Landroid/telephony/ims/ImsMmTelManager$CapabilityCallback$CapabilityBinder;
-Landroid/telephony/ims/ImsMmTelManager$RegistrationCallback$RegistrationBinder;
-Landroid/telephony/ims/ImsReasonInfo;
-Landroid/telephony/ims/ProvisioningManager$Callback$CallbackBinder;
-Landroid/telephony/ModemActivityInfo;
-Landroid/telephony/ModemInfo;
-Landroid/telephony/NetworkRegistrationInfo;
-Landroid/telephony/NetworkService;
+Landroid/telephony/TelephonyFrameworkInitializer;
+Landroid/telephony/TelephonyLocalConnection;
Landroid/telephony/TelephonyManager;
-Landroid/telephony/VoiceSpecificRegistrationInfo;
-Landroid/text/format/DateFormat;
-Landroid/text/method/SingleLineTransformationMethod;
-Landroid/text/Selection$MemoryTextWatcher;
-Landroid/text/SpanWatcher;
-Landroid/text/style/AlignmentSpan;
-Landroid/text/style/CharacterStyle;
-Landroid/text/style/LeadingMarginSpan;
-Landroid/text/style/LineBackgroundSpan;
-Landroid/text/style/LineHeightSpan;
-Landroid/text/style/MetricAffectingSpan;
-Landroid/text/style/ReplacementSpan;
-Landroid/text/style/SuggestionSpan;
-Landroid/text/style/TabStopSpan;
+Landroid/telephony/TelephonyRegistryManager;
+Landroid/text/DynamicLayout;
Landroid/text/TextUtils;
-Landroid/text/TextWatcher;
-Landroid/transition/ChangeClipBounds;
-Landroid/transition/ChangeImageTransform;
-Landroid/transition/ChangeTransform;
+Landroid/text/format/DateFormat;
+Landroid/text/format/DateUtils;
+Landroid/text/method/ArrowKeyMovementMethod;
+Landroid/text/method/LinkMovementMethod;
+Landroid/text/method/SingleLineTransformationMethod;
+Landroid/text/style/ClickableSpan;
+Landroid/timezone/TelephonyLookup;
+Landroid/timezone/TimeZoneFinder;
Landroid/util/ArrayMap;
Landroid/util/ArraySet;
-Landroid/util/DisplayMetrics;
Landroid/util/EventLog;
-Landroid/util/Log;
-Landroid/util/Patterns;
-Landroid/view/AbsSavedState$1;
-Landroid/view/accessibility/AccessibilityManager;
-Landroid/view/accessibility/AccessibilityManager$AccessibilityServicesStateChangeListener;
-Landroid/view/accessibility/AccessibilityManager$TouchExplorationStateChangeListener;
-Landroid/view/accessibility/AccessibilityNodeIdManager;
-Landroid/view/autofill/AutofillManager;
-Landroid/view/autofill/Helper;
+Landroid/util/NtpTrustedTime;
Landroid/view/Choreographer;
-Landroid/view/inputmethod/InputMethodManager;
-Landroid/view/IWindowManager;
+Landroid/view/CrossWindowBlurListeners;
+Landroid/view/DisplayCutout;
+Landroid/view/KeyEvent;
+Landroid/view/MotionEvent;
Landroid/view/PointerIcon;
-Landroid/view/RemoteAnimationAdapter;
-Landroid/view/ThreadedRenderer;
+Landroid/view/RoundedCorners;
+Landroid/view/SurfaceControl;
Landroid/view/View;
-Landroid/view/View$OnHoverListener;
+Landroid/view/ViewGroup$TouchTarget;
Landroid/view/ViewRootImpl;
-Landroid/view/ViewStub;
-Landroid/view/ViewStub$OnInflateListener;
Landroid/view/ViewTreeObserver;
-Landroid/view/WindowManager$LayoutParams;
Landroid/view/WindowManagerGlobal;
-Landroid/widget/ActionMenuPresenter$OverflowMenuButton;
-Landroid/widget/ActionMenuView;
-Landroid/widget/Button;
-Landroid/widget/CheckBox;
-Landroid/widget/FrameLayout;
-Landroid/widget/ImageButton;
+Landroid/view/accessibility/AccessibilityManager;
+Landroid/view/accessibility/AccessibilityNodeIdManager;
+Landroid/view/autofill/Helper;
+Landroid/view/inputmethod/IInputMethodManagerGlobalInvoker;
+Landroid/view/inputmethod/InputMethodManager;
+Landroid/webkit/CookieSyncManager;
+Landroid/webkit/WebView;
+Landroid/webkit/WebViewFactory;
+Landroid/webkit/WebViewZygote;
+Landroid/widget/AbsListView;
Landroid/widget/ImageView;
Landroid/widget/LinearLayout;
-Landroid/widget/RelativeLayout;
-Landroid/widget/SeekBar;
-Landroid/widget/Space;
-Landroid/widget/TextView;
-Landroid/widget/Toolbar;
-[B
-Lcom/android/ims/ImsManager;
+Landroid/widget/Toast;
+Landroid/window/SurfaceSyncGroup;
+Lcom/android/i18n/timezone/TelephonyLookup;
+Lcom/android/i18n/timezone/TimeZoneFinder;
+Lcom/android/internal/config/appcloning/AppCloningDeviceConfigHelper;
+Lcom/android/internal/content/om/OverlayConfig;
+Lcom/android/internal/display/BrightnessSynchronizer;
+Lcom/android/internal/infra/AndroidFuture;
+Lcom/android/internal/inputmethod/ImeTracing;
+Lcom/android/internal/inputmethod/InputMethodPrivilegedOperationsRegistry;
+Lcom/android/internal/jank/InteractionJankMonitor$InstanceHolder;
+Lcom/android/internal/jank/InteractionJankMonitor;
Lcom/android/internal/logging/MetricsLogger;
Lcom/android/internal/os/BackgroundThread;
Lcom/android/internal/os/BinderInternal;
-Lcom/android/internal/os/BinderInternal$BinderProxyLimitListener;
+Lcom/android/internal/os/KernelCpuBpfTracking;
Lcom/android/internal/os/RuntimeInit;
Lcom/android/internal/os/SomeArgs;
-Lcom/android/internal/policy/DecorView;
-Lcom/android/internal/statusbar/IStatusBarService;
-Lcom/android/internal/telephony/AppSmsManager;
-Landroid/telephony/CallerInfoAsyncQuery$OnQueryCompleteListener;
-Lcom/android/internal/telephony/CarrierActionAgent;
-Lcom/android/internal/telephony/cat/CatService;
-Lcom/android/internal/telephony/cat/IconLoader;
-Lcom/android/internal/telephony/cat/RilMessageDecoder;
-Lcom/android/internal/telephony/cdma/CdmaSubscriptionSourceManager;
-Lcom/android/internal/telephony/cdma/EriManager;
-Lcom/android/internal/telephony/CellularNetworkValidator;
-Lcom/android/internal/telephony/CommandException;
-Lcom/android/internal/telephony/dataconnection/DataConnection$DcActivatingState;
-Lcom/android/internal/telephony/dataconnection/DataConnection$DcActiveState;
-Lcom/android/internal/telephony/dataconnection/DataConnection$DcInactiveState;
-Lcom/android/internal/telephony/dataconnection/DataEnabledSettings;
-Lcom/android/internal/telephony/dataconnection/DcTracker;
-Lcom/android/internal/telephony/euicc/EuiccCardController;
-Lcom/android/internal/telephony/euicc/EuiccController;
-Lcom/android/internal/telephony/GsmAlphabet;
-Lcom/android/internal/telephony/GsmCdmaCallTracker;
-Lcom/android/internal/telephony/GsmCdmaPhone;
-Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;
-Lcom/android/internal/telephony/IccSmsInterfaceManager;
-Lcom/android/internal/telephony/ims/ImsResolver;
-Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker;
-Lcom/android/internal/telephony/imsphone/ImsPhone;
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;
-Lcom/android/internal/telephony/ims/RcsMessageStoreController;
+Lcom/android/internal/os/ZygoteInit;
+Lcom/android/internal/policy/AttributeCache;
+Lcom/android/internal/protolog/BaseProtoLogImpl;
+Lcom/android/internal/protolog/ProtoLogImpl;
+Lcom/android/internal/statusbar/NotificationVisibility;
+Lcom/android/internal/telephony/CellBroadcastServiceManager;
Lcom/android/internal/telephony/IntentBroadcaster;
-Lcom/android/internal/telephony/ITelephonyRegistry$Stub$Proxy;
-Lcom/android/internal/telephony/metrics/TelephonyMetrics;
+Lcom/android/internal/telephony/MccTable;
Lcom/android/internal/telephony/MultiSimSettingController;
-Lcom/android/internal/telephony/nano/CarrierIdProto$CarrierAttribute;
-Lcom/android/internal/telephony/nano/CarrierIdProto$CarrierId;
-Lcom/android/internal/telephony/nano/TelephonyProto$RilDataCall;
-Lcom/android/internal/telephony/nano/TelephonyProto$SmsSession$Event;
-Lcom/android/internal/telephony/nano/TelephonyProto$TelephonyCallSession$Event$RilCall;
-Lcom/android/internal/telephony/NitzStateMachine;
+Lcom/android/internal/telephony/PackageChangeReceiver;
Lcom/android/internal/telephony/PhoneConfigurationManager;
Lcom/android/internal/telephony/PhoneFactory;
-Lcom/android/internal/telephony/PhoneSwitcher;
Lcom/android/internal/telephony/ProxyController;
-Lcom/android/internal/telephony/RadioConfig;
-Lcom/android/internal/telephony/RIL;
Lcom/android/internal/telephony/RILRequest;
-Lcom/android/internal/telephony/RilWakelockInfo;
-Lcom/android/internal/telephony/ServiceStateTracker;
-Lcom/android/internal/telephony/SimActivationTracker;
+Lcom/android/internal/telephony/RadioConfig;
+Lcom/android/internal/telephony/RadioInterfaceCapabilityController;
Lcom/android/internal/telephony/SmsApplication;
Lcom/android/internal/telephony/SmsBroadcastUndelivered;
-Lcom/android/internal/telephony/SmsStorageMonitor;
-Lcom/android/internal/telephony/SmsUsageMonitor;
-Lcom/android/internal/telephony/SubscriptionController;
-Lcom/android/internal/telephony/SubscriptionInfoUpdater;
+Lcom/android/internal/telephony/SomeArgs;
Lcom/android/internal/telephony/TelephonyComponentFactory;
Lcom/android/internal/telephony/TelephonyDevController;
-Lcom/android/internal/telephony/TelephonyTester;
-Lcom/android/internal/telephony/uicc/AdnRecordCache;
-Lcom/android/internal/telephony/uicc/UiccCardApplication;
+Lcom/android/internal/telephony/cat/CatService;
+Lcom/android/internal/telephony/cdma/CdmaInboundSmsHandler;
+Lcom/android/internal/telephony/cdma/CdmaSubscriptionSourceManager;
+Lcom/android/internal/telephony/euicc/EuiccCardController;
+Lcom/android/internal/telephony/euicc/EuiccController;
+Lcom/android/internal/telephony/ims/ImsResolver;
+Lcom/android/internal/telephony/metrics/TelephonyMetrics;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$CarrierIdMismatch;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$CellularDataServiceSwitch;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$CellularServiceState;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$DataCallSession;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$EmergencyNumbersInfo;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$GbaEvent;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsDedicatedBearerEvent;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsDedicatedBearerListenerEvent;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsRegistrationFeatureTagStats;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsRegistrationServiceDescStats;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsRegistrationStats;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsRegistrationTermination;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$IncomingSms;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$NetworkRequests;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$NetworkRequestsV2;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$OutgoingShortCodeSms;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$OutgoingSms;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$PresenceNotifyEvent;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$RcsAcsProvisioningStats;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$RcsClientProvisioningStats;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteController;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteIncomingDatagram;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteOutgoingDatagram;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteProvision;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteSession;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteSosMessageRecommender;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SipDelegateStats;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SipMessageResponse;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SipTransportFeatureTagStats;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SipTransportSession;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$UceEventStats;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$UnmeteredNetworks;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$VoiceCallRatUsage;
+Lcom/android/internal/telephony/nano/PersistAtomsProto$VoiceCallSession;
+Lcom/android/internal/telephony/nano/TelephonyProto$RilDataCall;
+Lcom/android/internal/telephony/nano/TelephonyProto$TelephonyCallSession$Event$RilCall;
+Lcom/android/internal/telephony/nano/TelephonyProto$TelephonyServiceState$NetworkRegistrationInfo;
+Lcom/android/internal/telephony/satellite/PointingAppController;
+Lcom/android/internal/telephony/satellite/SatelliteModemInterface;
Lcom/android/internal/telephony/uicc/UiccController;
-Lcom/android/internal/telephony/uicc/UiccProfile;
Lcom/android/internal/telephony/uicc/UiccStateChangedLauncher;
-Lcom/android/internal/telephony/uicc/UsimFileHandler;
-Lcom/android/internal/telephony/uicc/VoiceMailConstants;
-Lcom/android/internal/util/LatencyTracker;
-Lcom/android/internal/util/StateMachine$SmHandler;
-Lcom/android/okhttp/OkHttpClient;
-Lcom/android/okhttp/okio/AsyncTimeout;
-Lcom/android/okhttp/okio/SegmentPool;
+Lcom/android/internal/util/ContrastColorUtil;
+Lcom/android/internal/view/WindowManagerPolicyThread;
+Lcom/android/org/bouncycastle/crypto/CryptoServicesRegistrar;
Lcom/android/phone/ecc/nano/ProtobufEccData$CountryInfo;
Lcom/android/phone/ecc/nano/ProtobufEccData$EccInfo;
-Lcom/android/server/sip/SipWakeupTimer;
-Lcom/android/server/SystemConfig;
+Lcom/android/server/AppWidgetBackupBridge;
Ldalvik/system/BaseDexClassLoader;
Ldalvik/system/BlockGuard;
Ldalvik/system/CloseGuard;
Ldalvik/system/RuntimeHooks;
Ldalvik/system/SocketTagger;
-Ljava/io/BufferedReader;
-Ljava/lang/AssertionError;
-Ljava/lang/Boolean;
-Ljava/lang/Byte;
-Ljava/lang/Character;
-Ljava/lang/CharSequence;
-Ljava/lang/Class;
-Ljava/lang/IllegalAccessException;
-Ljava/lang/IllegalStateException;
-Ljava/lang/NoSuchMethodException;
-Ljava/lang/NullPointerException;
-Ljava/lang/Object;
-[Ljava/lang/Object;
-Ljava/lang/ref/FinalizerReference;
-Ljava/lang/Runnable;
-Ljava/lang/SecurityException;
-Ljava/lang/Short;
-[Ljava/lang/String;
+Ldalvik/system/VMRuntime;
+Ldalvik/system/ZipPathValidator;
+Ldalvik/system/ZygoteHooks;
Ljava/lang/System;
Ljava/lang/Thread;
Ljava/lang/Throwable;
-Ljava/lang/UnsatisfiedLinkError;
-Ljava/net/Inet6Address;
-Ljava/net/Socket;
-Ljava/net/SocketException;
+Ljava/lang/ref/FinalizerReference;
+Ljava/lang/ref/ReferenceQueue;
+Ljava/net/ResponseCache;
Ljava/nio/Bits;
Ljava/nio/charset/Charset;
-Ljava/security/interfaces/RSAPrivateKey;
Ljava/security/Provider;
Ljava/util/Collections;
-Ljava/util/concurrent/Executor;
Ljava/util/GregorianCalendar;
-Ljava/util/Locale;
Ljava/util/Locale$NoImagePreloadHolder;
+Ljava/util/Locale;
Ljava/util/Scanner;
-Ljava/util/Set;
Ljava/util/TimeZone;
+Ljava/util/concurrent/ForkJoinPool;
+Ljava/util/concurrent/ThreadLocalRandom;
+Ljavax/net/ServerSocketFactory;
Ljavax/net/SocketFactory;
-Ljavax/net/ssl/HttpsURLConnection;
Ljavax/net/ssl/HttpsURLConnection$NoPreloadHolder;
+Ljavax/net/ssl/HttpsURLConnection;
Ljavax/net/ssl/SSLContext;
-Ljavax/net/ssl/SSLSessionContext;
+Ljavax/net/ssl/SSLServerSocketFactory;
Ljavax/net/ssl/SSLSocketFactory;
Llibcore/io/Libcore;
-Llibcore/io/Memory;
Llibcore/net/NetworkSecurityPolicy;
-Llibcore/timezone/TimeZoneFinder;
-Lorg/apache/http/params/HttpParams;
Lsun/misc/Cleaner;
-Lsun/nio/ch/FileChannelImpl;
Lsun/nio/ch/FileChannelImpl$Unmapper;
-Lsun/nio/fs/UnixChannelFactory;
+Lsun/nio/ch/FileChannelImpl;
Lsun/security/jca/Providers;
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 332c53c..d97f718 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -3632,18 +3632,12 @@
}
public final class AutofillManager {
- method public void clearAutofillRequestCallback();
- method @RequiresPermission(android.Manifest.permission.PROVIDE_OWN_AUTOFILL_SUGGESTIONS) public void setAutofillRequestCallback(@NonNull java.util.concurrent.Executor, @NonNull android.view.autofill.AutofillRequestCallback);
field public static final String ANY_HINT = "any";
field public static final int FLAG_SMART_SUGGESTION_OFF = 0; // 0x0
field public static final int FLAG_SMART_SUGGESTION_SYSTEM = 1; // 0x1
field public static final int MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS = 120000; // 0x1d4c0
}
- public interface AutofillRequestCallback {
- method public void onFillRequest(@Nullable android.view.inputmethod.InlineSuggestionsRequest, @NonNull android.os.CancellationSignal, @NonNull android.service.autofill.FillCallback);
- }
-
}
package android.view.contentcapture {
@@ -3767,11 +3761,6 @@
method @NonNull public static android.view.inputmethod.InlineSuggestionInfo newInlineSuggestionInfo(@NonNull android.widget.inline.InlinePresentationSpec, @NonNull String, @Nullable String[], @NonNull String, boolean);
}
- public static final class InlineSuggestionsRequest.Builder {
- method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setClientSupported(boolean);
- method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setServiceSupported(boolean);
- }
-
public final class InlineSuggestionsResponse implements android.os.Parcelable {
method @NonNull public static android.view.inputmethod.InlineSuggestionsResponse newInlineSuggestionsResponse(@NonNull java.util.List<android.view.inputmethod.InlineSuggestion>);
}
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 61d6787..2ae7216 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -403,8 +403,11 @@
private static final String KEY_SPLASH_SCREEN_STYLE =
"android.activity.splashScreenStyle";
- /** See {@link #setTransientLaunch()}. */
- private static final String KEY_TRANSIENT_LAUNCH = "android.activity.transientLaunch";
+ /**
+ * See {@link #setTransientLaunch()}.
+ * @hide
+ */
+ public static final String KEY_TRANSIENT_LAUNCH = "android.activity.transientLaunch";
/** see {@link #makeLaunchIntoPip(PictureInPictureParams)}. */
private static final String KEY_LAUNCH_INTO_PIP_PARAMS =
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index 36e5762..3c6ff28 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -137,7 +137,7 @@
* activities inside it belong to a managed profile user, and that user has just
* been locked.
*/
- void onTaskProfileLocked(in ActivityManager.RunningTaskInfo taskInfo);
+ void onTaskProfileLocked(in ActivityManager.RunningTaskInfo taskInfo, int userId);
/**
* Called when a task snapshot got updated.
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 99a7fa2..705b5ee 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -407,7 +407,7 @@
}
private static void checkPendingIntent(int flags, @NonNull Intent intent,
- @NonNull Context context) {
+ @NonNull Context context, boolean isActivityResultType) {
final boolean isFlagImmutableSet = (flags & PendingIntent.FLAG_IMMUTABLE) != 0;
final boolean isFlagMutableSet = (flags & PendingIntent.FLAG_MUTABLE) != 0;
final String packageName = context.getPackageName();
@@ -428,11 +428,12 @@
throw new IllegalArgumentException(msg);
}
- // For apps with target SDK < U, warn that creation or retrieval of a mutable
- // implicit PendingIntent will be blocked from target SDK U onwards for security
- // reasons. The block itself happens on the server side, but this warning has to
- // stay here to preserve the client side stack trace for app developers.
- if (isNewMutableDisallowedImplicitPendingIntent(flags, intent)
+ // For apps with target SDK < U, warn that creation or retrieval of a mutable implicit
+ // PendingIntent that is not of type {@link ActivityManager#INTENT_SENDER_ACTIVITY_RESULT}
+ // will be blocked from target SDK U onwards for security reasons. The block itself
+ // happens on the server side, but this warning has to stay here to preserve the client
+ // side stack trace for app developers.
+ if (isNewMutableDisallowedImplicitPendingIntent(flags, intent, isActivityResultType)
&& !Compatibility.isChangeEnabled(BLOCK_MUTABLE_IMPLICIT_PENDING_INTENT)) {
String msg = "New mutable implicit PendingIntent: pkg=" + packageName
+ ", action=" + intent.getAction()
@@ -445,7 +446,13 @@
/** @hide */
public static boolean isNewMutableDisallowedImplicitPendingIntent(int flags,
- @NonNull Intent intent) {
+ @NonNull Intent intent, boolean isActivityResultType) {
+ if (isActivityResultType) {
+ // Pending intents of type {@link ActivityManager#INTENT_SENDER_ACTIVITY_RESULT}
+ // should be ignored as they are intrinsically tied to a target which means they
+ // are already explicit.
+ return false;
+ }
boolean isFlagNoCreateSet = (flags & PendingIntent.FLAG_NO_CREATE) != 0;
boolean isFlagMutableSet = (flags & PendingIntent.FLAG_MUTABLE) != 0;
boolean isImplicit = (intent.getComponent() == null) && (intent.getPackage() == null);
@@ -534,7 +541,7 @@
@NonNull Intent intent, int flags, Bundle options, UserHandle user) {
String packageName = context.getPackageName();
String resolvedType = intent.resolveTypeIfNeeded(context.getContentResolver());
- checkPendingIntent(flags, intent, context);
+ checkPendingIntent(flags, intent, context, /* isActivityResultType */ false);
try {
intent.migrateExtraStreamToClipData(context);
intent.prepareToLeaveProcess(context);
@@ -668,7 +675,7 @@
intents[i].migrateExtraStreamToClipData(context);
intents[i].prepareToLeaveProcess(context);
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
- checkPendingIntent(flags, intents[i], context);
+ checkPendingIntent(flags, intents[i], context, /* isActivityResultType */ false);
}
try {
IIntentSender target =
@@ -721,7 +728,7 @@
Intent intent, int flags, UserHandle userHandle) {
String packageName = context.getPackageName();
String resolvedType = intent.resolveTypeIfNeeded(context.getContentResolver());
- checkPendingIntent(flags, intent, context);
+ checkPendingIntent(flags, intent, context, /* isActivityResultType */ false);
try {
intent.prepareToLeaveProcess(context);
IIntentSender target =
@@ -800,7 +807,7 @@
Intent intent, int flags, int serviceKind) {
String packageName = context.getPackageName();
String resolvedType = intent.resolveTypeIfNeeded(context.getContentResolver());
- checkPendingIntent(flags, intent, context);
+ checkPendingIntent(flags, intent, context, /* isActivityResultType */ false);
try {
intent.prepareToLeaveProcess(context);
IIntentSender target =
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index 774bc06..0290cee 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -154,8 +154,18 @@
}
@Override
+ public void onTaskProfileLocked(RunningTaskInfo taskInfo, int userId)
+ throws RemoteException {
+ onTaskProfileLocked(taskInfo);
+ }
+
+ /**
+ * @deprecated see {@link #onTaskProfileLocked(RunningTaskInfo, int)}
+ */
+ @Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public void onTaskProfileLocked(RunningTaskInfo taskInfo) throws RemoteException {
+ public void onTaskProfileLocked(RunningTaskInfo taskInfo)
+ throws RemoteException {
}
@Override
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 27f5545..e0364cb 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -13401,11 +13401,10 @@
/**
* Called by a device admin or holder of the permission
* {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE} to set the short
- * support message. This will be displayed to the user
- * in settings screens where funtionality has been disabled by the admin. The message should be
- * limited to a short statement such as "This setting is disabled by your administrator. Contact
- * someone@example.com for support." If the message is longer than 200 characters it may be
- * truncated.
+ * support message. This will be displayed to the user in settings screens where functionality
+ * has been disabled by the admin. The message should be limited to a short statement such as
+ * "This setting is disabled by your administrator. Contact someone@example.com for support."
+ * If the message is longer than 200 characters it may be truncated.
* <p>
* If the short support message needs to be localized, it is the responsibility of the
* {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
@@ -13460,7 +13459,8 @@
/**
* Called by a device admin to set the long support message. This will be displayed to the user
- * in the device administators settings screen.
+ * in the device administrators settings screen. If the message is longer than 20000 characters
+ * it may be truncated.
* <p>
* If the long support message needs to be localized, it is the responsibility of the
* {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
diff --git a/core/java/android/credentials/ui/RequestInfo.java b/core/java/android/credentials/ui/RequestInfo.java
index 09d2db8..9ebb058 100644
--- a/core/java/android/credentials/ui/RequestInfo.java
+++ b/core/java/android/credentials/ui/RequestInfo.java
@@ -30,6 +30,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
/**
* Contains information about the request that initiated this UX flow.
@@ -64,6 +66,9 @@
@Nullable
private final CreateCredentialRequest mCreateCredentialRequest;
+ @NonNull
+ private final List<String> mDefaultProviderIds;
+
@Nullable
private final GetCredentialRequest mGetCredentialRequest;
@@ -83,7 +88,8 @@
@NonNull String appPackageName) {
return new RequestInfo(
token, TYPE_CREATE, appPackageName, createCredentialRequest, null,
- /*hasPermissionToOverrideDefault=*/ false);
+ /*hasPermissionToOverrideDefault=*/ false,
+ /*defaultProviderIds=*/ new ArrayList<>());
}
/**
@@ -94,10 +100,11 @@
@NonNull
public static RequestInfo newCreateRequestInfo(
@NonNull IBinder token, @NonNull CreateCredentialRequest createCredentialRequest,
- @NonNull String appPackageName, boolean hasPermissionToOverrideDefault) {
+ @NonNull String appPackageName, boolean hasPermissionToOverrideDefault,
+ @NonNull List<String> defaultProviderIds) {
return new RequestInfo(
token, TYPE_CREATE, appPackageName, createCredentialRequest, null,
- hasPermissionToOverrideDefault);
+ hasPermissionToOverrideDefault, defaultProviderIds);
}
/** Creates new {@code RequestInfo} for a get-credential flow. */
@@ -107,7 +114,8 @@
@NonNull String appPackageName) {
return new RequestInfo(
token, TYPE_GET, appPackageName, null, getCredentialRequest,
- /*hasPermissionToOverrideDefault=*/ false);
+ /*hasPermissionToOverrideDefault=*/ false,
+ /*defaultProviderIds=*/ new ArrayList<>());
}
@@ -149,6 +157,20 @@
}
/**
+ * Returns default provider identifier (flattened component name) configured from the user
+ * settings.
+ *
+ * Will only be possibly non-empty for the create use case. Not meaningful for the sign-in use
+ * case.
+ *
+ * @hide
+ */
+ @NonNull
+ public List<String> getDefaultProviderIds() {
+ return mDefaultProviderIds;
+ }
+
+ /**
* Returns the non-null GetCredentialRequest when the type of the request is {@link
* #TYPE_GET}, or null otherwise.
*/
@@ -161,13 +183,15 @@
@NonNull String appPackageName,
@Nullable CreateCredentialRequest createCredentialRequest,
@Nullable GetCredentialRequest getCredentialRequest,
- boolean hasPermissionToOverrideDefault) {
+ boolean hasPermissionToOverrideDefault,
+ @NonNull List<String> defaultProviderIds) {
mToken = token;
mType = type;
mAppPackageName = appPackageName;
mCreateCredentialRequest = createCredentialRequest;
mGetCredentialRequest = getCredentialRequest;
mHasPermissionToOverrideDefault = hasPermissionToOverrideDefault;
+ mDefaultProviderIds = defaultProviderIds == null ? new ArrayList<>() : defaultProviderIds;
}
private RequestInfo(@NonNull Parcel in) {
@@ -188,6 +212,7 @@
mCreateCredentialRequest = createCredentialRequest;
mGetCredentialRequest = getCredentialRequest;
mHasPermissionToOverrideDefault = in.readBoolean();
+ mDefaultProviderIds = in.createStringArrayList();
}
@Override
@@ -198,6 +223,7 @@
dest.writeTypedObject(mCreateCredentialRequest, flags);
dest.writeTypedObject(mGetCredentialRequest, flags);
dest.writeBoolean(mHasPermissionToOverrideDefault);
+ dest.writeStringList(mDefaultProviderIds);
}
@Override
diff --git a/core/java/android/net/metrics/WakeupStats.java b/core/java/android/net/metrics/WakeupStats.java
index bb36536..fac747c 100644
--- a/core/java/android/net/metrics/WakeupStats.java
+++ b/core/java/android/net/metrics/WakeupStats.java
@@ -80,18 +80,20 @@
break;
}
- switch (ev.dstHwAddr.getAddressType()) {
- case MacAddress.TYPE_UNICAST:
- l2UnicastCount++;
- break;
- case MacAddress.TYPE_MULTICAST:
- l2MulticastCount++;
- break;
- case MacAddress.TYPE_BROADCAST:
- l2BroadcastCount++;
- break;
- default:
- break;
+ if (ev.dstHwAddr != null) {
+ switch (ev.dstHwAddr.getAddressType()) {
+ case MacAddress.TYPE_UNICAST:
+ l2UnicastCount++;
+ break;
+ case MacAddress.TYPE_MULTICAST:
+ l2MulticastCount++;
+ break;
+ case MacAddress.TYPE_BROADCAST:
+ l2BroadcastCount++;
+ break;
+ default:
+ break;
+ }
}
increment(ethertypes, ev.ethertype);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3487b01..4a46beb 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4677,16 +4677,22 @@
"display_color_mode_vendor_hint";
/**
- * Whether or not the peak refresh rate should be forced. 0=no, 1=yes
+ * The user selected min refresh rate in frames per second.
+ *
+ * If this isn't set, 0 will be used.
* @hide
*/
- public static final String FORCE_PEAK_REFRESH_RATE = "force_peak_refresh_rate";
+ @Readable
+ public static final String MIN_REFRESH_RATE = "min_refresh_rate";
/**
- * Whether or not the peak refresh rate should be used for some content. 0=no, 1=yes
+ * The user selected peak refresh rate in frames per second.
+ *
+ * If this isn't set, the system falls back to a device specific default.
* @hide
*/
- public static final String SMOOTH_DISPLAY = "smooth_display";
+ @Readable
+ public static final String PEAK_REFRESH_RATE = "peak_refresh_rate";
/**
* The amount of time in milliseconds before the device goes to sleep or begins
@@ -11496,6 +11502,8 @@
public static final int DEVICE_STATE_ROTATION_KEY_HALF_FOLDED = 1;
/** @hide */
public static final int DEVICE_STATE_ROTATION_KEY_UNFOLDED = 2;
+ /** @hide */
+ public static final int DEVICE_STATE_ROTATION_KEY_REAR_DISPLAY = 3;
/**
* The different postures that can be used as keys with
@@ -11507,6 +11515,7 @@
DEVICE_STATE_ROTATION_KEY_FOLDED,
DEVICE_STATE_ROTATION_KEY_HALF_FOLDED,
DEVICE_STATE_ROTATION_KEY_UNFOLDED,
+ DEVICE_STATE_ROTATION_KEY_REAR_DISPLAY,
})
@Retention(RetentionPolicy.SOURCE)
public @interface DeviceStateRotationLockKey {
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index 4a848dd..8afae74 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -97,8 +97,6 @@
*/
public static final @RequestFlags int FLAG_VIEW_NOT_FOCUSED = 0x10;
- // The flag value 0x20 has been defined in AutofillManager.
-
/**
* Indicates the request supports fill dialog presentation for the fields, the
* system will send the request when the activity just started.
diff --git a/core/java/android/service/credentials/CredentialProviderInfoFactory.java b/core/java/android/service/credentials/CredentialProviderInfoFactory.java
index 1a1df6f..751c675 100644
--- a/core/java/android/service/credentials/CredentialProviderInfoFactory.java
+++ b/core/java/android/service/credentials/CredentialProviderInfoFactory.java
@@ -75,12 +75,13 @@
/**
* Constructs an information instance of the credential provider.
*
- * @param context the context object
+ * @param context the context object
* @param serviceComponent the serviceComponent of the provider service
- * @param userId the android userId for which the current process is running
+ * @param userId the android userId for which the current process is running
* @param isSystemProvider whether this provider is a system provider
* @throws PackageManager.NameNotFoundException If provider service is not found
- * @throws SecurityException If provider does not require the relevant permission
+ * @throws SecurityException If provider does not require the relevant
+ * permission
*/
public static CredentialProviderInfo create(
@NonNull Context context,
@@ -99,13 +100,15 @@
/**
* Constructs an information instance of the credential provider.
*
- * @param context the context object
- * @param serviceInfo the service info for the provider app. This must be retrieved from the
- * {@code PackageManager}
- * @param isSystemProvider whether the provider app is a system provider
+ * @param context the context object
+ * @param serviceInfo the service info for the provider app. This must
+ * be retrieved from the
+ * {@code PackageManager}
+ * @param isSystemProvider whether the provider app is a system provider
* @param disableSystemAppVerificationForTests whether to disable system app permission
- * verification so that tests can install system providers
- * @param isEnabled whether the user enabled this provider
+ * verification so that tests can install system
+ * providers
+ * @param isEnabled whether the user enabled this provider
* @throws SecurityException If provider does not require the relevant permission
*/
public static CredentialProviderInfo create(
@@ -374,7 +377,6 @@
if (appInfo == null || serviceInfo == null) {
continue;
}
-
services.add(serviceInfo);
} catch (SecurityException | PackageManager.NameNotFoundException e) {
Slog.e(TAG, "Error getting info for " + serviceInfo, e);
diff --git a/core/java/android/service/credentials/CredentialProviderService.java b/core/java/android/service/credentials/CredentialProviderService.java
index 53a5fd5..cf2e6a6 100644
--- a/core/java/android/service/credentials/CredentialProviderService.java
+++ b/core/java/android/service/credentials/CredentialProviderService.java
@@ -18,7 +18,6 @@
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
-import android.Manifest;
import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.SdkConstant;
@@ -35,7 +34,7 @@
import android.os.Looper;
import android.os.OutcomeReceiver;
import android.os.RemoteException;
-import android.util.Log;
+import android.util.Slog;
import java.util.Objects;
@@ -226,7 +225,7 @@
if (SERVICE_INTERFACE.equals(intent.getAction())) {
return mInterface.asBinder();
}
- Log.d(TAG, "Failed to bind with intent: " + intent);
+ Slog.w(TAG, "Failed to bind with intent: " + intent);
return null;
}
@@ -252,11 +251,6 @@
GetCredentialException>() {
@Override
public void onResult(BeginGetCredentialResponse result) {
- // If provider service does not possess the HYBRID permission, this
- // check will throw an exception in the provider process.
- if (result.getRemoteCredentialEntry() != null) {
- enforceRemoteEntryPermission();
- }
try {
callback.onSuccess(result);
} catch (RemoteException e) {
@@ -274,15 +268,6 @@
}
));
}
- private void enforceRemoteEntryPermission() {
- String permission =
- Manifest.permission.PROVIDE_REMOTE_CREDENTIALS;
- getApplicationContext().enforceCallingOrSelfPermission(
- permission,
- String.format("Provider must have %s, in order to set a "
- + "remote entry", permission)
- );
- }
@Override
public void onBeginCreateCredential(BeginCreateCredentialRequest request,
@@ -305,11 +290,6 @@
BeginCreateCredentialResponse, CreateCredentialException>() {
@Override
public void onResult(BeginCreateCredentialResponse result) {
- // If provider service does not possess the HYBRID permission, this
- // check will throw an exception in the provider process.
- if (result.getRemoteCreateEntry() != null) {
- enforceRemoteEntryPermission();
- }
try {
callback.onSuccess(result);
} catch (RemoteException e) {
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 79a4f54..7822dde 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -913,8 +913,6 @@
* sandboxed process.
* @param callback The callback to notify of detection events.
* @return An instanece of {@link VisualQueryDetector}.
- * @throws UnsupportedOperationException if only single detector is supported. Multiple detector
- * is only available for apps targeting {@link Build.VERSION_CODES#TIRAMISU} and above.
* @throws IllegalStateException when there is an existing {@link VisualQueryDetector}, or when
* there is a non-trusted hotword detector running.
*
@@ -935,21 +933,16 @@
throw new IllegalStateException("Not available until onReady() is called");
}
synchronized (mLock) {
- if (!CompatChanges.isChangeEnabled(MULTIPLE_ACTIVE_HOTWORD_DETECTORS)) {
- throw new UnsupportedOperationException("VisualQueryDetector is only available if "
- + "multiple detectors are allowed");
- } else {
- if (mActiveVisualQueryDetector != null) {
+ if (mActiveVisualQueryDetector != null) {
+ throw new IllegalStateException(
+ "There is already an active VisualQueryDetector. "
+ + "It must be destroyed to create a new one.");
+ }
+ for (HotwordDetector detector : mActiveDetectors) {
+ if (!detector.isUsingSandboxedDetectionService()) {
throw new IllegalStateException(
- "There is already an active VisualQueryDetector. "
- + "It must be destroyed to create a new one.");
- }
- for (HotwordDetector detector : mActiveDetectors) {
- if (!detector.isUsingSandboxedDetectionService()) {
- throw new IllegalStateException(
- "It disallows to create trusted and non-trusted detectors "
- + "at the same time.");
- }
+ "It disallows to create trusted and non-trusted detectors "
+ + "at the same time.");
}
}
@@ -1070,21 +1063,6 @@
mActiveVisualQueryDetector = null;
}
mActiveDetectors.remove(detector);
- shutdownHotwordDetectionServiceIfRequiredLocked();
- }
- }
-
- private void shutdownHotwordDetectionServiceIfRequiredLocked() {
- for (HotwordDetector detector : mActiveDetectors) {
- if (detector.isUsingSandboxedDetectionService()) {
- return;
- }
- }
-
- try {
- mSystemService.shutdownHotwordDetectionService();
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
}
}
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index f2373fb..d8fa533 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -360,6 +360,14 @@
public SparseArray<SurfaceControl.RefreshRateRange> thermalRefreshRateThrottling =
new SparseArray<>();
+ /**
+ * The ID of the brightness throttling data that should be used. This can change e.g. in
+ * concurrent displays mode in which a stricter brightness throttling policy might need to be
+ * used.
+ */
+ @Nullable
+ public String thermalBrightnessThrottlingDataId;
+
public static final @android.annotation.NonNull Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() {
@Override
public DisplayInfo createFromParcel(Parcel source) {
@@ -437,7 +445,9 @@
&& Objects.equals(displayShape, other.displayShape)
&& Objects.equals(layoutLimitedRefreshRate, other.layoutLimitedRefreshRate)
&& BrightnessSynchronizer.floatEquals(hdrSdrRatio, other.hdrSdrRatio)
- && thermalRefreshRateThrottling.contentEquals(other.thermalRefreshRateThrottling);
+ && thermalRefreshRateThrottling.contentEquals(other.thermalRefreshRateThrottling)
+ && Objects.equals(
+ thermalBrightnessThrottlingDataId, other.thermalBrightnessThrottlingDataId);
}
@Override
@@ -495,6 +505,7 @@
layoutLimitedRefreshRate = other.layoutLimitedRefreshRate;
hdrSdrRatio = other.hdrSdrRatio;
thermalRefreshRateThrottling = other.thermalRefreshRateThrottling;
+ thermalBrightnessThrottlingDataId = other.thermalBrightnessThrottlingDataId;
}
public void readFromParcel(Parcel source) {
@@ -559,6 +570,7 @@
hdrSdrRatio = source.readFloat();
thermalRefreshRateThrottling = source.readSparseArray(null,
SurfaceControl.RefreshRateRange.class);
+ thermalBrightnessThrottlingDataId = source.readString8();
}
@Override
@@ -620,6 +632,7 @@
dest.writeTypedObject(layoutLimitedRefreshRate, flags);
dest.writeFloat(hdrSdrRatio);
dest.writeSparseArray(thermalRefreshRateThrottling);
+ dest.writeString8(thermalBrightnessThrottlingDataId);
}
@Override
@@ -889,6 +902,8 @@
}
sb.append(", thermalRefreshRateThrottling ");
sb.append(thermalRefreshRateThrottling);
+ sb.append(", thermalBrightnessThrottlingDataId ");
+ sb.append(thermalBrightnessThrottlingDataId);
sb.append("}");
return sb.toString();
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index f7b7d33..e39b3a1 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -16,7 +16,6 @@
package android.view.autofill;
-import static android.Manifest.permission.PROVIDE_OWN_AUTOFILL_SUGGESTIONS;
import static android.service.autofill.FillRequest.FLAG_IME_SHOWING;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
@@ -30,7 +29,6 @@
import static android.view.autofill.Helper.toList;
import android.accessibilityservice.AccessibilityServiceInfo;
-import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -52,21 +50,16 @@
import android.content.pm.ResolveInfo;
import android.graphics.Rect;
import android.metrics.LogMaker;
-import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
-import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IBinder;
-import android.os.ICancellationSignal;
import android.os.Looper;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.SystemClock;
import android.service.autofill.AutofillService;
-import android.service.autofill.FillCallback;
import android.service.autofill.FillEventHistory;
-import android.service.autofill.IFillCallback;
import android.service.autofill.UserData;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -87,7 +80,6 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeProvider;
import android.view.accessibility.AccessibilityWindowInfo;
-import android.view.inputmethod.InlineSuggestionsRequest;
import android.view.inputmethod.InputMethodManager;
import android.widget.CheckBox;
import android.widget.DatePicker;
@@ -187,12 +179,6 @@
* shows an autofill save UI if the value of savable views have changed. If the user selects the
* option to Save, the current value of the views is then sent to the autofill service.
*
- * <p>There is another choice for the application to provide it's datasets to the Autofill framework
- * by setting an {@link AutofillRequestCallback} through
- * {@link #setAutofillRequestCallback(Executor, AutofillRequestCallback)}. The application can use
- * its callback instead of the default {@link AutofillService}. See
- * {@link AutofillRequestCallback} for more details.
- *
* <h3 id="additional-notes">Additional notes</h3>
*
* <p>It is safe to call <code>AutofillManager</code> methods from any thread.
@@ -326,7 +312,6 @@
/** @hide */ public static final int FLAG_ADD_CLIENT_DEBUG = 0x2;
/** @hide */ public static final int FLAG_ADD_CLIENT_VERBOSE = 0x4;
/** @hide */ public static final int FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY = 0x8;
- /** @hide */ public static final int FLAG_ENABLED_CLIENT_SUGGESTIONS = 0x20;
// NOTE: flag below is used by the session start receiver only, hence it can have values above
/** @hide */ public static final int RECEIVER_FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY = 0x1;
@@ -653,11 +638,6 @@
@GuardedBy("mLock")
private boolean mEnabledForAugmentedAutofillOnly;
- @GuardedBy("mLock")
- @Nullable private AutofillRequestCallback mAutofillRequestCallback;
- @GuardedBy("mLock")
- @Nullable private Executor mRequestCallbackExecutor;
-
/**
* Indicates whether there is already a field to do a fill request after
* the activity started.
@@ -2338,44 +2318,6 @@
return new AutofillId(parent.getAutofillViewId(), virtualId);
}
- /**
- * Sets the client's suggestions callback for autofill.
- *
- * @see AutofillRequestCallback
- *
- * @param executor specifies the thread upon which the callbacks will be invoked.
- * @param callback which handles autofill request to provide client's suggestions.
- *
- * @hide
- */
- @TestApi
- @RequiresPermission(PROVIDE_OWN_AUTOFILL_SUGGESTIONS)
- public void setAutofillRequestCallback(@NonNull @CallbackExecutor Executor executor,
- @NonNull AutofillRequestCallback callback) {
- if (mContext.checkSelfPermission(PROVIDE_OWN_AUTOFILL_SUGGESTIONS)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires PROVIDE_OWN_AUTOFILL_SUGGESTIONS permission!");
- }
-
- synchronized (mLock) {
- mRequestCallbackExecutor = executor;
- mAutofillRequestCallback = callback;
- }
- }
-
- /**
- * clears the client's suggestions callback for autofill.
- *
- * @hide
- */
- @TestApi
- public void clearAutofillRequestCallback() {
- synchronized (mLock) {
- mRequestCallbackExecutor = null;
- mAutofillRequestCallback = null;
- }
- }
-
@GuardedBy("mLock")
private void startSessionLocked(@NonNull AutofillId id, @NonNull Rect bounds,
@NonNull AutofillValue value, int flags) {
@@ -2436,13 +2378,6 @@
}
}
- if (mAutofillRequestCallback != null) {
- if (sDebug) {
- Log.d(TAG, "startSession with the client suggestions provider");
- }
- flags |= FLAG_ENABLED_CLIENT_SUGGESTIONS;
- }
-
mService.startSession(client.autofillClientGetActivityToken(),
mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
mCallback != null, flags, clientActivity,
@@ -2796,28 +2731,6 @@
}
}
- private void onFillRequest(InlineSuggestionsRequest request,
- CancellationSignal cancellationSignal, FillCallback callback) {
- final AutofillRequestCallback autofillRequestCallback;
- final Executor executor;
- synchronized (mLock) {
- autofillRequestCallback = mAutofillRequestCallback;
- executor = mRequestCallbackExecutor;
- }
- if (autofillRequestCallback != null && executor != null) {
- final long ident = Binder.clearCallingIdentity();
- try {
- executor.execute(() ->
- autofillRequestCallback.onFillRequest(
- request, cancellationSignal, callback));
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- } else {
- callback.onSuccess(null);
- }
- }
-
/** @hide */
public static final int SET_STATE_FLAG_ENABLED = 0x01;
/** @hide */
@@ -4374,23 +4287,6 @@
}
@Override
- public void requestFillFromClient(int id, InlineSuggestionsRequest request,
- IFillCallback callback) {
- final AutofillManager afm = mAfm.get();
- if (afm != null) {
- ICancellationSignal transport = CancellationSignal.createTransport();
- try {
- callback.onCancellable(transport);
- } catch (RemoteException e) {
- Slog.w(TAG, "Error requesting a cancellation", e);
- }
-
- afm.onFillRequest(request, CancellationSignal.fromTransport(transport),
- new FillCallback(callback, id));
- }
- }
-
- @Override
public void notifyFillDialogTriggerIds(List<AutofillId> ids) {
final AutofillManager afm = mAfm.get();
if (afm != null) {
diff --git a/core/java/android/view/autofill/AutofillRequestCallback.java b/core/java/android/view/autofill/AutofillRequestCallback.java
deleted file mode 100644
index 10a088b..0000000
--- a/core/java/android/view/autofill/AutofillRequestCallback.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view.autofill;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.TestApi;
-import android.os.CancellationSignal;
-import android.service.autofill.FillCallback;
-import android.view.inputmethod.InlineSuggestionsRequest;
-
-/**
- * <p>This class is used to provide some input suggestions to the Autofill framework.
- *
- * <P>When the user is requested to input something, Autofill will try to query input suggestions
- * for the user choosing. If the application want to provide some internal input suggestions,
- * implements this callback and register via
- * {@link AutofillManager#setAutofillRequestCallback(java.util.concurrent.Executor,
- * AutofillRequestCallback)}. Autofill will callback the
- * {@link #onFillRequest(InlineSuggestionsRequest, CancellationSignal, FillCallback)} to request
- * input suggestions.
- *
- * <P>To make sure the callback to take effect, must register before the autofill session starts.
- * If the autofill session is started, calls {@link AutofillManager#cancel()} to finish current
- * session, and then the callback will be used at the next restarted session.
- *
- * <P>To create a {@link android.service.autofill.FillResponse}, application should fetch
- * {@link AutofillId}s from its view structure. Below is an example:
- * <pre class="prettyprint">
- * AutofillId usernameId = findViewById(R.id.username).getAutofillId();
- * AutofillId passwordId = findViewById(R.id.password).getAutofillId();
- * </pre>
- * To learn more about creating a {@link android.service.autofill.FillResponse}, read
- * <a href="/guide/topics/text/autofill-services#fill">Fill out client views</a>.
- *
- * <P>To fallback to the default {@link android.service.autofill.AutofillService}, just respond
- * a null of the {@link android.service.autofill.FillResponse}. And then Autofill will do a fill
- * request with the default {@link android.service.autofill.AutofillService}. Or clear the callback
- * from {@link AutofillManager} via {@link AutofillManager#clearAutofillRequestCallback()}. If the
- * client would like to keep no suggestions for the field, respond with an empty
- * {@link android.service.autofill.FillResponse} which has no dataset.
- *
- * <P>IMPORTANT: This should not be used for displaying anything other than input suggestions, or
- * the keyboard may choose to block your app from the inline strip.
- *
- * @hide
- */
-@TestApi
-public interface AutofillRequestCallback {
- /**
- * Called by the Android system to decide if a screen can be autofilled by the callback.
- *
- * @param inlineSuggestionsRequest the {@link InlineSuggestionsRequest request} to handle if
- * currently inline suggestions are supported and can be displayed.
- * @param cancellationSignal signal for observing cancellation requests. The system will use
- * this to notify you that the fill result is no longer needed and you should stop
- * handling this fill request in order to save resources.
- * @param callback object used to notify the result of the request.
- */
- void onFillRequest(@Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
- @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback);
-}
diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
index 2e5967c..51afe4c 100644
--- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
@@ -24,11 +24,9 @@
import android.content.IntentSender;
import android.graphics.Rect;
import android.os.IBinder;
-import android.service.autofill.IFillCallback;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
import android.view.autofill.IAutofillWindowPresenter;
-import android.view.inputmethod.InlineSuggestionsRequest;
import android.view.KeyEvent;
import com.android.internal.os.IResultReceiver;
@@ -144,12 +142,6 @@
void requestShowSoftInput(in AutofillId id);
/**
- * Requests to determine if a screen can be autofilled by the client app.
- */
- void requestFillFromClient(int id, in InlineSuggestionsRequest request,
- in IFillCallback callback);
-
- /**
* Notifies autofill ids that require to show the fill dialog.
*/
void notifyFillDialogTriggerIds(in List<AutofillId> ids);
diff --git a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
index 77a2b5b..581feca 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
@@ -112,22 +112,6 @@
private @Nullable InlinePresentationSpec mInlineTooltipPresentationSpec;
/**
- * Whether the IME supports inline suggestions from the default Autofill service that
- * provides the input view.
- *
- * Note: The default value is {@code true}.
- */
- private boolean mServiceSupported;
-
- /**
- * Whether the IME supports inline suggestions from the application that provides the
- * input view.
- *
- * Note: The default value is {@code true}.
- */
- private boolean mClientSupported;
-
- /**
* @hide
* @see {@link #mHostInputToken}.
*/
@@ -221,15 +205,9 @@
return Bundle.EMPTY;
}
- private static boolean defaultServiceSupported() {
- return true;
- }
-
- private static boolean defaultClientSupported() {
- return true;
- }
-
- /** @hide */
+ /**
+ * @hide
+ */
abstract static class BaseBuilder {
abstract Builder setInlinePresentationSpecs(
@NonNull List<android.widget.inline.InlinePresentationSpec> specs);
@@ -241,25 +219,14 @@
abstract Builder setHostDisplayId(int value);
}
- /** @hide */
- public boolean isServiceSupported() {
- return mServiceSupported;
- }
- /** @hide */
- public boolean isClientSupported() {
- return mClientSupported;
- }
-
-
-
- // Code below generated by codegen v1.0.22.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
+ // $ codegen $ANDROID_BUILD_TOP/./frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -275,9 +242,7 @@
@NonNull Bundle extras,
@Nullable IBinder hostInputToken,
int hostDisplayId,
- @Nullable InlinePresentationSpec inlineTooltipPresentationSpec,
- boolean serviceSupported,
- boolean clientSupported) {
+ @Nullable InlinePresentationSpec inlineTooltipPresentationSpec) {
this.mMaxSuggestionCount = maxSuggestionCount;
this.mInlinePresentationSpecs = inlinePresentationSpecs;
com.android.internal.util.AnnotationValidations.validate(
@@ -294,8 +259,6 @@
this.mHostInputToken = hostInputToken;
this.mHostDisplayId = hostDisplayId;
this.mInlineTooltipPresentationSpec = inlineTooltipPresentationSpec;
- this.mServiceSupported = serviceSupported;
- this.mClientSupported = clientSupported;
onConstructed();
}
@@ -379,9 +342,7 @@
}
/**
- * The {@link InlinePresentationSpec} for the inline suggestion tooltip in the response.
- *
- * @see android.service.autofill.InlinePresentation#createTooltipPresentation(Slice, InlinePresentationSpec)
+ * Specifies the UI specification for the inline suggestion tooltip in the response.
*/
@DataClass.Generated.Member
public @Nullable InlinePresentationSpec getInlineTooltipPresentationSpec() {
@@ -402,9 +363,7 @@
"extras = " + mExtras + ", " +
"hostInputToken = " + mHostInputToken + ", " +
"hostDisplayId = " + mHostDisplayId + ", " +
- "inlineTooltipPresentationSpec = " + mInlineTooltipPresentationSpec + ", " +
- "serviceSupported = " + mServiceSupported + ", " +
- "clientSupported = " + mClientSupported +
+ "inlineTooltipPresentationSpec = " + mInlineTooltipPresentationSpec +
" }";
}
@@ -428,9 +387,7 @@
&& extrasEquals(that.mExtras)
&& java.util.Objects.equals(mHostInputToken, that.mHostInputToken)
&& mHostDisplayId == that.mHostDisplayId
- && java.util.Objects.equals(mInlineTooltipPresentationSpec, that.mInlineTooltipPresentationSpec)
- && mServiceSupported == that.mServiceSupported
- && mClientSupported == that.mClientSupported;
+ && java.util.Objects.equals(mInlineTooltipPresentationSpec, that.mInlineTooltipPresentationSpec);
}
@Override
@@ -448,8 +405,6 @@
_hash = 31 * _hash + java.util.Objects.hashCode(mHostInputToken);
_hash = 31 * _hash + mHostDisplayId;
_hash = 31 * _hash + java.util.Objects.hashCode(mInlineTooltipPresentationSpec);
- _hash = 31 * _hash + Boolean.hashCode(mServiceSupported);
- _hash = 31 * _hash + Boolean.hashCode(mClientSupported);
return _hash;
}
@@ -460,8 +415,6 @@
// void parcelFieldName(Parcel dest, int flags) { ... }
int flg = 0;
- if (mServiceSupported) flg |= 0x100;
- if (mClientSupported) flg |= 0x200;
if (mHostInputToken != null) flg |= 0x20;
if (mInlineTooltipPresentationSpec != null) flg |= 0x80;
dest.writeInt(flg);
@@ -487,11 +440,9 @@
// static FieldType unparcelFieldName(Parcel in) { ... }
int flg = in.readInt();
- boolean serviceSupported = (flg & 0x100) != 0;
- boolean clientSupported = (flg & 0x200) != 0;
int maxSuggestionCount = in.readInt();
List<InlinePresentationSpec> inlinePresentationSpecs = new ArrayList<>();
- in.readParcelableList(inlinePresentationSpecs, InlinePresentationSpec.class.getClassLoader(), android.widget.inline.InlinePresentationSpec.class);
+ in.readParcelableList(inlinePresentationSpecs, InlinePresentationSpec.class.getClassLoader());
String hostPackageName = in.readString();
LocaleList supportedLocales = (LocaleList) in.readTypedObject(LocaleList.CREATOR);
Bundle extras = in.readBundle();
@@ -515,8 +466,6 @@
this.mHostInputToken = hostInputToken;
this.mHostDisplayId = hostDisplayId;
this.mInlineTooltipPresentationSpec = inlineTooltipPresentationSpec;
- this.mServiceSupported = serviceSupported;
- this.mClientSupported = clientSupported;
onConstructed();
}
@@ -550,8 +499,6 @@
private @Nullable IBinder mHostInputToken;
private int mHostDisplayId;
private @Nullable InlinePresentationSpec mInlineTooltipPresentationSpec;
- private boolean mServiceSupported;
- private boolean mClientSupported;
private long mBuilderFieldsSet = 0L;
@@ -684,9 +631,7 @@
}
/**
- * The {@link InlinePresentationSpec} for the inline suggestion tooltip in the response.
- *
- * @see android.service.autofill.InlinePresentation#createTooltipPresentation(Slice, InlinePresentationSpec)s
+ * Specifies the UI specification for the inline suggestion tooltip in the response.
*/
@DataClass.Generated.Member
public @NonNull Builder setInlineTooltipPresentationSpec(@NonNull InlinePresentationSpec value) {
@@ -696,44 +641,10 @@
return this;
}
- /**
- * Whether the IME supports inline suggestions from the default Autofill service that
- * provides the input view.
- *
- * Note: The default value is {@code true}.
- *
- * @hide
- */
- @TestApi
- @DataClass.Generated.Member
- public @NonNull Builder setServiceSupported(boolean value) {
- checkNotUsed();
- mBuilderFieldsSet |= 0x100;
- mServiceSupported = value;
- return this;
- }
-
- /**
- * Whether the IME supports inline suggestions from the application that provides the
- * input view.
- *
- * Note: The default value is {@code true}.
- *
- * @hide
- */
- @TestApi
- @DataClass.Generated.Member
- public @NonNull Builder setClientSupported(boolean value) {
- checkNotUsed();
- mBuilderFieldsSet |= 0x200;
- mClientSupported = value;
- return this;
- }
-
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull InlineSuggestionsRequest build() {
checkNotUsed();
- mBuilderFieldsSet |= 0x400; // Mark builder used
+ mBuilderFieldsSet |= 0x100; // Mark builder used
if ((mBuilderFieldsSet & 0x1) == 0) {
mMaxSuggestionCount = defaultMaxSuggestionCount();
@@ -756,12 +667,6 @@
if ((mBuilderFieldsSet & 0x80) == 0) {
mInlineTooltipPresentationSpec = defaultInlineTooltipPresentationSpec();
}
- if ((mBuilderFieldsSet & 0x100) == 0) {
- mServiceSupported = defaultServiceSupported();
- }
- if ((mBuilderFieldsSet & 0x200) == 0) {
- mClientSupported = defaultClientSupported();
- }
InlineSuggestionsRequest o = new InlineSuggestionsRequest(
mMaxSuggestionCount,
mInlinePresentationSpecs,
@@ -770,14 +675,12 @@
mExtras,
mHostInputToken,
mHostDisplayId,
- mInlineTooltipPresentationSpec,
- mServiceSupported,
- mClientSupported);
+ mInlineTooltipPresentationSpec);
return o;
}
private void checkNotUsed() {
- if ((mBuilderFieldsSet & 0x400) != 0) {
+ if ((mBuilderFieldsSet & 0x100) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
@@ -785,10 +688,10 @@
}
@DataClass.Generated(
- time = 1615798784918L,
- codegenVersion = "1.0.22",
+ time = 1682382296877L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java",
- inputSignatures = "public static final int SUGGESTION_COUNT_UNLIMITED\nprivate final int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.widget.inline.InlinePresentationSpec> mInlinePresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @android.annotation.NonNull android.os.Bundle mExtras\nprivate @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate int mHostDisplayId\nprivate @android.annotation.Nullable android.widget.inline.InlinePresentationSpec mInlineTooltipPresentationSpec\nprivate boolean mServiceSupported\nprivate boolean mClientSupported\nprivate static final @android.compat.annotation.ChangeId @android.compat.annotation.EnabledSince long IME_AUTOFILL_DEFAULT_SUPPORTED_LOCALES_IS_EMPTY\npublic void setHostInputToken(android.os.IBinder)\nprivate boolean extrasEquals(android.os.Bundle)\nprivate void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic void setHostDisplayId(int)\nprivate void onConstructed()\npublic void filterContentTypes()\nprivate static int defaultMaxSuggestionCount()\nprivate static java.lang.String defaultHostPackageName()\nprivate static android.widget.inline.InlinePresentationSpec defaultInlineTooltipPresentationSpec()\nprivate static android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.NonNull android.os.Bundle defaultExtras()\nprivate static boolean defaultServiceSupported()\nprivate static boolean defaultClientSupported()\npublic boolean isServiceSupported()\npublic boolean isClientSupported()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
+ inputSignatures = "public static final int SUGGESTION_COUNT_UNLIMITED\nprivate final int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.widget.inline.InlinePresentationSpec> mInlinePresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @android.annotation.NonNull android.os.Bundle mExtras\nprivate @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate int mHostDisplayId\nprivate @android.annotation.Nullable android.widget.inline.InlinePresentationSpec mInlineTooltipPresentationSpec\nprivate static final @android.compat.annotation.ChangeId @android.compat.annotation.EnabledSince long IME_AUTOFILL_DEFAULT_SUPPORTED_LOCALES_IS_EMPTY\npublic void setHostInputToken(android.os.IBinder)\nprivate boolean extrasEquals(android.os.Bundle)\nprivate void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic void setHostDisplayId(int)\nprivate void onConstructed()\npublic void filterContentTypes()\nprivate static int defaultMaxSuggestionCount()\nprivate static java.lang.String defaultHostPackageName()\nprivate static android.widget.inline.InlinePresentationSpec defaultInlineTooltipPresentationSpec()\nprivate static android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.NonNull android.os.Bundle defaultExtras()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index 8f270f5..62f3c90 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -412,4 +412,32 @@
public boolean setImeConsumesInput(boolean imeConsumesInput) {
return mTarget.setImeConsumesInput(imeConsumesInput);
}
+
+ /**
+ * Called by the system when it needs to take a snapshot of multiple text-related data in an
+ * atomic manner.
+ *
+ * <p><strong>Editor authors</strong>: Supporting this method is strongly encouraged. Atomically
+ * taken {@link TextSnapshot} is going to be really helpful for the system when optimizing IPCs
+ * in a safe and deterministic manner. Return {@code null} if an atomically taken
+ * {@link TextSnapshot} is unavailable. The system continues supporting such a scenario
+ * gracefully.</p>
+ *
+ * <p><strong>IME authors</strong>: Currently IMEs cannot call this method directly and always
+ * receive {@code null} as the result.</p>
+ *
+ * <p>Beware that there is a bug that this method was not overridden in
+ * {@link InputConnectionWrapper}, which ended up always returning {@code null} when gets
+ * called even if the wrapped {@link InputConnection} implements this method. The bug was
+ * fixed in {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}.</p>
+ *
+ * @return {@code null} if {@link TextSnapshot} is unavailable and/or this API is called from
+ * IMEs. Beware the bug in older devices mentioned above.
+ * @throws NullPointerException if the target is {@code null}.
+ */
+ @Nullable
+ @Override
+ public TextSnapshot takeSnapshot() {
+ return mTarget.takeSnapshot();
+ }
}
diff --git a/core/java/android/window/ScreenCapture.java b/core/java/android/window/ScreenCapture.java
index 95451a9..fa7f577 100644
--- a/core/java/android/window/ScreenCapture.java
+++ b/core/java/android/window/ScreenCapture.java
@@ -198,17 +198,21 @@
* Create ScreenshotHardwareBuffer from an existing HardwareBuffer object.
*
* @param hardwareBuffer The existing HardwareBuffer object
- * @param namedColorSpace Integer value of a named color space {@link ColorSpace.Named}
+ * @param dataspace Dataspace describing the content.
+ * {@see android.hardware.DataSpace}
* @param containsSecureLayers Indicates whether this graphic buffer contains captured
* contents of secure layers, in which case the screenshot
* should not be persisted.
* @param containsHdrLayers Indicates whether this graphic buffer contains HDR content.
*/
private static ScreenshotHardwareBuffer createFromNative(HardwareBuffer hardwareBuffer,
- int namedColorSpace, boolean containsSecureLayers, boolean containsHdrLayers) {
- ColorSpace colorSpace = ColorSpace.get(ColorSpace.Named.values()[namedColorSpace]);
+ int dataspace, boolean containsSecureLayers, boolean containsHdrLayers) {
+ ColorSpace colorSpace = ColorSpace.getFromDataSpace(dataspace);
return new ScreenshotHardwareBuffer(
- hardwareBuffer, colorSpace, containsSecureLayers, containsHdrLayers);
+ hardwareBuffer,
+ colorSpace != null ? colorSpace : ColorSpace.get(ColorSpace.Named.SRGB),
+ containsSecureLayers,
+ containsHdrLayers);
}
public ColorSpace getColorSpace() {
@@ -271,8 +275,8 @@
public final boolean mAllowProtected;
public final long mUid;
public final boolean mGrayscale;
-
final SurfaceControl[] mExcludeLayers;
+ public final boolean mHintForSeamlessTransition;
private CaptureArgs(CaptureArgs.Builder<? extends CaptureArgs.Builder<?>> builder) {
mPixelFormat = builder.mPixelFormat;
@@ -284,6 +288,7 @@
mUid = builder.mUid;
mGrayscale = builder.mGrayscale;
mExcludeLayers = builder.mExcludeLayers;
+ mHintForSeamlessTransition = builder.mHintForSeamlessTransition;
}
private CaptureArgs(Parcel in) {
@@ -305,6 +310,7 @@
} else {
mExcludeLayers = null;
}
+ mHintForSeamlessTransition = in.readBoolean();
}
/** Release any layers if set using {@link Builder#setExcludeLayers(SurfaceControl[])}. */
@@ -352,6 +358,7 @@
private long mUid = -1;
private boolean mGrayscale;
private SurfaceControl[] mExcludeLayers;
+ private boolean mHintForSeamlessTransition;
/**
* Construct a new {@link CaptureArgs} with the set parameters. The builder remains
@@ -449,6 +456,21 @@
}
/**
+ * Set whether the screenshot will be used in a system animation.
+ * This hint is used for picking the "best" colorspace for the screenshot, in particular
+ * for mixing HDR and SDR content.
+ * E.g., hintForSeamlessTransition is false, then a colorspace suitable for file
+ * encoding, such as BT2100, may be chosen. Otherwise, then the display's color space
+ * would be chosen, with the possibility of having an extended brightness range. This
+ * is important for screenshots that are directly re-routed to a SurfaceControl in
+ * order to preserve accurate colors.
+ */
+ public T setHintForSeamlessTransition(boolean hintForSeamlessTransition) {
+ mHintForSeamlessTransition = hintForSeamlessTransition;
+ return getThis();
+ }
+
+ /**
* Each sub class should return itself to allow the builder to chain properly
*/
T getThis() {
@@ -471,7 +493,6 @@
dest.writeBoolean(mAllowProtected);
dest.writeLong(mUid);
dest.writeBoolean(mGrayscale);
-
if (mExcludeLayers != null) {
dest.writeInt(mExcludeLayers.length);
for (SurfaceControl excludeLayer : mExcludeLayers) {
@@ -480,6 +501,7 @@
} else {
dest.writeInt(0);
}
+ dest.writeBoolean(mHintForSeamlessTransition);
}
public static final Parcelable.Creator<CaptureArgs> CREATOR =
@@ -627,6 +649,7 @@
setUid(args.mUid);
setGrayscale(args.mGrayscale);
setExcludeLayers(args.mExcludeLayers);
+ setHintForSeamlessTransition(args.mHintForSeamlessTransition);
}
public Builder(SurfaceControl layer) {
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 51382a4..4d0132e 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -21,6 +21,8 @@
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.os.Handler;
import android.os.RemoteException;
import android.os.SystemProperties;
@@ -421,36 +423,45 @@
return false;
}
- boolean requestsPredictiveBack;
+ boolean requestsPredictiveBack = false;
// Check if the context is from an activity.
while ((context instanceof ContextWrapper) && !(context instanceof Activity)) {
context = ((ContextWrapper) context).getBaseContext();
}
+ boolean shouldCheckActivity = false;
+
if (context instanceof Activity) {
final Activity activity = (Activity) context;
- if (activity.getActivityInfo().hasOnBackInvokedCallbackEnabled()) {
- requestsPredictiveBack =
- activity.getActivityInfo().isOnBackInvokedCallbackEnabled();
- } else {
- requestsPredictiveBack =
- context.getApplicationInfo().isOnBackInvokedCallbackEnabled();
- }
+ final ActivityInfo activityInfo = activity.getActivityInfo();
+ if (activityInfo != null) {
+ if (activityInfo.hasOnBackInvokedCallbackEnabled()) {
+ shouldCheckActivity = true;
+ requestsPredictiveBack = activityInfo.isOnBackInvokedCallbackEnabled();
- if (DEBUG) {
- Log.d(TAG, TextUtils.formatSimple("Activity: %s isPredictiveBackEnabled=%s",
- activity.getComponentName(),
- requestsPredictiveBack));
+ if (DEBUG) {
+ Log.d(TAG, TextUtils.formatSimple(
+ "Activity: %s isPredictiveBackEnabled=%s",
+ activity.getComponentName(),
+ requestsPredictiveBack));
+ }
+ }
+ } else {
+ Log.w(TAG, "The ActivityInfo is null, so we cannot verify if this Activity"
+ + " has the 'android:enableOnBackInvokedCallback' attribute."
+ + " The application attribute will be used as a fallback.");
}
- } else {
- requestsPredictiveBack =
- context.getApplicationInfo().isOnBackInvokedCallbackEnabled();
+ }
+
+ if (!shouldCheckActivity) {
+ final ApplicationInfo applicationInfo = context.getApplicationInfo();
+ requestsPredictiveBack = applicationInfo.isOnBackInvokedCallbackEnabled();
if (DEBUG) {
Log.d(TAG, TextUtils.formatSimple("App: %s requestsPredictiveBack=%s",
- context.getApplicationInfo().packageName,
+ applicationInfo.packageName,
requestsPredictiveBack));
}
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 499d38c..50f393b 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -1725,16 +1725,17 @@
if (inWorkProfile) {
((TextView) findViewById(R.id.open_cross_profile)).setText(
- devicePolicyResourcesManager.getString(MINIRESOLVER_OPEN_IN_WORK,
- () -> getString(R.string.miniresolver_open_in_work, targetDisplayLabel),
+ devicePolicyResourcesManager.getString(MINIRESOLVER_OPEN_IN_PERSONAL,
+ () -> getString(R.string.miniresolver_open_in_personal,
+ targetDisplayLabel),
targetDisplayLabel));
((Button) findViewById(R.id.use_same_profile_browser)).setText(
devicePolicyResourcesManager.getString(MINIRESOLVER_USE_WORK_BROWSER,
() -> getString(R.string.miniresolver_use_work_browser)));
} else {
((TextView) findViewById(R.id.open_cross_profile)).setText(
- devicePolicyResourcesManager.getString(MINIRESOLVER_OPEN_IN_PERSONAL,
- () -> getString(R.string.miniresolver_open_in_personal,
+ devicePolicyResourcesManager.getString(MINIRESOLVER_OPEN_IN_WORK,
+ () -> getString(R.string.miniresolver_open_in_work,
targetDisplayLabel),
targetDisplayLabel));
((Button) findViewById(R.id.use_same_profile_browser)).setText(
diff --git a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
index 853fe2f..86c2893 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
@@ -76,7 +76,7 @@
/** Gating the removal of sorting-notifications-by-interruptiveness. */
public static final Flag NO_SORT_BY_INTERRUPTIVENESS =
- devFlag("persist.sysui.notification.no_sort_by_interruptiveness");
+ releasedFlag("persist.sysui.notification.no_sort_by_interruptiveness");
/** Gating the logging of DND state change events. */
public static final Flag LOG_DND_STATE_EVENTS =
@@ -115,7 +115,7 @@
}
/**
- * Creates a flag that is enabled by default in debuggable builds.
+ * Creates a flag that is disabled by default in debuggable builds.
* It can be enabled by setting this flag's SystemProperty to 1.
*
* This flag is ALWAYS disabled in release builds.
diff --git a/core/java/com/android/internal/display/RefreshRateSettingsUtils.java b/core/java/com/android/internal/display/RefreshRateSettingsUtils.java
deleted file mode 100644
index 39d8380..0000000
--- a/core/java/com/android/internal/display/RefreshRateSettingsUtils.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.display;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.hardware.display.DisplayManager;
-import android.provider.Settings;
-import android.util.Log;
-import android.view.Display;
-
-/**
- * Constants and utility methods for refresh rate settings.
- */
-public class RefreshRateSettingsUtils {
-
- private static final String TAG = "RefreshRateSettingsUtils";
-
- public static final float DEFAULT_REFRESH_RATE = 60f;
-
- /**
- * Find the highest refresh rate among all the modes of the default display.
- * @param context The context
- * @return The highest refresh rate
- */
- public static float findHighestRefreshRateForDefaultDisplay(Context context) {
- final DisplayManager dm = context.getSystemService(DisplayManager.class);
- final Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
-
- if (display == null) {
- Log.w(TAG, "No valid default display device");
- return DEFAULT_REFRESH_RATE;
- }
-
- float maxRefreshRate = DEFAULT_REFRESH_RATE;
- for (Display.Mode mode : display.getSupportedModes()) {
- if (Math.round(mode.getRefreshRate()) > maxRefreshRate) {
- maxRefreshRate = mode.getRefreshRate();
- }
- }
- return maxRefreshRate;
- }
-
- /**
- * Get the min refresh rate which is determined by
- * {@link Settings.System.FORCE_PEAK_REFRESH_RATE}.
- * @param context The context
- * @return The min refresh rate
- */
- public static float getMinRefreshRate(Context context) {
- final ContentResolver cr = context.getContentResolver();
- int forcePeakRefreshRateSetting = Settings.System.getIntForUser(cr,
- Settings.System.FORCE_PEAK_REFRESH_RATE, -1, cr.getUserId());
- return forcePeakRefreshRateSetting == 1
- ? findHighestRefreshRateForDefaultDisplay(context)
- : 0;
- }
-
- /**
- * Get the peak refresh rate which is determined by {@link Settings.System.SMOOTH_DISPLAY}.
- * @param context The context
- * @param defaultPeakRefreshRate The refresh rate to return if the setting doesn't have a value
- * @return The peak refresh rate
- */
- public static float getPeakRefreshRate(Context context, float defaultPeakRefreshRate) {
- final ContentResolver cr = context.getContentResolver();
- int smoothDisplaySetting = Settings.System.getIntForUser(cr,
- Settings.System.SMOOTH_DISPLAY, -1, cr.getUserId());
- switch (smoothDisplaySetting) {
- case 0:
- return DEFAULT_REFRESH_RATE;
- case 1:
- return findHighestRefreshRateForDefaultDisplay(context);
- default:
- return defaultPeakRefreshRate;
- }
- }
-}
diff --git a/core/java/com/android/internal/util/TraceBuffer.java b/core/java/com/android/internal/util/TraceBuffer.java
index bfcd65d..fcc77bd4 100644
--- a/core/java/com/android/internal/util/TraceBuffer.java
+++ b/core/java/com/android/internal/util/TraceBuffer.java
@@ -103,6 +103,10 @@
this(bufferCapacity, new ProtoOutputStreamProvider(), null);
}
+ public TraceBuffer(int bufferCapacity, Consumer<T> protoDequeuedCallback) {
+ this(bufferCapacity, new ProtoOutputStreamProvider(), protoDequeuedCallback);
+ }
+
public TraceBuffer(int bufferCapacity, ProtoProvider protoProvider,
Consumer<T> protoDequeuedCallback) {
mBufferCapacity = bufferCapacity;
diff --git a/core/jni/android_window_ScreenCapture.cpp b/core/jni/android_window_ScreenCapture.cpp
index 1b67a0d..986dbe9 100644
--- a/core/jni/android_window_ScreenCapture.cpp
+++ b/core/jni/android_window_ScreenCapture.cpp
@@ -46,6 +46,7 @@
jfieldID uid;
jfieldID grayscale;
jmethodID getNativeExcludeLayers;
+ jfieldID hintForSeamlessTransition;
} gCaptureArgsClassInfo;
static struct {
@@ -69,23 +70,6 @@
jmethodID builder;
} gScreenshotHardwareBufferClassInfo;
-enum JNamedColorSpace : jint {
- // ColorSpace.Named.SRGB.ordinal() = 0;
- SRGB = 0,
-
- // ColorSpace.Named.DISPLAY_P3.ordinal() = 7;
- DISPLAY_P3 = 7,
-};
-
-constexpr jint fromDataspaceToNamedColorSpaceValue(const ui::Dataspace dataspace) {
- switch (dataspace) {
- case ui::Dataspace::DISPLAY_P3:
- return JNamedColorSpace::DISPLAY_P3;
- default:
- return JNamedColorSpace::SRGB;
- }
-}
-
static void checkAndClearException(JNIEnv* env, const char* methodName) {
if (env->ExceptionCheck()) {
ALOGE("An exception was thrown by callback '%s'.", methodName);
@@ -119,12 +103,11 @@
captureResults.fenceResult.value()->waitForever(LOG_TAG);
jobject jhardwareBuffer = android_hardware_HardwareBuffer_createFromAHardwareBuffer(
env, captureResults.buffer->toAHardwareBuffer());
- const jint namedColorSpace =
- fromDataspaceToNamedColorSpaceValue(captureResults.capturedDataspace);
jobject screenshotHardwareBuffer =
env->CallStaticObjectMethod(gScreenshotHardwareBufferClassInfo.clazz,
gScreenshotHardwareBufferClassInfo.builder,
- jhardwareBuffer, namedColorSpace,
+ jhardwareBuffer,
+ static_cast<jint>(captureResults.capturedDataspace),
captureResults.capturedSecureLayers,
captureResults.capturedHdrLayers);
checkAndClearException(env, "builder");
@@ -185,6 +168,9 @@
captureArgs.excludeHandles.emplace(excludeObject->getHandle());
}
}
+ captureArgs.hintForSeamlessTransition =
+ env->GetBooleanField(captureArgsObject,
+ gCaptureArgsClassInfo.hintForSeamlessTransition);
}
static DisplayCaptureArgs displayCaptureArgsFromObject(JNIEnv* env,
@@ -318,9 +304,10 @@
GetFieldIDOrDie(env, captureArgsClazz, "mAllowProtected", "Z");
gCaptureArgsClassInfo.uid = GetFieldIDOrDie(env, captureArgsClazz, "mUid", "J");
gCaptureArgsClassInfo.grayscale = GetFieldIDOrDie(env, captureArgsClazz, "mGrayscale", "Z");
-
gCaptureArgsClassInfo.getNativeExcludeLayers =
GetMethodIDOrDie(env, captureArgsClazz, "getNativeExcludeLayers", "()[J");
+ gCaptureArgsClassInfo.hintForSeamlessTransition =
+ GetFieldIDOrDie(env, captureArgsClazz, "mHintForSeamlessTransition", "Z");
jclass displayCaptureArgsClazz =
FindClassOrDie(env, "android/window/ScreenCapture$DisplayCaptureArgs");
diff --git a/core/proto/android/companion/telecom.proto b/core/proto/android/companion/telecom.proto
index 9ccadbf..3a9e5ee 100644
--- a/core/proto/android/companion/telecom.proto
+++ b/core/proto/android/companion/telecom.proto
@@ -20,9 +20,9 @@
option java_multiple_files = true;
-// Next index: 2
+// Next index: 4
message Telecom {
- // Next index: 5
+ // Next index: 6
message Call {
// UUID representing this call
int64 id = 1;
@@ -34,6 +34,8 @@
// Human-readable name of the app processing this call
string app_name = 2;
bytes app_icon = 3;
+ // Unique identifier for this app, such as a package name.
+ string app_identifier = 4;
}
Origin origin = 2;
@@ -59,9 +61,11 @@
REJECT_AND_BLOCK = 9;
IGNORE = 10;
}
- repeated Control controls_available = 4;
+ repeated Control controls = 4;
}
// The list of active calls.
repeated Call calls = 1;
+ // The list of requested calls or call changes.
+ repeated Call requests = 2;
}
diff --git a/core/res/res/drawable-hdpi/pointer_all_scroll.png b/core/res/res/drawable-hdpi/pointer_all_scroll.png
index 095aadc..4af84c3 100644
--- a/core/res/res/drawable-hdpi/pointer_all_scroll.png
+++ b/core/res/res/drawable-hdpi/pointer_all_scroll.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pointer_horizontal_double_arrow.png b/core/res/res/drawable-hdpi/pointer_horizontal_double_arrow.png
index 9388f16..c4018c8 100644
--- a/core/res/res/drawable-hdpi/pointer_horizontal_double_arrow.png
+++ b/core/res/res/drawable-hdpi/pointer_horizontal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pointer_top_left_diagonal_double_arrow.png b/core/res/res/drawable-hdpi/pointer_top_left_diagonal_double_arrow.png
index ab52bff..58bb0d4 100644
--- a/core/res/res/drawable-hdpi/pointer_top_left_diagonal_double_arrow.png
+++ b/core/res/res/drawable-hdpi/pointer_top_left_diagonal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pointer_top_right_diagonal_double_arrow.png b/core/res/res/drawable-hdpi/pointer_top_right_diagonal_double_arrow.png
index 1250d35..1981d41 100644
--- a/core/res/res/drawable-hdpi/pointer_top_right_diagonal_double_arrow.png
+++ b/core/res/res/drawable-hdpi/pointer_top_right_diagonal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pointer_vertical_double_arrow.png b/core/res/res/drawable-hdpi/pointer_vertical_double_arrow.png
index 6730c7b..d4ba79a 100644
--- a/core/res/res/drawable-hdpi/pointer_vertical_double_arrow.png
+++ b/core/res/res/drawable-hdpi/pointer_vertical_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_all_scroll.png b/core/res/res/drawable-mdpi/pointer_all_scroll.png
index 3db456e..1b81d0a 100644
--- a/core/res/res/drawable-mdpi/pointer_all_scroll.png
+++ b/core/res/res/drawable-mdpi/pointer_all_scroll.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_all_scroll_large.png b/core/res/res/drawable-mdpi/pointer_all_scroll_large.png
index 120e1d7..9e1f5c9 100644
--- a/core/res/res/drawable-mdpi/pointer_all_scroll_large.png
+++ b/core/res/res/drawable-mdpi/pointer_all_scroll_large.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_horizontal_double_arrow.png b/core/res/res/drawable-mdpi/pointer_horizontal_double_arrow.png
index 20f319a..d1b3441 100644
--- a/core/res/res/drawable-mdpi/pointer_horizontal_double_arrow.png
+++ b/core/res/res/drawable-mdpi/pointer_horizontal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_horizontal_double_arrow_large.png b/core/res/res/drawable-mdpi/pointer_horizontal_double_arrow_large.png
index 33ef5c9..4e26371 100644
--- a/core/res/res/drawable-mdpi/pointer_horizontal_double_arrow_large.png
+++ b/core/res/res/drawable-mdpi/pointer_horizontal_double_arrow_large.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_top_left_diagonal_double_arrow.png b/core/res/res/drawable-mdpi/pointer_top_left_diagonal_double_arrow.png
index fe7d496..34c0c6a 100644
--- a/core/res/res/drawable-mdpi/pointer_top_left_diagonal_double_arrow.png
+++ b/core/res/res/drawable-mdpi/pointer_top_left_diagonal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_top_left_diagonal_double_arrow_large.png b/core/res/res/drawable-mdpi/pointer_top_left_diagonal_double_arrow_large.png
index 7b2e20c..87ec184 100644
--- a/core/res/res/drawable-mdpi/pointer_top_left_diagonal_double_arrow_large.png
+++ b/core/res/res/drawable-mdpi/pointer_top_left_diagonal_double_arrow_large.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_top_right_diagonal_double_arrow.png b/core/res/res/drawable-mdpi/pointer_top_right_diagonal_double_arrow.png
index 95a6620..40b9c7e 100644
--- a/core/res/res/drawable-mdpi/pointer_top_right_diagonal_double_arrow.png
+++ b/core/res/res/drawable-mdpi/pointer_top_right_diagonal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_top_right_diagonal_double_arrow_large.png b/core/res/res/drawable-mdpi/pointer_top_right_diagonal_double_arrow_large.png
index 2e2904b..6a85b49 100644
--- a/core/res/res/drawable-mdpi/pointer_top_right_diagonal_double_arrow_large.png
+++ b/core/res/res/drawable-mdpi/pointer_top_right_diagonal_double_arrow_large.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_vertical_double_arrow.png b/core/res/res/drawable-mdpi/pointer_vertical_double_arrow.png
index ae6bfed..9bd89bf 100644
--- a/core/res/res/drawable-mdpi/pointer_vertical_double_arrow.png
+++ b/core/res/res/drawable-mdpi/pointer_vertical_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_vertical_double_arrow_large.png b/core/res/res/drawable-mdpi/pointer_vertical_double_arrow_large.png
index 3beb1d1..5a69bbc 100644
--- a/core/res/res/drawable-mdpi/pointer_vertical_double_arrow_large.png
+++ b/core/res/res/drawable-mdpi/pointer_vertical_double_arrow_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_all_scroll.png b/core/res/res/drawable-xhdpi/pointer_all_scroll.png
index e9d05d5..85aa022 100644
--- a/core/res/res/drawable-xhdpi/pointer_all_scroll.png
+++ b/core/res/res/drawable-xhdpi/pointer_all_scroll.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_all_scroll_large.png b/core/res/res/drawable-xhdpi/pointer_all_scroll_large.png
index 1fd54fb..7448339 100644
--- a/core/res/res/drawable-xhdpi/pointer_all_scroll_large.png
+++ b/core/res/res/drawable-xhdpi/pointer_all_scroll_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_horizontal_double_arrow.png b/core/res/res/drawable-xhdpi/pointer_horizontal_double_arrow.png
index caf2a97..dd37f92 100644
--- a/core/res/res/drawable-xhdpi/pointer_horizontal_double_arrow.png
+++ b/core/res/res/drawable-xhdpi/pointer_horizontal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_horizontal_double_arrow_large.png b/core/res/res/drawable-xhdpi/pointer_horizontal_double_arrow_large.png
index 2f22640..9e031e8 100644
--- a/core/res/res/drawable-xhdpi/pointer_horizontal_double_arrow_large.png
+++ b/core/res/res/drawable-xhdpi/pointer_horizontal_double_arrow_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_top_left_diagonal_double_arrow.png b/core/res/res/drawable-xhdpi/pointer_top_left_diagonal_double_arrow.png
index a36deb3..150d80d 100644
--- a/core/res/res/drawable-xhdpi/pointer_top_left_diagonal_double_arrow.png
+++ b/core/res/res/drawable-xhdpi/pointer_top_left_diagonal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_top_left_diagonal_double_arrow_large.png b/core/res/res/drawable-xhdpi/pointer_top_left_diagonal_double_arrow_large.png
index 6870e23..bae907a 100644
--- a/core/res/res/drawable-xhdpi/pointer_top_left_diagonal_double_arrow_large.png
+++ b/core/res/res/drawable-xhdpi/pointer_top_left_diagonal_double_arrow_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_top_right_diagonal_double_arrow.png b/core/res/res/drawable-xhdpi/pointer_top_right_diagonal_double_arrow.png
index c8d6d1f..3b23143 100644
--- a/core/res/res/drawable-xhdpi/pointer_top_right_diagonal_double_arrow.png
+++ b/core/res/res/drawable-xhdpi/pointer_top_right_diagonal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_top_right_diagonal_double_arrow_large.png b/core/res/res/drawable-xhdpi/pointer_top_right_diagonal_double_arrow_large.png
index 5bfb771..a90b286 100644
--- a/core/res/res/drawable-xhdpi/pointer_top_right_diagonal_double_arrow_large.png
+++ b/core/res/res/drawable-xhdpi/pointer_top_right_diagonal_double_arrow_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_vertical_double_arrow.png b/core/res/res/drawable-xhdpi/pointer_vertical_double_arrow.png
index 720df91..3e7f850 100644
--- a/core/res/res/drawable-xhdpi/pointer_vertical_double_arrow.png
+++ b/core/res/res/drawable-xhdpi/pointer_vertical_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_vertical_double_arrow_large.png b/core/res/res/drawable-xhdpi/pointer_vertical_double_arrow_large.png
index 82b30d1..090e3ca 100644
--- a/core/res/res/drawable-xhdpi/pointer_vertical_double_arrow_large.png
+++ b/core/res/res/drawable-xhdpi/pointer_vertical_double_arrow_large.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/pointer_all_scroll.png b/core/res/res/drawable-xxhdpi/pointer_all_scroll.png
index 808143a..92aae72 100644
--- a/core/res/res/drawable-xxhdpi/pointer_all_scroll.png
+++ b/core/res/res/drawable-xxhdpi/pointer_all_scroll.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/pointer_horizontal_double_arrow.png b/core/res/res/drawable-xxhdpi/pointer_horizontal_double_arrow.png
index 677ccad..b1e2509 100644
--- a/core/res/res/drawable-xxhdpi/pointer_horizontal_double_arrow.png
+++ b/core/res/res/drawable-xxhdpi/pointer_horizontal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/pointer_top_left_diagonal_double_arrow.png b/core/res/res/drawable-xxhdpi/pointer_top_left_diagonal_double_arrow.png
index e01aa64..2d1217c 100644
--- a/core/res/res/drawable-xxhdpi/pointer_top_left_diagonal_double_arrow.png
+++ b/core/res/res/drawable-xxhdpi/pointer_top_left_diagonal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/pointer_top_right_diagonal_double_arrow.png b/core/res/res/drawable-xxhdpi/pointer_top_right_diagonal_double_arrow.png
index e947e0e..a99fb24 100644
--- a/core/res/res/drawable-xxhdpi/pointer_top_right_diagonal_double_arrow.png
+++ b/core/res/res/drawable-xxhdpi/pointer_top_right_diagonal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/pointer_vertical_double_arrow.png b/core/res/res/drawable-xxhdpi/pointer_vertical_double_arrow.png
index c867247..1f065fa 100644
--- a/core/res/res/drawable-xxhdpi/pointer_vertical_double_arrow.png
+++ b/core/res/res/drawable-xxhdpi/pointer_vertical_double_arrow.png
Binary files differ
diff --git a/core/res/res/layout-television/user_switching_dialog.xml b/core/res/res/layout-television/user_switching_dialog.xml
deleted file mode 100644
index 72150e3..0000000
--- a/core/res/res/layout-television/user_switching_dialog.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?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.
--->
-
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/message"
- style="?attr/textAppearanceListItem"
- android:layout_width="match_parent"
- android:background="@color/background_leanback_dark"
- android:textColor="@color/primary_text_leanback_dark"
- android:layout_height="match_parent"
- android:gravity="center"
- android:paddingStart="?attr/dialogPreferredPadding"
- android:paddingEnd="?attr/dialogPreferredPadding"
- android:paddingTop="24dp"
- android:paddingBottom="24dp" />
diff --git a/core/res/res/values-mcc310/config.xml b/core/res/res/values-mcc310/config.xml
index df398f9..76abcee 100644
--- a/core/res/res/values-mcc310/config.xml
+++ b/core/res/res/values-mcc310/config.xml
@@ -22,4 +22,7 @@
<!-- Whether safe headphone volume is enabled or not (country specific). -->
<bool name="config_safe_media_volume_enabled">false</bool>
+ <!-- Whether safe headphone sound dosage warning is enabled or not (country specific). -->
+ <bool name="config_safe_sound_dosage_mcc_enabled">false</bool>
+
</resources>
diff --git a/core/res/res/values-mcc311/config.xml b/core/res/res/values-mcc311/config.xml
index df398f9..6e0b678 100644
--- a/core/res/res/values-mcc311/config.xml
+++ b/core/res/res/values-mcc311/config.xml
@@ -22,4 +22,7 @@
<!-- Whether safe headphone volume is enabled or not (country specific). -->
<bool name="config_safe_media_volume_enabled">false</bool>
+ <!-- Whether safe headphone sound dosage warning is enabled or not (country specific). -->
+ <bool name="config_safe_sound_dosage_enabled">false</bool>
+
</resources>
diff --git a/core/res/res/values-mcc312/config.xml b/core/res/res/values-mcc312/config.xml
index df398f9..6e0b678 100644
--- a/core/res/res/values-mcc312/config.xml
+++ b/core/res/res/values-mcc312/config.xml
@@ -22,4 +22,7 @@
<!-- Whether safe headphone volume is enabled or not (country specific). -->
<bool name="config_safe_media_volume_enabled">false</bool>
+ <!-- Whether safe headphone sound dosage warning is enabled or not (country specific). -->
+ <bool name="config_safe_sound_dosage_enabled">false</bool>
+
</resources>
diff --git a/core/res/res/values-mcc313/config.xml b/core/res/res/values-mcc313/config.xml
index df398f9..6e0b678 100644
--- a/core/res/res/values-mcc313/config.xml
+++ b/core/res/res/values-mcc313/config.xml
@@ -22,4 +22,7 @@
<!-- Whether safe headphone volume is enabled or not (country specific). -->
<bool name="config_safe_media_volume_enabled">false</bool>
+ <!-- Whether safe headphone sound dosage warning is enabled or not (country specific). -->
+ <bool name="config_safe_sound_dosage_enabled">false</bool>
+
</resources>
diff --git a/core/res/res/values-mcc314/config.xml b/core/res/res/values-mcc314/config.xml
index df398f9..6e0b678 100644
--- a/core/res/res/values-mcc314/config.xml
+++ b/core/res/res/values-mcc314/config.xml
@@ -22,4 +22,7 @@
<!-- Whether safe headphone volume is enabled or not (country specific). -->
<bool name="config_safe_media_volume_enabled">false</bool>
+ <!-- Whether safe headphone sound dosage warning is enabled or not (country specific). -->
+ <bool name="config_safe_sound_dosage_enabled">false</bool>
+
</resources>
diff --git a/core/res/res/values-mcc315/config.xml b/core/res/res/values-mcc315/config.xml
index df398f9..6e0b678 100644
--- a/core/res/res/values-mcc315/config.xml
+++ b/core/res/res/values-mcc315/config.xml
@@ -22,4 +22,7 @@
<!-- Whether safe headphone volume is enabled or not (country specific). -->
<bool name="config_safe_media_volume_enabled">false</bool>
+ <!-- Whether safe headphone sound dosage warning is enabled or not (country specific). -->
+ <bool name="config_safe_sound_dosage_enabled">false</bool>
+
</resources>
diff --git a/core/res/res/values-mcc316/config.xml b/core/res/res/values-mcc316/config.xml
index df398f9..6e0b678 100644
--- a/core/res/res/values-mcc316/config.xml
+++ b/core/res/res/values-mcc316/config.xml
@@ -22,4 +22,7 @@
<!-- Whether safe headphone volume is enabled or not (country specific). -->
<bool name="config_safe_media_volume_enabled">false</bool>
+ <!-- Whether safe headphone sound dosage warning is enabled or not (country specific). -->
+ <bool name="config_safe_sound_dosage_enabled">false</bool>
+
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 12dad7e..7bc3ab8 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2105,9 +2105,6 @@
<!-- The default volume for the ring stream -->
<integer name="config_audio_ring_vol_default">5</integer>
- <!-- Enable sound dose computation and warnings -->
- <bool name="config_audio_csd_enabled_default">true</bool>
-
<!-- The default value for whether head tracking for
spatial audio is enabled for a newly connected audio device -->
<bool name="config_spatial_audio_head_tracking_enabled_default">false</bool>
@@ -2939,6 +2936,9 @@
<!-- Whether safe headphone volume is enabled or not (country specific). -->
<bool name="config_safe_media_volume_enabled">true</bool>
+ <!-- Whether safe headphone sound dosage warning is enabled or not (country specific). -->
+ <bool name="config_safe_sound_dosage_enabled">true</bool>
+
<!-- Whether safe headphone volume warning dialog is disabled on Vol+ (operator specific). -->
<bool name="config_safe_media_disable_on_volume_up">true</bool>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index bc0af12..ad864b1 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -96,12 +96,12 @@
<!-- Width of the navigation bar when it is placed vertically on the screen in car mode -->
<dimen name="navigation_bar_width_car_mode">96dp</dimen>
<!-- Height of notification icons in the status bar -->
- <dimen name="status_bar_icon_size">22dip</dimen>
+ <dimen name="status_bar_icon_size">18sp</dimen>
<!-- Desired size of system icons in status bar. -->
- <dimen name="status_bar_system_icon_size">15dp</dimen>
+ <dimen name="status_bar_system_icon_size">15sp</dimen>
<!-- Intrinsic size of most system icons in status bar. This is the default value that
is used if a Drawable reports an intrinsic size of 0. -->
- <dimen name="status_bar_system_icon_intrinsic_size">17dp</dimen>
+ <dimen name="status_bar_system_icon_intrinsic_size">17sp</dimen>
<!-- Size of the giant number (unread count) in the notifications -->
<dimen name="status_bar_content_number_size">48sp</dimen>
<!-- Margin at the edge of the screen to ignore touch events for in the windowshade. -->
@@ -330,7 +330,7 @@
<dimen name="notification_icon_circle_start">16dp</dimen>
<!-- size (width and height) of the icon in the notification header -->
- <dimen name="notification_header_icon_size_ambient">18dp</dimen>
+ <dimen name="notification_header_icon_size_ambient">18sp</dimen>
<!-- The margin before the start of the app name in the header. -->
<dimen name="notification_header_app_name_margin_start">3dp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index bb10f7a..e25425d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -283,7 +283,6 @@
<java-symbol type="attr" name="autofillSaveCustomSubtitleMaxHeight"/>
<java-symbol type="bool" name="action_bar_embed_tabs" />
<java-symbol type="bool" name="action_bar_expanded_action_views_exclusive" />
- <java-symbol type="bool" name="config_audio_csd_enabled_default" />
<java-symbol type="integer" name="config_audio_notif_vol_default" />
<java-symbol type="integer" name="config_audio_notif_vol_steps" />
<java-symbol type="integer" name="config_audio_ring_vol_default" />
@@ -349,6 +348,7 @@
<java-symbol type="bool" name="config_useDevInputEventForAudioJack" />
<java-symbol type="bool" name="config_safe_media_volume_enabled" />
<java-symbol type="bool" name="config_safe_media_disable_on_volume_up" />
+ <java-symbol type="bool" name="config_safe_sound_dosage_enabled" />
<java-symbol type="bool" name="config_camera_sound_forced" />
<java-symbol type="bool" name="config_dontPreferApn" />
<java-symbol type="bool" name="config_restartRadioAfterProvisioning" />
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/AidlTestUtils.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/AidlTestUtils.java
index cce1b2b..6c70192 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/AidlTestUtils.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/AidlTestUtils.java
@@ -80,7 +80,7 @@
/* vendorIds= */ null);
}
- static android.hardware.broadcastradio.ProgramSelector makeHalFmSelector(int freq) {
+ static android.hardware.broadcastradio.ProgramSelector makeHalFmSelector(long freq) {
ProgramIdentifier halId = makeHalIdentifier(IdentifierType.AMFM_FREQUENCY_KHZ, freq);
return makeHalSelector(halId, /* secondaryIds= */ new ProgramIdentifier[0]);
}
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsResultTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsResultTest.java
index df3ddfd..b54c156 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsResultTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsResultTest.java
@@ -52,6 +52,7 @@
{Result.INVALID_STATE, RadioTuner.TUNER_RESULT_INVALID_STATE},
{Result.NOT_SUPPORTED, RadioTuner.TUNER_RESULT_NOT_SUPPORTED},
{Result.TIMEOUT, RadioTuner.TUNER_RESULT_TIMEOUT},
+ {Result.CANCELED, RadioTuner.TUNER_RESULT_CANCELED},
{Result.UNKNOWN_ERROR, RadioTuner.TUNER_RESULT_UNKNOWN_ERROR}
});
}
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java
index aea0178..2ef923d 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java
@@ -27,11 +27,13 @@
import android.hardware.broadcastradio.ProgramInfo;
import android.hardware.broadcastradio.ProgramListChunk;
import android.hardware.broadcastradio.Properties;
+import android.hardware.broadcastradio.Result;
import android.hardware.broadcastradio.VendorKeyValue;
import android.hardware.radio.Announcement;
import android.hardware.radio.ProgramList;
import android.hardware.radio.ProgramSelector;
import android.hardware.radio.RadioManager;
+import android.os.ServiceSpecificException;
import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
import com.android.server.broadcastradio.ExtendedRadioMockitoTestCase;
@@ -153,6 +155,16 @@
}
@Test
+ public void throwOnError_withCancelException() {
+ ServiceSpecificException halException = new ServiceSpecificException(Result.CANCELED);
+
+ RuntimeException thrown = ConversionUtils.throwOnError(halException, "tune");
+
+ expect.withMessage("Exception thrown for canceling error").that(thrown)
+ .hasMessageThat().contains("tune: CANCELED");
+ }
+
+ @Test
public void propertiesFromHalProperties_idsMatch() {
expect.withMessage("Properties id")
.that(MODULE_PROPERTIES.getId()).isEqualTo(TEST_ID);
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
index f85748c..84aa864 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
@@ -1168,13 +1168,29 @@
doReturn(USER_ID_2).when(() -> RadioServiceUserController.getCurrentUser());
mHalTunerCallback.onCurrentProgramInfoChanged(AidlTestUtils.makeHalProgramInfo(
- AidlTestUtils.makeHalFmSelector(/* freq= */ 97300), SIGNAL_QUALITY));
+ AidlTestUtils.makeHalFmSelector(AM_FM_FREQUENCY_LIST[1]), SIGNAL_QUALITY));
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
.onCurrentProgramInfoChanged(any());
}
@Test
+ public void onTuneFailed_forTunerCallback() throws Exception {
+ int numSessions = 3;
+ openAidlClients(numSessions);
+ android.hardware.broadcastradio.ProgramSelector halSel = AidlTestUtils.makeHalFmSelector(
+ AM_FM_FREQUENCY_LIST[1]);
+ ProgramSelector sel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
+
+ mHalTunerCallback.onTuneFailed(Result.CANCELED, halSel);
+
+ for (int index = 0; index < numSessions; index++) {
+ verify(mAidlTunerCallbackMocks[index], CALLBACK_TIMEOUT)
+ .onTuneFailed(RadioTuner.TUNER_RESULT_CANCELED, sel);
+ }
+ }
+
+ @Test
public void onAntennaStateChange_forTunerCallback() throws Exception {
int numSessions = 3;
openAidlClients(numSessions);
diff --git a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
index bf8c7c6..72969f7 100644
--- a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
+++ b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
@@ -112,6 +112,7 @@
Paths.get("/data/misc/wmtrace/layers_trace.winscope"),
Paths.get("/data/misc/wmtrace/transactions_trace.winscope"),
Paths.get("/data/misc/wmtrace/transition_trace.winscope"),
+ Paths.get("/data/misc/wmtrace/shell_transition_trace.winscope"),
};
private static final Path[] UI_TRACES_GENERATED_DURING_BUGREPORT = {
Paths.get("/data/misc/wmtrace/layers_trace_from_transactions.winscope"),
diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
index a3eda8d..f45db23 100644
--- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
@@ -39,7 +39,6 @@
import android.widget.TextView;
import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.FlakyTest;
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Before;
@@ -55,7 +54,6 @@
* atest FrameworksCoreTests:ImeInsetsSourceConsumerTest
*/
@Presubmit
-@FlakyTest(detail = "Promote once confirmed non-flaky")
@RunWith(AndroidJUnit4.class)
public class ImeInsetsSourceConsumerTest {
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 596f351..7c2759a 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1183,6 +1183,12 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/AppTransitionController.java"
},
+ "-1005167552": {
+ "message": "Playing #%d in parallel on track #%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/TransitionController.java"
+ },
"-1003678883": {
"message": "Cleaning splash screen token=%s",
"level": "VERBOSE",
@@ -1447,6 +1453,12 @@
"group": "WM_DEBUG_TASKS",
"at": "com\/android\/server\/wm\/RootWindowContainer.java"
},
+ "-774908272": {
+ "message": "Marking #%d animation as SYNC.",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/TransitionController.java"
+ },
"-771177730": {
"message": "Removing focused app token:%s displayId=%d",
"level": "VERBOSE",
@@ -1495,12 +1507,6 @@
"group": "WM_DEBUG_CONFIGURATION",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
- "-741766551": {
- "message": "Content Recording: Ignoring session on invalid virtual display",
- "level": "VERBOSE",
- "group": "WM_DEBUG_CONTENT_RECORDING",
- "at": "com\/android\/server\/wm\/ContentRecordingController.java"
- },
"-732715767": {
"message": "Unable to retrieve window container to start recording for display %d",
"level": "VERBOSE",
@@ -2017,6 +2023,12 @@
"group": "WM_DEBUG_WALLPAPER",
"at": "com\/android\/server\/wm\/WallpaperController.java"
},
+ "-266707683": {
+ "message": "Moving #%d from collecting to waiting.",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
+ "at": "com\/android\/server\/wm\/TransitionController.java"
+ },
"-262984451": {
"message": "Relaunch failed %s",
"level": "INFO",
@@ -2089,6 +2101,12 @@
"group": "WM_DEBUG_WINDOW_MOVEMENT",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-186693085": {
+ "message": "Starting a Recents transition which can be parallel.",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"-182877285": {
"message": "Wallpaper layer changed: assigning layers + relayout",
"level": "VERBOSE",
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 302c72e..dd4b58e 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -40,6 +40,7 @@
import android.graphics.drawable.NinePatchDrawable;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
+import android.media.MediaFormat;
import android.net.Uri;
import android.os.Build;
import android.os.Trace;
@@ -914,8 +915,6 @@
case "image/jpeg":
case "image/webp":
case "image/gif":
- case "image/heif":
- case "image/heic":
case "image/bmp":
case "image/x-ico":
case "image/vnd.wap.wbmp":
@@ -930,6 +929,9 @@
case "image/x-pentax-pef":
case "image/x-samsung-srw":
return true;
+ case "image/heif":
+ case "image/heic":
+ return isHevcDecoderSupported();
case "image/avif":
return isP010SupportedForAV1();
default:
@@ -2067,6 +2069,28 @@
return decodeBitmapImpl(src, null);
}
+ private static boolean sIsHevcDecoderSupported = false;
+ private static boolean sIsHevcDecoderSupportedInitialized = false;
+ private static final Object sIsHevcDecoderSupportedLock = new Object();
+
+ /*
+ * Check if HEVC decoder is supported by the device.
+ */
+ @SuppressWarnings("AndroidFrameworkCompatChange")
+ private static boolean isHevcDecoderSupported() {
+ synchronized (sIsHevcDecoderSupportedLock) {
+ if (sIsHevcDecoderSupportedInitialized) {
+ return sIsHevcDecoderSupported;
+ }
+ MediaFormat format = new MediaFormat();
+ format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_VIDEO_HEVC);
+ MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+ sIsHevcDecoderSupported = mcl.findDecoderForFormat(format) != null;
+ sIsHevcDecoderSupportedInitialized = true;
+ return sIsHevcDecoderSupported;
+ }
+ }
+
private static boolean sIsP010SupportedForAV1 = false;
private static boolean sIsP010SupportedForHEVC = false;
private static boolean sIsP010SupportedFlagsInitialized = false;
@@ -2105,20 +2129,20 @@
* Checks if the device supports decoding 10-bit for the given mime type.
*/
private static void checkP010SupportforAV1HEVC() {
- MediaCodecList codecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
+ MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
for (MediaCodecInfo mediaCodecInfo : codecList.getCodecInfos()) {
if (mediaCodecInfo.isEncoder()) {
continue;
}
for (String mediaType : mediaCodecInfo.getSupportedTypes()) {
- if (mediaType.equalsIgnoreCase("video/av01")
- || mediaType.equalsIgnoreCase("video/hevc")) {
+ if (mediaType.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AV1)
+ || mediaType.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
MediaCodecInfo.CodecCapabilities codecCapabilities =
mediaCodecInfo.getCapabilitiesForType(mediaType);
for (int i = 0; i < codecCapabilities.colorFormats.length; ++i) {
if (codecCapabilities.colorFormats[i]
== MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010) {
- if (mediaType.equalsIgnoreCase("video/av01")) {
+ if (mediaType.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AV1)) {
sIsP010SupportedForAV1 = true;
} else {
sIsP010SupportedForHEVC = true;
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 54978bd..6a79bc1 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -125,6 +125,34 @@
// End ProtoLog
+gensrcs {
+ name: "wm-shell-protos",
+
+ tools: [
+ "aprotoc",
+ "protoc-gen-javastream",
+ "soong_zip",
+ ],
+
+ tool_files: [
+ ":libprotobuf-internal-protos",
+ ],
+
+ cmd: "mkdir -p $(genDir)/$(in) " +
+ "&& $(location aprotoc) " +
+ " --plugin=$(location protoc-gen-javastream) " +
+ " --javastream_out=$(genDir)/$(in) " +
+ " -Iexternal/protobuf/src " +
+ " -I . " +
+ " $(in) " +
+ "&& $(location soong_zip) -jar -o $(out) -C $(genDir)/$(in) -D $(genDir)/$(in)",
+
+ srcs: [
+ "proto/**/*.proto",
+ ],
+ output_extension: "srcjar",
+}
+
java_library {
name: "WindowManager-Shell-proto",
@@ -142,6 +170,7 @@
// TODO(b/168581922) protologtool do not support kotlin(*.kt)
":wm_shell-sources-kt",
":wm_shell-aidls",
+ ":wm-shell-protos",
],
resource_dirs: [
"res",
diff --git a/libs/WindowManager/Shell/proto/wm_shell_transition_trace.proto b/libs/WindowManager/Shell/proto/wm_shell_transition_trace.proto
new file mode 100644
index 0000000..6e01101
--- /dev/null
+++ b/libs/WindowManager/Shell/proto/wm_shell_transition_trace.proto
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package com.android.wm.shell;
+
+option java_multiple_files = true;
+
+/* Represents a file full of transition entries.
+ Encoded, it should start with 0x09 0x57 0x4D 0x53 0x54 0x52 0x41 0x43 0x45 (.WMSTRACE), such
+ that it can be easily identified. */
+message WmShellTransitionTraceProto {
+ /* constant; MAGIC_NUMBER = (long) MAGIC_NUMBER_H << 32 | MagicNumber.MAGIC_NUMBER_L
+ (this is needed because enums have to be 32 bits and there's no nice way to put 64bit
+ constants into .proto files. */
+ enum MagicNumber {
+ INVALID = 0;
+ MAGIC_NUMBER_L = 0x54534D57; /* WMST (little-endian ASCII) */
+ MAGIC_NUMBER_H = 0x45434152; /* RACE (little-endian ASCII) */
+ }
+
+ // Must be the first field, set to value in MagicNumber
+ required fixed64 magic_number = 1;
+ repeated Transition transitions = 2;
+ repeated HandlerMapping handlerMappings = 3;
+}
+
+message Transition {
+ required int32 id = 1;
+ optional int64 dispatch_time_ns = 2;
+ optional int32 handler = 3;
+ optional int64 merge_time_ns = 4;
+ optional int64 merge_request_time_ns = 5;
+ optional int32 merged_into = 6;
+ optional int64 abort_time_ns = 7;
+}
+
+message HandlerMapping {
+ required int32 id = 1;
+ required string name = 2;
+}
diff --git a/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml b/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml
index 5aff415..7f1aac3 100644
--- a/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml
+++ b/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml
@@ -73,11 +73,13 @@
android:textAlignment="center"/>
<LinearLayout
+ android:id="@+id/letterbox_restart_dialog_checkbox_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:paddingVertical="14dp"
android:orientation="horizontal"
android:layout_gravity="center_vertical"
- android:layout_marginVertical="32dp">
+ android:layout_marginVertical="18dp">
<CheckBox
android:id="@+id/letterbox_restart_dialog_checkbox"
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index 76eb094..a3916b7 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -125,4 +125,7 @@
<!-- Whether the additional education about reachability is enabled -->
<bool name="config_letterboxIsReachabilityEducationEnabled">false</bool>
+
+ <!-- Whether DragAndDrop capability is enabled -->
+ <bool name="config_enableShellDragDrop">true</bool>
</resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index d3f3958..24fd86b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -297,7 +297,7 @@
public BubbleInfo asBubbleBarBubble() {
return new BubbleInfo(getKey(),
getFlags(),
- getShortcutInfo().getId(),
+ getShortcutId(),
getIcon(),
getUser().getIdentifier(),
getPackageName());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 21f02b1..3eb9fa2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -260,7 +260,7 @@
/** One handed mode controller to register transition listener. */
private Optional<OneHandedController> mOneHandedOptional;
/** Drag and drop controller to register listener for onDragStarted. */
- private DragAndDropController mDragAndDropController;
+ private Optional<DragAndDropController> mDragAndDropController;
/** Used to send bubble events to launcher. */
private Bubbles.BubbleStateListener mBubbleStateListener;
@@ -286,7 +286,7 @@
BubblePositioner positioner,
DisplayController displayController,
Optional<OneHandedController> oneHandedOptional,
- DragAndDropController dragAndDropController,
+ Optional<DragAndDropController> dragAndDropController,
@ShellMainThread ShellExecutor mainExecutor,
@ShellMainThread Handler mainHandler,
@ShellBackgroundThread ShellExecutor bgExecutor,
@@ -469,7 +469,7 @@
});
mOneHandedOptional.ifPresent(this::registerOneHandedState);
- mDragAndDropController.addListener(this::collapseStack);
+ mDragAndDropController.ifPresent(controller -> controller.addListener(this::collapseStack));
// Clear out any persisted bubbles on disk that no longer have a valid user.
List<UserInfo> users = mUserManager.getAliveUsers();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java
index 0f9260c..9abf0f6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java
@@ -38,7 +38,7 @@
default void onTaskStackChanged() { }
- default void onTaskProfileLocked(RunningTaskInfo taskInfo) { }
+ default void onTaskProfileLocked(RunningTaskInfo taskInfo, int userId) { }
default void onTaskDisplayChanged(int taskId, int newDisplayId) { }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java
index e2106e4..d8859ba 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java
@@ -150,8 +150,8 @@
}
@Override
- public void onTaskProfileLocked(ActivityManager.RunningTaskInfo taskInfo) {
- mMainHandler.obtainMessage(ON_TASK_PROFILE_LOCKED, taskInfo).sendToTarget();
+ public void onTaskProfileLocked(ActivityManager.RunningTaskInfo taskInfo, int userId) {
+ mMainHandler.obtainMessage(ON_TASK_PROFILE_LOCKED, userId, 0, taskInfo).sendToTarget();
}
@Override
@@ -348,8 +348,9 @@
case ON_TASK_PROFILE_LOCKED: {
final ActivityManager.RunningTaskInfo
info = (ActivityManager.RunningTaskInfo) msg.obj;
+ final int userId = msg.arg1;
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
- mTaskStackListeners.get(i).onTaskProfileLocked(info);
+ mTaskStackListeners.get(i).onTaskProfileLocked(info, userId);
}
break;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleInfo.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleInfo.java
index b0dea72..d27d05b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleInfo.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleInfo.java
@@ -35,6 +35,7 @@
private String mKey; // Same key as the Notification
private int mFlags; // Flags from BubbleMetadata
+ @Nullable
private String mShortcutId;
private int mUserId;
private String mPackageName;
@@ -46,7 +47,7 @@
@Nullable
private Icon mIcon;
- public BubbleInfo(String key, int flags, String shortcutId, @Nullable Icon icon,
+ public BubbleInfo(String key, int flags, @Nullable String shortcutId, @Nullable Icon icon,
int userId, String packageName) {
mKey = key;
mFlags = flags;
@@ -69,10 +70,12 @@
return mKey;
}
+ @Nullable
public String getShortcutId() {
return mShortcutId;
}
+ @Nullable
public Icon getIcon() {
return mIcon;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 9eba5ec..e7dede7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -738,10 +738,6 @@
getRefBounds2(mTempRect);
t.setPosition(leash2, mTempRect.left, mTempRect.top)
.setWindowCrop(leash2, mTempRect.width(), mTempRect.height());
- // Make right or bottom side surface always higher than left or top side to avoid weird
- // animation when dismiss split. e.g. App surface fling above on decor surface.
- t.setLayer(leash1, 1);
- t.setLayer(leash2, 2);
if (mImePositionProcessor.adjustSurfaceLayoutForIme(
t, dividerLeash, leash1, leash2, dimLayer1, dimLayer2)) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogLayout.java
index c53e638..05fd5f1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogLayout.java
@@ -95,6 +95,9 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ final View checkboxContainer = findViewById(
+ R.id.letterbox_restart_dialog_checkbox_container);
+ final CheckBox checkbox = findViewById(R.id.letterbox_restart_dialog_checkbox);
mDialogContainer = findViewById(R.id.letterbox_restart_dialog_container);
mDialogTitle = findViewById(R.id.letterbox_restart_dialog_title);
mBackgroundDim = getBackground().mutate();
@@ -103,5 +106,6 @@
// We add a no-op on-click listener to the dialog container so that clicks on it won't
// propagate to the listener of the layout (which represents the background dim).
mDialogContainer.setOnClickListener(view -> {});
+ checkboxContainer.setOnClickListener(view -> checkbox.performClick());
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java
index e9957fd..12d51f5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java
@@ -41,11 +41,11 @@
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
-import java.util.Optional;
-
import dagger.Module;
import dagger.Provides;
+import java.util.Optional;
+
/**
* Provides dependencies from {@link com.android.wm.shell}, these dependencies are only
* accessible from components within the WM subcomponent (can be explicitly exposed to the
@@ -81,7 +81,7 @@
DisplayController displayController,
DisplayImeController displayImeController,
DisplayInsetsController displayInsetsController,
- DragAndDropController dragAndDropController,
+ Optional<DragAndDropController> dragAndDropController,
Transitions transitions,
TransactionPool transactionPool,
IconProvider iconProvider,
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 9808c59..80e920f 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
@@ -186,15 +186,15 @@
@WMSingleton
@Provides
- static DragAndDropController provideDragAndDropController(Context context,
+ static Optional<DragAndDropController> provideDragAndDropController(Context context,
ShellInit shellInit,
ShellController shellController,
DisplayController displayController,
UiEventLogger uiEventLogger,
IconProvider iconProvider,
@ShellMainThread ShellExecutor mainExecutor) {
- return new DragAndDropController(context, shellInit, shellController, displayController,
- uiEventLogger, iconProvider, mainExecutor);
+ return Optional.ofNullable(DragAndDropController.create(context, shellInit, shellController,
+ displayController, uiEventLogger, iconProvider, mainExecutor));
}
@WMSingleton
@@ -544,13 +544,14 @@
DisplayController displayController,
@ShellMainThread ShellExecutor mainExecutor,
@ShellMainThread Handler mainHandler,
- @ShellAnimationThread ShellExecutor animExecutor) {
+ @ShellAnimationThread ShellExecutor animExecutor,
+ ShellCommandHandler shellCommandHandler) {
if (!context.getResources().getBoolean(R.bool.config_registerShellTransitionsOnInit)) {
// TODO(b/238217847): Force override shell init if registration is disabled
shellInit = new ShellInit(mainExecutor);
}
return new Transitions(context, shellInit, shellController, organizer, pool,
- displayController, mainExecutor, mainHandler, animExecutor);
+ displayController, mainExecutor, mainHandler, animExecutor, shellCommandHandler);
}
@WMSingleton
@@ -796,7 +797,7 @@
DisplayController displayController,
DisplayImeController displayImeController,
DisplayInsetsController displayInsetsController,
- DragAndDropController dragAndDropController,
+ Optional<DragAndDropController> dragAndDropControllerOptional,
ShellTaskOrganizer shellTaskOrganizer,
Optional<BubbleController> bubblesOptional,
Optional<SplitScreenController> splitScreenOptional,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 2f0f56c..f3130d3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -171,7 +171,7 @@
BubblePositioner positioner,
DisplayController displayController,
@DynamicOverride Optional<OneHandedController> oneHandedOptional,
- DragAndDropController dragAndDropController,
+ Optional<DragAndDropController> dragAndDropController,
@ShellMainThread ShellExecutor mainExecutor,
@ShellMainThread Handler mainHandler,
@ShellBackgroundThread ShellExecutor bgExecutor,
@@ -320,7 +320,7 @@
DisplayController displayController,
DisplayImeController displayImeController,
DisplayInsetsController displayInsetsController,
- DragAndDropController dragAndDropController,
+ Optional<DragAndDropController> dragAndDropController,
Transitions transitions,
TransactionPool transactionPool,
IconProvider iconProvider,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
index 86ea725..b9d2be2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
@@ -264,10 +264,10 @@
/**
* Show apps on desktop
*/
- void showDesktopApps() {
+ void showDesktopApps(int displayId) {
// Bring apps to front, ignoring their visibility status to always ensure they are on top.
WindowContainerTransaction wct = new WindowContainerTransaction();
- bringDesktopAppsToFront(wct);
+ bringDesktopAppsToFront(displayId, wct);
if (!wct.isEmpty()) {
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
@@ -280,12 +280,12 @@
}
/** Get number of tasks that are marked as visible */
- int getVisibleTaskCount() {
- return mDesktopModeTaskRepository.getVisibleTaskCount();
+ int getVisibleTaskCount(int displayId) {
+ return mDesktopModeTaskRepository.getVisibleTaskCount(displayId);
}
- private void bringDesktopAppsToFront(WindowContainerTransaction wct) {
- final ArraySet<Integer> activeTasks = mDesktopModeTaskRepository.getActiveTasks();
+ private void bringDesktopAppsToFront(int displayId, WindowContainerTransaction wct) {
+ final ArraySet<Integer> activeTasks = mDesktopModeTaskRepository.getActiveTasks(displayId);
ProtoLog.d(WM_SHELL_DESKTOP_MODE, "bringDesktopAppsToFront: tasks=%s", activeTasks.size());
final List<RunningTaskInfo> taskInfos = new ArrayList<>();
@@ -386,6 +386,7 @@
@Override
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@NonNull TransitionRequestInfo request) {
+ RunningTaskInfo triggerTask = request.getTriggerTask();
// Only do anything if we are in desktop mode and opening/moving-to-front a task/app in
// freeform
if (!DesktopModeStatus.isActive(mContext)) {
@@ -399,16 +400,15 @@
WindowManager.transitTypeToString(request.getType()));
return null;
}
- if (request.getTriggerTask() == null
- || request.getTriggerTask().getWindowingMode() != WINDOWING_MODE_FREEFORM) {
+ if (triggerTask == null || triggerTask.getWindowingMode() != WINDOWING_MODE_FREEFORM) {
ProtoLog.d(WM_SHELL_DESKTOP_MODE, "skip shell transition request: not freeform task");
return null;
}
ProtoLog.d(WM_SHELL_DESKTOP_MODE, "handle shell transition request: %s", request);
WindowContainerTransaction wct = new WindowContainerTransaction();
- bringDesktopAppsToFront(wct);
- wct.reorder(request.getTriggerTask().token, true /* onTop */);
+ bringDesktopAppsToFront(triggerTask.displayId, wct);
+ wct.reorder(triggerTask.token, true /* onTop */);
return wct;
}
@@ -493,16 +493,17 @@
mController = null;
}
- public void showDesktopApps() {
+ @Override
+ public void showDesktopApps(int displayId) {
executeRemoteCallWithTaskPermission(mController, "showDesktopApps",
- DesktopModeController::showDesktopApps);
+ controller -> controller.showDesktopApps(displayId));
}
@Override
- public int getVisibleTaskCount() throws RemoteException {
+ public int getVisibleTaskCount(int displayId) throws RemoteException {
int[] result = new int[1];
executeRemoteCallWithTaskPermission(mController, "getVisibleTaskCount",
- controller -> result[0] = controller.getVisibleTaskCount(),
+ controller -> result[0] = controller.getVisibleTaskCount(displayId),
true /* blocking */
);
return result[0];
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
index 12f8ea2..00cc57f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
@@ -20,6 +20,8 @@
import android.util.ArrayMap
import android.util.ArraySet
import android.util.SparseArray
+import androidx.core.util.forEach
+import androidx.core.util.keyIterator
import androidx.core.util.valueIterator
import java.util.concurrent.Executor
import java.util.function.Consumer
@@ -29,14 +31,18 @@
*/
class DesktopModeTaskRepository {
- /**
- * Set of task ids that are marked as active in desktop mode.
- * Active tasks in desktop mode are freeform tasks that are visible or have been visible after
- * desktop mode was activated.
- * Task gets removed from this list when it vanishes. Or when desktop mode is turned off.
- */
- private val activeTasks = ArraySet<Int>()
- private val visibleTasks = ArraySet<Int>()
+ /** Task data that is tracked per display */
+ private data class DisplayData(
+ /**
+ * Set of task ids that are marked as active in desktop mode. Active tasks in desktop mode
+ * are freeform tasks that are visible or have been visible after desktop mode was
+ * activated. Task gets removed from this list when it vanishes. Or when desktop mode is
+ * turned off.
+ */
+ val activeTasks: ArraySet<Int> = ArraySet(),
+ val visibleTasks: ArraySet<Int> = ArraySet(),
+ )
+
// Tasks currently in freeform mode, ordered from top to bottom (top is at index 0).
private val freeformTasksInZOrder = mutableListOf<Int>()
private val activeTasksListeners = ArraySet<ActiveTasksListener>()
@@ -47,9 +53,22 @@
private var desktopGestureExclusionListener: Consumer<Region>? = null
private var desktopGestureExclusionExecutor: Executor? = null
- /**
- * Add a [ActiveTasksListener] to be notified of updates to active tasks in the repository.
- */
+ private val displayData =
+ object : SparseArray<DisplayData>() {
+ /**
+ * Get the [DisplayData] associated with this [displayId]
+ *
+ * Creates a new instance if one does not exist
+ */
+ fun getOrCreate(displayId: Int): DisplayData {
+ if (!contains(displayId)) {
+ put(displayId, DisplayData())
+ }
+ return get(displayId)
+ }
+ }
+
+ /** Add a [ActiveTasksListener] to be notified of updates to active tasks in the repository. */
fun addActiveTaskListener(activeTasksListener: ActiveTasksListener) {
activeTasksListeners.add(activeTasksListener)
}
@@ -57,10 +76,17 @@
/**
* Add a [VisibleTasksListener] to be notified when freeform tasks are visible or not.
*/
- fun addVisibleTasksListener(visibleTasksListener: VisibleTasksListener, executor: Executor) {
- visibleTasksListeners.put(visibleTasksListener, executor)
- executor.execute(
- Runnable { visibleTasksListener.onVisibilityChanged(visibleTasks.size > 0) })
+ fun addVisibleTasksListener(
+ visibleTasksListener: VisibleTasksListener,
+ executor: Executor
+ ) {
+ visibleTasksListeners[visibleTasksListener] = executor
+ displayData.keyIterator().forEach { displayId ->
+ val visibleTasks = getVisibleTaskCount(displayId)
+ executor.execute {
+ visibleTasksListener.onVisibilityChanged(displayId, visibleTasks > 0)
+ }
+ }
}
/**
@@ -100,14 +126,21 @@
}
/**
- * Mark a task with given [taskId] as active.
+ * Mark a task with given [taskId] as active on given [displayId]
*
- * @return `true` if the task was not active
+ * @return `true` if the task was not active on given [displayId]
*/
- fun addActiveTask(taskId: Int): Boolean {
- val added = activeTasks.add(taskId)
+ fun addActiveTask(displayId: Int, taskId: Int): Boolean {
+ // Check if task is active on another display, if so, remove it
+ displayData.forEach { id, data ->
+ if (id != displayId && data.activeTasks.remove(taskId)) {
+ activeTasksListeners.onEach { it.onActiveTasksChanged(id) }
+ }
+ }
+
+ val added = displayData.getOrCreate(displayId).activeTasks.add(taskId)
if (added) {
- activeTasksListeners.onEach { it.onActiveTasksChanged() }
+ activeTasksListeners.onEach { it.onActiveTasksChanged(displayId) }
}
return added
}
@@ -118,65 +151,93 @@
* @return `true` if the task was active
*/
fun removeActiveTask(taskId: Int): Boolean {
- val removed = activeTasks.remove(taskId)
- if (removed) {
- activeTasksListeners.onEach { it.onActiveTasksChanged() }
+ var result = false
+ displayData.forEach { displayId, data ->
+ if (data.activeTasks.remove(taskId)) {
+ activeTasksListeners.onEach { it.onActiveTasksChanged(displayId) }
+ result = true
+ }
}
- return removed
+ return result
}
/**
* Check if a task with the given [taskId] was marked as an active task
*/
fun isActiveTask(taskId: Int): Boolean {
- return activeTasks.contains(taskId)
+ return displayData.valueIterator().asSequence().any { data ->
+ data.activeTasks.contains(taskId)
+ }
}
/**
* Whether a task is visible.
*/
fun isVisibleTask(taskId: Int): Boolean {
- return visibleTasks.contains(taskId)
+ return displayData.valueIterator().asSequence().any { data ->
+ data.visibleTasks.contains(taskId)
+ }
}
/**
- * Get a set of the active tasks
+ * Get a set of the active tasks for given [displayId]
*/
- fun getActiveTasks(): ArraySet<Int> {
- return ArraySet(activeTasks)
+ fun getActiveTasks(displayId: Int): ArraySet<Int> {
+ return ArraySet(displayData[displayId]?.activeTasks)
}
/**
* Get a list of freeform tasks, ordered from top-bottom (top at index 0).
*/
+ // TODO(b/278084491): pass in display id
fun getFreeformTasksInZOrder(): List<Int> {
return freeformTasksInZOrder
}
/**
* Updates whether a freeform task with this id is visible or not and notifies listeners.
+ *
+ * If the task was visible on a different display with a different displayId, it is removed from
+ * the set of visible tasks on that display. Listeners will be notified.
*/
- fun updateVisibleFreeformTasks(taskId: Int, visible: Boolean) {
- val prevCount: Int = visibleTasks.size
+ fun updateVisibleFreeformTasks(displayId: Int, taskId: Int, visible: Boolean) {
if (visible) {
- visibleTasks.add(taskId)
- } else {
- visibleTasks.remove(taskId)
- }
- if (prevCount == 0 && visibleTasks.size == 1 ||
- prevCount > 0 && visibleTasks.size == 0) {
- for ((listener, executor) in visibleTasksListeners) {
- executor.execute(
- Runnable { listener.onVisibilityChanged(visibleTasks.size > 0) })
+ // Task is visible. Check if we need to remove it from any other display.
+ val otherDisplays = displayData.keyIterator().asSequence().filter { it != displayId }
+ for (otherDisplayId in otherDisplays) {
+ if (displayData[otherDisplayId].visibleTasks.remove(taskId)) {
+ // Task removed from other display, check if we should notify listeners
+ if (displayData[otherDisplayId].visibleTasks.isEmpty()) {
+ notifyVisibleTaskListeners(otherDisplayId, hasVisibleFreeformTasks = false)
+ }
+ }
}
}
+
+ val prevCount = getVisibleTaskCount(displayId)
+ if (visible) {
+ displayData.getOrCreate(displayId).visibleTasks.add(taskId)
+ } else {
+ displayData[displayId]?.visibleTasks?.remove(taskId)
+ }
+ val newCount = getVisibleTaskCount(displayId)
+ // Check if count changed and if there was no tasks or this is the first task
+ if (prevCount != newCount && (prevCount == 0 || newCount == 0)) {
+ notifyVisibleTaskListeners(displayId, newCount > 0)
+ }
+ }
+
+ private fun notifyVisibleTaskListeners(displayId: Int, hasVisibleFreeformTasks: Boolean) {
+ visibleTasksListeners.forEach { (listener, executor) ->
+ executor.execute { listener.onVisibilityChanged(displayId, hasVisibleFreeformTasks) }
+ }
}
/**
- * Get number of tasks that are marked as visible
+ * Get number of tasks that are marked as visible on given [displayId]
*/
- fun getVisibleTaskCount(): Int {
- return visibleTasks.size
+ fun getVisibleTaskCount(displayId: Int): Int {
+ return displayData[displayId]?.visibleTasks?.size ?: 0
}
/**
@@ -226,7 +287,7 @@
* Called when the active tasks change in desktop mode.
*/
@JvmDefault
- fun onActiveTasksChanged() {}
+ fun onActiveTasksChanged(displayId: Int) {}
}
/**
@@ -237,6 +298,6 @@
* Called when the desktop starts or stops showing freeform tasks.
*/
@JvmDefault
- fun onVisibilityChanged(hasVisibleFreeformTasks: Boolean) {}
+ fun onVisibilityChanged(displayId: Int, hasVisibleFreeformTasks: Boolean) {}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 0d56023..c814fe5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -97,10 +97,11 @@
}
/** Show all tasks, that are part of the desktop, on top of launcher */
- fun showDesktopApps() {
+ fun showDesktopApps(displayId: Int) {
ProtoLog.v(WM_SHELL_DESKTOP_MODE, "showDesktopApps")
val wct = WindowContainerTransaction()
- bringDesktopAppsToFront(wct)
+ // TODO(b/278084491): pass in display id
+ bringDesktopAppsToFront(displayId, wct)
// Execute transaction if there are pending operations
if (!wct.isEmpty) {
@@ -114,8 +115,8 @@
}
/** Get number of tasks that are marked as visible */
- fun getVisibleTaskCount(): Int {
- return desktopModeTaskRepository.getVisibleTaskCount()
+ fun getVisibleTaskCount(displayId: Int): Int {
+ return desktopModeTaskRepository.getVisibleTaskCount(displayId)
}
/** Move a task with given `taskId` to desktop */
@@ -129,7 +130,7 @@
val wct = WindowContainerTransaction()
// Bring other apps to front first
- bringDesktopAppsToFront(wct)
+ bringDesktopAppsToFront(task.displayId, wct)
addMoveToDesktopChanges(wct, task.token)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
@@ -165,7 +166,7 @@
freeformBounds: Rect
) {
val wct = WindowContainerTransaction()
- bringDesktopAppsToFront(wct)
+ bringDesktopAppsToFront(taskInfo.displayId, wct)
addMoveToDesktopChanges(wct, taskInfo.getToken())
wct.setBounds(taskInfo.token, freeformBounds)
@@ -244,9 +245,9 @@
?: WINDOWING_MODE_UNDEFINED
}
- private fun bringDesktopAppsToFront(wct: WindowContainerTransaction) {
+ private fun bringDesktopAppsToFront(displayId: Int, wct: WindowContainerTransaction) {
ProtoLog.v(WM_SHELL_DESKTOP_MODE, "bringDesktopAppsToFront")
- val activeTasks = desktopModeTaskRepository.getActiveTasks()
+ val activeTasks = desktopModeTaskRepository.getActiveTasks(displayId)
// First move home to front and then other tasks on top of it
moveHomeTaskToFront(wct)
@@ -290,18 +291,17 @@
request: TransitionRequestInfo
): WindowContainerTransaction? {
// Check if we should skip handling this transition
- val task: RunningTaskInfo? = request.triggerTask
val shouldHandleRequest =
when {
// Only handle open or to front transitions
request.type != TRANSIT_OPEN && request.type != TRANSIT_TO_FRONT -> false
// Only handle when it is a task transition
- task == null -> false
+ request.triggerTask == null -> false
// Only handle standard type tasks
- task.activityType != ACTIVITY_TYPE_STANDARD -> false
+ request.triggerTask.activityType != ACTIVITY_TYPE_STANDARD -> false
// Only handle fullscreen or freeform tasks
- task.windowingMode != WINDOWING_MODE_FULLSCREEN &&
- task.windowingMode != WINDOWING_MODE_FREEFORM -> false
+ request.triggerTask.windowingMode != WINDOWING_MODE_FULLSCREEN &&
+ request.triggerTask.windowingMode != WINDOWING_MODE_FREEFORM -> false
// Otherwise process it
else -> true
}
@@ -310,10 +310,11 @@
return null
}
- val activeTasks = desktopModeTaskRepository.getActiveTasks()
+ val task: RunningTaskInfo = request.triggerTask
+ val activeTasks = desktopModeTaskRepository.getActiveTasks(task.displayId)
// Check if we should switch a fullscreen task to freeform
- if (task?.windowingMode == WINDOWING_MODE_FULLSCREEN) {
+ if (task.windowingMode == WINDOWING_MODE_FULLSCREEN) {
// If there are any visible desktop tasks, switch the task to freeform
if (activeTasks.any { desktopModeTaskRepository.isVisibleTask(it) }) {
ProtoLog.d(
@@ -329,7 +330,7 @@
}
// CHeck if we should switch a freeform task to fullscreen
- if (task?.windowingMode == WINDOWING_MODE_FREEFORM) {
+ if (task.windowingMode == WINDOWING_MODE_FREEFORM) {
// If no visible desktop tasks, switch this task to freeform as the transition came
// outside of this controller
if (activeTasks.none { desktopModeTaskRepository.isVisibleTask(it) }) {
@@ -559,20 +560,19 @@
controller = null
}
- override fun showDesktopApps() {
+ override fun showDesktopApps(displayId: Int) {
ExecutorUtils.executeRemoteCallWithTaskPermission(
controller,
- "showDesktopApps",
- Consumer(DesktopTasksController::showDesktopApps)
- )
+ "showDesktopApps"
+ ) { c -> c.showDesktopApps(displayId) }
}
- override fun getVisibleTaskCount(): Int {
+ override fun getVisibleTaskCount(displayId: Int): Int {
val result = IntArray(1)
ExecutorUtils.executeRemoteCallWithTaskPermission(
controller,
"getVisibleTaskCount",
- { controller -> result[0] = controller.getVisibleTaskCount() },
+ { controller -> result[0] = controller.getVisibleTaskCount(displayId) },
true /* blocking */
)
return result[0]
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
index d0739e1..899d672 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
@@ -21,9 +21,9 @@
*/
interface IDesktopMode {
- /** Show apps on the desktop */
- void showDesktopApps();
+ /** Show apps on the desktop on the given display */
+ void showDesktopApps(int displayId);
- /** Get count of visible desktop tasks */
- int getVisibleTaskCount();
+ /** Get count of visible desktop tasks on the given display */
+ int getVisibleTaskCount(int displayId);
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index 4cfaae6..091de3a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -94,7 +94,24 @@
void onDragStarted();
}
- public DragAndDropController(Context context,
+ /**
+ * Creates {@link DragAndDropController}. Returns {@code null} if the feature is disabled.
+ */
+ public static DragAndDropController create(Context context,
+ ShellInit shellInit,
+ ShellController shellController,
+ DisplayController displayController,
+ UiEventLogger uiEventLogger,
+ IconProvider iconProvider,
+ ShellExecutor mainExecutor) {
+ if (!context.getResources().getBoolean(R.bool.config_enableShellDragDrop)) {
+ return null;
+ }
+ return new DragAndDropController(context, shellInit, shellController, displayController,
+ uiEventLogger, iconProvider, mainExecutor);
+ }
+
+ DragAndDropController(Context context,
ShellInit shellInit,
ShellController shellController,
DisplayController displayController,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
index 48487bc..22541bbd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
@@ -94,11 +94,12 @@
mDesktopModeTaskRepository.ifPresent(repository -> {
repository.addOrMoveFreeformTaskToTop(taskInfo.taskId);
if (taskInfo.isVisible) {
- if (repository.addActiveTask(taskInfo.taskId)) {
+ if (repository.addActiveTask(taskInfo.displayId, taskInfo.taskId)) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
"Adding active freeform task: #%d", taskInfo.taskId);
}
- repository.updateVisibleFreeformTasks(taskInfo.taskId, true);
+ repository.updateVisibleFreeformTasks(taskInfo.displayId, taskInfo.taskId,
+ true);
}
});
}
@@ -117,7 +118,7 @@
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
"Removing active freeform task: #%d", taskInfo.taskId);
}
- repository.updateVisibleFreeformTasks(taskInfo.taskId, false);
+ repository.updateVisibleFreeformTasks(taskInfo.displayId, taskInfo.taskId, false);
});
}
@@ -137,12 +138,13 @@
if (DesktopModeStatus.isAnyEnabled()) {
mDesktopModeTaskRepository.ifPresent(repository -> {
if (taskInfo.isVisible) {
- if (repository.addActiveTask(taskInfo.taskId)) {
+ if (repository.addActiveTask(taskInfo.displayId, taskInfo.taskId)) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
"Adding active freeform task: #%d", taskInfo.taskId);
}
}
- repository.updateVisibleFreeformTasks(taskInfo.taskId, taskInfo.isVisible);
+ repository.updateVisibleFreeformTasks(taskInfo.displayId, taskInfo.taskId,
+ taskInfo.isVisible);
});
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
index e1a56a1..6b6a7bc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
@@ -153,6 +153,8 @@
@Override
public void onTransitionMerged(@NonNull IBinder merged, @NonNull IBinder playing) {
+ mWindowDecorViewModel.onTransitionMerged(merged, playing);
+
final List<ActivityManager.RunningTaskInfo> infoOfMerged =
mTransitionToTaskInfo.get(merged);
if (infoOfMerged == null) {
@@ -169,8 +171,6 @@
} else {
mTransitionToTaskInfo.put(playing, infoOfMerged);
}
-
- mWindowDecorViewModel.onTransitionMerged(merged, playing);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 566c130..d3e7f9c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -72,7 +72,6 @@
import android.window.TaskSnapshot;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
-import android.window.WindowContainerTransactionCallback;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
@@ -139,17 +138,6 @@
// the runnable to execute after WindowContainerTransactions is applied to finish resizing pip
private Runnable mPipFinishResizeWCTRunnable;
- private final WindowContainerTransactionCallback mPipFinishResizeWCTCallback =
- new WindowContainerTransactionCallback() {
- @Override
- public void onTransactionReady(int id, SurfaceControl.Transaction t) {
- t.apply();
-
- // execute the runnable if non-null after WCT is applied to finish resizing pip
- maybePerformFinishResizeCallback();
- }
- };
-
private void maybePerformFinishResizeCallback() {
if (mPipFinishResizeWCTRunnable != null) {
mPipFinishResizeWCTRunnable.run();
@@ -175,6 +163,7 @@
final int direction = animator.getTransitionDirection();
if (mIsCancelled) {
sendOnPipTransitionFinished(direction);
+ maybePerformFinishResizeCallback();
return;
}
final int animationType = animator.getAnimationType();
@@ -199,6 +188,10 @@
|| isRemovePipDirection(direction);
if (mPipTransitionState.getTransitionState() != PipTransitionState.EXITING_PIP
|| isExitPipDirection) {
+ // execute the finish resize callback if needed after the transaction is committed
+ tx.addTransactionCommittedListener(mMainExecutor,
+ PipTaskOrganizer.this::maybePerformFinishResizeCallback);
+
// Finish resize as long as we're not exiting PIP, or, if we are, only if this is
// the end of an exit PIP animation.
// This is necessary in case there was a resize animation ongoing when exit PIP
@@ -1614,12 +1607,8 @@
if (direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
mSplitScreenOptional.ifPresent(splitScreenController ->
splitScreenController.enterSplitScreen(mTaskInfo.taskId, wasPipTopLeft, wct));
- } else if (direction == TRANSITION_DIRECTION_LEAVE_PIP) {
- // when leaving PiP we can call the callback without sync
- maybePerformFinishResizeCallback();
- mTaskOrganizer.applyTransaction(wct);
} else {
- mTaskOrganizer.applySyncTransaction(wct, mPipFinishResizeWCTCallback);
+ mTaskOrganizer.applyTransaction(wct);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index b0bb14b..f8e1435 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -1060,13 +1060,22 @@
/** Save the state to restore to on re-entry. */
public void saveReentryState(Rect pipBounds) {
float snapFraction = mPipBoundsAlgorithm.getSnapFraction(pipBounds);
- if (mPipBoundsState.hasUserResizedPip()) {
- final Rect reentryBounds = mTouchHandler.getUserResizeBounds();
- final Size reentrySize = new Size(reentryBounds.width(), reentryBounds.height());
- mPipBoundsState.saveReentryState(reentrySize, snapFraction);
- } else {
+
+ if (!mPipBoundsState.hasUserResizedPip()) {
mPipBoundsState.saveReentryState(null /* bounds */, snapFraction);
+ return;
}
+
+ Size reentrySize = new Size(pipBounds.width(), pipBounds.height());
+
+ // TODO: b/279937014 Investigate why userResizeBounds are empty with shell transitions on
+ // fallback to using the userResizeBounds if userResizeBounds are not empty
+ if (!mTouchHandler.getUserResizeBounds().isEmpty()) {
+ Rect userResizeBounds = mTouchHandler.getUserResizeBounds();
+ reentrySize = new Size(userResizeBounds.width(), userResizeBounds.height());
+ }
+
+ mPipBoundsState.saveReentryState(reentrySize, snapFraction);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
index 956af70..281cae5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
@@ -104,6 +104,7 @@
private boolean mAllowGesture;
private boolean mIsAttached;
private boolean mIsEnabled;
+ private boolean mEnableTouch;
private boolean mEnablePinchResize;
private boolean mEnableDragCornerResize;
private boolean mIsSysUiStateValid;
@@ -138,6 +139,7 @@
mPhonePipMenuController = menuActivityController;
mPipUiEventLogger = pipUiEventLogger;
mPinchResizingAlgorithm = new PipPinchResizingAlgorithm();
+ mEnableTouch = true;
mUpdateResizeBoundsCallback = (rect) -> {
mUserResizeBounds.set(rect);
@@ -248,6 +250,11 @@
return;
}
+ if (!mEnableTouch) {
+ // No need to handle anything if touches are not enabled for resizing.
+ return;
+ }
+
// Don't allow resize when PiP is stashed.
if (mPipBoundsState.isStashed()) {
return;
@@ -581,14 +588,13 @@
mLastResizeBounds, movementBounds);
mPipBoundsAlgorithm.applySnapFraction(mLastResizeBounds, snapFraction);
- // disable the pinch resizing until the final bounds are updated
- final boolean prevEnablePinchResize = mEnablePinchResize;
- mEnablePinchResize = false;
+ // disable the resizing until the final bounds are updated
+ mEnableTouch = false;
mPipTaskOrganizer.scheduleAnimateResizePip(startBounds, mLastResizeBounds,
PINCH_RESIZE_SNAP_DURATION, mAngle, mUpdateResizeBoundsCallback, () -> {
// reset the pinch resizing to its default state
- mEnablePinchResize = prevEnablePinchResize;
+ mEnableTouch = true;
});
} else {
mPipTaskOrganizer.scheduleFinishResizePip(mLastResizeBounds,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index c5bfd87..5c9709c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -245,7 +245,7 @@
}
@Override
- public void onActiveTasksChanged() {
+ public void onActiveTasksChanged(int displayId) {
notifyRecentTasksChanged();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index eb4d2a1..bffc51c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -549,6 +549,14 @@
// are in mOpening.
for (int i = 0; i < closingTasks.size(); ++i) {
final TransitionInfo.Change change = closingTasks.get(i);
+ final int pausingIdx = TaskState.indexOf(mPausingTasks, change);
+ if (pausingIdx >= 0) {
+ mPausingTasks.remove(pausingIdx);
+ didMergeThings = true;
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ " closing pausing taskId=%d", change.getTaskInfo().taskId);
+ continue;
+ }
int openingIdx = TaskState.indexOf(mOpeningTasks, change);
if (openingIdx < 0) {
Slog.w(TAG, "Closing a task that wasn't opening, this may be split or"
@@ -601,6 +609,11 @@
didMergeThings = true;
mState = STATE_NEW_TASK;
}
+ if (mPausingTasks.isEmpty()) {
+ // The pausing tasks may be removed by the incoming closing tasks.
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ "[%d] RecentsController.merge: empty pausing tasks", mInstanceId);
+ }
if (!hasTaskChange) {
// Activity only transition, so consume the merge as it doesn't affect the rest of
// recents.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 6432459..af52350 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -165,7 +165,7 @@
private final DisplayController mDisplayController;
private final DisplayImeController mDisplayImeController;
private final DisplayInsetsController mDisplayInsetsController;
- private final DragAndDropController mDragAndDropController;
+ private final Optional<DragAndDropController> mDragAndDropController;
private final Transitions mTransitions;
private final TransactionPool mTransactionPool;
private final IconProvider mIconProvider;
@@ -191,7 +191,7 @@
DisplayController displayController,
DisplayImeController displayImeController,
DisplayInsetsController displayInsetsController,
- DragAndDropController dragAndDropController,
+ Optional<DragAndDropController> dragAndDropController,
Transitions transitions,
TransactionPool transactionPool,
IconProvider iconProvider,
@@ -253,7 +253,7 @@
mDisplayController = displayController;
mDisplayImeController = displayImeController;
mDisplayInsetsController = displayInsetsController;
- mDragAndDropController = dragAndDropController;
+ mDragAndDropController = Optional.of(dragAndDropController);
mTransitions = transitions;
mTransactionPool = transactionPool;
mIconProvider = iconProvider;
@@ -289,7 +289,7 @@
// TODO: Multi-display
mStageCoordinator = createStageCoordinator();
}
- mDragAndDropController.setSplitScreenController(this);
+ mDragAndDropController.ifPresent(controller -> controller.setSplitScreenController(this));
}
protected StageCoordinator createStageCoordinator() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
index 51b8000..a2af93f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
@@ -30,8 +30,6 @@
import static com.android.wm.shell.splitscreen.SplitScreenController.exitReasonToString;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_DISMISS;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_DISMISS_SNAP;
-import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE;
-import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -165,7 +163,7 @@
t.setLayer(leash, Integer.MAX_VALUE);
t.show(leash);
}
- boolean isOpening = isOpeningTransition(info);
+ boolean isOpening = TransitionUtil.isOpeningType(info.getType());
if (isOpening && (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) {
// fade in
startExampleAnimation(leash, true /* show */);
@@ -295,14 +293,16 @@
@Nullable RemoteTransition remoteTransition,
Transitions.TransitionHandler handler,
@Nullable TransitionConsumedCallback consumedCallback,
- @Nullable TransitionFinishedCallback finishedCallback) {
+ @Nullable TransitionFinishedCallback finishedCallback,
+ int extraTransitType) {
if (mPendingEnter != null) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " splitTransition "
+ " skip to start enter split transition since it already exist. ");
return null;
}
final IBinder transition = mTransitions.startTransition(transitType, wct, handler);
- setEnterTransition(transition, remoteTransition, consumedCallback, finishedCallback);
+ setEnterTransition(transition, remoteTransition, consumedCallback, finishedCallback,
+ extraTransitType);
return transition;
}
@@ -310,9 +310,10 @@
void setEnterTransition(@NonNull IBinder transition,
@Nullable RemoteTransition remoteTransition,
@Nullable TransitionConsumedCallback consumedCallback,
- @Nullable TransitionFinishedCallback finishedCallback) {
+ @Nullable TransitionFinishedCallback finishedCallback,
+ int extraTransitType) {
mPendingEnter = new TransitSession(
- transition, consumedCallback, finishedCallback, remoteTransition);
+ transition, consumedCallback, finishedCallback, remoteTransition, extraTransitType);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " splitTransition "
+ " deduced Enter split screen");
@@ -513,12 +514,6 @@
mTransitions.getAnimExecutor().execute(va::start);
}
- private boolean isOpeningTransition(TransitionInfo info) {
- return TransitionUtil.isOpeningType(info.getType())
- || info.getType() == TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE
- || info.getType() == TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
- }
-
/** Calls when the transition got consumed. */
interface TransitionConsumedCallback {
void onConsumed(boolean aborted);
@@ -539,16 +534,19 @@
/** Whether the transition was canceled. */
boolean mCanceled;
+ /** A note for extra transit type, to help indicate custom transition. */
+ final int mExtraTransitType;
+
TransitSession(IBinder transition,
@Nullable TransitionConsumedCallback consumedCallback,
@Nullable TransitionFinishedCallback finishedCallback) {
- this(transition, consumedCallback, finishedCallback, null /* remoteTransition */);
+ this(transition, consumedCallback, finishedCallback, null /* remoteTransition */, 0);
}
TransitSession(IBinder transition,
@Nullable TransitionConsumedCallback consumedCallback,
@Nullable TransitionFinishedCallback finishedCallback,
- @Nullable RemoteTransition remoteTransition) {
+ @Nullable RemoteTransition remoteTransition, int extraTransitType) {
mTransition = transition;
mConsumedCallback = consumedCallback;
mFinishedCallback = finishedCallback;
@@ -560,6 +558,7 @@
mTransitions.getMainExecutor(), remoteTransition);
mRemoteHandler.setTransition(transition);
}
+ mExtraTransitType = extraTransitType;
}
/** Sets transition consumed callback. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 4c903f5..0ef26fc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -446,26 +446,10 @@
RemoteAnimationTarget[] wallpapers,
RemoteAnimationTarget[] nonApps,
final IRemoteAnimationFinishedCallback finishedCallback) {
- boolean openingToSide = false;
- if (apps != null) {
- for (int i = 0; i < apps.length; ++i) {
- if (apps[i].mode == MODE_OPENING
- && mSideStage.containsTask(apps[i].taskId)) {
- openingToSide = true;
- break;
- }
- }
- } else if (mSideStage.getChildCount() != 0) {
- // There are chances the entering app transition got canceled by performing
- // rotation transition. Checks if there is any child task existed in split
- // screen before fallback to cancel entering flow.
- openingToSide = true;
- }
-
- if (isEnteringSplit && !openingToSide) {
+ if (isEnteringSplit && mSideStage.getChildCount() == 0) {
mMainExecutor.execute(() -> exitSplitScreen(
- mSideStage.getChildCount() == 0 ? mMainStage : mSideStage,
- EXIT_REASON_UNKNOWN));
+ null /* childrenToTop */, EXIT_REASON_UNKNOWN));
+ mSplitUnsupportedToast.show();
}
if (finishedCallback != null) {
@@ -526,17 +510,17 @@
wct.sendPendingIntent(intent, fillInIntent, options);
// If split screen is not activated, we're expecting to open a pair of apps to split.
- final int transitType = mMainStage.isActive()
+ final int extraTransitType = mMainStage.isActive()
? TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE : TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
prepareEnterSplitScreen(wct, null /* taskInfo */, position);
- mSplitTransitions.startEnterTransition(transitType, wct, null, this,
+ mSplitTransitions.startEnterTransition(TRANSIT_TO_FRONT, wct, null, this,
null /* consumedCallback */,
(finishWct, finishT) -> {
if (!evictWct.isEmpty()) {
finishWct.merge(evictWct, true);
}
- } /* finishedCallback */);
+ } /* finishedCallback */, extraTransitType);
}
/** Launches an activity into split by legacy transition. */
@@ -550,26 +534,10 @@
RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
IRemoteAnimationFinishedCallback finishedCallback,
SurfaceControl.Transaction t) {
- boolean openingToSide = false;
- if (apps != null) {
- for (int i = 0; i < apps.length; ++i) {
- if (apps[i].mode == MODE_OPENING
- && mSideStage.containsTask(apps[i].taskId)) {
- openingToSide = true;
- break;
- }
- }
- } else if (mSideStage.getChildCount() != 0) {
- // There are chances the entering app transition got canceled by performing
- // rotation transition. Checks if there is any child task existed in split
- // screen before fallback to cancel entering flow.
- openingToSide = true;
- }
-
- if (isEnteringSplit && !openingToSide && apps != null) {
+ if (isEnteringSplit && mSideStage.getChildCount() == 0) {
mMainExecutor.execute(() -> exitSplitScreen(
- mSideStage.getChildCount() == 0 ? mMainStage : mSideStage,
- EXIT_REASON_UNKNOWN));
+ null /* childrenToTop */, EXIT_REASON_UNKNOWN));
+ mSplitUnsupportedToast.show();
}
if (apps != null) {
@@ -709,7 +677,8 @@
wct.startTask(mainTaskId, mainOptions);
mSplitTransitions.startEnterTransition(
- TRANSIT_SPLIT_SCREEN_PAIR_OPEN, wct, remoteTransition, this, null, null);
+ TRANSIT_TO_FRONT, wct, remoteTransition, this, null, null,
+ TRANSIT_SPLIT_SCREEN_PAIR_OPEN);
setEnterInstanceId(instanceId);
}
@@ -760,7 +729,8 @@
}
mSplitTransitions.startEnterTransition(
- TRANSIT_SPLIT_SCREEN_PAIR_OPEN, wct, remoteTransition, this, null, null);
+ TRANSIT_TO_FRONT, wct, remoteTransition, this, null, null,
+ TRANSIT_SPLIT_SCREEN_PAIR_OPEN);
setEnterInstanceId(instanceId);
}
@@ -1088,7 +1058,7 @@
private void onRemoteAnimationFinishedOrCancelled(WindowContainerTransaction evictWct) {
mIsDividerRemoteAnimating = false;
mShouldUpdateRecents = true;
- mSplitRequest = null;
+ clearRequestIfPresented();
// If any stage has no child after animation finished, it means that split will display
// nothing, such status will happen if task and intent is same app but not support
// multi-instance, we should exit split and expand that app as full screen.
@@ -1108,7 +1078,7 @@
private void onRemoteAnimationFinished(RemoteAnimationTarget[] apps) {
mIsDividerRemoteAnimating = false;
mShouldUpdateRecents = true;
- mSplitRequest = null;
+ clearRequestIfPresented();
// If any stage has no child after finished animation, that side of the split will display
// nothing. This might happen if starting the same app on the both sides while not
// supporting multi-instance. Exit the split screen and expand that app to full screen.
@@ -1381,6 +1351,7 @@
});
mShouldUpdateRecents = false;
mIsDividerRemoteAnimating = false;
+ mSplitRequest = null;
mSplitLayout.getInvisibleBounds(mTempRect1);
if (childrenToTop == null || childrenToTop.getTopVisibleChildTaskId() == INVALID_TASK_ID) {
@@ -1473,6 +1444,13 @@
}
}
+ private void clearRequestIfPresented() {
+ if (mSideStageListener.mVisible && mSideStageListener.mHasChildren
+ && mMainStageListener.mVisible && mSideStageListener.mHasChildren) {
+ mSplitRequest = null;
+ }
+ }
+
/**
* Returns whether the split pair in the recent tasks list should be broken.
*/
@@ -1851,6 +1829,7 @@
true /* setReparentLeafTaskIfRelaunch */);
setRootForceTranslucent(true, wct);
} else {
+ clearRequestIfPresented();
wct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token,
false /* setReparentLeafTaskIfRelaunch */);
setRootForceTranslucent(false, wct);
@@ -2010,7 +1989,7 @@
}
if (mMainStageListener.mHasChildren && mSideStageListener.mHasChildren) {
mShouldUpdateRecents = true;
- mSplitRequest = null;
+ clearRequestIfPresented();
updateRecentTasksSplitPair();
if (!mLogger.hasStartedSession()) {
@@ -2334,7 +2313,8 @@
out = new WindowContainerTransaction();
prepareEnterSplitScreen(out);
mSplitTransitions.setEnterTransition(transition, request.getRemoteTransition(),
- null /* consumedCallback */, null /* finishedCallback */);
+ null /* consumedCallback */, null /* finishedCallback */,
+ 0 /* extraTransitType */);
}
}
return out;
@@ -2573,7 +2553,8 @@
}
}
- if (info.getType() == TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE) {
+ if (mSplitTransitions.mPendingEnter.mExtraTransitType
+ == TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE) {
if (mainChild == null && sideChild == null) {
Log.w(TAG, "Launched a task in split, but didn't receive any task in transition.");
mSplitTransitions.mPendingEnter.cancel(null /* finishedCb */);
@@ -2716,6 +2697,7 @@
}
});
mShouldUpdateRecents = false;
+ mSplitRequest = null;
// Update local states.
setSplitsVisible(false);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index ead0bcd..a841b7f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -220,20 +220,12 @@
mCallbacks.onNoLongerSupportMultiWindow();
return;
}
- if (taskInfo.topActivity == null && mChildrenTaskInfo.contains(taskInfo.taskId)
- && mChildrenTaskInfo.get(taskInfo.taskId).topActivity != null) {
- // If top activity become null, it means the task is about to vanish, we use this
- // signal to remove it from children list earlier for smooth dismiss transition.
- mChildrenTaskInfo.remove(taskInfo.taskId);
- mChildrenLeashes.remove(taskInfo.taskId);
- } else {
- mChildrenTaskInfo.put(taskInfo.taskId, taskInfo);
- }
+ mChildrenTaskInfo.put(taskInfo.taskId, taskInfo);
mCallbacks.onChildTaskStatusChanged(taskInfo.taskId, true /* present */,
taskInfo.isVisible);
- if (!ENABLE_SHELL_TRANSITIONS && mChildrenLeashes.contains(taskInfo.taskId)) {
- updateChildTaskSurface(taskInfo, mChildrenLeashes.get(taskInfo.taskId),
- false /* firstAppeared */);
+ if (!ENABLE_SHELL_TRANSITIONS) {
+ updateChildTaskSurface(
+ taskInfo, mChildrenLeashes.get(taskInfo.taskId), false /* firstAppeared */);
}
} else {
throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo
@@ -267,6 +259,9 @@
return;
}
sendStatusChanged();
+ } else {
+ throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo
+ + "\n mRootTaskInfo: " + mRootTaskInfo);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java
index 46d2a5a..27d520d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java
@@ -72,7 +72,7 @@
DisplayController displayController,
DisplayImeController displayImeController,
DisplayInsetsController displayInsetsController,
- DragAndDropController dragAndDropController,
+ Optional<DragAndDropController> dragAndDropController,
Transitions transitions,
TransactionPool transactionPool,
IconProvider iconProvider,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java
index 7991c52..2ab4c75 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java
@@ -82,6 +82,10 @@
mGuard.open("release");
}
+ SurfaceControl getSurfaceControl() {
+ return mSurfaceControl;
+ }
+
/**
* Sets the provided {@link TaskViewBase}, which is used to notify the client part about the
* task related changes and getting the current bounds.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
index 81d69a4..c7e534a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
@@ -336,6 +336,19 @@
tv.prepareOpenAnimation(taskIsNew, startTransaction, finishTransaction,
chg.getTaskInfo(), chg.getLeash(), wct);
changesHandled++;
+ } else if (chg.getMode() == TRANSIT_CHANGE) {
+ TaskViewTaskController tv = findTaskView(chg.getTaskInfo());
+ if (tv == null) {
+ if (pending != null) {
+ Slog.w(TAG, "Found a non-TaskView task in a TaskView Transition. This "
+ + "shouldn't happen, so there may be a visual artifact: "
+ + chg.getTaskInfo().taskId);
+ }
+ continue;
+ }
+ startTransaction.reparent(chg.getLeash(), tv.getSurfaceControl());
+ finishTransaction.reparent(chg.getLeash(), tv.getSurfaceControl());
+ changesHandled++;
}
}
if (stillNeedsMatchingLaunch) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
index d25318d..9ce2209 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
@@ -144,6 +144,7 @@
.setCaptureSecureLayers(true)
.setAllowProtected(true)
.setSourceCrop(new Rect(0, 0, mStartWidth, mStartHeight))
+ .setHintForSeamlessTransition(true)
.build();
ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
ScreenCapture.captureLayers(args);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java
new file mode 100644
index 0000000..ba364f8
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2023 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.transition;
+
+import static android.os.Build.IS_USER;
+
+import static com.android.wm.shell.WmShellTransitionTraceProto.MAGIC_NUMBER;
+import static com.android.wm.shell.WmShellTransitionTraceProto.MAGIC_NUMBER_H;
+import static com.android.wm.shell.WmShellTransitionTraceProto.MAGIC_NUMBER_L;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.util.Log;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.util.TraceBuffer;
+import com.android.wm.shell.sysui.ShellCommandHandler;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Helper class to collect and dump transition traces.
+ */
+public class Tracer implements ShellCommandHandler.ShellCommandActionHandler {
+ private static final int ALWAYS_ON_TRACING_CAPACITY = 15 * 1024; // 15 KB
+ private static final int ACTIVE_TRACING_BUFFER_CAPACITY = 5000 * 1024; // 5 MB
+
+ private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
+
+ static final String WINSCOPE_EXT = ".winscope";
+ private static final String TRACE_FILE =
+ "/data/misc/wmtrace/shell_transition_trace" + WINSCOPE_EXT;
+
+ private final Object mEnabledLock = new Object();
+ private boolean mActiveTracingEnabled = false;
+
+ private final TraceBuffer mTraceBuffer = new TraceBuffer(ALWAYS_ON_TRACING_CAPACITY,
+ (proto) -> handleOnEntryRemovedFromTrace(proto));
+ private final Map<Object, Runnable> mRemovedFromTraceCallbacks = new HashMap<>();
+
+ private final Map<Transitions.TransitionHandler, Integer> mHandlerIds = new HashMap<>();
+ private final Map<Transitions.TransitionHandler, Integer> mHandlerUseCountInTrace =
+ new HashMap<>();
+
+ /**
+ * Adds an entry in the trace to log that a transition has been dispatched to a handler.
+ *
+ * @param transitionId The id of the transition being dispatched.
+ * @param handler The handler the transition is being dispatched to.
+ */
+ public void logDispatched(int transitionId, Transitions.TransitionHandler handler) {
+ final int handlerId;
+ if (mHandlerIds.containsKey(handler)) {
+ handlerId = mHandlerIds.get(handler);
+ } else {
+ // + 1 to avoid 0 ids which can be confused with missing value when dumped to proto
+ handlerId = mHandlerIds.size() + 1;
+ mHandlerIds.put(handler, handlerId);
+ }
+
+ ProtoOutputStream outputStream = new ProtoOutputStream();
+ final long protoToken =
+ outputStream.start(com.android.wm.shell.WmShellTransitionTraceProto.TRANSITIONS);
+
+ outputStream.write(com.android.wm.shell.Transition.ID, transitionId);
+ outputStream.write(com.android.wm.shell.Transition.DISPATCH_TIME_NS,
+ SystemClock.elapsedRealtimeNanos());
+ outputStream.write(com.android.wm.shell.Transition.HANDLER, handlerId);
+
+ outputStream.end(protoToken);
+
+ final int useCountAfterAdd = mHandlerUseCountInTrace.getOrDefault(handler, 0) + 1;
+ mHandlerUseCountInTrace.put(handler, useCountAfterAdd);
+
+ mRemovedFromTraceCallbacks.put(outputStream, () -> {
+ final int useCountAfterRemove = mHandlerUseCountInTrace.get(handler) - 1;
+ mHandlerUseCountInTrace.put(handler, useCountAfterRemove);
+ });
+
+ mTraceBuffer.add(outputStream);
+ }
+
+ /**
+ * Adds an entry in the trace to log that a request to merge a transition was made.
+ *
+ * @param mergeRequestedTransitionId The id of the transition we are requesting to be merged.
+ * @param playingTransitionId The id of the transition we was to merge the transition into.
+ */
+ public void logMergeRequested(int mergeRequestedTransitionId, int playingTransitionId) {
+ ProtoOutputStream outputStream = new ProtoOutputStream();
+ final long protoToken =
+ outputStream.start(com.android.wm.shell.WmShellTransitionTraceProto.TRANSITIONS);
+
+ outputStream.write(com.android.wm.shell.Transition.ID, mergeRequestedTransitionId);
+ outputStream.write(com.android.wm.shell.Transition.MERGE_REQUEST_TIME_NS,
+ SystemClock.elapsedRealtimeNanos());
+ outputStream.write(com.android.wm.shell.Transition.MERGED_INTO, playingTransitionId);
+
+ outputStream.end(protoToken);
+
+ mTraceBuffer.add(outputStream);
+ }
+
+ /**
+ * Adds an entry in the trace to log that a transition was merged by the handler.
+ *
+ * @param mergedTransitionId The id of the transition that was merged.
+ * @param playingTransitionId The id of the transition the transition was merged into.
+ */
+ public void logMerged(int mergedTransitionId, int playingTransitionId) {
+ ProtoOutputStream outputStream = new ProtoOutputStream();
+ final long protoToken =
+ outputStream.start(com.android.wm.shell.WmShellTransitionTraceProto.TRANSITIONS);
+
+ outputStream.write(com.android.wm.shell.Transition.ID, mergedTransitionId);
+ outputStream.write(
+ com.android.wm.shell.Transition.MERGE_TIME_NS, SystemClock.elapsedRealtimeNanos());
+ outputStream.write(com.android.wm.shell.Transition.MERGED_INTO, playingTransitionId);
+
+ outputStream.end(protoToken);
+
+ mTraceBuffer.add(outputStream);
+ }
+
+ /**
+ * Adds an entry in the trace to log that a transition was aborted.
+ *
+ * @param transitionId The id of the transition that was aborted.
+ */
+ public void logAborted(int transitionId) {
+ ProtoOutputStream outputStream = new ProtoOutputStream();
+ final long protoToken =
+ outputStream.start(com.android.wm.shell.WmShellTransitionTraceProto.TRANSITIONS);
+
+ outputStream.write(com.android.wm.shell.Transition.ID, transitionId);
+ outputStream.write(
+ com.android.wm.shell.Transition.ABORT_TIME_NS, SystemClock.elapsedRealtimeNanos());
+
+ outputStream.end(protoToken);
+
+ mTraceBuffer.add(outputStream);
+ }
+
+ /**
+ * Starts collecting transitions for the trace.
+ * If called while a trace is already running, this will reset the trace.
+ */
+ public void startTrace(@Nullable PrintWriter pw) {
+ if (IS_USER) {
+ LogAndPrintln.e(pw, "Tracing is not supported on user builds.");
+ return;
+ }
+ Trace.beginSection("Tracer#startTrace");
+ LogAndPrintln.i(pw, "Starting shell transition trace.");
+ synchronized (mEnabledLock) {
+ mActiveTracingEnabled = true;
+ mTraceBuffer.resetBuffer();
+ mTraceBuffer.setCapacity(ACTIVE_TRACING_BUFFER_CAPACITY);
+ }
+ Trace.endSection();
+ }
+
+ /**
+ * Stops collecting the transition trace and dump to trace to file.
+ *
+ * Dumps the trace to @link{TRACE_FILE}.
+ */
+ public void stopTrace(@Nullable PrintWriter pw) {
+ stopTrace(pw, new File(TRACE_FILE));
+ }
+
+ /**
+ * Stops collecting the transition trace and dump to trace to file.
+ * @param outputFile The file to dump the transition trace to.
+ */
+ public void stopTrace(@Nullable PrintWriter pw, File outputFile) {
+ if (IS_USER) {
+ LogAndPrintln.e(pw, "Tracing is not supported on user builds.");
+ return;
+ }
+ Trace.beginSection("Tracer#stopTrace");
+ LogAndPrintln.i(pw, "Stopping shell transition trace.");
+ synchronized (mEnabledLock) {
+ mActiveTracingEnabled = false;
+ writeTraceToFileLocked(pw, outputFile);
+ mTraceBuffer.resetBuffer();
+ mTraceBuffer.setCapacity(ALWAYS_ON_TRACING_CAPACITY);
+ }
+ Trace.endSection();
+ }
+
+ /**
+ * Being called while taking a bugreport so that tracing files can be included in the bugreport.
+ *
+ * @param pw Print writer
+ */
+ public void saveForBugreport(@Nullable PrintWriter pw) {
+ if (IS_USER) {
+ LogAndPrintln.e(pw, "Tracing is not supported on user builds.");
+ return;
+ }
+ Trace.beginSection("TransitionTracer#saveForBugreport");
+ synchronized (mEnabledLock) {
+ final File outputFile = new File(TRACE_FILE);
+ writeTraceToFileLocked(pw, outputFile);
+ }
+ Trace.endSection();
+ }
+
+ private void writeTraceToFileLocked(@Nullable PrintWriter pw, File file) {
+ Trace.beginSection("TransitionTracer#writeTraceToFileLocked");
+ try {
+ ProtoOutputStream proto = new ProtoOutputStream();
+ proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
+ writeHandlerMappingToProto(proto);
+ int pid = android.os.Process.myPid();
+ LogAndPrintln.i(pw, "Writing file to " + file.getAbsolutePath()
+ + " from process " + pid);
+ mTraceBuffer.writeTraceToFile(file, proto);
+ } catch (IOException e) {
+ LogAndPrintln.e(pw, "Unable to write buffer to file", e);
+ }
+ Trace.endSection();
+ }
+
+ private void writeHandlerMappingToProto(ProtoOutputStream outputStream) {
+ for (Transitions.TransitionHandler handler : mHandlerUseCountInTrace.keySet()) {
+ final int count = mHandlerUseCountInTrace.get(handler);
+ if (count > 0) {
+ final long protoToken = outputStream.start(
+ com.android.wm.shell.WmShellTransitionTraceProto.HANDLER_MAPPINGS);
+ outputStream.write(com.android.wm.shell.HandlerMapping.ID,
+ mHandlerIds.get(handler));
+ outputStream.write(com.android.wm.shell.HandlerMapping.NAME,
+ handler.getClass().getName());
+ outputStream.end(protoToken);
+ }
+ }
+ }
+
+ private void handleOnEntryRemovedFromTrace(Object proto) {
+ if (mRemovedFromTraceCallbacks.containsKey(proto)) {
+ mRemovedFromTraceCallbacks.get(proto).run();
+ mRemovedFromTraceCallbacks.remove(proto);
+ }
+ }
+
+ @Override
+ public boolean onShellCommand(String[] args, PrintWriter pw) {
+ switch (args[0]) {
+ case "start": {
+ startTrace(pw);
+ return true;
+ }
+ case "stop": {
+ stopTrace(pw);
+ return true;
+ }
+ case "save-for-bugreport": {
+ saveForBugreport(pw);
+ return true;
+ }
+ default: {
+ pw.println("Invalid command: " + args[0]);
+ printShellCommandHelp(pw, "");
+ return false;
+ }
+ }
+ }
+
+ @Override
+ public void printShellCommandHelp(PrintWriter pw, String prefix) {
+ pw.println(prefix + "start");
+ pw.println(prefix + " Start tracing the transitions.");
+ pw.println(prefix + "stop");
+ pw.println(prefix + " Stop tracing the transitions.");
+ pw.println(prefix + "save-for-bugreport");
+ pw.println(prefix + " Flush in memory transition trace to file.");
+ }
+
+ private static class LogAndPrintln {
+ private static final String LOG_TAG = "ShellTransitionTracer";
+
+ private static void i(@Nullable PrintWriter pw, String msg) {
+ Log.i(LOG_TAG, msg);
+ if (pw != null) {
+ pw.println(msg);
+ pw.flush();
+ }
+ }
+
+ private static void e(@Nullable PrintWriter pw, String msg) {
+ Log.e(LOG_TAG, msg);
+ if (pw != null) {
+ pw.println("ERROR: " + msg);
+ pw.flush();
+ }
+ }
+
+ private static void e(@Nullable PrintWriter pw, String msg, @NonNull Exception e) {
+ Log.e(LOG_TAG, msg, e);
+ if (pw != null) {
+ pw.println("ERROR: " + msg + " ::\n " + e);
+ pw.flush();
+ }
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index a4057b1..f79f1f7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -74,10 +74,12 @@
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.util.TransitionUtil;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -106,7 +108,8 @@
* track, it will be marked as SYNC. This means that all currently active tracks must be flushed
* before the SYNC transition can play.
*/
-public class Transitions implements RemoteCallable<Transitions> {
+public class Transitions implements RemoteCallable<Transitions>,
+ ShellCommandHandler.ShellCommandActionHandler {
static final String TAG = "ShellTransitions";
/** Set to {@code true} to enable shell transitions. */
@@ -165,12 +168,15 @@
private final ShellController mShellController;
private final ShellTransitionImpl mImpl = new ShellTransitionImpl();
private final SleepHandler mSleepHandler = new SleepHandler();
-
+ private final Tracer mTracer = new Tracer();
private boolean mIsRegistered = false;
/** List of possible handlers. Ordered by specificity (eg. tapped back to front). */
private final ArrayList<TransitionHandler> mHandlers = new ArrayList<>();
+ @Nullable
+ private final ShellCommandHandler mShellCommandHandler;
+
private final ArrayList<TransitionObserver> mObservers = new ArrayList<>();
/** List of {@link Runnable} instances to run when the last active transition has finished. */
@@ -246,8 +252,23 @@
@NonNull WindowOrganizer organizer,
@NonNull TransactionPool pool,
@NonNull DisplayController displayController,
- @NonNull ShellExecutor mainExecutor, @NonNull Handler mainHandler,
+ @NonNull ShellExecutor mainExecutor,
+ @NonNull Handler mainHandler,
@NonNull ShellExecutor animExecutor) {
+ this(context, shellInit, shellController, organizer, pool, displayController, mainExecutor,
+ mainHandler, animExecutor, null);
+ }
+
+ public Transitions(@NonNull Context context,
+ @NonNull ShellInit shellInit,
+ @NonNull ShellController shellController,
+ @NonNull WindowOrganizer organizer,
+ @NonNull TransactionPool pool,
+ @NonNull DisplayController displayController,
+ @NonNull ShellExecutor mainExecutor,
+ @NonNull Handler mainHandler,
+ @NonNull ShellExecutor animExecutor,
+ @Nullable ShellCommandHandler shellCommandHandler) {
mOrganizer = organizer;
mContext = context;
mMainExecutor = mainExecutor;
@@ -263,6 +284,7 @@
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "addHandler: Default");
// Next lowest priority is remote transitions.
mHandlers.add(mRemoteTransitionHandler);
+ mShellCommandHandler = shellCommandHandler;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "addHandler: Remote");
shellInit.addInitCallback(this::onInit, this);
}
@@ -294,6 +316,10 @@
// Pre-load the instance.
TransitionMetrics.getInstance();
}
+
+ if (mShellCommandHandler != null) {
+ mShellCommandHandler.addCommandCallback("transitions", this, this);
+ }
}
public boolean isRegistered() {
@@ -766,6 +792,7 @@
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Transition %s ready while"
+ " %s is still animating. Notify the animating transition"
+ " in case they can be merged", ready, playing);
+ mTracer.logMergeRequested(ready.mInfo.getDebugId(), playing.mInfo.getDebugId());
playing.mHandler.mergeAnimation(ready.mToken, ready.mInfo, ready.mStartT,
playing.mToken, (wct, cb) -> onMerged(playing, ready));
}
@@ -799,6 +826,7 @@
for (int i = 0; i < mObservers.size(); ++i) {
mObservers.get(i).onTransitionMerged(merged.mToken, playing.mToken);
}
+ mTracer.logMerged(merged.mInfo.getDebugId(), playing.mInfo.getDebugId());
// See if we should merge another transition.
processReadyQueue(track);
}
@@ -825,6 +853,8 @@
// Otherwise give every other handler a chance
active.mHandler = dispatchTransition(active.mToken, active.mInfo, active.mStartT,
active.mFinishT, (wct, cb) -> onFinish(active, wct, cb), active.mHandler);
+
+ mTracer.logDispatched(active.mInfo.getDebugId(), active.mHandler);
}
/**
@@ -876,6 +906,8 @@
transition.mFinishT.apply();
transition.mAborted = true;
+ mTracer.logAborted(transition.mInfo.getDebugId());
+
if (transition.mHandler != null) {
// Notifies to clean-up the aborted transition.
transition.mHandler.onTransitionConsumed(
@@ -1350,4 +1382,26 @@
mMainExecutor.execute(() -> dispatchAnimScaleSetting(mTransitionAnimationScaleSetting));
}
}
+
+
+ @Override
+ public boolean onShellCommand(String[] args, PrintWriter pw) {
+ switch (args[0]) {
+ case "tracing": {
+ mTracer.onShellCommand(Arrays.copyOfRange(args, 1, args.length), pw);
+ return true;
+ }
+ default: {
+ pw.println("Invalid command: " + args[0]);
+ printShellCommandHelp(pw, "");
+ return false;
+ }
+ }
+ }
+
+ @Override
+ public void printShellCommandHelp(PrintWriter pw, String prefix) {
+ pw.println(prefix + "tracing");
+ mTracer.printShellCommandHelp(pw, prefix + " ");
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 4ef3350..4cda571 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -113,11 +113,6 @@
private boolean mDragToDesktopAnimationStarted;
private float mCaptionDragStartX;
- // These values keep track of any transitions to freeform to stop relayout from running on
- // changing task so that shellTransitions has a chance to animate the transition
- private int mPauseRelayoutForTask = -1;
- private IBinder mTransitionPausingRelayout;
-
public DesktopModeWindowDecorViewModel(
Context context,
Handler mainHandler,
@@ -195,22 +190,25 @@
@NonNull TransitionInfo info,
@NonNull TransitionInfo.Change change) {
if (change.getMode() == WindowManager.TRANSIT_CHANGE
- && info.getType() == Transitions.TRANSIT_ENTER_DESKTOP_MODE) {
- mTransitionPausingRelayout = transition;
+ && (info.getType() == Transitions.TRANSIT_ENTER_DESKTOP_MODE)) {
+ mWindowDecorByTaskId.get(change.getTaskInfo().taskId)
+ .addTransitionPausingRelayout(transition);
}
}
@Override
public void onTransitionMerged(@NonNull IBinder merged, @NonNull IBinder playing) {
- if (merged.equals(mTransitionPausingRelayout)) {
- mTransitionPausingRelayout = playing;
+ for (int i = 0; i < mWindowDecorByTaskId.size(); i++) {
+ final DesktopModeWindowDecoration decor = mWindowDecorByTaskId.valueAt(i);
+ decor.mergeTransitionPausingRelayout(merged, playing);
}
}
@Override
public void onTransitionFinished(@NonNull IBinder transition) {
- if (transition.equals(mTransitionPausingRelayout)) {
- mPauseRelayoutForTask = -1;
+ for (int i = 0; i < mWindowDecorByTaskId.size(); i++) {
+ final DesktopModeWindowDecoration decor = mWindowDecorByTaskId.valueAt(i);
+ decor.removeTransitionPausingRelayout(transition);
}
}
@@ -225,12 +223,7 @@
incrementEventReceiverTasks(taskInfo.displayId);
}
- // TaskListener callbacks and shell transitions aren't synchronized, so starting a shell
- // transition can trigger an onTaskInfoChanged call that updates the task's SurfaceControl
- // and interferes with the transition animation that is playing at the same time.
- if (taskInfo.taskId != mPauseRelayoutForTask) {
- decoration.relayout(taskInfo);
- }
+ decoration.relayout(taskInfo);
}
@Override
@@ -555,8 +548,7 @@
relevantDecor.mTaskInfo.displayId);
if (ev.getY() > 2 * statusBarHeight) {
if (DesktopModeStatus.isProto2Enabled()) {
- mPauseRelayoutForTask = relevantDecor.mTaskInfo.taskId;
- centerAndMoveToDesktopWithAnimation(relevantDecor, ev);
+ animateToDesktop(relevantDecor, ev);
} else if (DesktopModeStatus.isProto1Enabled()) {
mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(true));
}
@@ -632,6 +624,15 @@
}
/**
+ * Blocks relayout until transition is finished and transitions to Desktop
+ */
+ private void animateToDesktop(DesktopModeWindowDecoration relevantDecor,
+ MotionEvent ev) {
+ relevantDecor.incrementRelayoutBlock();
+ centerAndMoveToDesktopWithAnimation(relevantDecor, ev);
+ }
+
+ /**
* Animates a window to the center, grows to freeform size, and transitions to Desktop Mode.
* @param relevantDecor the window decor of the task to be animated
* @param ev the motion event that triggers the animation
@@ -658,10 +659,9 @@
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- mDesktopTasksController.ifPresent(
- c -> c.onDragPositioningEndThroughStatusBar(
- relevantDecor.mTaskInfo,
- calculateFreeformBounds(FINAL_FREEFORM_SCALE)));
+ mDesktopTasksController.ifPresent(c ->
+ c.onDragPositioningEndThroughStatusBar(relevantDecor.mTaskInfo,
+ calculateFreeformBounds(FINAL_FREEFORM_SCALE)));
}
});
animator.start();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index b1c3791..95ed42a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -30,6 +30,7 @@
import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.os.Handler;
+import android.os.IBinder;
import android.util.Log;
import android.view.Choreographer;
import android.view.MotionEvent;
@@ -49,6 +50,9 @@
import com.android.wm.shell.windowdecor.viewholder.DesktopModeFocusedWindowDecorationViewHolder;
import com.android.wm.shell.windowdecor.viewholder.DesktopModeWindowDecorationViewHolder;
+import java.util.HashSet;
+import java.util.Set;
+
/**
* Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with
* {@link DesktopModeWindowDecorViewModel}.
@@ -83,6 +87,9 @@
private TaskCornersListener mCornersListener;
+ private final Set<IBinder> mTransitionsPausingRelayout = new HashSet<>();
+ private int mRelayoutBlock;
+
DesktopModeWindowDecoration(
Context context,
DisplayController displayController,
@@ -134,6 +141,13 @@
@Override
void relayout(ActivityManager.RunningTaskInfo taskInfo) {
+ // TaskListener callbacks and shell transitions aren't synchronized, so starting a shell
+ // transition can trigger an onTaskInfoChanged call that updates the task's SurfaceControl
+ // and interferes with the transition animation that is playing at the same time.
+ if (mRelayoutBlock > 0) {
+ return;
+ }
+
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
// Use |applyStartTransactionOnDraw| so that the transaction (that applies task crop) is
// synced with the buffer transaction (that draws the View). Both will be shown on screen
@@ -455,6 +469,40 @@
return cornersRegion;
}
+ /**
+ * If transition exists in mTransitionsPausingRelayout, remove the transition and decrement
+ * mRelayoutBlock
+ */
+ void removeTransitionPausingRelayout(IBinder transition) {
+ if (mTransitionsPausingRelayout.remove(transition)) {
+ mRelayoutBlock--;
+ }
+ }
+
+ /**
+ * Add transition to mTransitionsPausingRelayout
+ */
+ void addTransitionPausingRelayout(IBinder transition) {
+ mTransitionsPausingRelayout.add(transition);
+ }
+
+ /**
+ * If two transitions merge and the merged transition is in mTransitionsPausingRelayout,
+ * remove the merged transition from the set and add the transition it was merged into.
+ */
+ public void mergeTransitionPausingRelayout(IBinder merged, IBinder playing) {
+ if (mTransitionsPausingRelayout.remove(merged)) {
+ mTransitionsPausingRelayout.add(playing);
+ }
+ }
+
+ /**
+ * Increase mRelayoutBlock, stopping relayout if mRelayoutBlock is now greater than 0.
+ */
+ public void incrementRelayoutBlock() {
+ mRelayoutBlock++;
+ }
+
static class Factory {
DesktopModeWindowDecoration create(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
index ef8332f..1d416c6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
@@ -86,9 +86,10 @@
public void onDragPositioningEnd(float x, float y) {
PointF delta = DragPositioningCallbackUtility.calculateDelta(x, y,
mRepositionStartPoint);
- if (mHasMoved && DragPositioningCallbackUtility.changeBounds(mCtrlType, mHasMoved,
- mRepositionTaskBounds, mTaskBoundsAtDragStart, mStableBounds, delta,
- mDisplayController, mDesktopWindowDecoration)) {
+ if (mHasMoved) {
+ DragPositioningCallbackUtility.changeBounds(mCtrlType, mHasMoved,
+ mRepositionTaskBounds, mTaskBoundsAtDragStart, mStableBounds, delta,
+ mDisplayController, mDesktopWindowDecoration);
DragPositioningCallbackUtility.applyTaskBoundsChange(
new WindowContainerTransaction(), mDesktopWindowDecoration,
mRepositionTaskBounds, mTaskOrganizer);
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt
new file mode 100644
index 0000000..e06e074
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 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.flicker
+
+import android.app.Instrumentation
+import android.tools.device.flicker.junit.FlickerBuilderProvider
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.tapl.LauncherInstrumentation
+
+abstract class BaseBenchmarkTest
+@JvmOverloads
+constructor(
+ protected open val flicker: FlickerTest,
+ protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation(),
+ protected val tapl: LauncherInstrumentation = LauncherInstrumentation()
+) {
+ /** Specification of the test transition to execute */
+ abstract val transition: FlickerBuilder.() -> Unit
+
+ /**
+ * Entry point for the test runner. It will use this method to initialize and cache flicker
+ * executions
+ */
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ setup { flicker.scenario.setIsTablet(tapl.isTablet) }
+ transition()
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
index 86edc25..c98c5a0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
@@ -17,24 +17,10 @@
package com.android.wm.shell.flicker
import android.app.Instrumentation
-import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerBuilderProvider
-import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.tapl.LauncherInstrumentation
-import com.android.server.wm.flicker.entireScreenCovered
-import com.android.server.wm.flicker.navBarLayerIsVisibleAtStartAndEnd
-import com.android.server.wm.flicker.navBarLayerPositionAtStartAndEnd
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerIsVisibleAtStartAndEnd
-import com.android.server.wm.flicker.statusBarLayerPositionAtStartAndEnd
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.taskBarLayerIsVisibleAtStartAndEnd
-import com.android.server.wm.flicker.taskBarWindowIsAlwaysVisible
-import org.junit.Assume
-import org.junit.Test
/**
* Base test class containing common assertions for [ComponentNameMatcher.NAV_BAR],
@@ -44,124 +30,7 @@
abstract class BaseTest
@JvmOverloads
constructor(
- protected val flicker: FlickerTest,
- protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation(),
- protected val tapl: LauncherInstrumentation = LauncherInstrumentation()
-) {
- /** Specification of the test transition to execute */
- abstract val transition: FlickerBuilder.() -> Unit
-
- /**
- * Entry point for the test runner. It will use this method to initialize and cache flicker
- * executions
- */
- @FlickerBuilderProvider
- fun buildFlicker(): FlickerBuilder {
- return FlickerBuilder(instrumentation).apply {
- setup { flicker.scenario.setIsTablet(tapl.isTablet) }
- transition()
- }
- }
-
- /** Checks that all parts of the screen are covered during the transition */
- @Presubmit @Test open fun entireScreenCovered() = flicker.entireScreenCovered()
-
- /**
- * Checks that the [ComponentNameMatcher.NAV_BAR] layer is visible during the whole transition
- */
- @Presubmit
- @Test
- open fun navBarLayerIsVisibleAtStartAndEnd() {
- Assume.assumeFalse(flicker.scenario.isTablet)
- flicker.navBarLayerIsVisibleAtStartAndEnd()
- }
-
- /**
- * Checks the position of the [ComponentNameMatcher.NAV_BAR] at the start and end of the
- * transition
- */
- @Presubmit
- @Test
- open fun navBarLayerPositionAtStartAndEnd() {
- Assume.assumeFalse(flicker.scenario.isTablet)
- flicker.navBarLayerPositionAtStartAndEnd()
- }
-
- /**
- * Checks that the [ComponentNameMatcher.NAV_BAR] window is visible during the whole transition
- *
- * Note: Phones only
- */
- @Presubmit
- @Test
- open fun navBarWindowIsAlwaysVisible() {
- Assume.assumeFalse(flicker.scenario.isTablet)
- flicker.navBarWindowIsAlwaysVisible()
- }
-
- /**
- * Checks that the [ComponentNameMatcher.TASK_BAR] layer is visible during the whole transition
- */
- @Presubmit
- @Test
- open fun taskBarLayerIsVisibleAtStartAndEnd() {
- Assume.assumeTrue(flicker.scenario.isTablet)
- flicker.taskBarLayerIsVisibleAtStartAndEnd()
- }
-
- /**
- * Checks that the [ComponentNameMatcher.TASK_BAR] window is visible during the whole transition
- *
- * Note: Large screen only
- */
- @Presubmit
- @Test
- open fun taskBarWindowIsAlwaysVisible() {
- Assume.assumeTrue(flicker.scenario.isTablet)
- flicker.taskBarWindowIsAlwaysVisible()
- }
-
- /**
- * Checks that the [ComponentNameMatcher.STATUS_BAR] layer is visible during the whole
- * transition
- */
- @Presubmit
- @Test
- open fun statusBarLayerIsVisibleAtStartAndEnd() = flicker.statusBarLayerIsVisibleAtStartAndEnd()
-
- /**
- * Checks the position of the [ComponentNameMatcher.STATUS_BAR] at the start and end of the
- * transition
- */
- @Presubmit
- @Test
- open fun statusBarLayerPositionAtStartAndEnd() = flicker.statusBarLayerPositionAtStartAndEnd()
-
- /**
- * Checks that the [ComponentNameMatcher.STATUS_BAR] window is visible during the whole
- * transition
- */
- @Presubmit
- @Test
- open fun statusBarWindowIsAlwaysVisible() = flicker.statusBarWindowIsAlwaysVisible()
-
- /**
- * Checks that all layers that are visible on the trace, are visible for at least 2 consecutive
- * entries.
- */
- @Presubmit
- @Test
- open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
- flicker.assertLayers { this.visibleLayersShownMoreThanOneConsecutiveEntry() }
- }
-
- /**
- * Checks that all windows that are visible on the trace, are visible for at least 2 consecutive
- * entries.
- */
- @Presubmit
- @Test
- open fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
- flicker.assertWm { this.visibleWindowsShownMoreThanOneConsecutiveEntry() }
- }
-}
+ override val flicker: FlickerTest,
+ instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation(),
+ tapl: LauncherInstrumentation = LauncherInstrumentation()
+) : BaseBenchmarkTest(flicker, instrumentation, tapl), ICommonAssertions
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/ICommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/ICommonAssertions.kt
new file mode 100644
index 0000000..02d9a056
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/ICommonAssertions.kt
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2023 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.flicker
+
+import android.platform.test.annotations.Presubmit
+import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.device.flicker.legacy.FlickerTest
+import com.android.server.wm.flicker.entireScreenCovered
+import com.android.server.wm.flicker.navBarLayerIsVisibleAtStartAndEnd
+import com.android.server.wm.flicker.navBarLayerPositionAtStartAndEnd
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisibleAtStartAndEnd
+import com.android.server.wm.flicker.statusBarLayerPositionAtStartAndEnd
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.taskBarLayerIsVisibleAtStartAndEnd
+import com.android.server.wm.flicker.taskBarWindowIsAlwaysVisible
+import org.junit.Assume
+import org.junit.Test
+
+interface ICommonAssertions {
+ val flicker: FlickerTest
+
+ /** Checks that all parts of the screen are covered during the transition */
+ @Presubmit @Test fun entireScreenCovered() = flicker.entireScreenCovered()
+
+ /**
+ * Checks that the [ComponentNameMatcher.NAV_BAR] layer is visible during the whole transition
+ */
+ @Presubmit
+ @Test
+ fun navBarLayerIsVisibleAtStartAndEnd() {
+ Assume.assumeFalse(flicker.scenario.isTablet)
+ flicker.navBarLayerIsVisibleAtStartAndEnd()
+ }
+
+ /**
+ * Checks the position of the [ComponentNameMatcher.NAV_BAR] at the start and end of the
+ * transition
+ */
+ @Presubmit
+ @Test
+ fun navBarLayerPositionAtStartAndEnd() {
+ Assume.assumeFalse(flicker.scenario.isTablet)
+ flicker.navBarLayerPositionAtStartAndEnd()
+ }
+
+ /**
+ * Checks that the [ComponentNameMatcher.NAV_BAR] window is visible during the whole transition
+ *
+ * Note: Phones only
+ */
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() {
+ Assume.assumeFalse(flicker.scenario.isTablet)
+ flicker.navBarWindowIsAlwaysVisible()
+ }
+
+ /**
+ * Checks that the [ComponentNameMatcher.TASK_BAR] layer is visible during the whole transition
+ */
+ @Presubmit
+ @Test
+ fun taskBarLayerIsVisibleAtStartAndEnd() {
+ Assume.assumeTrue(flicker.scenario.isTablet)
+ flicker.taskBarLayerIsVisibleAtStartAndEnd()
+ }
+
+ /**
+ * Checks that the [ComponentNameMatcher.TASK_BAR] window is visible during the whole transition
+ *
+ * Note: Large screen only
+ */
+ @Presubmit
+ @Test
+ fun taskBarWindowIsAlwaysVisible() {
+ Assume.assumeTrue(flicker.scenario.isTablet)
+ flicker.taskBarWindowIsAlwaysVisible()
+ }
+
+ /**
+ * Checks that the [ComponentNameMatcher.STATUS_BAR] layer is visible during the whole
+ * transition
+ */
+ @Presubmit
+ @Test
+ fun statusBarLayerIsVisibleAtStartAndEnd() = flicker.statusBarLayerIsVisibleAtStartAndEnd()
+
+ /**
+ * Checks the position of the [ComponentNameMatcher.STATUS_BAR] at the start and end of the
+ * transition
+ */
+ @Presubmit
+ @Test
+ fun statusBarLayerPositionAtStartAndEnd() = flicker.statusBarLayerPositionAtStartAndEnd()
+
+ /**
+ * Checks that the [ComponentNameMatcher.STATUS_BAR] window is visible during the whole
+ * transition
+ */
+ @Presubmit @Test fun statusBarWindowIsAlwaysVisible() = flicker.statusBarWindowIsAlwaysVisible()
+
+ /**
+ * Checks that all layers that are visible on the trace, are visible for at least 2 consecutive
+ * entries.
+ */
+ @Presubmit
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ flicker.assertLayers { this.visibleLayersShownMoreThanOneConsecutiveEntry() }
+ }
+
+ /**
+ * Checks that all windows that are visible on the trace, are visible for at least 2 consecutive
+ * entries.
+ */
+ @Presubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ flicker.assertWm { this.visibleWindowsShownMoreThanOneConsecutiveEntry() }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
index d53eac0..b7e73ad 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
@@ -26,6 +26,7 @@
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
@@ -34,6 +35,7 @@
import com.android.wm.shell.flicker.splitAppLayerBoundsKeepVisible
import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtStart
+import com.android.wm.shell.flicker.splitscreen.benchmark.CopyContentInSplitBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -49,29 +51,19 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CopyContentInSplit(flicker: FlickerTest) : SplitScreenBase(flicker) {
- private val textEditApp = SplitScreenUtils.getIme(instrumentation)
- private val MagnifierLayer = ComponentNameMatcher("", "magnifier surface bbq wrapper#")
- private val PopupWindowLayer = ComponentNameMatcher("", "PopupWindow:")
-
+class CopyContentInSplit(override val flicker: FlickerTest) :
+ CopyContentInSplitBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, textEditApp) }
- transitions {
- SplitScreenUtils.copyContentInSplit(
- instrumentation,
- device,
- primaryApp,
- textEditApp
- )
- }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
@IwTest(focusArea = "sysui")
@Presubmit
@Test
- fun cujCompleted() {
+ override fun cujCompleted() {
flicker.appWindowIsVisibleAtStart(primaryApp)
flicker.appWindowIsVisibleAtStart(textEditApp)
flicker.splitScreenDividerIsVisibleAtStart()
@@ -128,8 +120,8 @@
ComponentNameMatcher.SNAPSHOT,
ComponentNameMatcher.IME_SNAPSHOT,
EdgeExtensionComponentMatcher(),
- MagnifierLayer,
- PopupWindowLayer
+ magnifierLayer,
+ popupWindowLayer
)
)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
index 1b55f39..3fd6d17 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
@@ -17,22 +17,21 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
import android.tools.device.helpers.WindowUtils
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.appWindowBecomesInvisible
import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
import com.android.wm.shell.flicker.layerBecomesInvisible
import com.android.wm.shell.flicker.layerIsVisibleAtEnd
import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesInvisible
-import com.android.wm.shell.flicker.splitScreenDismissed
import com.android.wm.shell.flicker.splitScreenDividerBecomesInvisible
+import com.android.wm.shell.flicker.splitscreen.benchmark.DismissSplitScreenByDividerBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -48,37 +47,16 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class DismissSplitScreenByDivider(flicker: FlickerTest) : SplitScreenBase(flicker) {
+class DismissSplitScreenByDivider(override val flicker: FlickerTest) :
+ DismissSplitScreenByDividerBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp) }
- transitions {
- if (tapl.isTablet) {
- SplitScreenUtils.dragDividerToDismissSplit(
- device,
- wmHelper,
- dragToRight = false,
- dragToBottom = true
- )
- } else {
- SplitScreenUtils.dragDividerToDismissSplit(
- device,
- wmHelper,
- dragToRight = true,
- dragToBottom = true
- )
- }
- wmHelper.StateSyncBuilder().withFullScreenApp(secondaryApp).waitForAndVerify()
- }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
- @IwTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() = flicker.splitScreenDismissed(primaryApp, secondaryApp, toHome = false)
-
@Presubmit
@Test
fun splitScreenDividerBecomesInvisible() = flicker.splitScreenDividerBecomesInvisible()
@@ -176,12 +154,4 @@
@Test
override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
- }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
index 2e81b30..e05b221 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
@@ -17,18 +17,18 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.appWindowBecomesInvisible
import com.android.wm.shell.flicker.layerBecomesInvisible
import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesInvisible
-import com.android.wm.shell.flicker.splitScreenDismissed
import com.android.wm.shell.flicker.splitScreenDividerBecomesInvisible
+import com.android.wm.shell.flicker.splitscreen.benchmark.DismissSplitScreenByGoHomeBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -44,21 +44,14 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class DismissSplitScreenByGoHome(flicker: FlickerTest) : SplitScreenBase(flicker) {
-
+class DismissSplitScreenByGoHome(override val flicker: FlickerTest) :
+ DismissSplitScreenByGoHomeBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp) }
- transitions {
- tapl.goHome()
- wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
- }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
- @IwTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() = flicker.splitScreenDismissed(primaryApp, secondaryApp, toHome = true)
@Presubmit
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
index 5180791..0b0a3da 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
@@ -24,6 +24,7 @@
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
@@ -32,8 +33,7 @@
import com.android.wm.shell.flicker.splitAppLayerBoundsChanges
import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtStart
-import org.junit.Assume
-import org.junit.Before
+import com.android.wm.shell.flicker.splitscreen.benchmark.DragDividerToResizeBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -49,24 +49,19 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class DragDividerToResize(flicker: FlickerTest) : SplitScreenBase(flicker) {
-
+class DragDividerToResize(override val flicker: FlickerTest) :
+ DragDividerToResizeBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp) }
- transitions { SplitScreenUtils.dragDividerToResizeAndWait(device, wmHelper) }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
- @Before
- fun before() {
- Assume.assumeTrue(tapl.isTablet || !flicker.scenario.isLandscapeOrSeascapeAtStart)
- }
-
@IwTest(focusArea = "sysui")
@Presubmit
@Test
- fun cujCompleted() {
+ override fun cujCompleted() {
flicker.appWindowIsVisibleAtStart(primaryApp)
flicker.appWindowIsVisibleAtStart(secondaryApp)
flicker.splitScreenDividerIsVisibleAtStart()
@@ -74,9 +69,6 @@
flicker.appWindowIsVisibleAtEnd(primaryApp)
flicker.appWindowIsVisibleAtEnd(secondaryApp)
flicker.splitScreenDividerIsVisibleAtEnd()
-
- // TODO(b/246490534): Add validation for resized app after withAppTransitionIdle is
- // robust enough to get the correct end state.
}
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
index 69da1e2..e558686 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
@@ -26,6 +25,7 @@
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
import com.android.wm.shell.flicker.appWindowBecomesVisible
import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
@@ -34,9 +34,7 @@
import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesVisibleByDrag
import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
-import com.android.wm.shell.flicker.splitScreenEntered
-import org.junit.Assume
-import org.junit.Before
+import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenByDragFromAllAppsBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -53,40 +51,15 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenByDragFromAllApps(flicker: FlickerTest) : SplitScreenBase(flicker) {
-
- @Before
- fun before() {
- Assume.assumeTrue(tapl.isTablet)
- }
-
+class EnterSplitScreenByDragFromAllApps(override val flicker: FlickerTest) :
+ EnterSplitScreenByDragFromAllAppsBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup {
- tapl.goHome()
- primaryApp.launchViaIntent(wmHelper)
- }
- transitions {
- tapl.launchedAppState.taskbar
- .openAllApps()
- .getAppIcon(secondaryApp.appName)
- .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
- SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
- }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
- @IwTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() =
- flicker.splitScreenEntered(
- primaryApp,
- secondaryApp,
- fromOtherApp = false,
- appExistAtStart = false
- )
-
@FlakyTest(bugId = 245472831)
@Test
fun splitScreenDividerBecomesVisible() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt
index 1773846..ab8ecc5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
@@ -26,6 +25,7 @@
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
import com.android.wm.shell.flicker.layerBecomesVisible
@@ -33,9 +33,7 @@
import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesVisibleByDrag
import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
-import com.android.wm.shell.flicker.splitScreenEntered
-import org.junit.Assume
-import org.junit.Before
+import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenByDragFromNotificationBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -52,39 +50,16 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenByDragFromNotification(flicker: FlickerTest) : SplitScreenBase(flicker) {
-
- private val sendNotificationApp = SplitScreenUtils.getSendNotification(instrumentation)
-
- @Before
- fun before() {
- Assume.assumeTrue(tapl.isTablet)
- }
-
+class EnterSplitScreenByDragFromNotification(override val flicker: FlickerTest) :
+ EnterSplitScreenByDragFromNotificationBenchmark(flicker), ICommonAssertions {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup {
- // Send a notification
- sendNotificationApp.launchViaIntent(wmHelper)
- sendNotificationApp.postNotification(wmHelper)
- tapl.goHome()
- primaryApp.launchViaIntent(wmHelper)
- }
- transitions {
- SplitScreenUtils.dragFromNotificationToSplit(instrumentation, device, wmHelper)
- SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, sendNotificationApp)
- }
- teardown { sendNotificationApp.exit(wmHelper) }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
- @IwTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() =
- flicker.splitScreenEntered(primaryApp, sendNotificationApp, fromOtherApp = false)
-
@FlakyTest(bugId = 245472831)
@Test
fun splitScreenDividerBecomesVisible() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt
index c1977e9..516ca97 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
@@ -25,15 +24,14 @@
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
import com.android.wm.shell.flicker.layerBecomesVisible
import com.android.wm.shell.flicker.layerIsVisibleAtEnd
import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesVisibleByDrag
import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
-import com.android.wm.shell.flicker.splitScreenEntered
-import org.junit.Assume
-import org.junit.Before
+import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenByDragFromShortcutBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -49,42 +47,16 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenByDragFromShortcut(flicker: FlickerTest) : SplitScreenBase(flicker) {
-
- @Before
- fun before() {
- Assume.assumeTrue(tapl.isTablet)
- }
+class EnterSplitScreenByDragFromShortcut(override val flicker: FlickerTest) :
+ EnterSplitScreenByDragFromShortcutBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup {
- tapl.goHome()
- SplitScreenUtils.createShortcutOnHotseatIfNotExist(tapl, secondaryApp.appName)
- primaryApp.launchViaIntent(wmHelper)
- }
- transitions {
- tapl.launchedAppState.taskbar
- .getAppIcon(secondaryApp.appName)
- .openDeepShortcutMenu()
- .getMenuItem("Split Screen Secondary Activity")
- .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
- SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
- }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
- @IwTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() =
- flicker.splitScreenEntered(
- primaryApp,
- secondaryApp,
- fromOtherApp = false,
- appExistAtStart = false
- )
-
@Presubmit
@Test
fun splitScreenDividerBecomesVisible() = flicker.splitScreenDividerBecomesVisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt
index 3bea66e..4af7e24 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
@@ -26,6 +25,7 @@
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
import com.android.wm.shell.flicker.appWindowBecomesVisible
import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
@@ -34,9 +34,7 @@
import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesVisibleByDrag
import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
-import com.android.wm.shell.flicker.splitScreenEntered
-import org.junit.Assume
-import org.junit.Before
+import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenByDragFromTaskbarBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -53,41 +51,16 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenByDragFromTaskbar(flicker: FlickerTest) : SplitScreenBase(flicker) {
-
- @Before
- fun before() {
- Assume.assumeTrue(tapl.isTablet)
- }
-
+class EnterSplitScreenByDragFromTaskbar(override val flicker: FlickerTest) :
+ EnterSplitScreenByDragFromTaskbarBenchmark(flicker), ICommonAssertions {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup {
- tapl.goHome()
- SplitScreenUtils.createShortcutOnHotseatIfNotExist(tapl, secondaryApp.appName)
- primaryApp.launchViaIntent(wmHelper)
- }
- transitions {
- tapl.launchedAppState.taskbar
- .getAppIcon(secondaryApp.appName)
- .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
- SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
- }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
- @IwTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() =
- flicker.splitScreenEntered(
- primaryApp,
- secondaryApp,
- fromOtherApp = false,
- appExistAtStart = false
- )
-
@FlakyTest(bugId = 245472831)
@Test
fun splitScreenDividerBecomesVisible() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
index c453877..faad9e8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
@@ -17,20 +17,20 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.appWindowBecomesVisible
import com.android.wm.shell.flicker.layerBecomesVisible
import com.android.wm.shell.flicker.layerIsVisibleAtEnd
import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesVisible
import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
-import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenFromOverviewBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -46,31 +46,15 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenFromOverview(flicker: FlickerTest) : SplitScreenBase(flicker) {
+class EnterSplitScreenFromOverview(override val flicker: FlickerTest) :
+ EnterSplitScreenFromOverviewBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup {
- primaryApp.launchViaIntent(wmHelper)
- secondaryApp.launchViaIntent(wmHelper)
- tapl.goHome()
- wmHelper
- .StateSyncBuilder()
- .withAppTransitionIdle()
- .withHomeActivityVisible()
- .waitForAndVerify()
- }
- transitions {
- SplitScreenUtils.splitFromOverview(tapl, device)
- SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
- }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
- @IwTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
-
@Presubmit
@Test
fun splitScreenDividerBecomesVisible() = flicker.splitScreenDividerBecomesVisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
index 7abdc06..195b73a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
@@ -20,25 +20,33 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
import com.android.server.wm.flicker.helpers.setRotation
-import com.android.wm.shell.flicker.BaseTest
+import com.android.wm.shell.flicker.BaseBenchmarkTest
-abstract class SplitScreenBase(flicker: FlickerTest) : BaseTest(flicker) {
+abstract class SplitScreenBase(flicker: FlickerTest) : BaseBenchmarkTest(flicker) {
protected val context: Context = instrumentation.context
protected val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
protected val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
- /** {@inheritDoc} */
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- setup {
- tapl.setEnableRotation(true)
- setRotation(flicker.scenario.startRotation)
- tapl.setExpectedRotation(flicker.scenario.startRotation.value)
- tapl.workspace.switchToOverview().dismissAllTasks()
- }
- teardown {
- primaryApp.exit(wmHelper)
- secondaryApp.exit(wmHelper)
- }
+ protected open val defaultSetup: FlickerBuilder.() -> Unit = {
+ setup {
+ tapl.setEnableRotation(true)
+ setRotation(flicker.scenario.startRotation)
+ tapl.setExpectedRotation(flicker.scenario.startRotation.value)
+ tapl.workspace.switchToOverview().dismissAllTasks()
}
+ }
+
+ protected open val defaultTeardown: FlickerBuilder.() -> Unit = {
+ teardown {
+ primaryApp.exit(wmHelper)
+ secondaryApp.exit(wmHelper)
+ }
+ }
+
+ protected open val withoutTracing: FlickerBuilder.() -> Unit = {
+ withoutLayerTracing()
+ withoutWindowManagerTracing()
+ withoutTransitionTracing()
+ withoutTransactionsTracing()
+ }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
index fbb7c71..8cf871f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
@@ -20,14 +20,12 @@
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
-import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
-import android.tools.device.helpers.WindowUtils
-import android.tools.device.traces.parsers.WindowManagerStateHelper
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
@@ -36,6 +34,7 @@
import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtStart
+import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchAppByDoubleTapDividerBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -51,98 +50,19 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchAppByDoubleTapDivider(flicker: FlickerTest) : SplitScreenBase(flicker) {
-
+class SwitchAppByDoubleTapDivider(override val flicker: FlickerTest) :
+ SwitchAppByDoubleTapDividerBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp) }
- transitions {
- SplitScreenUtils.doubleTapDividerToSwitch(device)
- wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
-
- waitForLayersToSwitch(wmHelper)
- waitForWindowsToSwitch(wmHelper)
- }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
- private fun waitForWindowsToSwitch(wmHelper: WindowManagerStateHelper) {
- wmHelper
- .StateSyncBuilder()
- .add("appWindowsSwitched") {
- val primaryAppWindow =
- it.wmState.visibleWindows.firstOrNull { window ->
- primaryApp.windowMatchesAnyOf(window)
- }
- ?: return@add false
- val secondaryAppWindow =
- it.wmState.visibleWindows.firstOrNull { window ->
- secondaryApp.windowMatchesAnyOf(window)
- }
- ?: return@add false
-
- if (isLandscape(flicker.scenario.endRotation)) {
- return@add if (flicker.scenario.isTablet) {
- secondaryAppWindow.frame.right <= primaryAppWindow.frame.left
- } else {
- primaryAppWindow.frame.right <= secondaryAppWindow.frame.left
- }
- } else {
- return@add if (flicker.scenario.isTablet) {
- primaryAppWindow.frame.bottom <= secondaryAppWindow.frame.top
- } else {
- primaryAppWindow.frame.bottom <= secondaryAppWindow.frame.top
- }
- }
- }
- .waitForAndVerify()
- }
-
- private fun waitForLayersToSwitch(wmHelper: WindowManagerStateHelper) {
- wmHelper
- .StateSyncBuilder()
- .add("appLayersSwitched") {
- val primaryAppLayer =
- it.layerState.visibleLayers.firstOrNull { window ->
- primaryApp.layerMatchesAnyOf(window)
- }
- ?: return@add false
- val secondaryAppLayer =
- it.layerState.visibleLayers.firstOrNull { window ->
- secondaryApp.layerMatchesAnyOf(window)
- }
- ?: return@add false
-
- val primaryVisibleRegion = primaryAppLayer.visibleRegion?.bounds ?: return@add false
- val secondaryVisibleRegion =
- secondaryAppLayer.visibleRegion?.bounds ?: return@add false
-
- if (isLandscape(flicker.scenario.endRotation)) {
- return@add if (flicker.scenario.isTablet) {
- secondaryVisibleRegion.right <= primaryVisibleRegion.left
- } else {
- primaryVisibleRegion.right <= secondaryVisibleRegion.left
- }
- } else {
- return@add if (flicker.scenario.isTablet) {
- primaryVisibleRegion.bottom <= secondaryVisibleRegion.top
- } else {
- primaryVisibleRegion.bottom <= secondaryVisibleRegion.top
- }
- }
- }
- .waitForAndVerify()
- }
-
- private fun isLandscape(rotation: Rotation): Boolean {
- val displayBounds = WindowUtils.getDisplayBounds(rotation)
- return displayBounds.width > displayBounds.height
- }
-
@IwTest(focusArea = "sysui")
@Presubmit
@Test
- fun cujCompleted() {
+ override fun cujCompleted() {
flicker.appWindowIsVisibleAtStart(primaryApp)
flicker.appWindowIsVisibleAtStart(secondaryApp)
flicker.splitScreenDividerIsVisibleAtStart()
@@ -150,9 +70,6 @@
flicker.appWindowIsVisibleAtEnd(primaryApp)
flicker.appWindowIsVisibleAtEnd(secondaryApp)
flicker.splitScreenDividerIsVisibleAtEnd()
-
- // TODO(b/246490534): Add validation for switched app after withAppTransitionIdle is
- // robust enough to get the correct end state.
}
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
index d675bfb..078d95d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
@@ -25,11 +24,12 @@
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.appWindowBecomesVisible
import com.android.wm.shell.flicker.layerBecomesVisible
import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
-import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBackToSplitFromAnotherAppBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -45,29 +45,15 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchBackToSplitFromAnotherApp(flicker: FlickerTest) : SplitScreenBase(flicker) {
- val thirdApp = SplitScreenUtils.getNonResizeable(instrumentation)
-
+class SwitchBackToSplitFromAnotherApp(override val flicker: FlickerTest) :
+ SwitchBackToSplitFromAnotherAppBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup {
- SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
-
- thirdApp.launchViaIntent(wmHelper)
- wmHelper.StateSyncBuilder().withWindowSurfaceAppeared(thirdApp).waitForAndVerify()
- }
- transitions {
- tapl.launchedAppState.quickSwitchToPreviousApp()
- SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
- }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
- @IwTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
-
@Presubmit
@Test
fun splitScreenDividerBecomesVisible() = flicker.splitScreenDividerBecomesVisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
index 9f4cb8c..7c84243 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
@@ -25,11 +24,12 @@
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.appWindowBecomesVisible
import com.android.wm.shell.flicker.layerBecomesVisible
import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
-import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBackToSplitFromHomeBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -45,28 +45,15 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchBackToSplitFromHome(flicker: FlickerTest) : SplitScreenBase(flicker) {
-
+class SwitchBackToSplitFromHome(override val flicker: FlickerTest) :
+ SwitchBackToSplitFromHomeBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup {
- SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
-
- tapl.goHome()
- wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
- }
- transitions {
- tapl.workspace.quickSwitchToPreviousApp()
- SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
- }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
- @IwTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
-
@Presubmit
@Test
fun splitScreenDividerBecomesVisible() = flicker.splitScreenDividerBecomesVisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
index a33d8ca..7c46d3e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
@@ -25,11 +24,12 @@
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.appWindowBecomesVisible
import com.android.wm.shell.flicker.layerBecomesVisible
import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
-import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBackToSplitFromRecentBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -45,28 +45,15 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchBackToSplitFromRecent(flicker: FlickerTest) : SplitScreenBase(flicker) {
-
+class SwitchBackToSplitFromRecent(override val flicker: FlickerTest) :
+ SwitchBackToSplitFromRecentBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup {
- SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
-
- tapl.goHome()
- wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
- }
- transitions {
- tapl.workspace.switchToOverview().currentTask.open()
- SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
- }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
- @IwTest(focusArea = "sysui")
- @Presubmit
- @Test
- fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
-
@Presubmit
@Test
fun splitScreenDividerBecomesVisible() = flicker.splitScreenDividerBecomesVisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
index 4c96b3a..3b2da8d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
@@ -24,6 +24,7 @@
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
import com.android.wm.shell.flicker.appWindowBecomesInvisible
import com.android.wm.shell.flicker.appWindowBecomesVisible
@@ -36,6 +37,7 @@
import com.android.wm.shell.flicker.splitAppLayerBoundsSnapToDivider
import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtStart
+import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBetweenSplitPairsBenchmark
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -51,32 +53,19 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchBetweenSplitPairs(flicker: FlickerTest) : SplitScreenBase(flicker) {
- private val thirdApp = SplitScreenUtils.getIme(instrumentation)
- private val fourthApp = SplitScreenUtils.getSendNotification(instrumentation)
-
+class SwitchBetweenSplitPairs(override val flicker: FlickerTest) :
+ SwitchBetweenSplitPairsBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this)
- setup {
- SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
- SplitScreenUtils.enterSplit(wmHelper, tapl, device, thirdApp, fourthApp)
- SplitScreenUtils.waitForSplitComplete(wmHelper, thirdApp, fourthApp)
- }
- transitions {
- tapl.launchedAppState.quickSwitchToPreviousApp()
- SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
- }
- teardown {
- thirdApp.exit(wmHelper)
- fourthApp.exit(wmHelper)
- }
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
}
@IwTest(focusArea = "sysui")
@Presubmit
@Test
- fun cujCompleted() {
+ override fun cujCompleted() {
flicker.appWindowIsVisibleAtStart(thirdApp)
flicker.appWindowIsVisibleAtStart(fourthApp)
flicker.splitScreenDividerIsVisibleAtStart()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt
new file mode 100644
index 0000000..a189a3f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2023 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.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class CopyContentInSplitBenchmark(override val flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+ protected val textEditApp = SplitScreenUtils.getIme(instrumentation)
+ protected val magnifierLayer = ComponentNameMatcher("", "magnifier surface bbq wrapper#")
+ protected val popupWindowLayer = ComponentNameMatcher("", "PopupWindow:")
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, textEditApp) }
+ transitions {
+ SplitScreenUtils.copyContentInSplit(
+ instrumentation,
+ device,
+ primaryApp,
+ textEditApp
+ )
+ }
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ open fun cujCompleted() {
+ // The validation of copied text is already done in SplitScreenUtils.copyContentInSplit()
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests()
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt
new file mode 100644
index 0000000..55ab7b3
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2023 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.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitScreenDismissed
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class DismissSplitScreenByDividerBenchmark(flicker: FlickerTest) : SplitScreenBase(flicker) {
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp) }
+ transitions {
+ if (tapl.isTablet) {
+ SplitScreenUtils.dragDividerToDismissSplit(
+ device,
+ wmHelper,
+ dragToRight = false,
+ dragToBottom = true
+ )
+ } else {
+ SplitScreenUtils.dragDividerToDismissSplit(
+ device,
+ wmHelper,
+ dragToRight = true,
+ dragToBottom = true
+ )
+ }
+ wmHelper.StateSyncBuilder().withFullScreenApp(secondaryApp).waitForAndVerify()
+ }
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ fun cujCompleted() = flicker.splitScreenDismissed(primaryApp, secondaryApp, toHome = false)
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests()
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt
new file mode 100644
index 0000000..c4cfd1a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 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.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitScreenDismissed
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class DismissSplitScreenByGoHomeBenchmark(override val flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp) }
+ transitions {
+ tapl.goHome()
+ wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
+ }
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ fun cujCompleted() = flicker.splitScreenDismissed(primaryApp, secondaryApp, toHome = true)
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests()
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt
new file mode 100644
index 0000000..146287c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2023 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.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class DragDividerToResizeBenchmark(override val flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp) }
+ transitions { SplitScreenUtils.dragDividerToResizeAndWait(device, wmHelper) }
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @Before
+ fun before() {
+ Assume.assumeTrue(tapl.isTablet || !flicker.scenario.isLandscapeOrSeascapeAtStart)
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ open fun cujCompleted() {
+ // TODO(b/246490534): Add validation for resized app after withAppTransitionIdle is
+ // robust enough to get the correct end state.
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests()
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
new file mode 100644
index 0000000..cc71502
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2023 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.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.NavBar
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class EnterSplitScreenByDragFromAllAppsBenchmark(override val flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ tapl.goHome()
+ primaryApp.launchViaIntent(wmHelper)
+ }
+ transitions {
+ tapl.launchedAppState.taskbar
+ .openAllApps()
+ .getAppIcon(secondaryApp.appName)
+ .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @Before
+ fun before() {
+ Assume.assumeTrue(tapl.isTablet)
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ fun cujCompleted() =
+ flicker.splitScreenEntered(
+ primaryApp,
+ secondaryApp,
+ fromOtherApp = false,
+ appExistAtStart = false
+ )
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ )
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt
new file mode 100644
index 0000000..de78f09
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2023 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.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.NavBar
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class EnterSplitScreenByDragFromNotificationBenchmark(override val flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+ protected val sendNotificationApp = SplitScreenUtils.getSendNotification(instrumentation)
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ // Send a notification
+ sendNotificationApp.launchViaIntent(wmHelper)
+ sendNotificationApp.postNotification(wmHelper)
+ tapl.goHome()
+ primaryApp.launchViaIntent(wmHelper)
+ }
+ transitions {
+ SplitScreenUtils.dragFromNotificationToSplit(instrumentation, device, wmHelper)
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, sendNotificationApp)
+ }
+ teardown { sendNotificationApp.exit(wmHelper) }
+ }
+
+ /** {@inheritDoc} */
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ fun cujCompleted() =
+ flicker.splitScreenEntered(primaryApp, sendNotificationApp, fromOtherApp = false)
+
+ @Before
+ fun before() {
+ Assume.assumeTrue(tapl.isTablet)
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ )
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
new file mode 100644
index 0000000..a29eb40
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2023 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.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.NavBar
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class EnterSplitScreenByDragFromShortcutBenchmark(flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+ @Before
+ fun before() {
+ Assume.assumeTrue(tapl.isTablet)
+ }
+
+ protected val thisTransition: FlickerBuilder.() -> Unit = {
+ setup {
+ tapl.goHome()
+ SplitScreenUtils.createShortcutOnHotseatIfNotExist(tapl, secondaryApp.appName)
+ primaryApp.launchViaIntent(wmHelper)
+ }
+ transitions {
+ tapl.launchedAppState.taskbar
+ .getAppIcon(secondaryApp.appName)
+ .openDeepShortcutMenu()
+ .getMenuItem("Split Screen Secondary Activity")
+ .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ fun cujCompleted() =
+ flicker.splitScreenEntered(
+ primaryApp,
+ secondaryApp,
+ fromOtherApp = false,
+ appExistAtStart = false
+ )
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ )
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
new file mode 100644
index 0000000..b2395ca
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2023 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.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.NavBar
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class EnterSplitScreenByDragFromTaskbarBenchmark(override val flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ tapl.goHome()
+ SplitScreenUtils.createShortcutOnHotseatIfNotExist(tapl, secondaryApp.appName)
+ primaryApp.launchViaIntent(wmHelper)
+ }
+ transitions {
+ tapl.launchedAppState.taskbar
+ .getAppIcon(secondaryApp.appName)
+ .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+ }
+
+ /** {@inheritDoc} */
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ fun cujCompleted() =
+ flicker.splitScreenEntered(
+ primaryApp,
+ secondaryApp,
+ fromOtherApp = false,
+ appExistAtStart = false
+ )
+
+ @Before
+ fun before() {
+ Assume.assumeTrue(tapl.isTablet)
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ )
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt
new file mode 100644
index 0000000..e1d85d0
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2023 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.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class EnterSplitScreenFromOverviewBenchmark(override val flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ primaryApp.launchViaIntent(wmHelper)
+ secondaryApp.launchViaIntent(wmHelper)
+ tapl.goHome()
+ wmHelper
+ .StateSyncBuilder()
+ .withAppTransitionIdle()
+ .withHomeActivityVisible()
+ .waitForAndVerify()
+ }
+ transitions {
+ SplitScreenUtils.splitFromOverview(tapl, device)
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests()
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
new file mode 100644
index 0000000..ba8c460
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2023 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.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.helpers.WindowUtils
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class SwitchAppByDoubleTapDividerBenchmark(override val flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp) }
+ transitions {
+ SplitScreenUtils.doubleTapDividerToSwitch(device)
+ wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
+
+ waitForLayersToSwitch(wmHelper)
+ waitForWindowsToSwitch(wmHelper)
+ }
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ private fun waitForWindowsToSwitch(wmHelper: WindowManagerStateHelper) {
+ wmHelper
+ .StateSyncBuilder()
+ .add("appWindowsSwitched") {
+ val primaryAppWindow =
+ it.wmState.visibleWindows.firstOrNull { window ->
+ primaryApp.windowMatchesAnyOf(window)
+ }
+ ?: return@add false
+ val secondaryAppWindow =
+ it.wmState.visibleWindows.firstOrNull { window ->
+ secondaryApp.windowMatchesAnyOf(window)
+ }
+ ?: return@add false
+
+ if (isLandscape(flicker.scenario.endRotation)) {
+ return@add if (flicker.scenario.isTablet) {
+ secondaryAppWindow.frame.right <= primaryAppWindow.frame.left
+ } else {
+ primaryAppWindow.frame.right <= secondaryAppWindow.frame.left
+ }
+ } else {
+ return@add if (flicker.scenario.isTablet) {
+ primaryAppWindow.frame.bottom <= secondaryAppWindow.frame.top
+ } else {
+ primaryAppWindow.frame.bottom <= secondaryAppWindow.frame.top
+ }
+ }
+ }
+ .waitForAndVerify()
+ }
+
+ private fun waitForLayersToSwitch(wmHelper: WindowManagerStateHelper) {
+ wmHelper
+ .StateSyncBuilder()
+ .add("appLayersSwitched") {
+ val primaryAppLayer =
+ it.layerState.visibleLayers.firstOrNull { window ->
+ primaryApp.layerMatchesAnyOf(window)
+ }
+ ?: return@add false
+ val secondaryAppLayer =
+ it.layerState.visibleLayers.firstOrNull { window ->
+ secondaryApp.layerMatchesAnyOf(window)
+ }
+ ?: return@add false
+
+ val primaryVisibleRegion = primaryAppLayer.visibleRegion?.bounds ?: return@add false
+ val secondaryVisibleRegion =
+ secondaryAppLayer.visibleRegion?.bounds ?: return@add false
+
+ if (isLandscape(flicker.scenario.endRotation)) {
+ return@add if (flicker.scenario.isTablet) {
+ secondaryVisibleRegion.right <= primaryVisibleRegion.left
+ } else {
+ primaryVisibleRegion.right <= secondaryVisibleRegion.left
+ }
+ } else {
+ return@add if (flicker.scenario.isTablet) {
+ primaryVisibleRegion.bottom <= secondaryVisibleRegion.top
+ } else {
+ primaryVisibleRegion.bottom <= secondaryVisibleRegion.top
+ }
+ }
+ }
+ .waitForAndVerify()
+ }
+
+ private fun isLandscape(rotation: Rotation): Boolean {
+ val displayBounds = WindowUtils.getDisplayBounds(rotation)
+ return displayBounds.width > displayBounds.height
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ open fun cujCompleted() {
+ // TODO(b/246490534): Add validation for switched app after withAppTransitionIdle is
+ // robust enough to get the correct end state.
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ )
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt
new file mode 100644
index 0000000..bbb2edc
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2023 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.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.NavBar
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class SwitchBackToSplitFromAnotherAppBenchmark(override val flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+ private val thirdApp = SplitScreenUtils.getNonResizeable(instrumentation)
+
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
+
+ thirdApp.launchViaIntent(wmHelper)
+ wmHelper.StateSyncBuilder().withWindowSurfaceAppeared(thirdApp).waitForAndVerify()
+ }
+ transitions {
+ tapl.launchedAppState.quickSwitchToPreviousApp()
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ )
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt
new file mode 100644
index 0000000..fa38293
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2023 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.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.NavBar
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class SwitchBackToSplitFromHomeBenchmark(override val flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
+
+ tapl.goHome()
+ wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
+ }
+ transitions {
+ tapl.workspace.quickSwitchToPreviousApp()
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ )
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt
new file mode 100644
index 0000000..1064bd9
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2023 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.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.common.NavBar
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitScreenEntered
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class SwitchBackToSplitFromRecentBenchmark(override val flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
+
+ tapl.goHome()
+ wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
+ }
+ transitions {
+ tapl.workspace.switchToOverview().currentTask.open()
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ withoutTracing(this)
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @IwTest(focusArea = "sysui")
+ @Presubmit
+ @Test
+ fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ )
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt
new file mode 100644
index 0000000..8f4393f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2023 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.flicker.splitscreen.benchmark
+
+import android.platform.test.annotations.IwTest
+import android.platform.test.annotations.Presubmit
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
+import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class SwitchBetweenSplitPairsBenchmark(override val flicker: FlickerTest) :
+ SplitScreenBase(flicker) {
+ protected val thirdApp = SplitScreenUtils.getIme(instrumentation)
+ protected val fourthApp = SplitScreenUtils.getSendNotification(instrumentation)
+
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, thirdApp, fourthApp)
+ SplitScreenUtils.waitForSplitComplete(wmHelper, thirdApp, fourthApp)
+ }
+ transitions {
+ tapl.launchedAppState.quickSwitchToPreviousApp()
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+ teardown {
+ thirdApp.exit(wmHelper)
+ fourthApp.exit(wmHelper)
+ }
+ }
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @IwTest(focusArea = "sysui") @Presubmit @Test open fun cujCompleted() {}
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests()
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java
index de967bf..afec1ee 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java
@@ -33,6 +33,7 @@
import android.content.res.Resources;
import android.graphics.drawable.Icon;
import android.os.Bundle;
+import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -42,6 +43,7 @@
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.bubbles.BubbleInfo;
import org.junit.Before;
import org.junit.Test;
@@ -77,7 +79,7 @@
Intent target = new Intent(mContext, BubblesTestActivity.class);
Notification.BubbleMetadata metadata = new Notification.BubbleMetadata.Builder(
PendingIntent.getActivity(mContext, 0, target, PendingIntent.FLAG_MUTABLE),
- Icon.createWithResource(mContext, R.drawable.bubble_ic_create_bubble))
+ Icon.createWithResource(mContext, R.drawable.bubble_ic_create_bubble))
.build();
when(mSbn.getNotification()).thenReturn(mNotif);
when(mNotif.getBubbleMetadata()).thenReturn(metadata);
@@ -179,6 +181,34 @@
assertThat(bubble.isConversation()).isFalse();
}
+ @Test
+ public void testBubbleAsBubbleBarBubble_withShortcut() {
+ Bubble bubble = createBubbleWithShortcut();
+ BubbleInfo bubbleInfo = bubble.asBubbleBarBubble();
+
+ assertThat(bubble.getShortcutInfo()).isNotNull();
+ assertThat(bubbleInfo.getShortcutId()).isNotNull();
+ assertThat(bubbleInfo.getShortcutId()).isEqualTo(bubble.getShortcutId());
+ assertThat(bubbleInfo.getKey()).isEqualTo(bubble.getKey());
+ assertThat(bubbleInfo.getUserId()).isEqualTo(bubble.getUser().getIdentifier());
+ assertThat(bubbleInfo.getPackageName()).isEqualTo(bubble.getPackageName());
+ }
+
+ @Test
+ public void testBubbleAsBubbleBarBubble_withoutShortcut() {
+ Intent intent = new Intent(mContext, BubblesTestActivity.class);
+ intent.setPackage(mContext.getPackageName());
+ Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1 /* userId */),
+ null /* icon */, mMainExecutor);
+ BubbleInfo bubbleInfo = bubble.asBubbleBarBubble();
+
+ assertThat(bubble.getShortcutInfo()).isNull();
+ assertThat(bubbleInfo.getShortcutId()).isNull();
+ assertThat(bubbleInfo.getKey()).isEqualTo(bubble.getKey());
+ assertThat(bubbleInfo.getUserId()).isEqualTo(bubble.getUser().getIdentifier());
+ assertThat(bubbleInfo.getPackageName()).isEqualTo(bubble.getPackageName());
+ }
+
private Bubble createBubbleWithShortcut() {
ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(mContext)
.setId("mockShortcutId")
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java
index 1347e06..60ee918 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java
@@ -112,9 +112,9 @@
@Test
public void testOnTaskProfileLocked() {
ActivityManager.RunningTaskInfo info = mock(ActivityManager.RunningTaskInfo.class);
- mImpl.onTaskProfileLocked(info);
- verify(mCallback).onTaskProfileLocked(eq(info));
- verify(mOtherCallback).onTaskProfileLocked(eq(info));
+ mImpl.onTaskProfileLocked(info, 0);
+ verify(mCallback).onTaskProfileLocked(eq(info), eq(0));
+ verify(mOtherCallback).onTaskProfileLocked(eq(info), eq(0));
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
index 63de74f..d6387ee 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
@@ -20,6 +20,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOW_CONFIG_BOUNDS;
+import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_NONE;
@@ -82,6 +83,8 @@
@RunWith(AndroidTestingRunner.class)
public class DesktopModeControllerTest extends ShellTestCase {
+ private static final int SECOND_DISPLAY = 2;
+
@Mock
private ShellController mShellController;
@Mock
@@ -248,22 +251,22 @@
public void testShowDesktopApps_allAppsInvisible_bringsToFront() {
// Set up two active tasks on desktop, task2 is on top of task1.
RunningTaskInfo freeformTask1 = createFreeformTask();
- mDesktopModeTaskRepository.addActiveTask(freeformTask1.taskId);
+ mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, freeformTask1.taskId);
mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(freeformTask1.taskId);
mDesktopModeTaskRepository.updateVisibleFreeformTasks(
- freeformTask1.taskId, false /* visible */);
+ DEFAULT_DISPLAY, freeformTask1.taskId, false /* visible */);
RunningTaskInfo freeformTask2 = createFreeformTask();
- mDesktopModeTaskRepository.addActiveTask(freeformTask2.taskId);
+ mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, freeformTask2.taskId);
mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(freeformTask2.taskId);
mDesktopModeTaskRepository.updateVisibleFreeformTasks(
- freeformTask2.taskId, false /* visible */);
+ DEFAULT_DISPLAY, freeformTask2.taskId, false /* visible */);
when(mShellTaskOrganizer.getRunningTaskInfo(freeformTask1.taskId)).thenReturn(
freeformTask1);
when(mShellTaskOrganizer.getRunningTaskInfo(freeformTask2.taskId)).thenReturn(
freeformTask2);
// Run show desktop apps logic
- mController.showDesktopApps();
+ mController.showDesktopApps(DEFAULT_DISPLAY);
final WindowContainerTransaction wct = getBringAppsToFrontTransaction();
// Check wct has reorder calls
@@ -283,17 +286,19 @@
@Test
public void testShowDesktopApps_appsAlreadyVisible_bringsToFront() {
final RunningTaskInfo task1 = createFreeformTask();
- mDesktopModeTaskRepository.addActiveTask(task1.taskId);
+ mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, task1.taskId);
mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task1.taskId);
- mDesktopModeTaskRepository.updateVisibleFreeformTasks(task1.taskId, true /* visible */);
+ mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task1.taskId,
+ true /* visible */);
when(mShellTaskOrganizer.getRunningTaskInfo(task1.taskId)).thenReturn(task1);
final RunningTaskInfo task2 = createFreeformTask();
- mDesktopModeTaskRepository.addActiveTask(task2.taskId);
+ mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, task2.taskId);
mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task2.taskId);
- mDesktopModeTaskRepository.updateVisibleFreeformTasks(task2.taskId, true /* visible */);
+ mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task2.taskId,
+ true /* visible */);
when(mShellTaskOrganizer.getRunningTaskInfo(task2.taskId)).thenReturn(task2);
- mController.showDesktopApps();
+ mController.showDesktopApps(DEFAULT_DISPLAY);
final WindowContainerTransaction wct = getBringAppsToFrontTransaction();
// Check wct has reorder calls
@@ -312,17 +317,19 @@
@Test
public void testShowDesktopApps_someAppsInvisible_reordersAll() {
final RunningTaskInfo task1 = createFreeformTask();
- mDesktopModeTaskRepository.addActiveTask(task1.taskId);
+ mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, task1.taskId);
mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task1.taskId);
- mDesktopModeTaskRepository.updateVisibleFreeformTasks(task1.taskId, false /* visible */);
+ mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task1.taskId,
+ false /* visible */);
when(mShellTaskOrganizer.getRunningTaskInfo(task1.taskId)).thenReturn(task1);
final RunningTaskInfo task2 = createFreeformTask();
- mDesktopModeTaskRepository.addActiveTask(task2.taskId);
+ mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, task2.taskId);
mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task2.taskId);
- mDesktopModeTaskRepository.updateVisibleFreeformTasks(task2.taskId, true /* visible */);
+ mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task2.taskId,
+ true /* visible */);
when(mShellTaskOrganizer.getRunningTaskInfo(task2.taskId)).thenReturn(task2);
- mController.showDesktopApps();
+ mController.showDesktopApps(DEFAULT_DISPLAY);
final WindowContainerTransaction wct = getBringAppsToFrontTransaction();
// Both tasks should be reordered to top, even if one was already visible.
@@ -336,38 +343,87 @@
}
@Test
+ public void testShowDesktopApps_twoDisplays_bringsToFrontOnlyOneDisplay() {
+ RunningTaskInfo taskDefaultDisplay = createFreeformTask(DEFAULT_DISPLAY);
+ mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, taskDefaultDisplay.taskId);
+ mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(taskDefaultDisplay.taskId);
+ mDesktopModeTaskRepository.updateVisibleFreeformTasks(
+ DEFAULT_DISPLAY, taskDefaultDisplay.taskId, false /* visible */);
+ when(mShellTaskOrganizer.getRunningTaskInfo(taskDefaultDisplay.taskId)).thenReturn(
+ taskDefaultDisplay);
+
+ RunningTaskInfo taskSecondDisplay = createFreeformTask(SECOND_DISPLAY);
+ mDesktopModeTaskRepository.addActiveTask(SECOND_DISPLAY, taskSecondDisplay.taskId);
+ mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(taskSecondDisplay.taskId);
+ mDesktopModeTaskRepository.updateVisibleFreeformTasks(
+ SECOND_DISPLAY, taskSecondDisplay.taskId, false /* visible */);
+ when(mShellTaskOrganizer.getRunningTaskInfo(taskSecondDisplay.taskId)).thenReturn(
+ taskSecondDisplay);
+
+ mController.showDesktopApps(DEFAULT_DISPLAY);
+
+ WindowContainerTransaction wct = getBringAppsToFrontTransaction();
+ assertThat(wct.getHierarchyOps()).hasSize(1);
+ HierarchyOp op = wct.getHierarchyOps().get(0);
+ assertThat(op.getContainer()).isEqualTo(taskDefaultDisplay.token.asBinder());
+ }
+
+ @Test
public void testGetVisibleTaskCount_noTasks_returnsZero() {
- assertThat(mController.getVisibleTaskCount()).isEqualTo(0);
+ assertThat(mController.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(0);
}
@Test
public void testGetVisibleTaskCount_twoTasks_bothVisible_returnsTwo() {
RunningTaskInfo task1 = createFreeformTask();
- mDesktopModeTaskRepository.addActiveTask(task1.taskId);
+ mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, task1.taskId);
mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task1.taskId);
- mDesktopModeTaskRepository.updateVisibleFreeformTasks(task1.taskId, true /* visible */);
+ mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task1.taskId,
+ true /* visible */);
RunningTaskInfo task2 = createFreeformTask();
- mDesktopModeTaskRepository.addActiveTask(task2.taskId);
+ mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, task2.taskId);
mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task2.taskId);
- mDesktopModeTaskRepository.updateVisibleFreeformTasks(task2.taskId, true /* visible */);
+ mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task2.taskId,
+ true /* visible */);
- assertThat(mController.getVisibleTaskCount()).isEqualTo(2);
+ assertThat(mController.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(2);
}
@Test
public void testGetVisibleTaskCount_twoTasks_oneVisible_returnsOne() {
RunningTaskInfo task1 = createFreeformTask();
- mDesktopModeTaskRepository.addActiveTask(task1.taskId);
+ mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, task1.taskId);
mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task1.taskId);
- mDesktopModeTaskRepository.updateVisibleFreeformTasks(task1.taskId, true /* visible */);
+ mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task1.taskId,
+ true /* visible */);
RunningTaskInfo task2 = createFreeformTask();
- mDesktopModeTaskRepository.addActiveTask(task2.taskId);
+ mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, task2.taskId);
mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task2.taskId);
- mDesktopModeTaskRepository.updateVisibleFreeformTasks(task2.taskId, false /* visible */);
+ mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task2.taskId,
+ false /* visible */);
- assertThat(mController.getVisibleTaskCount()).isEqualTo(1);
+ assertThat(mController.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(1);
+ }
+
+ @Test
+ public void testGetVisibleTaskCount_twoTasksVisibleOnDifferentDisplays_returnsOne() {
+ RunningTaskInfo taskDefaultDisplay = createFreeformTask();
+ mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, taskDefaultDisplay.taskId);
+ mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(taskDefaultDisplay.taskId);
+ mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY,
+ taskDefaultDisplay.taskId,
+ true /* visible */);
+
+ RunningTaskInfo taskSecondDisplay = createFreeformTask();
+ mDesktopModeTaskRepository.addActiveTask(SECOND_DISPLAY, taskSecondDisplay.taskId);
+ mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(taskSecondDisplay.taskId);
+ mDesktopModeTaskRepository.updateVisibleFreeformTasks(SECOND_DISPLAY,
+ taskSecondDisplay.taskId,
+ true /* visible */);
+
+ assertThat(mController.getVisibleTaskCount(SECOND_DISPLAY)).isEqualTo(1);
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
index 45cb3a0..3bc2f0e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
@@ -17,10 +17,12 @@
package com.android.wm.shell.desktopmode
import android.testing.AndroidTestingRunner
+import android.view.Display.DEFAULT_DISPLAY
import androidx.test.filters.SmallTest
import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.TestShellExecutor
import com.google.common.truth.Truth.assertThat
+import junit.framework.Assert.fail
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -41,8 +43,8 @@
val listener = TestListener()
repo.addActiveTaskListener(listener)
- repo.addActiveTask(1)
- assertThat(listener.activeTaskChangedCalls).isEqualTo(1)
+ repo.addActiveTask(DEFAULT_DISPLAY, taskId = 1)
+ assertThat(listener.activeChangesOnDefaultDisplay).isEqualTo(1)
assertThat(repo.isActiveTask(1)).isTrue()
}
@@ -51,9 +53,9 @@
val listener = TestListener()
repo.addActiveTaskListener(listener)
- repo.addActiveTask(1)
- repo.addActiveTask(1)
- assertThat(listener.activeTaskChangedCalls).isEqualTo(1)
+ repo.addActiveTask(DEFAULT_DISPLAY, taskId = 1)
+ repo.addActiveTask(DEFAULT_DISPLAY, taskId = 1)
+ assertThat(listener.activeChangesOnDefaultDisplay).isEqualTo(1)
}
@Test
@@ -61,9 +63,22 @@
val listener = TestListener()
repo.addActiveTaskListener(listener)
- repo.addActiveTask(1)
- repo.addActiveTask(2)
- assertThat(listener.activeTaskChangedCalls).isEqualTo(2)
+ repo.addActiveTask(DEFAULT_DISPLAY, taskId = 1)
+ repo.addActiveTask(DEFAULT_DISPLAY, taskId = 2)
+ assertThat(listener.activeChangesOnDefaultDisplay).isEqualTo(2)
+ }
+
+ @Test
+ fun addActiveTask_multipleDisplays_notifiesCorrectListener() {
+ val listener = TestListener()
+ repo.addActiveTaskListener(listener)
+
+ repo.addActiveTask(DEFAULT_DISPLAY, taskId = 1)
+ repo.addActiveTask(DEFAULT_DISPLAY, taskId = 2)
+ repo.addActiveTask(SECOND_DISPLAY, taskId = 3)
+
+ assertThat(listener.activeChangesOnDefaultDisplay).isEqualTo(2)
+ assertThat(listener.activeChangesOnSecondaryDisplay).isEqualTo(1)
}
@Test
@@ -71,10 +86,10 @@
val listener = TestListener()
repo.addActiveTaskListener(listener)
- repo.addActiveTask(1)
+ repo.addActiveTask(DEFAULT_DISPLAY, taskId = 1)
repo.removeActiveTask(1)
// Notify once for add and once for remove
- assertThat(listener.activeTaskChangedCalls).isEqualTo(2)
+ assertThat(listener.activeChangesOnDefaultDisplay).isEqualTo(2)
assertThat(repo.isActiveTask(1)).isFalse()
}
@@ -83,7 +98,17 @@
val listener = TestListener()
repo.addActiveTaskListener(listener)
repo.removeActiveTask(99)
- assertThat(listener.activeTaskChangedCalls).isEqualTo(0)
+ assertThat(listener.activeChangesOnDefaultDisplay).isEqualTo(0)
+ }
+
+ @Test
+ fun remoteActiveTask_listenerForOtherDisplayNotNotified() {
+ val listener = TestListener()
+ repo.addActiveTaskListener(listener)
+ repo.addActiveTask(DEFAULT_DISPLAY, taskId = 1)
+ repo.removeActiveTask(1)
+ assertThat(listener.activeChangesOnSecondaryDisplay).isEqualTo(0)
+ assertThat(repo.isActiveTask(1)).isFalse()
}
@Test
@@ -93,14 +118,27 @@
@Test
fun addListener_notifiesVisibleFreeformTask() {
- repo.updateVisibleFreeformTasks(1, true)
+ repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true)
val listener = TestVisibilityListener()
val executor = TestShellExecutor()
repo.addVisibleTasksListener(listener, executor)
executor.flushAll()
- assertThat(listener.hasVisibleFreeformTasks).isTrue()
- assertThat(listener.visibleFreeformTaskChangedCalls).isEqualTo(1)
+ assertThat(listener.hasVisibleTasksOnDefaultDisplay).isTrue()
+ assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(1)
+ }
+
+ @Test
+ fun addListener_tasksOnDifferentDisplay_doesNotNotify() {
+ repo.updateVisibleFreeformTasks(SECOND_DISPLAY, taskId = 1, visible = true)
+ val listener = TestVisibilityListener()
+ val executor = TestShellExecutor()
+ repo.addVisibleTasksListener(listener, executor)
+ executor.flushAll()
+
+ assertThat(listener.hasVisibleTasksOnDefaultDisplay).isFalse()
+ // One call as adding listener notifies it
+ assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(0)
}
@Test
@@ -108,13 +146,61 @@
val listener = TestVisibilityListener()
val executor = TestShellExecutor()
repo.addVisibleTasksListener(listener, executor)
- repo.updateVisibleFreeformTasks(1, true)
- repo.updateVisibleFreeformTasks(2, true)
+ repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true)
+ repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 2, visible = true)
executor.flushAll()
- assertThat(listener.hasVisibleFreeformTasks).isTrue()
- // Equal to 2 because adding the listener notifies the current state
- assertThat(listener.visibleFreeformTaskChangedCalls).isEqualTo(2)
+ assertThat(listener.hasVisibleTasksOnDefaultDisplay).isTrue()
+ assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(1)
+ }
+
+ @Test
+ fun updateVisibleFreeformTasks_addVisibleTaskNotifiesListenerForThatDisplay() {
+ val listener = TestVisibilityListener()
+ val executor = TestShellExecutor()
+ repo.addVisibleTasksListener(listener, executor)
+
+ repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true)
+ executor.flushAll()
+
+ assertThat(listener.hasVisibleTasksOnDefaultDisplay).isTrue()
+ assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(1)
+ assertThat(listener.hasVisibleTasksOnSecondaryDisplay).isFalse()
+ assertThat(listener.visibleChangesOnSecondaryDisplay).isEqualTo(0)
+
+ repo.updateVisibleFreeformTasks(displayId = 1, taskId = 2, visible = true)
+ executor.flushAll()
+
+ // Listener for secondary display is notified
+ assertThat(listener.hasVisibleTasksOnSecondaryDisplay).isTrue()
+ assertThat(listener.visibleChangesOnSecondaryDisplay).isEqualTo(1)
+ // No changes to listener for default display
+ assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(1)
+ }
+
+ @Test
+ fun updateVisibleFreeformTasks_taskOnDefaultBecomesVisibleOnSecondDisplay_listenersNotified() {
+ val listener = TestVisibilityListener()
+ val executor = TestShellExecutor()
+ repo.addVisibleTasksListener(listener, executor)
+
+ repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true)
+ executor.flushAll()
+ assertThat(listener.hasVisibleTasksOnDefaultDisplay).isTrue()
+
+ // Mark task 1 visible on secondary display
+ repo.updateVisibleFreeformTasks(displayId = 1, taskId = 1, visible = true)
+ executor.flushAll()
+
+ // Default display should have 2 calls
+ // 1 - visible task added
+ // 2 - visible task removed
+ assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(2)
+ assertThat(listener.hasVisibleTasksOnDefaultDisplay).isFalse()
+
+ // Secondary display should have 1 call for visible task added
+ assertThat(listener.visibleChangesOnSecondaryDisplay).isEqualTo(1)
+ assertThat(listener.hasVisibleTasksOnSecondaryDisplay).isTrue()
}
@Test
@@ -122,52 +208,83 @@
val listener = TestVisibilityListener()
val executor = TestShellExecutor()
repo.addVisibleTasksListener(listener, executor)
- repo.updateVisibleFreeformTasks(1, true)
- repo.updateVisibleFreeformTasks(2, true)
+ repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true)
+ repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 2, visible = true)
executor.flushAll()
- assertThat(listener.hasVisibleFreeformTasks).isTrue()
- repo.updateVisibleFreeformTasks(1, false)
+ assertThat(listener.hasVisibleTasksOnDefaultDisplay).isTrue()
+ repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = false)
executor.flushAll()
- // Equal to 2 because adding the listener notifies the current state
- assertThat(listener.visibleFreeformTaskChangedCalls).isEqualTo(2)
+ assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(1)
- repo.updateVisibleFreeformTasks(2, false)
+ repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 2, visible = false)
executor.flushAll()
- assertThat(listener.hasVisibleFreeformTasks).isFalse()
- assertThat(listener.visibleFreeformTaskChangedCalls).isEqualTo(3)
+ assertThat(listener.hasVisibleTasksOnDefaultDisplay).isFalse()
+ assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(2)
}
@Test
fun getVisibleTaskCount() {
// No tasks, count is 0
- assertThat(repo.getVisibleTaskCount()).isEqualTo(0)
+ assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(0)
// New task increments count to 1
- repo.updateVisibleFreeformTasks(taskId = 1, visible = true)
- assertThat(repo.getVisibleTaskCount()).isEqualTo(1)
+ repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true)
+ assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(1)
// Visibility update to same task does not increase count
- repo.updateVisibleFreeformTasks(taskId = 1, visible = true)
- assertThat(repo.getVisibleTaskCount()).isEqualTo(1)
+ repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true)
+ assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(1)
// Second task visible increments count
- repo.updateVisibleFreeformTasks(taskId = 2, visible = true)
- assertThat(repo.getVisibleTaskCount()).isEqualTo(2)
+ repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 2, visible = true)
+ assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(2)
// Hiding a task decrements count
- repo.updateVisibleFreeformTasks(taskId = 1, visible = false)
- assertThat(repo.getVisibleTaskCount()).isEqualTo(1)
+ repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = false)
+ assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(1)
// Hiding all tasks leaves count at 0
- repo.updateVisibleFreeformTasks(taskId = 2, visible = false)
- assertThat(repo.getVisibleTaskCount()).isEqualTo(0)
+ repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 2, visible = false)
+ assertThat(repo.getVisibleTaskCount(displayId = 9)).isEqualTo(0)
// Hiding a not existing task, count remains at 0
- repo.updateVisibleFreeformTasks(taskId = 999, visible = false)
- assertThat(repo.getVisibleTaskCount()).isEqualTo(0)
+ repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 999, visible = false)
+ assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(0)
+ }
+
+ @Test
+ fun getVisibleTaskCount_multipleDisplays() {
+ assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(0)
+ assertThat(repo.getVisibleTaskCount(SECOND_DISPLAY)).isEqualTo(0)
+
+ // New task on default display increments count for that display only
+ repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true)
+ assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(1)
+ assertThat(repo.getVisibleTaskCount(SECOND_DISPLAY)).isEqualTo(0)
+
+ // New task on secondary display, increments count for that display only
+ repo.updateVisibleFreeformTasks(SECOND_DISPLAY, taskId = 2, visible = true)
+ assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(1)
+ assertThat(repo.getVisibleTaskCount(SECOND_DISPLAY)).isEqualTo(1)
+
+ // Marking task visible on another display, updates counts for both displays
+ repo.updateVisibleFreeformTasks(SECOND_DISPLAY, taskId = 1, visible = true)
+ assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(0)
+ assertThat(repo.getVisibleTaskCount(SECOND_DISPLAY)).isEqualTo(2)
+
+ // Marking task that is on secondary display, hidden on default display, does not affect
+ // secondary display
+ repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = false)
+ assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(0)
+ assertThat(repo.getVisibleTaskCount(SECOND_DISPLAY)).isEqualTo(2)
+
+ // Hiding a task on that display, decrements count
+ repo.updateVisibleFreeformTasks(SECOND_DISPLAY, taskId = 1, visible = false)
+ assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(0)
+ assertThat(repo.getVisibleTaskCount(SECOND_DISPLAY)).isEqualTo(1)
}
@Test
@@ -197,19 +314,40 @@
}
class TestListener : DesktopModeTaskRepository.ActiveTasksListener {
- var activeTaskChangedCalls = 0
- override fun onActiveTasksChanged() {
- activeTaskChangedCalls++
+ var activeChangesOnDefaultDisplay = 0
+ var activeChangesOnSecondaryDisplay = 0
+ override fun onActiveTasksChanged(displayId: Int) {
+ when (displayId) {
+ DEFAULT_DISPLAY -> activeChangesOnDefaultDisplay++
+ SECOND_DISPLAY -> activeChangesOnSecondaryDisplay++
+ else -> fail("Active task listener received unexpected display id: $displayId")
+ }
}
}
class TestVisibilityListener : DesktopModeTaskRepository.VisibleTasksListener {
- var hasVisibleFreeformTasks = false
- var visibleFreeformTaskChangedCalls = 0
+ var hasVisibleTasksOnDefaultDisplay = false
+ var hasVisibleTasksOnSecondaryDisplay = false
- override fun onVisibilityChanged(hasVisibleTasks: Boolean) {
- hasVisibleFreeformTasks = hasVisibleTasks
- visibleFreeformTaskChangedCalls++
+ var visibleChangesOnDefaultDisplay = 0
+ var visibleChangesOnSecondaryDisplay = 0
+
+ override fun onVisibilityChanged(displayId: Int, hasVisibleFreeformTasks: Boolean) {
+ when (displayId) {
+ DEFAULT_DISPLAY -> {
+ hasVisibleTasksOnDefaultDisplay = hasVisibleFreeformTasks
+ visibleChangesOnDefaultDisplay++
+ }
+ SECOND_DISPLAY -> {
+ hasVisibleTasksOnSecondaryDisplay = hasVisibleFreeformTasks
+ visibleChangesOnSecondaryDisplay++
+ }
+ else -> fail("Visible task listener received unexpected display id: $displayId")
+ }
}
}
+
+ companion object {
+ const val SECOND_DISPLAY = 1
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index c9bd695..f506969 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -25,6 +25,7 @@
import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED
import android.os.Binder
import android.testing.AndroidTestingRunner
+import android.view.Display.DEFAULT_DISPLAY
import android.view.WindowManager
import android.view.WindowManager.TRANSIT_CHANGE
import android.view.WindowManager.TRANSIT_NONE
@@ -84,10 +85,10 @@
@Mock lateinit var exitDesktopTransitionHandler: ExitDesktopTaskTransitionHandler
@Mock lateinit var enterDesktopTransitionHandler: EnterDesktopTaskTransitionHandler
- lateinit var mockitoSession: StaticMockitoSession
- lateinit var controller: DesktopTasksController
- lateinit var shellInit: ShellInit
- lateinit var desktopModeTaskRepository: DesktopModeTaskRepository
+ private lateinit var mockitoSession: StaticMockitoSession
+ private lateinit var controller: DesktopTasksController
+ private lateinit var shellInit: ShellInit
+ private lateinit var desktopModeTaskRepository: DesktopModeTaskRepository
// Mock running tasks are registered here so we can get the list from mock shell task organizer
private val runningTasks = mutableListOf<RunningTaskInfo>()
@@ -155,7 +156,7 @@
markTaskHidden(task1)
markTaskHidden(task2)
- controller.showDesktopApps()
+ controller.showDesktopApps(DEFAULT_DISPLAY)
val wct = getLatestWct(expectTransition = TRANSIT_NONE)
assertThat(wct.hierarchyOps).hasSize(3)
@@ -173,7 +174,7 @@
markTaskVisible(task1)
markTaskVisible(task2)
- controller.showDesktopApps()
+ controller.showDesktopApps(DEFAULT_DISPLAY)
val wct = getLatestWct(expectTransition = TRANSIT_NONE)
assertThat(wct.hierarchyOps).hasSize(3)
@@ -191,7 +192,7 @@
markTaskHidden(task1)
markTaskVisible(task2)
- controller.showDesktopApps()
+ controller.showDesktopApps(DEFAULT_DISPLAY)
val wct = getLatestWct(expectTransition = TRANSIT_NONE)
assertThat(wct.hierarchyOps).hasSize(3)
@@ -205,7 +206,7 @@
fun showDesktopApps_noActiveTasks_reorderHomeToTop() {
val homeTask = setUpHomeTask()
- controller.showDesktopApps()
+ controller.showDesktopApps(DEFAULT_DISPLAY)
val wct = getLatestWct(expectTransition = TRANSIT_NONE)
assertThat(wct.hierarchyOps).hasSize(1)
@@ -213,8 +214,26 @@
}
@Test
+ fun showDesktopApps_twoDisplays_bringsToFrontOnlyOneDisplay() {
+ val homeTaskDefaultDisplay = setUpHomeTask(DEFAULT_DISPLAY)
+ val taskDefaultDisplay = setUpFreeformTask(DEFAULT_DISPLAY)
+ setUpHomeTask(SECOND_DISPLAY)
+ val taskSecondDisplay = setUpFreeformTask(SECOND_DISPLAY)
+ markTaskHidden(taskDefaultDisplay)
+ markTaskHidden(taskSecondDisplay)
+
+ controller.showDesktopApps(DEFAULT_DISPLAY)
+
+ val wct = getLatestWct(expectTransition = TRANSIT_NONE)
+ assertThat(wct.hierarchyOps).hasSize(2)
+ // Expect order to be from bottom: home, task
+ wct.assertReorderAt(index = 0, homeTaskDefaultDisplay)
+ wct.assertReorderAt(index = 1, taskDefaultDisplay)
+ }
+
+ @Test
fun getVisibleTaskCount_noTasks_returnsZero() {
- assertThat(controller.getVisibleTaskCount()).isEqualTo(0)
+ assertThat(controller.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(0)
}
@Test
@@ -222,7 +241,7 @@
setUpHomeTask()
setUpFreeformTask().also(::markTaskVisible)
setUpFreeformTask().also(::markTaskVisible)
- assertThat(controller.getVisibleTaskCount()).isEqualTo(2)
+ assertThat(controller.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(2)
}
@Test
@@ -230,7 +249,15 @@
setUpHomeTask()
setUpFreeformTask().also(::markTaskVisible)
setUpFreeformTask().also(::markTaskHidden)
- assertThat(controller.getVisibleTaskCount()).isEqualTo(1)
+ assertThat(controller.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(1)
+ }
+
+ @Test
+ fun getVisibleTaskCount_twoTasksVisibleOnDifferentDisplays_returnsOne() {
+ setUpHomeTask()
+ setUpFreeformTask(DEFAULT_DISPLAY).also(::markTaskVisible)
+ setUpFreeformTask(SECOND_DISPLAY).also(::markTaskVisible)
+ assertThat(controller.getVisibleTaskCount(SECOND_DISPLAY)).isEqualTo(1)
}
@Test
@@ -258,6 +285,7 @@
controller.moveToDesktop(fullscreenTask)
with(getLatestWct(expectTransition = TRANSIT_CHANGE)) {
+ // Operations should include home task, freeform task
assertThat(hierarchyOps).hasSize(3)
assertReorderSequence(homeTask, freeformTask, fullscreenTask)
assertThat(changes[fullscreenTask.token.asBinder()]?.windowingMode)
@@ -266,6 +294,28 @@
}
@Test
+ fun moveToDesktop_onlyFreeformTasksFromCurrentDisplayBroughtToFront() {
+ setUpHomeTask(displayId = DEFAULT_DISPLAY)
+ val freeformTaskDefault = setUpFreeformTask(displayId = DEFAULT_DISPLAY)
+ val fullscreenTaskDefault = setUpFullscreenTask(displayId = DEFAULT_DISPLAY)
+ markTaskHidden(freeformTaskDefault)
+
+ val homeTaskSecond = setUpHomeTask(displayId = SECOND_DISPLAY)
+ val freeformTaskSecond = setUpFreeformTask(displayId = SECOND_DISPLAY)
+ markTaskHidden(freeformTaskSecond)
+
+ controller.moveToDesktop(fullscreenTaskDefault)
+
+ with(getLatestWct(expectTransition = TRANSIT_CHANGE)) {
+ // Check that hierarchy operations do not include tasks from second display
+ assertThat(hierarchyOps.map { it.container })
+ .doesNotContain(homeTaskSecond.token.asBinder())
+ assertThat(hierarchyOps.map { it.container })
+ .doesNotContain(freeformTaskSecond.token.asBinder())
+ }
+ }
+
+ @Test
fun moveToFullscreen() {
val task = setUpFreeformTask()
controller.moveToFullscreen(task)
@@ -281,6 +331,19 @@
}
@Test
+ fun moveToFullscreen_secondDisplayTaskHasFreeform_secondDisplayNotAffected() {
+ val taskDefaultDisplay = setUpFreeformTask(displayId = DEFAULT_DISPLAY)
+ val taskSecondDisplay = setUpFreeformTask(displayId = SECOND_DISPLAY)
+
+ controller.moveToFullscreen(taskDefaultDisplay)
+
+ with(getLatestWct(expectTransition = TRANSIT_CHANGE)) {
+ assertThat(changes.keys).contains(taskDefaultDisplay.token.asBinder())
+ assertThat(changes.keys).doesNotContain(taskSecondDisplay.token.asBinder())
+ }
+ }
+
+ @Test
fun getTaskWindowingMode() {
val fullscreenTask = setUpFullscreenTask()
val freeformTask = setUpFreeformTask()
@@ -324,6 +387,18 @@
}
@Test
+ fun handleRequest_fullscreenTask_freeformTaskOnOtherDisplay_returnNull() {
+ assumeTrue(ENABLE_SHELL_TRANSITIONS)
+
+ val fullscreenTaskDefaultDisplay = createFullscreenTask(displayId = DEFAULT_DISPLAY)
+ createFreeformTask(displayId = SECOND_DISPLAY)
+
+ val result =
+ controller.handleRequest(Binder(), createTransition(fullscreenTaskDefaultDisplay))
+ assertThat(result).isNull()
+ }
+
+ @Test
fun handleRequest_freeformTask_freeformVisible_returnNull() {
assumeTrue(ENABLE_SHELL_TRANSITIONS)
@@ -362,6 +437,18 @@
}
@Test
+ fun handleRequest_freeformTask_freeformOnOtherDisplayOnly_returnSwitchToFullscreenWCT() {
+ assumeTrue(ENABLE_SHELL_TRANSITIONS)
+
+ val taskDefaultDisplay = createFreeformTask(displayId = DEFAULT_DISPLAY)
+ createFreeformTask(displayId = SECOND_DISPLAY)
+
+ val result = controller.handleRequest(Binder(), createTransition(taskDefaultDisplay))
+ assertThat(result?.changes?.get(taskDefaultDisplay.token.asBinder())?.windowingMode)
+ .isEqualTo(WINDOWING_MODE_FULLSCREEN)
+ }
+
+ @Test
fun handleRequest_notOpenOrToFrontTransition_returnNull() {
assumeTrue(ENABLE_SHELL_TRANSITIONS)
@@ -400,35 +487,43 @@
assertThat(controller.handleRequest(Binder(), createTransition(task))).isNull()
}
- private fun setUpFreeformTask(): RunningTaskInfo {
- val task = createFreeformTask()
+ private fun setUpFreeformTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo {
+ val task = createFreeformTask(displayId)
whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
- desktopModeTaskRepository.addActiveTask(task.taskId)
+ desktopModeTaskRepository.addActiveTask(displayId, task.taskId)
desktopModeTaskRepository.addOrMoveFreeformTaskToTop(task.taskId)
runningTasks.add(task)
return task
}
- private fun setUpHomeTask(): RunningTaskInfo {
- val task = createHomeTask()
+ private fun setUpHomeTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo {
+ val task = createHomeTask(displayId)
whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
runningTasks.add(task)
return task
}
- private fun setUpFullscreenTask(): RunningTaskInfo {
- val task = createFullscreenTask()
+ private fun setUpFullscreenTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo {
+ val task = createFullscreenTask(displayId)
whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
runningTasks.add(task)
return task
}
private fun markTaskVisible(task: RunningTaskInfo) {
- desktopModeTaskRepository.updateVisibleFreeformTasks(task.taskId, visible = true)
+ desktopModeTaskRepository.updateVisibleFreeformTasks(
+ task.displayId,
+ task.taskId,
+ visible = true
+ )
}
private fun markTaskHidden(task: RunningTaskInfo) {
- desktopModeTaskRepository.updateVisibleFreeformTasks(task.taskId, visible = false)
+ desktopModeTaskRepository.updateVisibleFreeformTasks(
+ task.displayId,
+ task.taskId,
+ visible = false
+ )
}
private fun getLatestWct(
@@ -457,6 +552,10 @@
): TransitionRequestInfo {
return TransitionRequestInfo(type, task, null /* remoteTransition */)
}
+
+ companion object {
+ const val SECOND_DISPLAY = 2
+ }
}
private fun WindowContainerTransaction.assertReorderAt(index: Int, task: RunningTaskInfo) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt
index dc91d75..cf1ff32 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt
@@ -21,14 +21,17 @@
import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
+import android.view.Display.DEFAULT_DISPLAY
import com.android.wm.shell.TestRunningTaskInfoBuilder
class DesktopTestHelpers {
companion object {
/** Create a task that has windowing mode set to [WINDOWING_MODE_FREEFORM] */
@JvmStatic
- fun createFreeformTask(): RunningTaskInfo {
+ @JvmOverloads
+ fun createFreeformTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo {
return TestRunningTaskInfoBuilder()
+ .setDisplayId(displayId)
.setToken(MockToken().token())
.setActivityType(ACTIVITY_TYPE_STANDARD)
.setWindowingMode(WINDOWING_MODE_FREEFORM)
@@ -38,8 +41,10 @@
/** Create a task that has windowing mode set to [WINDOWING_MODE_FULLSCREEN] */
@JvmStatic
- fun createFullscreenTask(): RunningTaskInfo {
+ @JvmOverloads
+ fun createFullscreenTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo {
return TestRunningTaskInfoBuilder()
+ .setDisplayId(displayId)
.setToken(MockToken().token())
.setActivityType(ACTIVITY_TYPE_STANDARD)
.setWindowingMode(WINDOWING_MODE_FULLSCREEN)
@@ -49,8 +54,10 @@
/** Create a new home task */
@JvmStatic
- fun createHomeTask(): RunningTaskInfo {
+ @JvmOverloads
+ fun createHomeTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo {
return TestRunningTaskInfoBuilder()
+ .setDisplayId(displayId)
.setToken(MockToken().token())
.setActivityType(ACTIVITY_TYPE_HOME)
.setWindowingMode(WINDOWING_MODE_FULLSCREEN)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 6995d10..04f2c99 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -268,7 +268,7 @@
}
@Test
- public void saveReentryState_userHasResized_savesSize() {
+ public void saveReentryState_nonEmptyUserResizeBounds_savesSize() {
final Rect bounds = new Rect(0, 0, 10, 10);
final Rect resizedBounds = new Rect(0, 0, 30, 30);
when(mMockPipBoundsAlgorithm.getSnapFraction(bounds)).thenReturn(1.0f);
@@ -281,6 +281,19 @@
}
@Test
+ public void saveReentryState_emptyUserResizeBounds_savesSize() {
+ final Rect bounds = new Rect(0, 0, 10, 10);
+ final Rect resizedBounds = new Rect(0, 0, 0, 0);
+ when(mMockPipBoundsAlgorithm.getSnapFraction(bounds)).thenReturn(1.0f);
+ when(mMockPipTouchHandler.getUserResizeBounds()).thenReturn(resizedBounds);
+ when(mMockPipBoundsState.hasUserResizedPip()).thenReturn(true);
+
+ mPipController.saveReentryState(bounds);
+
+ verify(mMockPipBoundsState).saveReentryState(new Size(10, 10), 1.0f);
+ }
+
+ @Test
public void onDisplayConfigurationChanged_inPip_movePip() {
final int displayId = 1;
final Rect bounds = new Rect(0, 0, 10, 10);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index a9f311f..92cbf7f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -180,8 +180,9 @@
TestRemoteTransition testRemote = new TestRemoteTransition();
IBinder transition = mSplitScreenTransitions.startEnterTransition(
- TRANSIT_SPLIT_SCREEN_PAIR_OPEN, new WindowContainerTransaction(),
- new RemoteTransition(testRemote, "Test"), mStageCoordinator, null, null);
+ TRANSIT_OPEN, new WindowContainerTransaction(),
+ new RemoteTransition(testRemote, "Test"), mStageCoordinator, null, null,
+ TRANSIT_SPLIT_SCREEN_PAIR_OPEN);
mMainStage.onTaskAppeared(mMainChild, createMockSurface());
mSideStage.onTaskAppeared(mSideChild, createMockSurface());
boolean accepted = mStageCoordinator.startAnimation(transition, info,
@@ -397,7 +398,7 @@
}
private TransitionInfo createEnterPairInfo() {
- return new TransitionInfoBuilder(TRANSIT_SPLIT_SCREEN_PAIR_OPEN, 0)
+ return new TransitionInfoBuilder(TRANSIT_OPEN, 0)
.addChange(TRANSIT_OPEN, mMainChild)
.addChange(TRANSIT_OPEN, mSideChild)
.build();
@@ -406,9 +407,9 @@
private void enterSplit() {
TransitionInfo enterInfo = createEnterPairInfo();
IBinder enterTransit = mSplitScreenTransitions.startEnterTransition(
- TRANSIT_SPLIT_SCREEN_PAIR_OPEN, new WindowContainerTransaction(),
+ TRANSIT_OPEN, new WindowContainerTransaction(),
new RemoteTransition(new TestRemoteTransition(), "Test"),
- mStageCoordinator, null, null);
+ mStageCoordinator, null, null, TRANSIT_SPLIT_SCREEN_PAIR_OPEN);
mMainStage.onTaskAppeared(mMainChild, createMockSurface());
mSideStage.onTaskAppeared(mSideChild, createMockSurface());
mStageCoordinator.startAnimation(enterTransit, enterInfo,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
index 784ad9b..1a1bebd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
@@ -126,6 +126,12 @@
verify(mCallbacks).onStatusChanged(eq(mRootTask.isVisible), eq(true));
}
+ @Test(expected = IllegalArgumentException.class)
+ public void testUnknownTaskVanished() {
+ final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build();
+ mStageTaskListener.onTaskVanished(task);
+ }
+
@Test
public void testTaskVanished() {
// With shell transitions, the transition manages status changes, so skip this test.
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
new file mode 100644
index 0000000..348b365
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2023 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.windowdecor
+
+import android.app.ActivityManager
+import android.graphics.PointF
+import android.graphics.Rect
+import android.os.IBinder
+import android.testing.AndroidTestingRunner
+import android.view.Display
+import android.window.WindowContainerToken
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.DisplayLayout
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_BOTTOM
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP
+import com.google.common.truth.Truth.assertThat
+import junit.framework.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.Mockito.any
+import org.mockito.MockitoAnnotations
+
+/**
+ * Tests for [DragPositioningCallbackUtility].
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:DragPositioningCallbackUtilityTest
+ */
+@RunWith(AndroidTestingRunner::class)
+class DragPositioningCallbackUtilityTest {
+ @Mock
+ private lateinit var mockWindowDecoration: WindowDecoration<*>
+ @Mock
+ private lateinit var taskToken: WindowContainerToken
+ @Mock
+ private lateinit var taskBinder: IBinder
+ @Mock
+ private lateinit var mockDisplayController: DisplayController
+ @Mock
+ private lateinit var mockDisplayLayout: DisplayLayout
+ @Mock
+ private lateinit var mockDisplay: Display
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+
+ whenever(taskToken.asBinder()).thenReturn(taskBinder)
+ whenever(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
+ whenever(mockDisplayLayout.densityDpi()).thenReturn(DENSITY_DPI)
+ whenever(mockDisplayLayout.getStableBounds(any())).thenAnswer { i ->
+ (i.arguments.first() as Rect).set(STABLE_BOUNDS)
+ }
+
+ mockWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply {
+ taskId = TASK_ID
+ token = taskToken
+ minWidth = MIN_WIDTH
+ minHeight = MIN_HEIGHT
+ defaultMinSize = DEFAULT_MIN
+ displayId = DISPLAY_ID
+ configuration.windowConfiguration.bounds = STARTING_BOUNDS
+ }
+ mockWindowDecoration.mDisplay = mockDisplay
+ whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
+ }
+
+ @Test
+ fun testChangeBoundsDoesNotChangeHeightWhenLessThanMin() {
+ val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
+ val repositionTaskBounds = Rect()
+
+ // Resize to width of 95px and height of 5px with min width of 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 5
+ val newY = STARTING_BOUNDS.top.toFloat() + 95
+ val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
+
+ DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
+ false /* hasMoved */, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ mockDisplayController, mockWindowDecoration)
+
+ assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
+ assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top)
+ assertThat(repositionTaskBounds.right).isEqualTo(STARTING_BOUNDS.right - 5)
+ assertThat(repositionTaskBounds.bottom).isEqualTo(STARTING_BOUNDS.bottom)
+ }
+
+ @Test
+ fun testChangeBoundsDoesNotChangeWidthWhenLessThanMin() {
+ val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
+ val repositionTaskBounds = Rect()
+
+ // Resize to height of 95px and width of 5px with min width of 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 95
+ val newY = STARTING_BOUNDS.top.toFloat() + 5
+ val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
+
+ DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
+ false /* hasMoved */, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ mockDisplayController, mockWindowDecoration)
+
+ assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
+ assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top + 5)
+ assertThat(repositionTaskBounds.right).isEqualTo(STARTING_BOUNDS.right)
+ assertThat(repositionTaskBounds.bottom).isEqualTo(STARTING_BOUNDS.bottom)
+ }
+
+ @Test
+ fun testChangeBoundsDoesNotChangeHeightWhenNegative() {
+ val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
+ val repositionTaskBounds = Rect()
+
+ // Resize to width of 95px and width of -5px with minimum of 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 5
+ val newY = STARTING_BOUNDS.top.toFloat() + 105
+ val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
+
+ DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
+ false /* hasMoved */, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ mockDisplayController, mockWindowDecoration)
+
+ assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
+ assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top)
+ assertThat(repositionTaskBounds.right).isEqualTo(STARTING_BOUNDS.right - 5)
+ assertThat(repositionTaskBounds.bottom).isEqualTo(STARTING_BOUNDS.bottom)
+ }
+
+ @Test
+ fun testChangeBoundsRunsWhenResizeBoundsValid() {
+ val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
+ val repositionTaskBounds = Rect()
+
+ // Shrink to height 20px and width 20px with both min height/width equal to 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 80
+ val newY = STARTING_BOUNDS.top.toFloat() + 80
+ val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
+
+ DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
+ false /* hasMoved */, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ mockDisplayController, mockWindowDecoration)
+ assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
+ assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top + 80)
+ assertThat(repositionTaskBounds.right).isEqualTo(STARTING_BOUNDS.right - 80)
+ assertThat(repositionTaskBounds.bottom).isEqualTo(STARTING_BOUNDS.bottom)
+ }
+
+ @Test
+ fun testChangeBoundsDoesNotRunWithNegativeHeightAndWidth() {
+ val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
+ val repositionTaskBounds = Rect()
+ // Shrink to height -5px and width -5px with both min height/width equal to 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 105
+ val newY = STARTING_BOUNDS.top.toFloat() + 105
+
+ val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
+
+ DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
+ false /* hasMoved */, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ mockDisplayController, mockWindowDecoration)
+ assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
+ assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top)
+ assertThat(repositionTaskBounds.right).isEqualTo(STARTING_BOUNDS.right)
+ assertThat(repositionTaskBounds.bottom).isEqualTo(STARTING_BOUNDS.bottom)
+ }
+
+ @Test
+ fun testChangeBounds_toDisallowedBounds_freezesAtLimit() {
+ var hasMoved = false
+ val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.bottom.toFloat())
+ val repositionTaskBounds = Rect()
+ // Initial resize to width and height 110px.
+ var newX = STARTING_BOUNDS.right.toFloat() + 10
+ var newY = STARTING_BOUNDS.bottom.toFloat() + 10
+ var delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
+ assertTrue(DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM,
+ hasMoved, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ mockDisplayController, mockWindowDecoration))
+ hasMoved = true
+ // Resize width to 120px, height to disallowed area which should not result in a change.
+ newX += 10
+ newY = DISALLOWED_RESIZE_AREA.top.toFloat()
+ delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
+ assertTrue(DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM,
+ hasMoved, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ mockDisplayController, mockWindowDecoration))
+ assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
+ assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top)
+ assertThat(repositionTaskBounds.right).isEqualTo(STARTING_BOUNDS.right + 20)
+ assertThat(repositionTaskBounds.bottom).isEqualTo(STARTING_BOUNDS.bottom + 10)
+ }
+
+ companion object {
+ private const val TASK_ID = 5
+ private const val MIN_WIDTH = 10
+ private const val MIN_HEIGHT = 10
+ private const val DENSITY_DPI = 20
+ private const val DEFAULT_MIN = 40
+ private const val DISPLAY_ID = 1
+ private const val NAVBAR_HEIGHT = 50
+ private val DISPLAY_BOUNDS = Rect(0, 0, 2400, 1600)
+ private val STARTING_BOUNDS = Rect(0, 0, 100, 100)
+ private val DISALLOWED_RESIZE_AREA = Rect(
+ DISPLAY_BOUNDS.left,
+ DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT,
+ DISPLAY_BOUNDS.right,
+ DISPLAY_BOUNDS.bottom)
+ private val STABLE_BOUNDS = Rect(
+ DISPLAY_BOUNDS.left,
+ DISPLAY_BOUNDS.top,
+ DISPLAY_BOUNDS.right,
+ DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT
+ )
+ }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
index 84ccdde..5bea8f2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
@@ -14,7 +14,6 @@
import com.android.wm.shell.common.DisplayLayout
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.ShellTestCase
-import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_BOTTOM
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_UNDEFINED
@@ -22,7 +21,7 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.`when`
+import org.mockito.Mockito.`when` as whenever
import org.mockito.Mockito.any
import org.mockito.Mockito.argThat
import org.mockito.Mockito.never
@@ -72,10 +71,10 @@
mockDragStartListener
)
- `when`(taskToken.asBinder()).thenReturn(taskBinder)
- `when`(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
- `when`(mockDisplayLayout.densityDpi()).thenReturn(DENSITY_DPI)
- `when`(mockDisplayLayout.getStableBounds(any())).thenAnswer { i ->
+ whenever(taskToken.asBinder()).thenReturn(taskBinder)
+ whenever(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
+ whenever(mockDisplayLayout.densityDpi()).thenReturn(DENSITY_DPI)
+ whenever(mockDisplayLayout.getStableBounds(any())).thenAnswer { i ->
(i.arguments.first() as Rect).set(STABLE_BOUNDS)
}
@@ -89,7 +88,7 @@
configuration.windowConfiguration.bounds = STARTING_BOUNDS
}
mockWindowDecoration.mDisplay = mockDisplay
- `when`(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
+ whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
}
@Test
@@ -237,293 +236,6 @@
})
}
- @Test
- fun testDragResize_resize_setBoundsDoesNotChangeHeightWhenLessThanMin() {
- taskPositioner.onDragPositioningStart(
- CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
- STARTING_BOUNDS.right.toFloat(),
- STARTING_BOUNDS.top.toFloat()
- )
-
- // Resize to width of 95px and height of 5px with min width of 10px
- val newX = STARTING_BOUNDS.right.toFloat() - 5
- val newY = STARTING_BOUNDS.top.toFloat() + 95
- taskPositioner.onDragPositioningMove(
- newX,
- newY
- )
-
- taskPositioner.onDragPositioningEnd(newX, newY)
-
- verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
- return@argThat wct.changes.any { (token, change) ->
- token == taskBinder &&
- ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS)
- != 0) && change.configuration.windowConfiguration.bounds.top ==
- STARTING_BOUNDS.top &&
- change.configuration.windowConfiguration.bounds.bottom ==
- STARTING_BOUNDS.bottom
- }
- })
- }
-
- @Test
- fun testDragResize_resize_setBoundsDoesNotChangeWidthWhenLessThanMin() {
- taskPositioner.onDragPositioningStart(
- CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
- STARTING_BOUNDS.right.toFloat(),
- STARTING_BOUNDS.top.toFloat()
- )
-
- // Resize to height of 95px and width of 5px with min width of 10px
- val newX = STARTING_BOUNDS.right.toFloat() - 95
- val newY = STARTING_BOUNDS.top.toFloat() + 5
- taskPositioner.onDragPositioningMove(
- newX,
- newY
- )
-
- taskPositioner.onDragPositioningEnd(newX, newY)
-
- verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
- return@argThat wct.changes.any { (token, change) ->
- token == taskBinder &&
- ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS)
- != 0) && change.configuration.windowConfiguration.bounds.right ==
- STARTING_BOUNDS.right &&
- change.configuration.windowConfiguration.bounds.left ==
- STARTING_BOUNDS.left
- }
- })
- }
-
- @Test
- fun testDragResize_resize_setBoundsDoesNotChangeHeightWhenNegative() {
- taskPositioner.onDragPositioningStart(
- CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
- STARTING_BOUNDS.right.toFloat(),
- STARTING_BOUNDS.top.toFloat()
- )
-
- // Resize to height of -5px and width of 95px
- val newX = STARTING_BOUNDS.right.toFloat() - 5
- val newY = STARTING_BOUNDS.top.toFloat() + 105
- taskPositioner.onDragPositioningMove(
- newX,
- newY
- )
-
- taskPositioner.onDragPositioningEnd(newX, newY)
-
- verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
- return@argThat wct.changes.any { (token, change) ->
- token == taskBinder &&
- ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS)
- != 0) && change.configuration.windowConfiguration.bounds.top ==
- STARTING_BOUNDS.top &&
- change.configuration.windowConfiguration.bounds.bottom ==
- STARTING_BOUNDS.bottom
- }
- })
- }
-
- @Test
- fun testDragResize_resize_setBoundsDoesNotChangeWidthWhenNegative() {
- taskPositioner.onDragPositioningStart(
- CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
- STARTING_BOUNDS.right.toFloat(),
- STARTING_BOUNDS.top.toFloat()
- )
-
- // Resize to width of -5px and height of 95px
- val newX = STARTING_BOUNDS.right.toFloat() - 105
- val newY = STARTING_BOUNDS.top.toFloat() + 5
- taskPositioner.onDragPositioningMove(
- newX,
- newY
- )
-
- taskPositioner.onDragPositioningEnd(newX, newY)
-
- verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
- return@argThat wct.changes.any { (token, change) ->
- token == taskBinder &&
- ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS)
- != 0) && change.configuration.windowConfiguration.bounds.right ==
- STARTING_BOUNDS.right &&
- change.configuration.windowConfiguration.bounds.left ==
- STARTING_BOUNDS.left
- }
- })
- }
-
- @Test
- fun testDragResize_resize_setBoundsRunsWhenResizeBoundsValid() {
- taskPositioner.onDragPositioningStart(
- CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
- STARTING_BOUNDS.right.toFloat(),
- STARTING_BOUNDS.top.toFloat()
- )
-
- // Shrink to height 20px and width 20px with both min height/width equal to 10px
- val newX = STARTING_BOUNDS.right.toFloat() - 80
- val newY = STARTING_BOUNDS.top.toFloat() + 80
- taskPositioner.onDragPositioningMove(
- newX,
- newY
- )
-
- taskPositioner.onDragPositioningEnd(newX, newY)
-
- verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
- return@argThat wct.changes.any { (token, change) ->
- token == taskBinder &&
- ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
- }
- })
- }
-
- @Test
- fun testDragResize_resize_setBoundsDoesNotRunWithNegativeHeightAndWidth() {
- taskPositioner.onDragPositioningStart(
- CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
- STARTING_BOUNDS.right.toFloat(),
- STARTING_BOUNDS.top.toFloat()
- )
-
- // Shrink to height 5px and width 5px with both min height/width equal to 10px
- val newX = STARTING_BOUNDS.right.toFloat() - 95
- val newY = STARTING_BOUNDS.top.toFloat() + 95
- taskPositioner.onDragPositioningMove(
- newX,
- newY
- )
-
- taskPositioner.onDragPositioningEnd(newX, newY)
-
- verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
- return@argThat wct.changes.any { (token, change) ->
- token == taskBinder &&
- ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
- }
- })
- }
-
- @Test
- fun testDragResize_resize_useDefaultMinWhenMinWidthInvalid() {
- mockWindowDecoration.mTaskInfo.minWidth = -1
-
- taskPositioner.onDragPositioningStart(
- CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
- STARTING_BOUNDS.right.toFloat(),
- STARTING_BOUNDS.top.toFloat()
- )
-
- // Shrink to width and height of 3px with invalid minWidth = -1 and defaultMinSize = 5px
- val newX = STARTING_BOUNDS.right.toFloat() - 97
- val newY = STARTING_BOUNDS.top.toFloat() + 97
- taskPositioner.onDragPositioningMove(
- newX,
- newY
- )
-
- taskPositioner.onDragPositioningEnd(newX, newY)
-
- verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
- return@argThat wct.changes.any { (token, change) ->
- token == taskBinder &&
- ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
- }
- })
- }
-
- @Test
- fun testDragResize_resize_useMinWidthWhenValid() {
- taskPositioner.onDragPositioningStart(
- CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
- STARTING_BOUNDS.right.toFloat(),
- STARTING_BOUNDS.top.toFloat()
- )
-
- // Shrink to width and height of 7px with valid minWidth = 10px and defaultMinSize = 5px
- val newX = STARTING_BOUNDS.right.toFloat() - 93
- val newY = STARTING_BOUNDS.top.toFloat() + 93
- taskPositioner.onDragPositioningMove(
- newX,
- newY
- )
-
- taskPositioner.onDragPositioningEnd(newX, newY)
-
- verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
- return@argThat wct.changes.any { (token, change) ->
- token == taskBinder &&
- ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
- }
- })
- }
-
- fun testDragResize_toDisallowedBounds_freezesAtLimit() {
- taskPositioner.onDragPositioningStart(
- CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM, // Resize right-bottom corner
- STARTING_BOUNDS.right.toFloat(),
- STARTING_BOUNDS.bottom.toFloat()
- )
-
- // Resize the task by 10px to the right and bottom, a valid destination
- val newBounds = Rect(
- STARTING_BOUNDS.left,
- STARTING_BOUNDS.top,
- STARTING_BOUNDS.right + 10,
- STARTING_BOUNDS.bottom + 10)
- taskPositioner.onDragPositioningMove(
- newBounds.right.toFloat(),
- newBounds.bottom.toFloat()
- )
-
- // Resize the task by another 10px to the right (allowed) and to just in the disallowed
- // area of the Y coordinate.
- val newBounds2 = Rect(
- newBounds.left,
- newBounds.top,
- newBounds.right + 10,
- DISALLOWED_RESIZE_AREA.top
- )
- taskPositioner.onDragPositioningMove(
- newBounds2.right.toFloat(),
- newBounds2.bottom.toFloat()
- )
-
- taskPositioner.onDragPositioningEnd(newBounds2.right.toFloat(), newBounds2.bottom.toFloat())
-
- // The first resize falls in the allowed area, verify there's a change for it.
- verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
- return@argThat wct.changes.any { (token, change) ->
- token == taskBinder && change.ofBounds(newBounds)
- }
- })
- // The second resize falls in the disallowed area, verify there's no change for it.
- verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
- return@argThat wct.changes.any { (token, change) ->
- token == taskBinder && change.ofBounds(newBounds2)
- }
- })
- // Instead, there should be a change for its allowed portion (the X movement) with the Y
- // staying frozen in the last valid resize position.
- verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
- return@argThat wct.changes.any { (token, change) ->
- token == taskBinder && change.ofBounds(
- Rect(
- newBounds2.left,
- newBounds2.top,
- newBounds2.right,
- newBounds.bottom // Stayed at the first resize destination.
- )
- )
- }
- })
- }
-
private fun WindowContainerTransaction.Change.ofBounds(bounds: Rect): Boolean {
return ((windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0) &&
bounds == configuration.windowConfiguration.bounds
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
index bf365ca..498082b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
@@ -34,7 +34,7 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.`when`
+import org.mockito.Mockito.`when` as whenever
import org.mockito.Mockito.any
import org.mockito.Mockito.argThat
import org.mockito.Mockito.never
@@ -85,10 +85,10 @@
mockDragStartListener
)
- `when`(taskToken.asBinder()).thenReturn(taskBinder)
- `when`(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
- `when`(mockDisplayLayout.densityDpi()).thenReturn(DENSITY_DPI)
- `when`(mockDisplayLayout.getStableBounds(any())).thenAnswer { i ->
+ whenever(taskToken.asBinder()).thenReturn(taskBinder)
+ whenever(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
+ whenever(mockDisplayLayout.densityDpi()).thenReturn(DENSITY_DPI)
+ whenever(mockDisplayLayout.getStableBounds(any())).thenAnswer { i ->
(i.arguments.first() as Rect).set(STABLE_BOUNDS)
}
@@ -102,7 +102,7 @@
configuration.windowConfiguration.bounds = STARTING_BOUNDS
}
mockDesktopWindowDecoration.mDisplay = mockDisplay
- `when`(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
+ whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
}
@Test
diff --git a/libs/hwui/effects/GainmapRenderer.cpp b/libs/hwui/effects/GainmapRenderer.cpp
index bfe4eaf..613f52b 100644
--- a/libs/hwui/effects/GainmapRenderer.cpp
+++ b/libs/hwui/effects/GainmapRenderer.cpp
@@ -38,7 +38,7 @@
using namespace renderthread;
-static float getTargetHdrSdrRatio(const SkColorSpace* destColorspace) {
+float getTargetHdrSdrRatio(const SkColorSpace* destColorspace) {
// We should always have a known destination colorspace. If we don't we must be in some
// legacy mode where we're lost and also definitely not going to HDR
if (destColorspace == nullptr) {
diff --git a/libs/hwui/effects/GainmapRenderer.h b/libs/hwui/effects/GainmapRenderer.h
index 4ed2445..0ab03f0 100644
--- a/libs/hwui/effects/GainmapRenderer.h
+++ b/libs/hwui/effects/GainmapRenderer.h
@@ -25,6 +25,8 @@
namespace android::uirenderer {
+float getTargetHdrSdrRatio(const SkColorSpace* destColorspace);
+
void DrawGainmapBitmap(SkCanvas* c, const sk_sp<const SkImage>& image, const SkRect& src,
const SkRect& dst, const SkSamplingOptions& sampling, const SkPaint* paint,
SkCanvas::SrcRectConstraint constraint,
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index a4960ea..c58ba68 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -26,6 +26,7 @@
#include "SkM44.h"
#include "include/gpu/GpuTypes.h" // from Skia
#include "utils/GLUtils.h"
+#include <effects/GainmapRenderer.h>
namespace android {
namespace uirenderer {
@@ -129,6 +130,7 @@
info.height = fboSize.height();
mat4.getColMajor(&info.transform[0]);
info.color_space_ptr = canvas->imageInfo().colorSpace();
+ info.currentHdrSdrRatio = getTargetHdrSdrRatio(info.color_space_ptr);
// ensure that the framebuffer that the webview will render into is bound before we clear
// the stencil and/or draw the functor.
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
index e6ef95b..e299d12 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
@@ -30,6 +30,7 @@
#include "renderthread/VulkanManager.h"
#include "thread/ThreadBase.h"
#include "utils/TimeUtils.h"
+#include "effects/GainmapRenderer.h"
namespace android {
namespace uirenderer {
@@ -73,6 +74,7 @@
.clip_right = mClip.fRight,
.clip_bottom = mClip.fBottom,
.is_layer = !vulkan_info.fFromSwapchainOrAndroidWindow,
+ .currentHdrSdrRatio = getTargetHdrSdrRatio(mImageInfo.colorSpace()),
};
mat4.getColMajor(¶ms.transform[0]);
params.secondary_command_buffer = vulkan_info.fSecondaryCommandBuffer;
diff --git a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
index e168a7b..adf3c06 100644
--- a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
@@ -32,6 +32,7 @@
#include "renderthread/EglManager.h"
#include "thread/ThreadBase.h"
#include "utils/TimeUtils.h"
+#include "effects/GainmapRenderer.h"
#include <SkBlendMode.h>
@@ -139,6 +140,7 @@
info.height = mFBInfo.height();
mat4.getColMajor(&info.transform[0]);
info.color_space_ptr = canvas->imageInfo().colorSpace();
+ info.currentHdrSdrRatio = getTargetHdrSdrRatio(info.color_space_ptr);
glViewport(0, 0, info.width, info.height);
diff --git a/libs/hwui/private/hwui/DrawGlInfo.h b/libs/hwui/private/hwui/DrawGlInfo.h
index 501b8df..7888c87 100644
--- a/libs/hwui/private/hwui/DrawGlInfo.h
+++ b/libs/hwui/private/hwui/DrawGlInfo.h
@@ -86,6 +86,11 @@
// commands are issued.
kStatusDrew = 0x4
};
+
+ // The current HDR/SDR ratio that we are rendering to. The transform to SDR will already
+ // be baked into the color_space_ptr, so this is just to indicate the amount of extended
+ // range is available if desired
+ float currentHdrSdrRatio;
}; // struct DrawGlInfo
} // namespace uirenderer
diff --git a/libs/hwui/private/hwui/DrawVkInfo.h b/libs/hwui/private/hwui/DrawVkInfo.h
index 5c59657..8f7063d 100644
--- a/libs/hwui/private/hwui/DrawVkInfo.h
+++ b/libs/hwui/private/hwui/DrawVkInfo.h
@@ -71,6 +71,11 @@
// Input: Whether destination surface is offscreen surface.
bool is_layer;
+
+ // The current HDR/SDR ratio that we are rendering to. The transform to SDR will already
+ // be baked into the color_space_ptr, so this is just to indicate the amount of extended
+ // range is available if desired
+ float currentHdrSdrRatio;
};
} // namespace uirenderer
diff --git a/packages/CompanionDeviceManager/res/layout/list_item_permission.xml b/packages/CompanionDeviceManager/res/layout/list_item_permission.xml
index 6bfcd82..8c35da1 100644
--- a/packages/CompanionDeviceManager/res/layout/list_item_permission.xml
+++ b/packages/CompanionDeviceManager/res/layout/list_item_permission.xml
@@ -58,6 +58,7 @@
android:textSize="14sp"
android:layout_marginTop="2dp"
style="@style/TextAppearance"
+ android:focusable="true"
android:textColor="?android:attr/textColorSecondary"/>
</LinearLayout>
diff --git a/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml
index 74072e9..2502bbf 100644
--- a/packages/CompanionDeviceManager/res/values/strings.xml
+++ b/packages/CompanionDeviceManager/res/values/strings.xml
@@ -113,17 +113,11 @@
<!-- Back button for the helper consent dialog [CHAR LIMIT=30] -->
<string name="consent_back">Back</string>
- <!-- Action when permission list view is expanded CHAR LIMIT=30] -->
- <string name="permission_expanded">Expanded</string>
+ <!-- Expand permission in the list CHAR LIMIT=30] -->
+ <string name="permission_expand">Expand <xliff:g id="permission_type" example="Notification">%1$s</xliff:g></string>
- <!-- Expand action permission list CHAR LIMIT=30] -->
- <string name="permission_expand">Expand</string>
-
- <!-- Action when permission list view is collapsed CHAR LIMIT=30] -->
- <string name="permission_collapsed">Collapsed</string>
-
- <!-- Collapse action permission list CHAR LIMIT=30] -->
- <string name="permission_collapse">Collapse</string>
+ <!-- Collapse permission int the list CHAR LIMIT=30] -->
+ <string name="permission_collapse">Collapse <xliff:g id="permission_type" example="Notification">%1$s</xliff:g></string>
<!-- ================== System data transfer ==================== -->
<!-- Title of the permission sync confirmation dialog. [CHAR LIMIT=NONE] -->
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
index b86ef64..f594bf2 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
@@ -124,7 +124,7 @@
}
setAccessibility(view, viewType,
- AccessibilityNodeInfo.ACTION_CLICK, R.string.permission_expand);
+ AccessibilityNodeInfo.ACTION_CLICK, R.string.permission_expand, 0);
// Add expand buttons if the permissions are more than PERMISSION_SIZE in this list also
// make the summary invisible by default.
@@ -137,18 +137,16 @@
viewHolder.mExpandButton.setImageResource(R.drawable.btn_expand_less);
viewHolder.mPermissionSummary.setVisibility(View.VISIBLE);
viewHolder.mExpandButton.setTag(R.drawable.btn_expand_less);
- view.setContentDescription(mContext.getString(R.string.permission_expanded));
setAccessibility(view, viewType,
- AccessibilityNodeInfo.ACTION_CLICK, R.string.permission_collapse);
- viewHolder.mPermissionSummary.setFocusable(true);
+ AccessibilityNodeInfo.ACTION_CLICK,
+ R.string.permission_collapse, R.string.permission_expand);
} else {
viewHolder.mExpandButton.setImageResource(R.drawable.btn_expand_more);
viewHolder.mPermissionSummary.setVisibility(View.GONE);
viewHolder.mExpandButton.setTag(R.drawable.btn_expand_more);
- view.setContentDescription(mContext.getString(R.string.permission_collapsed));
setAccessibility(view, viewType,
- AccessibilityNodeInfo.ACTION_CLICK, R.string.permission_expanded);
- viewHolder.mPermissionSummary.setFocusable(false);
+ AccessibilityNodeInfo.ACTION_CLICK,
+ R.string.permission_expand, R.string.permission_collapse);
}
});
} else {
@@ -200,14 +198,20 @@
}
}
- private void setAccessibility(View view, int viewType, int action, int resourceId) {
- final String actionString = mContext.getString(resourceId);
+ private void setAccessibility(View view, int viewType, int action, int statusResourceId,
+ int actionResourceId) {
final String permission = mContext.getString(sTitleMap.get(viewType));
+
+ if (actionResourceId != 0) {
+ view.announceForAccessibility(
+ getHtmlFromResources(mContext, actionResourceId, permission));
+ }
+
view.setAccessibilityDelegate(new View.AccessibilityDelegate() {
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(host, info);
info.addAction(new AccessibilityNodeInfo.AccessibilityAction(action,
- actionString + permission));
+ getHtmlFromResources(mContext, statusResourceId, permission)));
}
});
}
diff --git a/packages/CredentialManager/res/values/strings.xml b/packages/CredentialManager/res/values/strings.xml
index a3b2752..3402857 100644
--- a/packages/CredentialManager/res/values/strings.xml
+++ b/packages/CredentialManager/res/values/strings.xml
@@ -86,6 +86,8 @@
<string name="use_provider_for_all_description">This password manager for <xliff:g id="username" example="becket@gmail.com">%1$s</xliff:g> will store your passwords and passkeys to help you easily sign in</string>
<!-- This is a label for a button that sets this password manager as the default. [CHAR LIMIT=20] -->
<string name="set_as_default">Set as default</string>
+ <!-- This is a button text to navigate the user to their system settings. [CHAR LIMIT=30] -->
+ <string name="settings">Settings</string>
<!-- This is a label for a button that makes this password manager be used just in this specific case. [CHAR LIMIT=20] -->
<string name="use_once">Use once</string>
<!-- Appears as an option row subtitle to show how many passwords and passkeys are saved in this option when there are passwords and passkeys. [CHAR LIMIT=80] -->
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
index 01f92c4..19b7e85 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
@@ -17,6 +17,7 @@
package com.android.settingslib.collapsingtoolbar;
import android.app.ActionBar;
+import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
@@ -59,7 +60,8 @@
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- if (mCustomizeLayoutResId > 0 && !BuildCompatUtils.isAtLeastS()) {
+ // for backward compatibility on R devices or wearable devices due to small device size.
+ if (mCustomizeLayoutResId > 0 && (!BuildCompatUtils.isAtLeastS() || isWatch())) {
super.setContentView(mCustomizeLayoutResId);
return;
}
@@ -157,6 +159,14 @@
return getToolbarDelegate().getAppBarLayout();
}
+ private boolean isWatch() {
+ PackageManager packageManager = getPackageManager();
+ if (packageManager == null) {
+ return false;
+ }
+ return packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH);
+ }
+
private CollapsingToolbarDelegate getToolbarDelegate() {
if (mToolbardelegate == null) {
mToolbardelegate = new CollapsingToolbarDelegate(new DelegateCallback());
diff --git a/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/PosturesHelper.kt b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/PosturesHelper.kt
index 9c70be9..6a13eb8 100644
--- a/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/PosturesHelper.kt
+++ b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/PosturesHelper.kt
@@ -19,6 +19,7 @@
import android.content.Context
import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_FOLDED
import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_HALF_FOLDED
+import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_REAR_DISPLAY
import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_UNFOLDED
import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_UNKNOWN
import android.provider.Settings.Secure.DeviceStateRotationLockKey
@@ -33,6 +34,8 @@
context.resources.getIntArray(R.array.config_halfFoldedDeviceStates)
private val unfoldedDeviceStates =
context.resources.getIntArray(R.array.config_openDeviceStates)
+ private val rearDisplayDeviceStates =
+ context.resources.getIntArray(R.array.config_rearDisplayDeviceStates)
@DeviceStateRotationLockKey
fun deviceStateToPosture(deviceState: Int): Int {
@@ -40,6 +43,7 @@
in foldedDeviceStates -> DEVICE_STATE_ROTATION_KEY_FOLDED
in halfFoldedDeviceStates -> DEVICE_STATE_ROTATION_KEY_HALF_FOLDED
in unfoldedDeviceStates -> DEVICE_STATE_ROTATION_KEY_UNFOLDED
+ in rearDisplayDeviceStates -> DEVICE_STATE_ROTATION_KEY_REAR_DISPLAY
else -> DEVICE_STATE_ROTATION_KEY_UNKNOWN
}
}
@@ -49,6 +53,7 @@
DEVICE_STATE_ROTATION_KEY_FOLDED -> foldedDeviceStates.firstOrNull()
DEVICE_STATE_ROTATION_KEY_HALF_FOLDED -> halfFoldedDeviceStates.firstOrNull()
DEVICE_STATE_ROTATION_KEY_UNFOLDED -> unfoldedDeviceStates.firstOrNull()
+ DEVICE_STATE_ROTATION_KEY_REAR_DISPLAY -> rearDisplayDeviceStates.firstOrNull()
else -> null
}
}
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_ic_info.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_ic_info.xml
deleted file mode 100644
index c8037c8..0000000
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_ic_info.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
- Copyright (C) 2021 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<!-- copy from frameworks/base/core/res/res/drawable/ic_info.xml-->
-<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="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/>
-</vector>
\ No newline at end of file
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
index ca84db8..b1c26e8 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
@@ -46,16 +46,6 @@
android:textAppearance="?android:attr/textAppearanceListItem"
style="@style/MainSwitchText.Settingslib" />
- <ImageView
- android:id="@+id/restricted_icon"
- android:layout_width="@dimen/settingslib_restricted_icon_size"
- android:layout_height="@dimen/settingslib_restricted_icon_size"
- android:tint="?android:attr/colorAccent"
- android:layout_gravity="center_vertical"
- android:layout_marginEnd="@dimen/settingslib_restricted_icon_margin_end"
- android:src="@drawable/settingslib_ic_info"
- android:visibility="gone" />
-
<Switch
android:id="@android:id/switch_widget"
android:layout_width="wrap_content"
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout-v33/settingslib_main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout-v33/settingslib_main_switch_bar.xml
index 2c2ad92..ab0cf31 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout-v33/settingslib_main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout-v33/settingslib_main_switch_bar.xml
@@ -49,16 +49,6 @@
android:lineBreakWordStyle="phrase"
style="@style/MainSwitchText.Settingslib" />
- <ImageView
- android:id="@+id/restricted_icon"
- android:layout_width="@dimen/settingslib_restricted_icon_size"
- android:layout_height="@dimen/settingslib_restricted_icon_size"
- android:tint="@color/settingslib_accent_primary_variant"
- android:layout_gravity="center_vertical"
- android:layout_marginEnd="@dimen/settingslib_restricted_icon_margin_end"
- android:src="@drawable/settingslib_ic_info"
- android:visibility="gone" />
-
<Switch
android:id="@android:id/switch_widget"
android:layout_width="wrap_content"
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml
index b39d09f..bf34db9 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml
@@ -38,17 +38,6 @@
android:layout_marginStart="@dimen/settingslib_switchbar_subsettings_margin_start"
android:textAlignment="viewStart"/>
- <ImageView
- android:id="@+id/restricted_icon"
- android:layout_width="@dimen/settingslib_restricted_icon_size"
- android:layout_height="@dimen/settingslib_restricted_icon_size"
- android:tint="?android:attr/colorAccent"
- android:theme="@android:style/Theme.Material"
- android:layout_gravity="center_vertical"
- android:layout_marginEnd="@dimen/settingslib_restricted_icon_margin_end"
- android:src="@drawable/settingslib_ic_info"
- android:visibility="gone"/>
-
<Switch
android:id="@android:id/switch_widget"
android:layout_width="wrap_content"
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values-v31/styles.xml b/packages/SettingsLib/MainSwitchPreference/res/values-v31/styles.xml
index a50fc7c..ad888e5 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values-v31/styles.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values-v31/styles.xml
@@ -17,9 +17,8 @@
<resources>
- <style name="MainSwitchText.Settingslib" parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
+ <style name="MainSwitchText.Settingslib" parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title.Inverse">
<item name="android:textSize">20sp</item>
<item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
- <item name="android:textColor">@android:color/black</item>
</style>
</resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml b/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
index 88b2c87..0d9ffff 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
@@ -17,16 +17,9 @@
<resources>
- <!-- Restricted icon size in switch bar -->
- <dimen name="settingslib_restricted_icon_size">@android:dimen/config_restrictedIconSize</dimen>
-
- <!-- Restricted icon in switch bar -->
- <dimen name="settingslib_restricted_icon_margin_end">16dp</dimen>
-
<!-- Size of title margin -->
<dimen name="settingslib_switch_title_margin">24dp</dimen>
- <!-- SwitchBar sub settings margin start / end -->
+ <!-- SwitchBar sub settings margin start -->
<dimen name="settingslib_switchbar_subsettings_margin_start">56dp</dimen>
- <dimen name="settingslib_switchbar_subsettings_margin_end">16dp</dimen>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/DefaultAppInfo.java b/packages/SettingsLib/src/com/android/settingslib/applications/DefaultAppInfo.java
index 3c45112..dae48db 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/DefaultAppInfo.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/DefaultAppInfo.java
@@ -17,6 +17,7 @@
package com.android.settingslib.applications;
import android.app.AppGlobals;
+import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -94,6 +95,10 @@
}
+ public @Nullable String getSummary() {
+ return this.summary;
+ }
+
@Override
public Drawable loadIcon() {
final IconDrawableFactory factory = IconDrawableFactory.newInstance(mContext);
diff --git a/packages/SettingsLib/tests/integ/Android.bp b/packages/SettingsLib/tests/integ/Android.bp
index d463170..ff3eeec 100644
--- a/packages/SettingsLib/tests/integ/Android.bp
+++ b/packages/SettingsLib/tests/integ/Android.bp
@@ -30,7 +30,10 @@
certificate: "platform",
- srcs: ["src/**/*.java"],
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
libs: [
"android.test.runner",
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/PosturesHelperTest.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/PosturesHelperTest.kt
new file mode 100644
index 0000000..d91c2fa
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/PosturesHelperTest.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.devicestate
+
+import android.content.Context
+import android.content.res.Resources
+import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_FOLDED
+import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_HALF_FOLDED
+import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_REAR_DISPLAY
+import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_UNFOLDED
+import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_UNKNOWN
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.internal.R
+import com.google.common.truth.Expect
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+private const val DEVICE_STATE_UNKNOWN = 0
+private const val DEVICE_STATE_CLOSED = 1
+private const val DEVICE_STATE_HALF_FOLDED = 2
+private const val DEVICE_STATE_OPEN = 3
+private const val DEVICE_STATE_REAR_DISPLAY = 4
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class PosturesHelperTest {
+
+ @get:Rule val expect: Expect = Expect.create()
+
+ @Mock private lateinit var context: Context
+
+ @Mock private lateinit var resources: Resources
+
+ private lateinit var posturesHelper: PosturesHelper
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ whenever(context.resources).thenReturn(resources)
+ whenever(resources.getIntArray(R.array.config_foldedDeviceStates))
+ .thenReturn(intArrayOf(DEVICE_STATE_CLOSED))
+ whenever(resources.getIntArray(R.array.config_halfFoldedDeviceStates))
+ .thenReturn(intArrayOf(DEVICE_STATE_HALF_FOLDED))
+ whenever(resources.getIntArray(R.array.config_openDeviceStates))
+ .thenReturn(intArrayOf(DEVICE_STATE_OPEN))
+ whenever(resources.getIntArray(R.array.config_rearDisplayDeviceStates))
+ .thenReturn(intArrayOf(DEVICE_STATE_REAR_DISPLAY))
+
+ posturesHelper = PosturesHelper(context)
+ }
+
+ @Test
+ fun deviceStateToPosture_mapsCorrectly() {
+ expect
+ .that(posturesHelper.deviceStateToPosture(DEVICE_STATE_CLOSED))
+ .isEqualTo(DEVICE_STATE_ROTATION_KEY_FOLDED)
+ expect
+ .that(posturesHelper.deviceStateToPosture(DEVICE_STATE_HALF_FOLDED))
+ .isEqualTo(DEVICE_STATE_ROTATION_KEY_HALF_FOLDED)
+ expect
+ .that(posturesHelper.deviceStateToPosture(DEVICE_STATE_OPEN))
+ .isEqualTo(DEVICE_STATE_ROTATION_KEY_UNFOLDED)
+ expect
+ .that(posturesHelper.deviceStateToPosture(DEVICE_STATE_REAR_DISPLAY))
+ .isEqualTo(DEVICE_STATE_ROTATION_KEY_REAR_DISPLAY)
+ expect
+ .that(posturesHelper.deviceStateToPosture(DEVICE_STATE_UNKNOWN))
+ .isEqualTo(DEVICE_STATE_ROTATION_KEY_UNKNOWN)
+ }
+
+ @Test
+ fun postureToDeviceState_mapsCorrectly() {
+ expect
+ .that(posturesHelper.postureToDeviceState(DEVICE_STATE_ROTATION_KEY_FOLDED))
+ .isEqualTo(DEVICE_STATE_CLOSED)
+ expect
+ .that(posturesHelper.postureToDeviceState(DEVICE_STATE_ROTATION_KEY_HALF_FOLDED))
+ .isEqualTo(DEVICE_STATE_HALF_FOLDED)
+ expect
+ .that(posturesHelper.postureToDeviceState(DEVICE_STATE_ROTATION_KEY_UNFOLDED))
+ .isEqualTo(DEVICE_STATE_OPEN)
+ expect
+ .that(posturesHelper.postureToDeviceState(DEVICE_STATE_ROTATION_KEY_REAR_DISPLAY))
+ .isEqualTo(DEVICE_STATE_REAR_DISPLAY)
+ expect.that(posturesHelper.postureToDeviceState(DEVICE_STATE_ROTATION_KEY_UNKNOWN)).isNull()
+ }
+}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index e4cc9f1..6a5535d 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -100,6 +100,5 @@
Settings.System.CAMERA_FLASH_NOTIFICATION,
Settings.System.SCREEN_FLASH_NOTIFICATION,
Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR,
- Settings.System.SMOOTH_DISPLAY
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index 4b72063..85623b2 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -226,6 +226,5 @@
VALIDATORS.put(System.CAMERA_FLASH_NOTIFICATION, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.SCREEN_FLASH_NOTIFICATION, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.SCREEN_FLASH_NOTIFICATION_COLOR, ANY_INTEGER_VALIDATOR);
- VALIDATORS.put(System.SMOOTH_DISPLAY, BOOLEAN_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index d1bd5e6..46b45d1 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -34,7 +34,6 @@
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
import static com.android.internal.accessibility.util.AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM;
-import static com.android.internal.display.RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE;
import static com.android.providers.settings.SettingsState.FALLBACK_FILE_SUFFIX;
import static com.android.providers.settings.SettingsState.getTypeFromKey;
import static com.android.providers.settings.SettingsState.getUserIdFromKey;
@@ -5674,7 +5673,7 @@
providers.addAll(Arrays.asList(resources.getStringArray(resourceId)));
} catch (Resources.NotFoundException e) {
Slog.w(LOG_TAG,
- "Get default array Cred Provider not found: " + e.toString());
+ "Get default array Cred Provider not found: " + e.toString());
}
try {
final String storedValue = resources.getString(resourceId);
@@ -5683,7 +5682,7 @@
}
} catch (Resources.NotFoundException e) {
Slog.w(LOG_TAG,
- "Get default Cred Provider not found: " + e.toString());
+ "Get default Cred Provider not found: " + e.toString());
}
if (!providers.isEmpty()) {
@@ -5732,8 +5731,8 @@
final Setting currentSetting = secureSettings
.getSettingLocked(Settings.Secure.CREDENTIAL_SERVICE);
if (currentSetting.isNull()) {
- final int resourceId = com.android.internal.R.array
- .config_defaultCredentialProviderService;
+ final int resourceId =
+ com.android.internal.R.array.config_defaultCredentialProviderService;
final Resources resources = getContext().getResources();
// If the config has not be defined we might get an exception.
final List<String> providers = new ArrayList<>();
@@ -5741,7 +5740,7 @@
providers.addAll(Arrays.asList(resources.getStringArray(resourceId)));
} catch (Resources.NotFoundException e) {
Slog.w(LOG_TAG,
- "Get default array Cred Provider not found: " + e.toString());
+ "Get default array Cred Provider not found: " + e.toString());
}
if (!providers.isEmpty()) {
@@ -5840,44 +5839,12 @@
currentVersion = 218;
}
- // v218: Convert Smooth Display and Force Peak Refresh Rate to a boolean
if (currentVersion == 218) {
- final String peakRefreshRateSettingName = "peak_refresh_rate";
- final String minRefreshRateSettingName = "min_refresh_rate";
-
- final SettingsState systemSettings = getSystemSettingsLocked(userId);
- final Setting peakRefreshRateSetting =
- systemSettings.getSettingLocked(peakRefreshRateSettingName);
- final Setting minRefreshRateSetting =
- systemSettings.getSettingLocked(minRefreshRateSettingName);
-
- float peakRefreshRate = DEFAULT_REFRESH_RATE;
- float minRefreshRate = 0;
- try {
- if (!peakRefreshRateSetting.isNull()) {
- peakRefreshRate = Float.parseFloat(peakRefreshRateSetting.getValue());
- }
- } catch (NumberFormatException e) {
- // Do nothing. Overwrite with default value.
- }
- try {
- if (!minRefreshRateSetting.isNull()) {
- minRefreshRate = Float.parseFloat(minRefreshRateSetting.getValue());
- }
- } catch (NumberFormatException e) {
- // Do nothing. Overwrite with default value.
- }
-
- systemSettings.deleteSettingLocked(peakRefreshRateSettingName);
- systemSettings.deleteSettingLocked(minRefreshRateSettingName);
-
- systemSettings.insertSettingLocked(Settings.System.SMOOTH_DISPLAY,
- peakRefreshRate > DEFAULT_REFRESH_RATE ? "1" : "0", /* tag= */ null,
- /* makeDefault= */ false, SettingsState.SYSTEM_PACKAGE_NAME);
- systemSettings.insertSettingLocked(Settings.System.FORCE_PEAK_REFRESH_RATE,
- minRefreshRate > 0 ? "1" : "0", /* tag= */ null,
- /* makeDefault= */ false, SettingsState.SYSTEM_PACKAGE_NAME);
-
+ // Version 219: Removed
+ // TODO(b/211737588): Back up the Smooth Display setting
+ // Future upgrades to the `peak_refresh_rate` and `min_refresh_rate` settings
+ // should account for the database in a non-upgraded and upgraded (change id:
+ // Ib2cb2dd100f06f5452083b7606109a486e795a0e) state.
currentVersion = 219;
}
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 36aa2ac..706666c 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -97,7 +97,8 @@
Settings.System.WHEN_TO_MAKE_WIFI_CALLS, // bug?
Settings.System.WINDOW_ORIENTATION_LISTENER_LOG, // used for debugging only
Settings.System.DESKTOP_MODE, // developer setting for internal prototyping
- Settings.System.FORCE_PEAK_REFRESH_RATE, // depends on hardware capabilities
+ Settings.System.MIN_REFRESH_RATE, // depends on hardware capabilities
+ Settings.System.PEAK_REFRESH_RATE, // depends on hardware capabilities
Settings.System.SCREEN_BRIGHTNESS_FLOAT,
Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ,
Settings.System.MULTI_AUDIO_FOCUS_ENABLED // form-factor/OEM specific
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 32d6b70..c8eb4b4 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -695,7 +695,9 @@
android:relinquishTaskIdentity="true"
android:configChanges=
"screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
- android:visibleToInstantApps="true"/>
+ android:visibleToInstantApps="true"
+ android:exported="false"
+ android:permission="android.permission.MANAGE_MEDIA_PROJECTION"/>
<!-- started from TvNotificationPanel -->
<activity
@@ -990,6 +992,18 @@
android:excludeFromRecents="true"
android:resizeableActivity="false"
android:theme="@android:style/Theme.NoDisplay" />
+
+ <activity
+ android:name=".notetask.LaunchNotesRoleSettingsTrampolineActivity"
+ android:exported="true"
+ android:excludeFromRecents="true"
+ android:resizeableActivity="false"
+ android:theme="@android:style/Theme.NoDisplay" >
+ <intent-filter>
+ <action android:name="com.android.systemui.action.MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
<!-- endregion -->
<!-- started from ControlsRequestReceiver -->
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index 77ddc6e..1ce3472 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -55,6 +55,7 @@
madym@google.com
mankoff@google.com
mateuszc@google.com
+mgalhardo@google.com
michaelmikhil@google.com
michschn@google.com
mkephart@google.com
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/DynamicColor.java b/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/DynamicColor.java
index e6b2c2f..e839d9b 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/DynamicColor.java
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/DynamicColor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 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.
@@ -71,12 +71,11 @@
* The base constructor for DynamicColor.
*
* <p>Functional arguments allow overriding without risks that come with subclasses. _Strongly_
- * prefer using one of the static convenience constructors. This class is arguably too flexible
- * to
+ * prefer using one of the static convenience constructors. This class is arguably too
+ * flexible to
* ensure it can support any scenario.
*
- * <p>For example, the default behavior of adjust tone at max contrast to be at a 7.0 ratio
- * with
+ * <p>For example, the default behavior of adjust tone at max contrast to be at a 7.0 ratio with
* its background is principled and matches a11y guidance. That does not mean it's the desired
* approach for _every_ design system, and every color pairing, always, in every case.
*
@@ -89,23 +88,23 @@
* lower and raise contrast are
* made.
* @param toneMinContrast given DynamicScheme, return tone in HCT/L* in L*a*b* this color
- * should
- * be at minimum contrast. See toneMinContrastDefault for the default
- * behavior, and strongly
+ * should
+ * be at minimum contrast. See toneMinContrastDefault for the
+ * default behavior, and strongly
* consider using it unless you have strong opinions on a11y. The
* static constructors use it.
* @param toneMaxContrast given DynamicScheme, return tone in HCT/L* in L*a*b* this color
- * should
- * be at maximum contrast. See toneMaxContrastDefault for the default
- * behavior, and strongly
+ * should
+ * be at maximum contrast. See toneMaxContrastDefault for the
+ * default behavior, and strongly
* consider using it unless you have strong opinions on a11y. The
* static constructors use it.
* @param toneDeltaConstraint given DynamicScheme, return a ToneDeltaConstraint instance that
* describes a requirement that this DynamicColor must always have
* some difference in tone/L*
* from another DynamicColor.<br>
- * Unlikely to be useful unless a design system has some distortions
- * where colors that don't
+ * Unlikely to be useful unless a design system has some
+ * distortions where colors that don't
* have a background/foreground relationship must have _some_
* difference in tone, yet, not
* enough difference to create meaningful contrast.
@@ -164,8 +163,8 @@
* <p>If the design system uses the same hex code on multiple backgrounds, define that in
* multiple
* DynamicColors so that the background is accurate for each one. If you define a DynamicColor
- * with one background, and actually use it on another, DynamicColor can't guarantee contrast.
- * For
+ * with one background, and actually use it on another, DynamicColor can't guarantee contrast
+ * . For
* example, if you use a color on both black and white, increasing the contrast on one
* necessarily
* decreases contrast of the other.
@@ -195,8 +194,8 @@
* for contrast, given a background, colors can adjust to
* increase/decrease contrast.
* @param toneDeltaConstraint Function that provides a ToneDeltaConstraint given DynamicScheme.
- * Useful for ensuring lightness difference between colors that don't
- * _require_ contrast or
+ * Useful for ensuring lightness difference between colors that
+ * don't _require_ contrast or
* have a formal background/foreground relationship.
*/
public static DynamicColor fromArgb(
@@ -212,17 +211,17 @@
* Create a DynamicColor.
*
* @param palette Function that provides a TonalPalette given DynamicScheme. A TonalPalette is
- * defined by a hue and chroma, so this replaces the need to specify hue/chroma.
- * By providing
+ * defined by a hue and chroma, so this replaces the need to specify
+ * hue/chroma. By providing
* a tonal palette, when contrast adjustments are made, intended chroma can be
* preserved. For
* example, at T/L* 90, there is a significant limit to the amount of chroma.
* There is no
- * colorful red, a red that light is pink. By preserving the _intended_ chroma if
- * lightness
+ * colorful red, a red that light is pink. By preserving the _intended_ chroma
+ * if lightness
* lowers for contrast adjustments, the intended chroma is restored.
- * @param tone Function that provides a tone given DynamicScheme. (useful for dark vs. light
- * mode)
+ * @param tone Function that provides a tone given DynamicScheme. (useful for dark vs.
+ * light mode)
*/
public static DynamicColor fromPalette(
Function<DynamicScheme, TonalPalette> palette, Function<DynamicScheme, Double> tone) {
@@ -232,16 +231,16 @@
/**
* Create a DynamicColor.
*
- * @param palette Function that provides a TonalPalette given DynamicScheme. A TonalPalette
- * is
+ * @param palette Function that provides a TonalPalette given DynamicScheme. A
+ * TonalPalette is
* defined by a hue and chroma, so this replaces the need to specify
* hue/chroma. By providing
- * a tonal palette, when contrast adjustments are made, intended chroma can be
- * preserved. For
- * example, at T/L* 90, there is a significant limit to the amount of chroma.
- * There is no
- * colorful red, a red that light is pink. By preserving the _intended_ chroma
- * if lightness
+ * a tonal palette, when contrast adjustments are made, intended chroma can
+ * be preserved. For
+ * example, at T/L* 90, there is a significant limit to the amount of
+ * chroma. There is no
+ * colorful red, a red that light is pink. By preserving the _intended_
+ * chroma if lightness
* lowers for contrast adjustments, the intended chroma is restored.
* @param tone Function that provides a tone given DynamicScheme. (useful for dark vs.
* light mode)
@@ -261,12 +260,12 @@
*
* @param palette Function that provides a TonalPalette given DynamicScheme. A
* TonalPalette is
- * defined by a hue and chroma, so this replaces the need to specify
- * hue/chroma. By providing
+ * defined by a hue and chroma, so this replaces the need to
+ * specify hue/chroma. By providing
* a tonal palette, when contrast adjustments are made, intended
* chroma can be preserved. For
- * example, at T/L* 90, there is a significant limit to the amount of
- * chroma. There is no
+ * example, at T/L* 90, there is a significant limit to the amount
+ * of chroma. There is no
* colorful red, a red that light is pink. By preserving the
* _intended_ chroma if lightness
* lowers for contrast adjustments, the intended chroma is restored.
@@ -277,8 +276,8 @@
* for contrast, given a background, colors can adjust to
* increase/decrease contrast.
* @param toneDeltaConstraint Function that provides a ToneDeltaConstraint given DynamicScheme.
- * Useful for ensuring lightness difference between colors that don't
- * _require_ contrast or
+ * Useful for ensuring lightness difference between colors that
+ * don't _require_ contrast or
* have a formal background/foreground relationship.
*/
public static DynamicColor fromPalette(
@@ -297,96 +296,6 @@
toneDeltaConstraint);
}
- /** Returns the ARGB (i.e. hex code) representation of the resolved color given scheme. */
- public int getArgb(DynamicScheme scheme) {
- final int argb = getHct(scheme).toInt();
- if (opacity == null) {
- return argb;
- }
- final double percentage = opacity.apply(scheme);
- final int alpha = MathUtils.clampInt(0, 255, (int) Math.round(percentage * 255));
- return (argb & 0x00ffffff) | (alpha << 24);
- }
-
- /** Returns the HCT representation of the resolved color given scheme. */
- public Hct getHct(DynamicScheme scheme) {
- final Hct cachedAnswer = hctCache.get(scheme);
- if (cachedAnswer != null) {
- return cachedAnswer;
- }
- // This is crucial for aesthetics: we aren't simply the taking the standard color
- // and changing its tone for contrast. Rather, we find the tone for contrast, then
- // use the specified chroma from the palette to construct a new color.
- //
- // For example, this enables colors with standard tone of T90, which has limited chroma, to
- // "recover" intended chroma as contrast increases.
- final Hct answer = Hct.from(hue.apply(scheme), chroma.apply(scheme), getTone(scheme));
- // NOMUTANTS--trivial test with onerous dependency injection requirement.
- if (hctCache.size() > 4) {
- hctCache.clear();
- }
- // NOMUTANTS--trivial test with onerous dependency injection requirement.
- hctCache.put(scheme, answer);
- return answer;
- }
-
- /** Returns the tone in HCT, ranging from 0 to 100, of the resolved color given scheme. */
- public double getTone(DynamicScheme scheme) {
- double answer = tone.apply(scheme);
-
- final boolean decreasingContrast = scheme.contrastLevel < 0.0;
- if (scheme.contrastLevel != 0.0) {
- final double startTone = tone.apply(scheme);
- final double endTone =
- decreasingContrast ? toneMinContrast.apply(scheme) : toneMaxContrast.apply(
- scheme);
- final double delta = (endTone - startTone) * Math.abs(scheme.contrastLevel);
- answer = delta + startTone;
- }
-
- final DynamicColor bgDynamicColor = background == null ? null : background.apply(scheme);
- double minRatio = Contrast.RATIO_MIN;
- double maxRatio = Contrast.RATIO_MAX;
- if (bgDynamicColor != null) {
- final boolean bgHasBg =
- bgDynamicColor.background != null && bgDynamicColor.background.apply(scheme)
- != null;
- final double standardRatio =
- Contrast.ratioOfTones(tone.apply(scheme), bgDynamicColor.tone.apply(scheme));
- if (decreasingContrast) {
- final double minContrastRatio =
- Contrast.ratioOfTones(
- toneMinContrast.apply(scheme),
- bgDynamicColor.toneMinContrast.apply(scheme));
- minRatio = bgHasBg ? minContrastRatio : 1.0;
- maxRatio = standardRatio;
- } else {
- final double maxContrastRatio =
- Contrast.ratioOfTones(
- toneMaxContrast.apply(scheme),
- bgDynamicColor.toneMaxContrast.apply(scheme));
- minRatio = bgHasBg ? min(maxContrastRatio, standardRatio) : 1.0;
- maxRatio = bgHasBg ? max(maxContrastRatio, standardRatio) : 21.0;
- }
- }
-
- final double finalMinRatio = minRatio;
- final double finalMaxRatio = maxRatio;
- final double finalAnswer = answer;
- answer =
- calculateDynamicTone(
- scheme,
- this.tone,
- (dynamicColor) -> dynamicColor.getTone(scheme),
- (a, b) -> finalAnswer,
- (s) -> bgDynamicColor,
- toneDeltaConstraint,
- (s) -> finalMinRatio,
- (s) -> finalMaxRatio);
-
- return answer;
- }
-
/**
* The default algorithm for calculating the tone of a color at minimum contrast.<br>
* If the original contrast ratio was >= 7.0, reach contrast 4.5.<br>
@@ -475,8 +384,8 @@
* <p>It enforces important properties:<br>
* #1. Desired contrast ratio is reached.<br>
* As contrast increases from standard to max, the tones involved should always be at least the
- * standard ratio. For example, if a button is T90, and button text is T0, and the button is T0
- * at
+ * standard ratio. For example, if a button is T90, and button text is T0, and the button is
+ * T0 at
* max contrast, the button text cannot simply linearly interpolate from T0 to T100, or at some
* point they'll both be at the same tone.
*
@@ -489,8 +398,7 @@
*
* <p>#3. Ensure tone delta with another color.<br>
* In design systems, there may be colors that don't have a pure background/foreground
- * relationship, but, do require different tones for visual differentiation.
- * ToneDeltaConstraint
+ * relationship, but, do require different tones for visual differentiation. ToneDeltaConstraint
* models this requirement, and DynamicColor enforces it.
*/
public static double calculateDynamicTone(
@@ -596,13 +504,16 @@
final boolean preferLighter = tonePrefersLightForeground(bgTone);
if (preferLighter) {
- // "Negligible difference" handles an edge case where the initial contrast ratio is high
+ // "Neglible difference" handles an edge case where the initial contrast ratio is high
// (ex. 13.0), and the ratio passed to the function is that high ratio, and both the
- // lighter and darker ratio fails to pass that ratio.
+ // lighter
+ // and darker ratio fails to pass that ratio.
//
// This was observed with Tonal Spot's On Primary Container turning black momentarily
- // between high and max contrast in light mode. PC's standard tone was T90, OPC's was
- // T10, it was light mode, and the contrast level was 0.6568521221032331.
+ // between
+ // high and max contrast in light mode. PC's standard tone was T90, OPC's was T10, it
+ // was
+ // light mode, and the contrast level was 0.6568521221032331.
final boolean negligibleDifference =
Math.abs(lighterRatio - darkerRatio) < 0.1 && lighterRatio < ratio
&& darkerRatio < ratio;
@@ -634,13 +545,109 @@
* <p>T60 used as to create the smallest discontinuity possible when skipping down to T49 in
* order
* to ensure light foregrounds.
+ *
+ * <p>Since `tertiaryContainer` in dark monochrome scheme requires a tone of 60, it should
+ * not be
+ * adjusted. Therefore, 60 is excluded here.
*/
public static boolean tonePrefersLightForeground(double tone) {
- return Math.round(tone) <= 60;
+ return Math.round(tone) < 60;
}
- /** Tones less than ~T50 always permit white at 4.5 contrast. */
+ /**
+ * Tones less than ~T50 always permit white at 4.5 contrast.
+ */
public static boolean toneAllowsLightForeground(double tone) {
return Math.round(tone) <= 49;
}
+
+ public int getArgb(DynamicScheme scheme) {
+ final int argb = getHct(scheme).toInt();
+ if (opacity == null) {
+ return argb;
+ }
+ final double percentage = opacity.apply(scheme);
+ final int alpha = MathUtils.clampInt(0, 255, (int) Math.round(percentage * 255));
+ return (argb & 0x00ffffff) | (alpha << 24);
+ }
+
+ public Hct getHct(DynamicScheme scheme) {
+ final Hct cachedAnswer = hctCache.get(scheme);
+ if (cachedAnswer != null) {
+ return cachedAnswer;
+ }
+ // This is crucial for aesthetics: we aren't simply the taking the standard color
+ // and changing its tone for contrast. Rather, we find the tone for contrast, then
+ // use the specified chroma from the palette to construct a new color.
+ //
+ // For example, this enables colors with standard tone of T90, which has limited chroma, to
+ // "recover" intended chroma as contrast increases.
+ final Hct answer = Hct.from(hue.apply(scheme), chroma.apply(scheme), getTone(scheme));
+ // NOMUTANTS--trivial test with onerous dependency injection requirement.
+ if (hctCache.size() > 4) {
+ hctCache.clear();
+ }
+ // NOMUTANTS--trivial test with onerous dependency injection requirement.
+ hctCache.put(scheme, answer);
+ return answer;
+ }
+
+ /**
+ * Returns the tone in HCT, ranging from 0 to 100, of the resolved color given scheme.
+ */
+ public double getTone(DynamicScheme scheme) {
+ double answer = tone.apply(scheme);
+
+ final boolean decreasingContrast = scheme.contrastLevel < 0.0;
+ if (scheme.contrastLevel != 0.0) {
+ final double startTone = tone.apply(scheme);
+ final double endTone =
+ decreasingContrast ? toneMinContrast.apply(scheme) : toneMaxContrast.apply(
+ scheme);
+ final double delta = (endTone - startTone) * Math.abs(scheme.contrastLevel);
+ answer = delta + startTone;
+ }
+
+ final DynamicColor bgDynamicColor = background == null ? null : background.apply(scheme);
+ double minRatio = Contrast.RATIO_MIN;
+ double maxRatio = Contrast.RATIO_MAX;
+ if (bgDynamicColor != null) {
+ final boolean bgHasBg =
+ bgDynamicColor.background != null && bgDynamicColor.background.apply(scheme)
+ != null;
+ final double standardRatio =
+ Contrast.ratioOfTones(tone.apply(scheme), bgDynamicColor.tone.apply(scheme));
+ if (decreasingContrast) {
+ final double minContrastRatio =
+ Contrast.ratioOfTones(
+ toneMinContrast.apply(scheme),
+ bgDynamicColor.toneMinContrast.apply(scheme));
+ minRatio = bgHasBg ? minContrastRatio : 1.0;
+ maxRatio = standardRatio;
+ } else {
+ final double maxContrastRatio =
+ Contrast.ratioOfTones(
+ toneMaxContrast.apply(scheme),
+ bgDynamicColor.toneMaxContrast.apply(scheme));
+ minRatio = bgHasBg ? min(maxContrastRatio, standardRatio) : 1.0;
+ maxRatio = bgHasBg ? max(maxContrastRatio, standardRatio) : 21.0;
+ }
+ }
+
+ final double finalMinRatio = minRatio;
+ final double finalMaxRatio = maxRatio;
+ final double finalAnswer = answer;
+ answer =
+ calculateDynamicTone(
+ scheme,
+ this.tone,
+ (dynamicColor) -> dynamicColor.getTone(scheme),
+ (a, b) -> finalAnswer,
+ (s) -> bgDynamicColor,
+ toneDeltaConstraint,
+ (s) -> finalMinRatio,
+ (s) -> finalMaxRatio);
+
+ return answer;
+ }
}
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/MaterialDynamicColors.java b/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/MaterialDynamicColors.java
index 5212e8e..21218a2 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/MaterialDynamicColors.java
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/MaterialDynamicColors.java
@@ -22,7 +22,7 @@
import com.android.systemui.monet.scheme.DynamicScheme;
import com.android.systemui.monet.scheme.Variant;
-/** Named colors, otherwise known as tokens, or roles, in the Material Design system. */
+/** Named colors, otherwise known as tokens, or roles, in the Material Design system.*/
// Prevent lint for Function.apply not being available on Android before API level 14 (4.0.1).
// "AndroidJdkLibsChecker" for Function, "NewApi" for Function.apply().
// A java_library Bazel rule with an Android constraint cannot skip these warnings without this
@@ -33,341 +33,54 @@
private static final double CONTAINER_ACCENT_TONE_DELTA = 15.0;
- private MaterialDynamicColors() {
+ public MaterialDynamicColors() {
}
- public static DynamicColor highestSurface(DynamicScheme s) {
- return s.isDark ? surfaceBright : surfaceDim;
- }
-
- public static final DynamicColor background =
- DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 6.0 : 98.0);
-
- public static final DynamicColor onBackground =
- DynamicColor.fromPalette(
- (s) -> s.neutralPalette, (s) -> s.isDark ? 90.0 : 10.0, (s) -> background);
-
- public static final DynamicColor surface =
- DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 6.0 : 98.0);
-
- public static final DynamicColor surfaceInverse =
- DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 90.0 : 30.0);
-
- public static final DynamicColor surfaceBright =
- DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 24.0 : 98.0);
-
- public static final DynamicColor surfaceDim =
- DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 6.0 : 87.0);
-
- public static final DynamicColor surfaceSub2 =
- DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 4.0 : 100.0);
-
- public static final DynamicColor surfaceSub1 =
- DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 10.0 : 96.0);
-
- public static final DynamicColor surfaceContainer =
- DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 12.0 : 94.0);
-
- public static final DynamicColor surfaceAdd1 =
- DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 17.0 : 92.0);
-
- public static final DynamicColor surfaceAdd2 =
- DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 22.0 : 90.0);
-
- public static final DynamicColor onSurface =
- DynamicColor.fromPalette(
- (s) -> s.neutralPalette, (s) -> s.isDark ? 90.0 : 10.0,
- (s) -> highestSurface(s));
-
- public static final DynamicColor onSurfaceInverse =
- DynamicColor.fromPalette(
- (s) -> s.neutralPalette, (s) -> s.isDark ? 20.0 : 95.0, (s) -> surfaceInverse);
-
- public static final DynamicColor surfaceVariant =
- DynamicColor.fromPalette((s) -> s.neutralVariantPalette, (s) -> s.isDark ? 30.0 : 90.0);
-
- public static final DynamicColor onSurfaceVariant =
- DynamicColor.fromPalette(
- (s) -> s.neutralVariantPalette, (s) -> s.isDark ? 80.0 : 30.0,
- (s) -> surfaceVariant);
-
- public static final DynamicColor outline =
- DynamicColor.fromPalette(
- (s) -> s.neutralVariantPalette, (s) -> 50.0, (s) -> highestSurface(s));
-
- public static final DynamicColor outlineVariant =
- DynamicColor.fromPalette(
- (s) -> s.neutralVariantPalette, (s) -> s.isDark ? 30.0 : 80.0,
- (s) -> highestSurface(s));
-
- public static final DynamicColor primaryContainer =
- DynamicColor.fromPalette(
- (s) -> s.primaryPalette,
- (s) -> {
- if (!isFidelity(s)) {
- return s.isDark ? 30.0 : 90.0;
- }
- return performAlbers(s.sourceColorHct, s);
- },
- (s) -> highestSurface(s));
-
- public static final DynamicColor onPrimaryContainer =
- DynamicColor.fromPalette(
- (s) -> s.primaryPalette,
- (s) -> {
- if (!isFidelity(s)) {
- return s.isDark ? 90.0 : 10.0;
- }
- return DynamicColor.contrastingTone(primaryContainer.tone.apply(s), 4.5);
- },
- (s) -> primaryContainer,
- null);
-
- public static final DynamicColor primary =
- DynamicColor.fromPalette(
- (s) -> s.primaryPalette,
- (s) -> s.isDark ? 80.0 : 40.0,
- (s) -> highestSurface(s),
- (s) ->
- new ToneDeltaConstraint(
- CONTAINER_ACCENT_TONE_DELTA,
- primaryContainer,
- s.isDark ? TonePolarity.DARKER : TonePolarity.LIGHTER));
-
- public static final DynamicColor primaryInverse =
- DynamicColor.fromPalette(
- (s) -> s.primaryPalette, (s) -> s.isDark ? 40.0 : 80.0, (s) -> surfaceInverse);
-
- public static final DynamicColor onPrimary =
- DynamicColor.fromPalette(
- (s) -> s.primaryPalette, (s) -> s.isDark ? 20.0 : 100.0, (s) -> primary);
-
- public static final DynamicColor secondaryContainer =
- DynamicColor.fromPalette(
- (s) -> s.secondaryPalette,
- (s) -> {
- final double initialTone = s.isDark ? 30.0 : 90.0;
- if (!isFidelity(s)) {
- return initialTone;
- }
- double answer =
- findDesiredChromaByTone(
- s.secondaryPalette.getHue(),
- s.secondaryPalette.getChroma(),
- initialTone,
- !s.isDark);
- answer = performAlbers(s.secondaryPalette.getHct(answer), s);
- return answer;
- },
- (s) -> highestSurface(s));
-
- public static final DynamicColor onSecondaryContainer =
- DynamicColor.fromPalette(
- (s) -> s.secondaryPalette,
- (s) -> {
- if (!isFidelity(s)) {
- return s.isDark ? 90.0 : 10.0;
- }
- return DynamicColor.contrastingTone(secondaryContainer.tone.apply(s), 4.5);
- },
- (s) -> secondaryContainer);
-
- public static final DynamicColor secondary =
- DynamicColor.fromPalette(
- (s) -> s.secondaryPalette,
- (s) -> s.isDark ? 80.0 : 40.0,
- (s) -> highestSurface(s),
- (s) ->
- new ToneDeltaConstraint(
- CONTAINER_ACCENT_TONE_DELTA,
- secondaryContainer,
- s.isDark ? TonePolarity.DARKER : TonePolarity.LIGHTER));
-
- public static final DynamicColor onSecondary =
- DynamicColor.fromPalette(
- (s) -> s.secondaryPalette, (s) -> s.isDark ? 20.0 : 100.0, (s) -> secondary);
-
- public static final DynamicColor tertiaryContainer =
- DynamicColor.fromPalette(
- (s) -> s.tertiaryPalette,
- (s) -> {
- if (!isFidelity(s)) {
- return s.isDark ? 30.0 : 90.0;
- }
- final double albersTone =
- performAlbers(s.tertiaryPalette.getHct(s.sourceColorHct.getTone()),
- s);
- final Hct proposedHct = s.tertiaryPalette.getHct(albersTone);
- return DislikeAnalyzer.fixIfDisliked(proposedHct).getTone();
- },
- (s) -> highestSurface(s));
-
- public static final DynamicColor onTertiaryContainer =
- DynamicColor.fromPalette(
- (s) -> s.tertiaryPalette,
- (s) -> {
- if (!isFidelity(s)) {
- return s.isDark ? 90.0 : 10.0;
- }
- return DynamicColor.contrastingTone(tertiaryContainer.tone.apply(s), 4.5);
- },
- (s) -> tertiaryContainer);
-
- public static final DynamicColor tertiary =
- DynamicColor.fromPalette(
- (s) -> s.tertiaryPalette,
- (s) -> s.isDark ? 80.0 : 40.0,
- (s) -> highestSurface(s),
- (s) ->
- new ToneDeltaConstraint(
- CONTAINER_ACCENT_TONE_DELTA,
- tertiaryContainer,
- s.isDark ? TonePolarity.DARKER : TonePolarity.LIGHTER));
-
- public static final DynamicColor onTertiary =
- DynamicColor.fromPalette(
- (s) -> s.tertiaryPalette, (s) -> s.isDark ? 20.0 : 100.0, (s) -> tertiary);
-
- public static final DynamicColor errorContainer =
- DynamicColor.fromPalette(
- (s) -> s.errorPalette, (s) -> s.isDark ? 30.0 : 90.0, (s) -> highestSurface(s));
-
- public static final DynamicColor onErrorContainer =
- DynamicColor.fromPalette(
- (s) -> s.errorPalette, (s) -> s.isDark ? 90.0 : 10.0, (s) -> errorContainer);
-
- public static final DynamicColor error =
- DynamicColor.fromPalette(
- (s) -> s.errorPalette,
- (s) -> s.isDark ? 80.0 : 40.0,
- (s) -> highestSurface(s),
- (s) ->
- new ToneDeltaConstraint(
- CONTAINER_ACCENT_TONE_DELTA,
- errorContainer,
- s.isDark ? TonePolarity.DARKER : TonePolarity.LIGHTER));
-
- public static final DynamicColor onError =
- DynamicColor.fromPalette((s) -> s.errorPalette, (s) -> s.isDark ? 20.0 : 100.0,
- (s) -> error);
-
- public static final DynamicColor primaryFixed =
- DynamicColor.fromPalette((s) -> s.primaryPalette, (s) -> 90.0,
- (s) -> highestSurface(s));
-
- public static final DynamicColor primaryFixedDarker =
- DynamicColor.fromPalette((s) -> s.primaryPalette, (s) -> 80.0,
- (s) -> highestSurface(s));
-
- public static final DynamicColor onPrimaryFixed =
- DynamicColor.fromPalette((s) -> s.primaryPalette, (s) -> 10.0,
- (s) -> primaryFixedDarker);
-
- public static final DynamicColor onPrimaryFixedVariant =
- DynamicColor.fromPalette((s) -> s.primaryPalette, (s) -> 30.0,
- (s) -> primaryFixedDarker);
-
- public static final DynamicColor secondaryFixed =
- DynamicColor.fromPalette((s) -> s.secondaryPalette, (s) -> 90.0,
- (s) -> highestSurface(s));
-
- public static final DynamicColor secondaryFixedDarker =
- DynamicColor.fromPalette((s) -> s.secondaryPalette, (s) -> 80.0,
- (s) -> highestSurface(s));
-
- public static final DynamicColor onSecondaryFixed =
- DynamicColor.fromPalette((s) -> s.secondaryPalette, (s) -> 10.0,
- (s) -> secondaryFixedDarker);
-
- public static final DynamicColor onSecondaryFixedVariant =
- DynamicColor.fromPalette((s) -> s.secondaryPalette, (s) -> 30.0,
- (s) -> secondaryFixedDarker);
-
- public static final DynamicColor tertiaryFixed =
- DynamicColor.fromPalette((s) -> s.tertiaryPalette, (s) -> 90.0,
- (s) -> highestSurface(s));
-
- public static final DynamicColor tertiaryFixedDarker =
- DynamicColor.fromPalette((s) -> s.tertiaryPalette, (s) -> 80.0,
- (s) -> highestSurface(s));
-
- public static final DynamicColor onTertiaryFixed =
- DynamicColor.fromPalette((s) -> s.tertiaryPalette, (s) -> 10.0,
- (s) -> tertiaryFixedDarker);
-
- public static final DynamicColor onTertiaryFixedVariant =
- DynamicColor.fromPalette((s) -> s.tertiaryPalette, (s) -> 30.0,
- (s) -> tertiaryFixedDarker);
-
/**
* These colors were present in Android framework before Android U, and used by MDC controls.
* They
* should be avoided, if possible. It's unclear if they're used on multiple backgrounds, and if
- * they are, they can't be adjusted for contrast.* For now, they will be set with no
- * background,
+ * they are, they can't be adjusted for contrast.* For now, they will be set with no background,
* and those won't adjust for contrast, avoiding issues.
*
- * <p>* For example, if the same color is on a white background _and_ black background, there's
- * no
+ * <p>* For example, if the same color is on a white background _and_ black background,
+ * there's no
* way to increase contrast with either without losing contrast with the other.
*/
// colorControlActivated documented as colorAccent in M3 & GM3.
// colorAccent documented as colorSecondary in M3 and colorPrimary in GM3.
// Android used Material's Container as Primary/Secondary/Tertiary at launch.
// Therefore, this is a duplicated version of Primary Container.
- public static final DynamicColor controlActivated =
- DynamicColor.fromPalette((s) -> s.primaryPalette, (s) -> s.isDark ? 30.0 : 90.0, null);
+ public static DynamicColor controlActivated() {
+ return DynamicColor.fromPalette((s) -> s.primaryPalette, (s) -> s.isDark ? 30.0 : 90.0, null);
+ }
- // colorControlNormal documented as textColorSecondary in M3 & GM3.
- // In Material, textColorSecondary points to onSurfaceVariant in the non-disabled state,
- // which is Neutral Variant T30/80 in light/dark.
- public static final DynamicColor controlNormal =
- DynamicColor.fromPalette((s) -> s.neutralVariantPalette, (s) -> s.isDark ? 80.0 : 30.0);
+ // Compatibility Keys Colors for Android
+ public static DynamicColor primaryPaletteKeyColor() {
+ return DynamicColor.fromPalette(
+ (s) -> s.primaryPalette, (s) -> s.primaryPalette.getKeyColor().getTone());
+ }
- // colorControlHighlight documented, in both M3 & GM3:
- // Light mode: #1f000000 dark mode: #33ffffff.
- // These are black and white with some alpha.
- // 1F hex = 31 decimal; 31 / 255 = 12% alpha.
- // 33 hex = 51 decimal; 51 / 255 = 20% alpha.
- // DynamicColors do not support alpha currently, and _may_ not need it for this use case,
- // depending on how MDC resolved alpha for the other cases.
- // Returning black in dark mode, white in light mode.
- public static final DynamicColor controlHighlight =
- new DynamicColor(
- s -> 0.0,
- s -> 0.0,
- s -> s.isDark ? 100.0 : 0.0,
- s -> s.isDark ? 0.20 : 0.12,
- null,
- scheme ->
- DynamicColor.toneMinContrastDefault(
- (s) -> s.isDark ? 100.0 : 0.0, null, scheme, null),
- scheme ->
- DynamicColor.toneMaxContrastDefault(
- (s) -> s.isDark ? 100.0 : 0.0, null, scheme, null),
- null);
+ public static DynamicColor secondaryPaletteKeyColor() {
+ return DynamicColor.fromPalette(
+ (s) -> s.secondaryPalette, (s) -> s.secondaryPalette.getKeyColor().getTone());
+ }
- // textColorPrimaryInverse documented, in both M3 & GM3, documented as N10/N90.
- public static final DynamicColor textPrimaryInverse =
- DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 10.0 : 90.0);
+ public static DynamicColor tertiaryPaletteKeyColor() {
+ return DynamicColor.fromPalette(
+ (s) -> s.tertiaryPalette, (s) -> s.tertiaryPalette.getKeyColor().getTone());
+ }
- // textColorSecondaryInverse and textColorTertiaryInverse both documented, in both M3 & GM3, as
- // NV30/NV80
- public static final DynamicColor textSecondaryAndTertiaryInverse =
- DynamicColor.fromPalette((s) -> s.neutralVariantPalette, (s) -> s.isDark ? 30.0 : 80.0);
+ public static DynamicColor neutralPaletteKeyColor() {
+ return DynamicColor.fromPalette(
+ (s) -> s.neutralPalette, (s) -> s.neutralPalette.getKeyColor().getTone());
+ }
- // textColorPrimaryInverseDisableOnly documented, in both M3 & GM3, as N10/N90
- public static final DynamicColor textPrimaryInverseDisableOnly =
- DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 10.0 : 90.0);
-
- // textColorSecondaryInverse and textColorTertiaryInverse in disabled state both documented,
- // in both M3 & GM3, as N10/N90
- public static final DynamicColor textSecondaryAndTertiaryInverseDisabled =
- DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 10.0 : 90.0);
-
- // textColorHintInverse documented, in both M3 & GM3, as N10/N90
- public static final DynamicColor textHintInverse =
- DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 10.0 : 90.0);
+ public static DynamicColor neutralVariantPaletteKeyColor() {
+ return DynamicColor.fromPalette(
+ (s) -> s.neutralVariantPalette,
+ (s) -> s.neutralVariantPalette.getKeyColor().getTone());
+ }
private static ViewingConditions viewingConditionsForAlbers(DynamicScheme scheme) {
return ViewingConditions.defaultWithBackgroundLstar(scheme.isDark ? 30.0 : 80.0);
@@ -377,6 +90,10 @@
return scheme.variant == Variant.FIDELITY || scheme.variant == Variant.CONTENT;
}
+ private static boolean isMonochrome(DynamicScheme scheme) {
+ return scheme.variant == Variant.MONOCHROME;
+ }
+
static double findDesiredChromaByTone(
double hue, double chroma, double tone, boolean byDecreasingTone) {
double answer = tone;
@@ -416,34 +133,456 @@
}
}
- // Compatibility mappings for Android
- public static final DynamicColor surfaceContainerLow = surfaceSub1;
- public static final DynamicColor surfaceContainerLowest = surfaceSub2;
- public static final DynamicColor surfaceContainerHigh = surfaceAdd1;
- public static final DynamicColor surfaceContainerHighest = surfaceAdd2;
- public static final DynamicColor primaryFixedDim = primaryFixedDarker;
- public static final DynamicColor secondaryFixedDim = secondaryFixedDarker;
- public static final DynamicColor tertiaryFixedDim = tertiaryFixedDarker;
+ public static DynamicColor highestSurface(DynamicScheme s) {
+ return s.isDark ? surfaceBright() : surfaceDim();
+ }
- // Compatibility Keys Colors for Android
- public static final DynamicColor primaryPaletteKeyColor =
- DynamicColor.fromPalette(
- (s) -> s.primaryPalette, (s) -> s.primaryPalette.getKeyColor().getTone());
+ public static DynamicColor background() {
+ return DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 6.0 : 98.0);
+ }
- public static final DynamicColor secondaryPaletteKeyColor =
- DynamicColor.fromPalette(
- (s) -> s.secondaryPalette, (s) -> s.secondaryPalette.getKeyColor().getTone());
+ public static DynamicColor onBackground() {
+ return DynamicColor.fromPalette(
+ (s) -> s.neutralPalette, (s) -> s.isDark ? 90.0 : 10.0, (s) -> background());
+ }
- public static final DynamicColor tertiaryPaletteKeyColor =
- DynamicColor.fromPalette(
- (s) -> s.tertiaryPalette, (s) -> s.tertiaryPalette.getKeyColor().getTone());
+ public static DynamicColor surface() {
+ return DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 6.0 : 98.0);
+ }
- public static final DynamicColor neutralPaletteKeyColor =
- DynamicColor.fromPalette(
- (s) -> s.neutralPalette, (s) -> s.neutralPalette.getKeyColor().getTone());
+ public static DynamicColor inverseSurface() {
+ return DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 90.0 : 20.0);
+ }
- public static final DynamicColor neutralVariantPaletteKeyColor =
- DynamicColor.fromPalette(
- (s) -> s.neutralVariantPalette,
- (s) -> s.neutralVariantPalette.getKeyColor().getTone());
+ public static DynamicColor surfaceBright() {
+ return DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 24.0 : 98.0);
+ }
+
+ public static DynamicColor surfaceDim() {
+ return DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 6.0 : 87.0);
+ }
+
+ public static DynamicColor surfaceContainerLowest() {
+ return DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 4.0 : 100.0);
+ }
+
+ public static DynamicColor surfaceContainerLow() {
+ return DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 10.0 : 96.0);
+ }
+
+ public static DynamicColor surfaceContainer() {
+ return DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 12.0 : 94.0);
+ }
+
+ public static DynamicColor surfaceContainerHigh() {
+ return DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 17.0 : 92.0);
+ }
+
+ public static DynamicColor surfaceContainerHighest() {
+ return DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 22.0 : 90.0);
+ }
+
+ public static DynamicColor onSurface() {
+ return DynamicColor.fromPalette(
+ (s) -> s.neutralPalette, (s) -> s.isDark ? 90.0 : 10.0,
+ MaterialDynamicColors::highestSurface);
+ }
+
+ public static DynamicColor inverseOnSurface() {
+ return DynamicColor.fromPalette(
+ (s) -> s.neutralPalette, (s) -> s.isDark ? 20.0 : 95.0, (s) -> inverseSurface());
+ }
+
+ public static DynamicColor surfaceVariant() {
+ return DynamicColor.fromPalette((s) -> s.neutralVariantPalette,
+ (s) -> s.isDark ? 30.0 : 90.0);
+ }
+
+ public static DynamicColor onSurfaceVariant() {
+ return DynamicColor.fromPalette(
+ (s) -> s.neutralVariantPalette, (s) -> s.isDark ? 80.0 : 30.0,
+ (s) -> surfaceVariant());
+ }
+
+ public static DynamicColor outline() {
+ return DynamicColor.fromPalette(
+ (s) -> s.neutralVariantPalette, (s) -> 50.0, MaterialDynamicColors::highestSurface);
+ }
+
+ public static DynamicColor outlineVariant() {
+ return DynamicColor.fromPalette(
+ (s) -> s.neutralVariantPalette, (s) -> s.isDark ? 30.0 : 80.0,
+ MaterialDynamicColors::highestSurface);
+ }
+
+ public static DynamicColor primaryContainer() {
+ return DynamicColor.fromPalette(
+ (s) -> s.primaryPalette,
+ (s) -> {
+ if (isFidelity(s)) {
+ return performAlbers(s.sourceColorHct, s);
+ }
+ if (isMonochrome(s)) {
+ return s.isDark ? 85.0 : 25.0;
+ }
+ return s.isDark ? 30.0 : 90.0;
+ },
+ MaterialDynamicColors::highestSurface);
+ }
+
+ public static DynamicColor onPrimaryContainer() {
+ return DynamicColor.fromPalette(
+ (s) -> s.primaryPalette,
+ (s) -> {
+ if (isFidelity(s)) {
+ return DynamicColor.contrastingTone(primaryContainer().tone.apply(s), 4.5);
+ }
+ if (isMonochrome(s)) {
+ return s.isDark ? 0.0 : 100.0;
+ }
+ return s.isDark ? 90.0 : 10.0;
+ },
+ (s) -> primaryContainer(),
+ null);
+ }
+
+ public static DynamicColor primary() {
+ return DynamicColor.fromPalette(
+ (s) -> s.primaryPalette,
+ (s) -> {
+ if (isMonochrome(s)) {
+ return s.isDark ? 100.0 : 0.0;
+ }
+ return s.isDark ? 80.0 : 40.0;
+ },
+ MaterialDynamicColors::highestSurface,
+ (s) ->
+ new ToneDeltaConstraint(
+ CONTAINER_ACCENT_TONE_DELTA,
+ primaryContainer(),
+ s.isDark ? TonePolarity.DARKER : TonePolarity.LIGHTER));
+ }
+
+ public static DynamicColor inversePrimary() {
+ return DynamicColor.fromPalette(
+ (s) -> s.primaryPalette, (s) -> s.isDark ? 40.0 : 80.0, (s) -> inverseSurface());
+ }
+
+ public static DynamicColor onPrimary() {
+ return DynamicColor.fromPalette(
+ (s) -> s.primaryPalette,
+ (s) -> {
+ if (isMonochrome(s)) {
+ return s.isDark ? 10.0 : 90.0;
+ }
+ return s.isDark ? 20.0 : 100.0;
+ },
+ (s) -> primary());
+ }
+
+ public static DynamicColor secondaryContainer() {
+ return DynamicColor.fromPalette(
+ (s) -> s.secondaryPalette,
+ (s) -> {
+ if (isMonochrome(s)) {
+ return s.isDark ? 30.0 : 85.0;
+ }
+ final double initialTone = s.isDark ? 30.0 : 90.0;
+ if (!isFidelity(s)) {
+ return initialTone;
+ }
+ double answer =
+ findDesiredChromaByTone(
+ s.secondaryPalette.getHue(),
+ s.secondaryPalette.getChroma(),
+ initialTone,
+ !s.isDark);
+ answer = performAlbers(s.secondaryPalette.getHct(answer), s);
+ return answer;
+ },
+ MaterialDynamicColors::highestSurface);
+ }
+
+ public static DynamicColor onSecondaryContainer() {
+ return DynamicColor.fromPalette(
+ (s) -> s.secondaryPalette,
+ (s) -> {
+ if (!isFidelity(s)) {
+ return s.isDark ? 90.0 : 10.0;
+ }
+ return DynamicColor.contrastingTone(secondaryContainer().tone.apply(s), 4.5);
+ },
+ (s) -> secondaryContainer());
+ }
+
+ public static DynamicColor secondary() {
+ return DynamicColor.fromPalette(
+ (s) -> s.secondaryPalette,
+ (s) -> s.isDark ? 80.0 : 40.0,
+ MaterialDynamicColors::highestSurface,
+ (s) ->
+ new ToneDeltaConstraint(
+ CONTAINER_ACCENT_TONE_DELTA,
+ secondaryContainer(),
+ s.isDark ? TonePolarity.DARKER : TonePolarity.LIGHTER));
+ }
+
+ public static DynamicColor onSecondary() {
+ return DynamicColor.fromPalette(
+ (s) -> s.secondaryPalette,
+ (s) -> {
+ if (isMonochrome(s)) {
+ return s.isDark ? 10.0 : 100.0;
+ }
+ return s.isDark ? 20.0 : 100.0;
+ },
+ (s) -> secondary());
+ }
+
+ public static DynamicColor tertiaryContainer() {
+ return DynamicColor.fromPalette(
+ (s) -> s.tertiaryPalette,
+ (s) -> {
+ if (isMonochrome(s)) {
+ return s.isDark ? 60.0 : 49.0;
+ }
+ if (!isFidelity(s)) {
+ return s.isDark ? 30.0 : 90.0;
+ }
+ final double albersTone =
+ performAlbers(s.tertiaryPalette.getHct(s.sourceColorHct.getTone()), s);
+ final Hct proposedHct = s.tertiaryPalette.getHct(albersTone);
+ return DislikeAnalyzer.fixIfDisliked(proposedHct).getTone();
+ },
+ MaterialDynamicColors::highestSurface);
+ }
+
+ public static DynamicColor onTertiaryContainer() {
+ return DynamicColor.fromPalette(
+ (s) -> s.tertiaryPalette,
+ (s) -> {
+ if (isMonochrome(s)) {
+ return s.isDark ? 0.0 : 100.0;
+ }
+ if (!isFidelity(s)) {
+ return s.isDark ? 90.0 : 10.0;
+ }
+ return DynamicColor.contrastingTone(tertiaryContainer().tone.apply(s), 4.5);
+ },
+ (s) -> tertiaryContainer());
+ }
+
+ public static DynamicColor tertiary() {
+ return DynamicColor.fromPalette(
+ (s) -> s.tertiaryPalette,
+ (s) -> {
+ if (isMonochrome(s)) {
+ return s.isDark ? 90.0 : 25.0;
+ }
+ return s.isDark ? 80.0 : 40.0;
+ },
+ MaterialDynamicColors::highestSurface,
+ (s) ->
+ new ToneDeltaConstraint(
+ CONTAINER_ACCENT_TONE_DELTA,
+ tertiaryContainer(),
+ s.isDark ? TonePolarity.DARKER : TonePolarity.LIGHTER));
+ }
+
+ public static DynamicColor onTertiary() {
+ return DynamicColor.fromPalette(
+ (s) -> s.tertiaryPalette,
+ (s) -> {
+ if (isMonochrome(s)) {
+ return s.isDark ? 10.0 : 90.0;
+ }
+ return s.isDark ? 20.0 : 100.0;
+ },
+ (s) -> tertiary());
+ }
+
+ public static DynamicColor errorContainer() {
+ return DynamicColor.fromPalette(
+ (s) -> s.errorPalette, (s) -> s.isDark ? 30.0 : 90.0,
+ MaterialDynamicColors::highestSurface);
+ }
+
+ public static DynamicColor onErrorContainer() {
+ return DynamicColor.fromPalette(
+ (s) -> s.errorPalette, (s) -> s.isDark ? 90.0 : 10.0, (s) -> errorContainer());
+ }
+
+ public static DynamicColor error() {
+ return DynamicColor.fromPalette(
+ (s) -> s.errorPalette,
+ (s) -> s.isDark ? 80.0 : 40.0,
+ MaterialDynamicColors::highestSurface,
+ (s) ->
+ new ToneDeltaConstraint(
+ CONTAINER_ACCENT_TONE_DELTA,
+ errorContainer(),
+ s.isDark ? TonePolarity.DARKER : TonePolarity.LIGHTER));
+ }
+
+ public static DynamicColor onError() {
+ return DynamicColor.fromPalette(
+ (s) -> s.errorPalette, (s) -> s.isDark ? 20.0 : 100.0, (s) -> error());
+ }
+
+ public static DynamicColor primaryFixed() {
+ return DynamicColor.fromPalette(
+ (s) -> s.primaryPalette,
+ (s) -> {
+ if (isMonochrome(s)) {
+ return s.isDark ? 100.0 : 10.0;
+ }
+ return 90.0;
+ },
+ MaterialDynamicColors::highestSurface);
+ }
+
+ public static DynamicColor primaryFixedDim() {
+ return DynamicColor.fromPalette(
+ (s) -> s.primaryPalette,
+ (s) -> {
+ if (isMonochrome(s)) {
+ return s.isDark ? 90.0 : 20.0;
+ }
+ return 80.0;
+ },
+ MaterialDynamicColors::highestSurface);
+ }
+
+ public static DynamicColor onPrimaryFixed() {
+ return DynamicColor.fromPalette(
+ (s) -> s.primaryPalette,
+ (s) -> {
+ if (isMonochrome(s)) {
+ return s.isDark ? 10.0 : 90.0;
+ }
+ return 10.0;
+ },
+ (s) -> primaryFixedDim());
+ }
+
+ public static DynamicColor onPrimaryFixedVariant() {
+ return DynamicColor.fromPalette(
+ (s) -> s.primaryPalette,
+ (s) -> {
+ if (isMonochrome(s)) {
+ return s.isDark ? 30.0 : 70.0;
+ }
+ return 30.0;
+ },
+ (s) -> primaryFixedDim());
+ }
+
+ public static DynamicColor secondaryFixed() {
+ return DynamicColor.fromPalette(
+ (s) -> s.secondaryPalette, (s) -> isMonochrome(s) ? 80.0 : 90.0,
+ MaterialDynamicColors::highestSurface);
+ }
+
+ public static DynamicColor secondaryFixedDim() {
+ return DynamicColor.fromPalette(
+ (s) -> s.secondaryPalette, (s) -> isMonochrome(s) ? 70.0 : 80.0,
+ MaterialDynamicColors::highestSurface);
+ }
+
+ public static DynamicColor onSecondaryFixed() {
+ return DynamicColor.fromPalette(
+ (s) -> s.secondaryPalette, (s) -> 10.0, (s) -> secondaryFixedDim());
+ }
+
+ public static DynamicColor onSecondaryFixedVariant() {
+ return DynamicColor.fromPalette(
+ (s) -> s.secondaryPalette,
+ (s) -> isMonochrome(s) ? 25.0 : 30.0,
+ (s) -> secondaryFixedDim());
+ }
+
+ public static DynamicColor tertiaryFixed() {
+ return DynamicColor.fromPalette(
+ (s) -> s.tertiaryPalette, (s) -> isMonochrome(s) ? 40.0 : 90.0,
+ MaterialDynamicColors::highestSurface);
+ }
+
+ public static DynamicColor tertiaryFixedDim() {
+ return DynamicColor.fromPalette(
+ (s) -> s.tertiaryPalette, (s) -> isMonochrome(s) ? 30.0 : 80.0,
+ MaterialDynamicColors::highestSurface);
+ }
+
+ public static DynamicColor onTertiaryFixed() {
+ return DynamicColor.fromPalette(
+ (s) -> s.tertiaryPalette, (s) -> isMonochrome(s) ? 90.0 : 10.0,
+ (s) -> tertiaryFixedDim());
+ }
+
+ public static DynamicColor onTertiaryFixedVariant() {
+ return DynamicColor.fromPalette(
+ (s) -> s.tertiaryPalette, (s) -> isMonochrome(s) ? 70.0 : 30.0,
+ (s) -> tertiaryFixedDim());
+ }
+
+ // colorControlNormal documented as textColorSecondary in M3 & GM3.
+ // In Material, textColorSecondary points to onSurfaceVariant in the non-disabled state,
+ // which is Neutral Variant T30/80 in light/dark.
+ public static DynamicColor controlNormal() {
+ return DynamicColor.fromPalette((s) -> s.neutralVariantPalette,
+ (s) -> s.isDark ? 80.0 : 30.0);
+ }
+
+ // colorControlHighlight documented, in both M3 & GM3:
+ // Light mode: #1f000000 dark mode: #33ffffff.
+ // These are black and white with some alpha.
+ // 1F hex = 31 decimal; 31 / 255 = 12% alpha.
+ // 33 hex = 51 decimal; 51 / 255 = 20% alpha.
+ // DynamicColors do not support alpha currently, and _may_ not need it for this use case,
+ // depending on how MDC resolved alpha for the other cases.
+ // Returning black in dark mode, white in light mode.
+ public static DynamicColor controlHighlight() {
+ return new DynamicColor(
+ s -> 0.0,
+ s -> 0.0,
+ s -> s.isDark ? 100.0 : 0.0,
+ s -> s.isDark ? 0.20 : 0.12,
+ null,
+ scheme ->
+
+ DynamicColor.toneMinContrastDefault((s) -> s.isDark ? 100.0 : 0.0, null,
+ scheme, null),
+ scheme ->
+ DynamicColor.toneMaxContrastDefault((s) -> s.isDark ? 100.0 : 0.0, null,
+ scheme, null),
+ null);
+ }
+
+ // textColorPrimaryInverse documented, in both M3 & GM3, documented as N10/N90.
+ public static DynamicColor textPrimaryInverse() {
+ return DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 10.0 : 90.0);
+ }
+
+ // textColorSecondaryInverse and textColorTertiaryInverse both documented, in both M3 & GM3, as
+ // NV30/NV80
+ public static DynamicColor textSecondaryAndTertiaryInverse() {
+ return DynamicColor.fromPalette((s) -> s.neutralVariantPalette,
+ (s) -> s.isDark ? 30.0 : 80.0);
+ }
+
+ // textColorPrimaryInverseDisableOnly documented, in both M3 & GM3, as N10/N90
+ public static DynamicColor textPrimaryInverseDisableOnly() {
+ return DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 10.0 : 90.0);
+ }
+
+ // textColorSecondaryInverse and textColorTertiaryInverse in disabled state both documented,
+ // in both M3 & GM3, as N10/N90
+ public static DynamicColor textSecondaryAndTertiaryInverseDisabled() {
+ return DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 10.0 : 90.0);
+ }
+
+ // textColorHintInverse documented, in both M3 & GM3, as N10/N90
+ public static DynamicColor textHintInverse() {
+ return DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 10.0 : 90.0);
+ }
}
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/scheme/SchemeTonalSpot.java b/packages/SystemUI/monet/src/com/android/systemui/monet/scheme/SchemeTonalSpot.java
index 8480684..cc6b492 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/scheme/SchemeTonalSpot.java
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/scheme/SchemeTonalSpot.java
@@ -32,7 +32,7 @@
TonalPalette.fromHueAndChroma(sourceColorHct.getHue(), 16.0),
TonalPalette.fromHueAndChroma(
MathUtils.sanitizeDegreesDouble(sourceColorHct.getHue() + 60.0), 24.0),
- TonalPalette.fromHueAndChroma(sourceColorHct.getHue(), 4.0),
+ TonalPalette.fromHueAndChroma(sourceColorHct.getHue(), 6.0),
TonalPalette.fromHueAndChroma(sourceColorHct.getHue(), 8.0));
}
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index 436145e..3244eb4 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -131,7 +131,8 @@
/**
* A rounded corner clipping that makes QS feel as if it were behind everything.
*/
- void setFancyClipping(int top, int bottom, int cornerRadius, boolean visible);
+ void setFancyClipping(int leftInset, int top, int rightInset, int bottom, int cornerRadius,
+ boolean visible, boolean fullWidth);
/**
* @return if quick settings is fully collapsed currently
diff --git a/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml b/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml
index 29832a0..934fa6f 100644
--- a/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml
+++ b/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml
@@ -30,7 +30,7 @@
<FrameLayout
android:id="@+id/inout_container"
- android:layout_height="17dp"
+ android:layout_height="@*android:dimen/status_bar_system_icon_intrinsic_size"
android:layout_width="wrap_content"
android:layout_gravity="center_vertical">
<ImageView
@@ -39,24 +39,25 @@
android:layout_width="wrap_content"
android:src="@drawable/ic_activity_down"
android:visibility="gone"
- android:paddingEnd="2dp"
+ android:paddingEnd="2sp"
/>
<ImageView
android:id="@+id/mobile_out"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/ic_activity_up"
- android:paddingEnd="2dp"
+ android:paddingEnd="2sp"
android:visibility="gone"
/>
</FrameLayout>
<ImageView
android:id="@+id/mobile_type"
- android:layout_height="wrap_content"
+ android:layout_height="@dimen/status_bar_mobile_signal_size"
android:layout_width="wrap_content"
android:layout_gravity="center_vertical"
- android:paddingStart="2.5dp"
- android:paddingEnd="1dp"
+ android:adjustViewBounds="true"
+ android:paddingStart="2.5sp"
+ android:paddingEnd="1sp"
android:visibility="gone" />
<Space
android:id="@+id/mobile_roaming_space"
@@ -70,14 +71,14 @@
android:layout_gravity="center_vertical">
<com.android.systemui.statusbar.AnimatedImageView
android:id="@+id/mobile_signal"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
+ android:layout_height="@dimen/status_bar_mobile_signal_size"
+ android:layout_width="@dimen/status_bar_mobile_signal_size"
systemui:hasOverlappingRendering="false"
/>
<ImageView
android:id="@+id/mobile_roaming"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="@dimen/status_bar_mobile_signal_size"
+ android:layout_height="@dimen/status_bar_mobile_signal_size"
android:src="@drawable/stat_sys_roaming"
android:contentDescription="@string/data_connection_roaming"
android:visibility="gone" />
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 4fc411e..4d289eb 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -22,6 +22,7 @@
<!-- Keyguard PIN pad styles -->
<style name="Keyguard.TextView" parent="@android:style/Widget.DeviceDefault.TextView">
<item name="android:textSize">@dimen/kg_status_line_font_size</item>
+ <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
</style>
<style name="Keyguard.TextView.EmergencyButton" parent="Theme.SystemUI">
<item name="android:textColor">?androidprv:attr/materialColorOnTertiaryFixed</item>
diff --git a/packages/SystemUI/res/drawable/ic_note_task_shortcut_keyguard.xml b/packages/SystemUI/res/drawable/ic_note_task_shortcut_keyguard.xml
index ee8d4883..a35504f 100644
--- a/packages/SystemUI/res/drawable/ic_note_task_shortcut_keyguard.xml
+++ b/packages/SystemUI/res/drawable/ic_note_task_shortcut_keyguard.xml
@@ -16,16 +16,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
- android:viewportHeight="24"
- android:viewportWidth="24">
+ android:viewportWidth="24"
+ android:viewportHeight="24">
<path
- android:fillAlpha="1"
- android:fillColor="@android:color/white"
- android:fillType="nonZero"
- android:pathData="M17.6258,4.96L19.0358,6.37L7.4058,18.01L5.9958,16.6L17.6258,4.96ZM16.1358,3.62L4.1258,15.63L3.0158,19.83C2.9058,20.45 3.3858,21 3.9958,21C4.0558,21 4.1058,21 4.1658,20.99L8.3658,19.88L20.3758,7.86C20.7758,7.46 20.9958,6.93 20.9958,6.37C20.9958,5.81 20.7758,5.28 20.3758,4.88L19.1058,3.61C18.7158,3.22 18.1858,3 17.6258,3C17.0658,3 16.5358,3.22 16.1358,3.62Z" />
+ android:pathData="M23.41,6L22,4.59C21.63,4.21 21.12,4 20.59,4C20.06,4 19.55,4.21 19.18,4.59L11.39,12.38L9.09,14.68L8.04,18.9C8.01,18.96 8,19.04 8,19.11C8,19.6 8.4,20 8.89,20C8.96,20 9.04,19.99 9.11,19.97L13.33,18.92L15.63,16.62L23.42,8.83C23.79,8.45 24,7.94 24,7.41C24,6.88 23.79,6.37 23.41,6ZM14.21,15.21L13.21,16.21L11.8,14.8L12.8,13.8L20.59,6L22,7.41L14.21,15.21Z"
+ android:fillColor="@android:color/white"/>
<path
- android:fillAlpha="1"
- android:fillColor="@android:color/white"
- android:fillType="nonZero"
- android:pathData="M20.1936,15.3369C20.3748,16.3837 19.9151,17.5414 18.8846,18.7597C19.1546,18.872 19.4576,18.9452 19.7724,18.9867C20.0839,19.0278 20.3683,19.0325 20.5749,19.0266C20.6772,19.0236 20.7578,19.0181 20.8101,19.0138C20.8362,19.0116 20.855,19.0097 20.8657,19.0085L20.8754,19.0074L20.875,19.0075C21.4217,18.9385 21.9214,19.325 21.9918,19.8718C22.0624,20.4195 21.6756,20.9208 21.1279,20.9914L21,19.9996C21.1279,20.9914 21.1265,20.9916 21.1265,20.9916L21.1249,20.9918L21.1211,20.9923L21.1107,20.9935L21.0795,20.997C21.0542,20.9998 21.0199,21.0032 20.9775,21.0067C20.8929,21.0138 20.7753,21.0216 20.6323,21.0257C20.3481,21.0339 19.9533,21.0279 19.5109,20.9695C18.873,20.8854 18.0393,20.6793 17.3106,20.1662C16.9605,20.3559 16.5876,20.4952 16.2299,20.6003C15.5742,20.7927 14.8754,20.8968 14.2534,20.9534C13.6801,21.0055 13.4553,21.0037 13.1015,21.0008C13.0689,21.0005 13.0352,21.0002 13,21H12.8594C12.8214,21.0002 12.785,21.0006 12.7504,21.0009C12.6524,21.0019 12.5683,21.0027 12.5,21H12.0562C12.0277,21.0003 12.0054,21.0006 11.9926,21.001L11.9751,21H9L11,19H11.9795C11.9929,18.9997 12.0064,18.9997 12.0199,19H12.4117C12.4534,18.9996 12.4864,18.9995 12.5,19H12.9675C12.977,18.9999 12.9878,18.9999 13,19C13.0446,19.0003 13.0859,19.0007 13.1249,19.0011C13.4259,19.0038 13.591,19.0054 14.0723,18.9616C14.6201,18.9118 15.1795,18.8242 15.6665,18.6813C15.753,18.6559 15.8346,18.6295 15.9114,18.6022C15.0315,17.2981 14.7125,16.1044 15.015,15.0829C15.4095,13.7511 16.6784,13.2418 17.7026,13.2864C18.7262,13.3309 19.954,13.9529 20.1936,15.3369ZM16.9327,15.6508C16.873,15.8523 16.8651,16.3878 17.4697,17.334C18.2007,16.4284 18.2585,15.8839 18.2229,15.6781C18.1939,15.5108 18.0297,15.3025 17.6157,15.2845C17.2025,15.2665 16.9885,15.4626 16.9327,15.6508Z" />
+ android:pathData="M6.688,20C2.047,20 0.333,18.65 0.333,16C0.333,13.61 2.439,12.474 5.713,12C6.792,11.844 7.344,11.397 7.344,10.927C7.344,9.625 4.679,9.705 3.833,9.667V7.667C3.833,7.667 6.792,7.667 8.208,8.729C8.932,9.272 9.333,9.979 9.333,11.05C9.333,12.52 8.281,13.677 5.713,13.885C4.017,14.023 2.333,14.52 2.333,16C2.333,17.33 4.013,18 7.333,18L6.688,20Z"
+ android:fillColor="@android:color/white"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_note_task_shortcut_widget.xml b/packages/SystemUI/res/drawable/ic_note_task_shortcut_widget.xml
index 7590182..860fc7d 100644
--- a/packages/SystemUI/res/drawable/ic_note_task_shortcut_widget.xml
+++ b/packages/SystemUI/res/drawable/ic_note_task_shortcut_widget.xml
@@ -13,19 +13,7 @@
~ 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:viewportHeight="24"
- android:viewportWidth="24">
- <path
- android:fillAlpha="1"
- android:fillColor="#636C6F"
- android:fillType="nonZero"
- android:pathData="M17.6258,4.96L19.0358,6.37L7.4058,18.01L5.9958,16.6L17.6258,4.96ZM16.1358,3.62L4.1258,15.63L3.0158,19.83C2.9058,20.45 3.3858,21 3.9958,21C4.0558,21 4.1058,21 4.1658,20.99L8.3658,19.88L20.3758,7.86C20.7758,7.46 20.9958,6.93 20.9958,6.37C20.9958,5.81 20.7758,5.28 20.3758,4.88L19.1058,3.61C18.7158,3.22 18.1858,3 17.6258,3C17.0658,3 16.5358,3.22 16.1358,3.62Z" />
- <path
- android:fillAlpha="1"
- android:fillColor="#636C6F"
- android:fillType="nonZero"
- android:pathData="M20.1936,15.3369C20.3748,16.3837 19.9151,17.5414 18.8846,18.7597C19.1546,18.872 19.4576,18.9452 19.7724,18.9867C20.0839,19.0278 20.3683,19.0325 20.5749,19.0266C20.6772,19.0236 20.7578,19.0181 20.8101,19.0138C20.8362,19.0116 20.855,19.0097 20.8657,19.0085L20.8754,19.0074L20.875,19.0075C21.4217,18.9385 21.9214,19.325 21.9918,19.8718C22.0624,20.4195 21.6756,20.9208 21.1279,20.9914L21,19.9996C21.1279,20.9914 21.1265,20.9916 21.1265,20.9916L21.1249,20.9918L21.1211,20.9923L21.1107,20.9935L21.0795,20.997C21.0542,20.9998 21.0199,21.0032 20.9775,21.0067C20.8929,21.0138 20.7753,21.0216 20.6323,21.0257C20.3481,21.0339 19.9533,21.0279 19.5109,20.9695C18.873,20.8854 18.0393,20.6793 17.3106,20.1662C16.9605,20.3559 16.5876,20.4952 16.2299,20.6003C15.5742,20.7927 14.8754,20.8968 14.2534,20.9534C13.6801,21.0055 13.4553,21.0037 13.1015,21.0008C13.0689,21.0005 13.0352,21.0002 13,21H12.8594C12.8214,21.0002 12.785,21.0006 12.7504,21.0009C12.6524,21.0019 12.5683,21.0027 12.5,21H12.0562C12.0277,21.0003 12.0054,21.0006 11.9926,21.001L11.9751,21H9L11,19H11.9795C11.9929,18.9997 12.0064,18.9997 12.0199,19H12.4117C12.4534,18.9996 12.4864,18.9995 12.5,19H12.9675C12.977,18.9999 12.9878,18.9999 13,19C13.0446,19.0003 13.0859,19.0007 13.1249,19.0011C13.4259,19.0038 13.591,19.0054 14.0723,18.9616C14.6201,18.9118 15.1795,18.8242 15.6665,18.6813C15.753,18.6559 15.8346,18.6295 15.9114,18.6022C15.0315,17.2981 14.7125,16.1044 15.015,15.0829C15.4095,13.7511 16.6784,13.2418 17.7026,13.2864C18.7262,13.3309 19.954,13.9529 20.1936,15.3369ZM16.9327,15.6508C16.873,15.8523 16.8651,16.3878 17.4697,17.334C18.2007,16.4284 18.2585,15.8839 18.2229,15.6781C18.1939,15.5108 18.0297,15.3025 17.6157,15.2845C17.2025,15.2665 16.9885,15.4626 16.9327,15.6508Z" />
-</vector>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/ic_note_task_shortcut_widget_background" />
+ <foreground android:drawable="@drawable/ic_note_task_shortcut_widget_foreground" />
+</adaptive-icon>
diff --git a/packages/SystemUI/res/drawable/ic_note_task_shortcut_widget_background.xml b/packages/SystemUI/res/drawable/ic_note_task_shortcut_widget_background.xml
new file mode 100644
index 0000000..9f98f07
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_note_task_shortcut_widget_background.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2023 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="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:pathData="M0,0h108v108h-108z"
+ android:fillColor="#0B57D0"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_note_task_shortcut_widget_foreground.xml b/packages/SystemUI/res/drawable/ic_note_task_shortcut_widget_foreground.xml
new file mode 100644
index 0000000..fcb3ef4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_note_task_shortcut_widget_foreground.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2023 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="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:pathData="M74.92,43L72.33,40.42C71.65,39.72 70.72,39.33 69.75,39.33C68.78,39.33 67.84,39.72 67.16,40.42L52.88,54.7L48.67,58.91L46.74,66.65C46.69,66.76 46.67,66.91 46.67,67.04C46.67,67.93 47.4,68.67 48.3,68.67C48.43,68.67 48.57,68.65 48.7,68.61L56.44,66.69L60.65,62.47L74.94,48.19C75.61,47.49 76,46.56 76,45.58C76,44.61 75.61,43.68 74.92,43ZM58.05,59.88L56.22,61.72L53.63,59.13L55.47,57.3L69.75,43L72.33,45.58L58.05,59.88Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M44.26,68.67C35.75,68.67 32.61,66.19 32.61,61.33C32.61,56.95 36.47,54.87 42.47,54C44.45,53.71 45.46,52.89 45.46,52.03C45.46,49.65 40.58,49.79 39.03,49.72V46.06C39.03,46.06 44.45,46.06 47.05,48C48.37,49 49.11,50.3 49.11,52.26C49.11,54.95 47.18,57.07 42.47,57.46C39.36,57.71 36.28,58.62 36.28,61.33C36.28,63.77 39.36,65 45.44,65L44.26,68.67Z"
+ android:fillColor="#ffffff"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/combined_qs_header.xml b/packages/SystemUI/res/layout/combined_qs_header.xml
index 441f963..e989372 100644
--- a/packages/SystemUI/res/layout/combined_qs_header.xml
+++ b/packages/SystemUI/res/layout/combined_qs_header.xml
@@ -126,8 +126,7 @@
<com.android.systemui.battery.BatteryMeterView
android:id="@+id/batteryRemainingIcon"
android:layout_width="wrap_content"
- android:layout_height="@dimen/large_screen_shade_header_min_height"
- app:layout_constraintHeight_min="@dimen/large_screen_shade_header_min_height"
+ android:layout_height="0dp"
app:layout_constrainedWidth="true"
app:textAppearance="@style/TextAppearance.QS.Status"
app:layout_constraintStart_toEndOf="@id/statusIcons"
diff --git a/packages/SystemUI/res/layout/screen_share_dialog.xml b/packages/SystemUI/res/layout/screen_share_dialog.xml
index 7dbe059..0d86e0a 100644
--- a/packages/SystemUI/res/layout/screen_share_dialog.xml
+++ b/packages/SystemUI/res/layout/screen_share_dialog.xml
@@ -76,7 +76,7 @@
android:orientation="horizontal"
android:layout_marginTop="@dimen/screenrecord_buttons_margin_top">
<TextView
- android:id="@+id/button_cancel"
+ android:id="@android:id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
@@ -87,7 +87,7 @@
android:layout_height="match_parent"
android:layout_weight="1"/>
<TextView
- android:id="@+id/button_start"
+ android:id="@android:id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
diff --git a/packages/SystemUI/res/layout/status_bar_wifi_group_inner.xml b/packages/SystemUI/res/layout/status_bar_wifi_group_inner.xml
index 0ea0653..473ab08 100644
--- a/packages/SystemUI/res/layout/status_bar_wifi_group_inner.xml
+++ b/packages/SystemUI/res/layout/status_bar_wifi_group_inner.xml
@@ -24,11 +24,11 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
- android:layout_marginStart="2.5dp"
+ android:layout_marginStart="2.5sp"
>
<FrameLayout
android:id="@+id/inout_container"
- android:layout_height="17dp"
+ android:layout_height="@*android:dimen/status_bar_system_icon_intrinsic_size"
android:layout_width="wrap_content"
android:gravity="center_vertical" >
<ImageView
@@ -37,14 +37,14 @@
android:layout_width="wrap_content"
android:src="@drawable/ic_activity_down"
android:visibility="gone"
- android:paddingEnd="2dp"
+ android:paddingEnd="2sp"
/>
<ImageView
android:id="@+id/wifi_out"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/ic_activity_up"
- android:paddingEnd="2dp"
+ android:paddingEnd="2sp"
android:visibility="gone"
/>
</FrameLayout>
@@ -62,7 +62,7 @@
<View
android:id="@+id/wifi_signal_spacer"
android:layout_width="@dimen/status_bar_wifi_signal_spacer_width"
- android:layout_height="4dp"
+ android:layout_height="4sp"
android:visibility="gone" />
<!-- Looks like CarStatusBar uses this... -->
@@ -75,7 +75,7 @@
<View
android:id="@+id/wifi_airplane_spacer"
android:layout_width="@dimen/status_bar_airplane_spacer_width"
- android:layout_height="4dp"
+ android:layout_height="4sp"
android:visibility="gone"
/>
</com.android.keyguard.AlphaOptimizedLinearLayout>
diff --git a/packages/SystemUI/res/raw/biometricprompt_rear_landscape_base.json b/packages/SystemUI/res/raw/biometricprompt_rear_landscape_base.json
new file mode 100644
index 0000000..49c1c40
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_rear_landscape_base.json
@@ -0,0 +1 @@
+{"v":"5.8.1","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"BiometricPrompt_Rear_Landscape_Base_Foldable","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 18","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[169.478,169.749,0],"ix":2,"l":2},"a":{"a":0,"k":[-48.123,-30.19,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".grey400","cl":"grey400","parent":13,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.741176486015,0.75686275959,0.776470601559,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"black circle matte","parent":13,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".grey904","cl":"grey904","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-62.577,35.536,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-2.552,0.087],[0,0]],"o":[[0,0],[0,-3.287],[0,0],[0,0]],"v":[[-2.301,8.869],[-2.301,-3.772],[2.301,-9.806],[2.301,9.806]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"black circle matte 2","parent":13,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".blue401","cl":"blue401","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-62.577,-27.655,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,3.286],[0,0],[-2.552,0.086],[0,0]],"o":[[0,0],[0,-3.286],[0,0],[-2.552,-0.086]],"v":[[-2.301,16.282],[-2.301,-16.281],[2.301,-22.313],[2.301,22.313]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"black circle matte 3","parent":13,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Finger 2","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-129,"s":[-67]},{"t":-29,"s":[0]}],"ix":10},"p":{"a":0,"k":[-75.352,41.307,0],"ix":2,"l":2},"a":{"a":0,"k":[94.648,211.307,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[6.72,-5.642],[0,0],[-9.394,-0.562],[-0.298,-0.038]],"o":[[-5.153,4.329],[3.882,-16.05],[0.31,0.019],[-0.044,0.75]],"v":[[0.863,12.222],[-8.931,14.755],[8.005,-15.108],[8.931,-15.021]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.792156875134,0.454901963472,0.376470595598,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[81.486,130.081],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 9","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.459,6.045],[-5.153,4.329],[-0.044,0.75],[3.116,-24.664],[5.23,-22.052],[8.666,11.92],[-2.9,9.135]],"o":[[0,0],[6.72,-5.642],[12.723,1.335],[-2.369,18.762],[-13.993,-5.333],[2.255,-5.502],[1.843,-5.815]],"v":[[-9.99,-18.348],[-0.196,-20.881],[7.872,-48.124],[21.578,-9.331],[12.104,48.124],[-22.574,21.555],[-14.791,-0.206]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.713725507259,0.384313732386,0.282352954149,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[82.545,163.184],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 8","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"black circle matte 4","parent":13,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".grey903","cl":"grey903","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-18.345,-92.442,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[24.07,0],[0,0],[-8.27,0],[0,0]],"o":[[0,0],[0,8.269],[0,0],[-14.024,-17.379]],"v":[[-29.778,-14.252],[-29.778,-0.721],[-14.805,14.252],[29.778,14.252]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"black circle matte 5","parent":13,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".grey902","cl":"grey902","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-15.947,-30.19,0],"ix":2,"l":2},"a":{"a":0,"k":[154.053,139.81,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[2.3,0.367],[0,0],[-2.364,0.157],[0,0]],"o":[[0,0],[2.3,-0.367],[0,0],[-2.364,-0.157]],"v":[[-3.5,75.533],[-3.5,-75.533],[3.5,-76.312],[3.5,76.312]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[113.225,139.81],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 7","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,8.269],[0,0],[2.181,-0.187],[0,0],[-2.23,0],[0,42.252],[10.593,13.127],[0,0]],"o":[[0,0],[-2.23,0],[0,0],[2.181,0.187],[42.252,0],[0,-18.182],[0,0],[-8.27,0]],"v":[[-34.946,-62.973],[-34.946,-76.504],[-41.558,-76.201],[-41.558,76.201],[-34.946,76.504],[41.558,0],[24.61,-48],[-19.973,-48]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[156.824,139.81],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 5","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".black 2","cl":"black","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-48.123,-30.19,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":-129,"s":[0,0,100]},{"t":-79,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".grey700","cl":"grey700","parent":15,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-56.481,-59.936,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[3.767,0],[0,0],[0,-3.767],[0,0],[-3.767,0],[0,0],[0,3.767],[0,0]],"o":[[0,0],[-3.767,0],[0,0],[0,3.767],[0,0],[3.767,0],[0,0],[0,-3.767]],"v":[[46.055,-14.479],[-46.056,-14.479],[-52.876,-7.659],[-52.876,7.658],[-46.056,14.479],[46.055,14.479],[52.876,7.658],[52.876,-7.659]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":".grey901","cl":"grey901","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[16.485,2.727,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[4.184,0],[0,0],[0,0],[0,0],[0,-4.375]],"o":[[0,4.184],[0,0],[0,0],[0,0],[4.375,0],[0,0]],"v":[[114.116,92.129],[106.54,99.705],[7.788,99.705],[7.788,-99.704],[106.161,-99.704],[114.116,-91.749]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[5.707,0],[0,0],[1.894,-1.05],[0.886,0.346],[0,0],[2.166,0],[0,0],[0,-5.707],[0,0],[0,-1.46],[0,0],[-1.133,-0.038],[0,0],[0,-1.459],[0,0],[-1.133,-0.038],[0,0],[-5.708,0],[0,0],[-1.894,1.05],[-0.846,-0.289],[0,0],[-2.166,0],[0,0],[0,5.706],[0,0]],"o":[[0,0],[-2.166,0],[-0.883,0.354],[0,0],[-1.895,-1.05],[0,0],[-5.708,0],[0,0],[-1.133,0.038],[0,0],[0,1.46],[0,0],[-1.133,0.038],[0,0],[0,1.46],[0,0],[0,5.707],[0,0],[2.165,0],[0.833,-0.334],[0,0],[1.894,1.05],[0,0],[5.707,0],[0,0],[0,-5.707]],"v":[[106.16,-102.082],[8.455,-102.082],[2.265,-100.48],[-0.488,-100.468],[-0.519,-100.48],[-6.71,-102.082],[-104.116,-102.082],[-114.45,-91.748],[-114.45,-36.119],[-116.494,-33.44],[-116.494,-18.979],[-114.45,-16.3],[-114.45,-0.877],[-116.494,1.802],[-116.494,28.704],[-114.45,31.383],[-114.45,91.749],[-104.116,102.083],[-6.495,102.083],[-0.305,100.481],[2.294,100.425],[2.395,100.481],[9.872,102.083],[106.161,102.083],[116.494,91.75],[116.494,-91.748]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.529411792755,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_rear_portrait_base.json b/packages/SystemUI/res/raw/biometricprompt_rear_portrait_base.json
new file mode 100644
index 0000000..9ea0d35
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_rear_portrait_base.json
@@ -0,0 +1 @@
+{"v":"5.8.1","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"BiometricPrompt_Rear_Portrait_Base_Foldable","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 18","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[169.478,169.749,0],"ix":2,"l":2},"a":{"a":0,"k":[-48.123,-30.19,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".grey400","cl":"grey400","parent":14,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.741176486015,0.75686275959,0.776470601559,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"black circle matte","parent":14,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".grey904","cl":"grey904","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-62.577,35.536,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-2.552,0.087],[0,0]],"o":[[0,0],[0,-3.287],[0,0],[0,0]],"v":[[-2.301,8.869],[-2.301,-3.772],[2.301,-9.806],[2.301,9.806]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"black circle matte 2","parent":14,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".blue401","cl":"blue401","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-62.577,-27.655,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,3.286],[0,0],[-2.552,0.086],[0,0]],"o":[[0,0],[0,-3.286],[0,0],[-2.552,-0.086]],"v":[[-2.301,16.282],[-2.301,-16.281],[2.301,-22.313],[2.301,22.313]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"black circle matte 3","parent":14,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Finger 3","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-2,"ix":10},"p":{"a":0,"k":[260.134,83.782,0],"ix":2,"l":2},"a":{"a":0,"k":[302.634,38.782,0],"ix":1,"l":2},"s":{"a":0,"k":[178,178,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.262,5.076],[0,0],[-0.424,-7.095],[-0.028,-0.225]],"o":[[3.269,-3.892],[-12.123,2.932],[0.015,0.234],[0.567,-0.034]],"v":[[9.232,0.652],[11.145,-6.746],[-11.412,6.046],[-11.346,6.746]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.792156875134,0.454901963472,0.376470595598,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[241.281,55.033],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 5","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[4.565,-1.102],[3.269,-3.892],[0.566,-0.033],[-18.63,2.353],[-16.656,3.951],[9.004,6.546],[6.9,-2.19]],"o":[[0,0],[-4.262,5.076],[1.008,9.61],[14.171,-1.79],[-4.028,-10.569],[-4.156,1.703],[-4.392,1.392]],"v":[[-13.858,-7.546],[-15.771,-0.148],[-36.349,5.946],[-7.047,16.299],[36.349,9.142],[16.281,-17.051],[-0.156,-11.172]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.713725507259,0.384313732386,0.282352954149,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[266.285,55.833],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 4","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"black circle matte 4","parent":14,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".grey903","cl":"grey903","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-18.345,-92.442,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[24.07,0],[0,0],[-8.27,0],[0,0]],"o":[[0,0],[0,8.269],[0,0],[-14.024,-17.379]],"v":[[-29.778,-14.252],[-29.778,-0.721],[-14.805,14.252],[29.778,14.252]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"black circle matte 5","parent":14,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".grey902","cl":"grey902","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-15.947,-30.19,0],"ix":2,"l":2},"a":{"a":0,"k":[154.053,139.81,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[2.3,0.367],[0,0],[-2.364,0.157],[0,0]],"o":[[0,0],[2.3,-0.367],[0,0],[-2.364,-0.157]],"v":[[-3.5,75.533],[-3.5,-75.533],[3.5,-76.312],[3.5,76.312]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[113.225,139.81],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 7","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,8.269],[0,0],[2.181,-0.187],[0,0],[-2.23,0],[0,42.252],[10.593,13.127],[0,0]],"o":[[0,0],[-2.23,0],[0,0],[2.181,0.187],[42.252,0],[0,-18.182],[0,0],[-8.27,0]],"v":[[-34.946,-62.973],[-34.946,-76.504],[-41.558,-76.201],[-41.558,76.201],[-34.946,76.504],[41.558,0],[24.61,-48],[-19.973,-48]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[156.824,139.81],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 5","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".black 2","cl":"black","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-48.123,-30.19,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":-129,"s":[0,0,100]},{"t":-79,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":".grey700","cl":"grey700","parent":16,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-56.481,-59.936,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[3.767,0],[0,0],[0,-3.767],[0,0],[-3.767,0],[0,0],[0,3.767],[0,0]],"o":[[0,0],[-3.767,0],[0,0],[0,3.767],[0,0],[3.767,0],[0,0],[0,-3.767]],"v":[[46.055,-14.479],[-46.056,-14.479],[-52.876,-7.659],[-52.876,7.658],[-46.056,14.479],[46.055,14.479],[52.876,7.658],[52.876,-7.659]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":".grey901","cl":"grey901","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[16.485,2.727,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[4.184,0],[0,0],[0,0],[0,0],[0,-4.375]],"o":[[0,4.184],[0,0],[0,0],[0,0],[4.375,0],[0,0]],"v":[[114.116,92.129],[106.54,99.705],[7.788,99.705],[7.788,-99.704],[106.161,-99.704],[114.116,-91.749]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[5.707,0],[0,0],[1.894,-1.05],[0.886,0.346],[0,0],[2.166,0],[0,0],[0,-5.707],[0,0],[0,-1.46],[0,0],[-1.133,-0.038],[0,0],[0,-1.459],[0,0],[-1.133,-0.038],[0,0],[-5.708,0],[0,0],[-1.894,1.05],[-0.846,-0.289],[0,0],[-2.166,0],[0,0],[0,5.706],[0,0]],"o":[[0,0],[-2.166,0],[-0.883,0.354],[0,0],[-1.895,-1.05],[0,0],[-5.708,0],[0,0],[-1.133,0.038],[0,0],[0,1.46],[0,0],[-1.133,0.038],[0,0],[0,1.46],[0,0],[0,5.707],[0,0],[2.165,0],[0.833,-0.334],[0,0],[1.894,1.05],[0,0],[5.707,0],[0,0],[0,-5.707]],"v":[[106.16,-102.082],[8.455,-102.082],[2.265,-100.48],[-0.488,-100.468],[-0.519,-100.48],[-6.71,-102.082],[-104.116,-102.082],[-114.45,-91.748],[-114.45,-36.119],[-116.494,-33.44],[-116.494,-18.979],[-114.45,-16.3],[-114.45,-0.877],[-116.494,1.802],[-116.494,28.704],[-114.45,31.383],[-114.45,91.749],[-104.116,102.083],[-6.495,102.083],[-0.305,100.481],[2.294,100.425],[2.395,100.481],[9.872,102.083],[106.161,102.083],[116.494,91.75],[116.494,-91.748]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.529411792755,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_rear_portrait_reverse_base.json b/packages/SystemUI/res/raw/biometricprompt_rear_portrait_reverse_base.json
new file mode 100644
index 0000000..f2b2593
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_rear_portrait_reverse_base.json
@@ -0,0 +1 @@
+{"v":"5.8.1","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"BiometricPrompt_Rear_Portrait_Reverse_Base_Foldable","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 18","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":270,"ix":10},"p":{"a":0,"k":[169.478,169.749,0],"ix":2,"l":2},"a":{"a":0,"k":[-48.123,-30.19,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".grey400","cl":"grey400","parent":13,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.741176486015,0.75686275959,0.776470601559,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"black circle matte","parent":13,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".grey904","cl":"grey904","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-62.577,35.536,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-2.552,0.087],[0,0]],"o":[[0,0],[0,-3.287],[0,0],[0,0]],"v":[[-2.301,8.869],[-2.301,-3.772],[2.301,-9.806],[2.301,9.806]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"black circle matte 2","parent":13,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".blue401","cl":"blue401","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-62.577,-27.655,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,3.286],[0,0],[-2.552,0.086],[0,0]],"o":[[0,0],[0,-3.286],[0,0],[-2.552,-0.086]],"v":[[-2.301,16.282],[-2.301,-16.281],[2.301,-22.313],[2.301,22.313]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"black circle matte 3","parent":13,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Finger 2","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-75.352,41.307,0],"ix":2,"l":2},"a":{"a":0,"k":[94.648,211.307,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[6.72,-5.642],[0,0],[-9.394,-0.562],[-0.298,-0.038]],"o":[[-5.153,4.329],[3.882,-16.05],[0.31,0.019],[-0.044,0.75]],"v":[[0.863,12.222],[-8.931,14.755],[8.005,-15.108],[8.931,-15.021]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.792156875134,0.454901963472,0.376470595598,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[81.486,130.081],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 9","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.459,6.045],[-5.153,4.329],[-0.044,0.75],[3.116,-24.664],[5.23,-22.052],[8.666,11.92],[-2.9,9.135]],"o":[[0,0],[6.72,-5.642],[12.723,1.335],[-2.369,18.762],[-13.993,-5.333],[2.255,-5.502],[1.843,-5.815]],"v":[[-9.99,-18.348],[-0.196,-20.881],[7.872,-48.124],[21.578,-9.331],[12.104,48.124],[-22.574,21.555],[-14.791,-0.206]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.713725507259,0.384313732386,0.282352954149,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[82.545,163.184],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 8","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"black circle matte 4","parent":13,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".grey903","cl":"grey903","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-18.345,-92.442,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[24.07,0],[0,0],[-8.27,0],[0,0]],"o":[[0,0],[0,8.269],[0,0],[-14.024,-17.379]],"v":[[-29.778,-14.252],[-29.778,-0.721],[-14.805,14.252],[29.778,14.252]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"black circle matte 5","parent":13,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".grey902","cl":"grey902","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-15.947,-30.19,0],"ix":2,"l":2},"a":{"a":0,"k":[154.053,139.81,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[2.3,0.367],[0,0],[-2.364,0.157],[0,0]],"o":[[0,0],[2.3,-0.367],[0,0],[-2.364,-0.157]],"v":[[-3.5,75.533],[-3.5,-75.533],[3.5,-76.312],[3.5,76.312]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[113.225,139.81],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 7","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,8.269],[0,0],[2.181,-0.187],[0,0],[-2.23,0],[0,42.252],[10.593,13.127],[0,0]],"o":[[0,0],[-2.23,0],[0,0],[2.181,0.187],[42.252,0],[0,-18.182],[0,0],[-8.27,0]],"v":[[-34.946,-62.973],[-34.946,-76.504],[-41.558,-76.201],[-41.558,76.201],[-34.946,76.504],[41.558,0],[24.61,-48],[-19.973,-48]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[156.824,139.81],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 5","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".black 2","cl":"black","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-48.123,-30.19,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":-129,"s":[0,0,100]},{"t":-79,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".grey700","cl":"grey700","parent":15,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-56.481,-59.936,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[3.767,0],[0,0],[0,-3.767],[0,0],[-3.767,0],[0,0],[0,3.767],[0,0]],"o":[[0,0],[-3.767,0],[0,0],[0,3.767],[0,0],[3.767,0],[0,0],[0,-3.767]],"v":[[46.055,-14.479],[-46.056,-14.479],[-52.876,-7.659],[-52.876,7.658],[-46.056,14.479],[46.055,14.479],[52.876,7.658],[52.876,-7.659]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":".grey901","cl":"grey901","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[16.485,2.727,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[4.184,0],[0,0],[0,0],[0,0],[0,-4.375]],"o":[[0,4.184],[0,0],[0,0],[0,0],[4.375,0],[0,0]],"v":[[114.116,92.129],[106.54,99.705],[7.788,99.705],[7.788,-99.704],[106.161,-99.704],[114.116,-91.749]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[5.707,0],[0,0],[1.894,-1.05],[0.886,0.346],[0,0],[2.166,0],[0,0],[0,-5.707],[0,0],[0,-1.46],[0,0],[-1.133,-0.038],[0,0],[0,-1.459],[0,0],[-1.133,-0.038],[0,0],[-5.708,0],[0,0],[-1.894,1.05],[-0.846,-0.289],[0,0],[-2.166,0],[0,0],[0,5.706],[0,0]],"o":[[0,0],[-2.166,0],[-0.883,0.354],[0,0],[-1.895,-1.05],[0,0],[-5.708,0],[0,0],[-1.133,0.038],[0,0],[0,1.46],[0,0],[-1.133,0.038],[0,0],[0,1.46],[0,0],[0,5.707],[0,0],[2.165,0],[0.833,-0.334],[0,0],[1.894,1.05],[0,0],[5.707,0],[0,0],[0,-5.707]],"v":[[106.16,-102.082],[8.455,-102.082],[2.265,-100.48],[-0.488,-100.468],[-0.519,-100.48],[-6.71,-102.082],[-104.116,-102.082],[-114.45,-91.748],[-114.45,-36.119],[-116.494,-33.44],[-116.494,-18.979],[-114.45,-16.3],[-114.45,-0.877],[-116.494,1.802],[-116.494,28.704],[-114.45,31.383],[-114.45,91.749],[-104.116,102.083],[-6.495,102.083],[-0.305,100.481],[2.294,100.425],[2.395,100.481],[9.872,102.083],[106.161,102.083],[116.494,91.75],[116.494,-91.748]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.529411792755,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml
index 2086459..f40615e 100644
--- a/packages/SystemUI/res/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp/dimens.xml
@@ -17,7 +17,7 @@
-->
<resources>
<!-- gap on either side of status bar notification icons -->
- <dimen name="status_bar_icon_padding">1dp</dimen>
+ <dimen name="status_bar_icon_padding">1sp</dimen>
<dimen name="controls_header_horizontal_padding">28dp</dimen>
<dimen name="controls_content_margin_horizontal">40dp</dimen>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 0aa880f..f5c4a4e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -122,26 +122,26 @@
<dimen name="status_bar_icon_size">@*android:dimen/status_bar_icon_size</dimen>
<!-- Default horizontal drawable padding for status bar icons. -->
- <dimen name="status_bar_horizontal_padding">2.5dp</dimen>
+ <dimen name="status_bar_horizontal_padding">2.5sp</dimen>
<!-- Height of the battery icon in the status bar. -->
- <dimen name="status_bar_battery_icon_height">13.0dp</dimen>
+ <dimen name="status_bar_battery_icon_height">13.0sp</dimen>
<!-- Width of the battery icon in the status bar. The battery drawable assumes a 12x20 canvas,
- so the width of the icon should be 13.0dp * (12.0 / 20.0) -->
- <dimen name="status_bar_battery_icon_width">7.8dp</dimen>
+ so the width of the icon should be 13.0sp * (12.0 / 20.0) -->
+ <dimen name="status_bar_battery_icon_width">7.8sp</dimen>
- <!-- The battery icon is 13dp tall, but the other system icons are 15dp tall (see
+ <!-- The battery icon is 13sp tall, but the other system icons are 15sp tall (see
@*android:dimen/status_bar_system_icon_size) with some top and bottom padding embedded in
- the drawables themselves. So, the battery icon may need an extra 1dp of spacing so that its
+ the drawables themselves. So, the battery icon may need an extra 1sp of spacing so that its
bottom still aligns with the bottom of all the other system icons. See b/258672854. -->
- <dimen name="status_bar_battery_extra_vertical_spacing">1dp</dimen>
+ <dimen name="status_bar_battery_extra_vertical_spacing">1sp</dimen>
<!-- The font size for the clock in the status bar. -->
<dimen name="status_bar_clock_size">14sp</dimen>
<!-- The starting padding for the clock in the status bar. -->
- <dimen name="status_bar_clock_starting_padding">7dp</dimen>
+ <dimen name="status_bar_clock_starting_padding">7sp</dimen>
<!-- The end padding for the clock in the status bar. -->
<dimen name="status_bar_clock_end_padding">0dp</dimen>
@@ -153,16 +153,19 @@
<dimen name="status_bar_left_clock_end_padding">2dp</dimen>
<!-- Spacing after the wifi signals that is present if there are any icons following it. -->
- <dimen name="status_bar_wifi_signal_spacer_width">2.5dp</dimen>
+ <dimen name="status_bar_wifi_signal_spacer_width">2.5sp</dimen>
<!-- Size of the view displaying the wifi signal icon in the status bar. -->
- <dimen name="status_bar_wifi_signal_size">@*android:dimen/status_bar_system_icon_size</dimen>
+ <dimen name="status_bar_wifi_signal_size">13sp</dimen>
+
+ <!-- Size of the view displaying the mobile signal icon in the status bar. -->
+ <dimen name="status_bar_mobile_signal_size">13sp</dimen>
<!-- Spacing before the airplane mode icon if there are any icons preceding it. -->
- <dimen name="status_bar_airplane_spacer_width">4dp</dimen>
+ <dimen name="status_bar_airplane_spacer_width">4sp</dimen>
<!-- Spacing between system icons. -->
- <dimen name="status_bar_system_icon_spacing">0dp</dimen>
+ <dimen name="status_bar_system_icon_spacing">2sp</dimen>
<!-- The amount to scale each of the status bar icons by. A value of 1 means no scaling. -->
<item name="status_bar_icon_scale_factor" format="float" type="dimen">1.0</item>
@@ -310,7 +313,7 @@
<dimen name="snooze_snackbar_min_height">56dp</dimen>
<!-- size at which Notification icons will be drawn in the status bar -->
- <dimen name="status_bar_icon_drawing_size">15dp</dimen>
+ <dimen name="status_bar_icon_drawing_size">15sp</dimen>
<!-- size at which Notification icons will be drawn on Ambient Display -->
<dimen name="status_bar_icon_drawing_size_dark">
@@ -321,22 +324,22 @@
<item type="dimen" name="status_bar_icon_drawing_alpha">90%</item>
<!-- gap on either side of status bar notification icons -->
- <dimen name="status_bar_icon_padding">0dp</dimen>
+ <dimen name="status_bar_icon_padding">0sp</dimen>
<!-- the padding on the start of the statusbar -->
- <dimen name="status_bar_padding_start">8dp</dimen>
+ <dimen name="status_bar_padding_start">8sp</dimen>
<!-- the padding on the end of the statusbar -->
- <dimen name="status_bar_padding_end">8dp</dimen>
+ <dimen name="status_bar_padding_end">8sp</dimen>
<!-- the padding on the top of the statusbar (usually 0) -->
- <dimen name="status_bar_padding_top">0dp</dimen>
+ <dimen name="status_bar_padding_top">0sp</dimen>
<!-- the radius of the overflow dot in the status bar -->
- <dimen name="overflow_dot_radius">2dp</dimen>
+ <dimen name="overflow_dot_radius">2sp</dimen>
<!-- the padding between dots in the icon overflow -->
- <dimen name="overflow_icon_dot_padding">3dp</dimen>
+ <dimen name="overflow_icon_dot_padding">3sp</dimen>
<!-- Dimensions related to screenshots -->
@@ -617,8 +620,8 @@
<dimen name="qs_footer_icon_size">20dp</dimen>
<dimen name="qs_header_row_min_height">48dp</dimen>
- <dimen name="qs_header_non_clickable_element_height">24dp</dimen>
- <dimen name="new_qs_header_non_clickable_element_height">24dp</dimen>
+ <dimen name="qs_header_non_clickable_element_height">24sp</dimen>
+ <dimen name="new_qs_header_non_clickable_element_height">24sp</dimen>
<dimen name="qs_footer_padding">20dp</dimen>
<dimen name="qs_security_footer_height">88dp</dimen>
@@ -822,7 +825,7 @@
<!-- Padding between the mobile signal indicator and the start icon when the roaming icon
is displayed in the upper left corner. -->
- <dimen name="roaming_icon_start_padding">2dp</dimen>
+ <dimen name="roaming_icon_start_padding">2sp</dimen>
<!-- Extra padding between the mobile data type icon and the strength indicator when the data
type icon is wide for the tile in quick settings. -->
@@ -1042,13 +1045,13 @@
<dimen name="display_cutout_margin_consumption">0px</dimen>
<!-- Height of the Ongoing App Ops chip -->
- <dimen name="ongoing_appops_chip_height">24dp</dimen>
+ <dimen name="ongoing_appops_chip_height">24sp</dimen>
<!-- Side padding between background of Ongoing App Ops chip and content -->
<dimen name="ongoing_appops_chip_side_padding">8dp</dimen>
<!-- Margin between icons of Ongoing App Ops chip -->
<dimen name="ongoing_appops_chip_icon_margin">4dp</dimen>
<!-- Icon size of Ongoing App Ops chip -->
- <dimen name="ongoing_appops_chip_icon_size">16dp</dimen>
+ <dimen name="ongoing_appops_chip_icon_size">16sp</dimen>
<!-- Radius of Ongoing App Ops chip corners -->
<dimen name="ongoing_appops_chip_bg_corner_radius">28dp</dimen>
<!-- One or two privacy items -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 853930e..c57fef1 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1257,7 +1257,10 @@
<string name="monitoring_description_managed_profile_network_logging">Your admin has turned on network logging, which monitors traffic in your work profile but not in your personal profile.</string>
<!-- Monitoring dialog: Description of an active VPN. [CHAR LIMIT=NONE]-->
- <string name="monitoring_description_named_vpn">This device is connected to the internet through <xliff:g id="vpn_app" example="Foo VPN App">%1$s</xliff:g>. Your network activity, including emails and browsing data, is visible to your IT admin.</string>
+ <string name="monitoring_description_named_vpn">This device is connected to the internet through <xliff:g id="vpn_app" example="Foo VPN App">%1$s</xliff:g>. Your network activity, including emails and browsing data, is visible to the VPN provider.</string>
+
+ <!-- Monitoring dialog: Description of an active VPN on a managed device. [CHAR LIMIT=NONE]-->
+ <string name="monitoring_description_managed_device_named_vpn">This device is connected to the internet through <xliff:g id="vpn_app" example="Foo VPN App">%1$s</xliff:g>. Your network activity, including emails and browsing data, is visible to your IT admin.</string>
<!-- Monitoring dialog: Description of two active VPNs. [CHAR LIMIT=NONE]-->
<string name="monitoring_description_two_named_vpns">This device is connected to the internet through <xliff:g id="vpn_app" example="Foo VPN App">%1$s</xliff:g> and <xliff:g id="vpn_app" example="Bar VPN App">%2$s</xliff:g>. Your network activity, including emails and browsing data, is visible to your IT admin.</string>
@@ -3035,6 +3038,19 @@
-->
<string name="keyguard_affordance_enablement_dialog_home_instruction_2">• At least one device is available</string>
+ <!---
+ Requirement for the notes app to be available for the user to use. This is shown as part of a
+ bulleted list of requirements. When all requirements are met, the app can be accessed through a
+ shortcut button on the lock screen. [CHAR LIMIT=NONE] -->
+ <string name="keyguard_affordance_enablement_dialog_notes_app_instruction">Select a default notes app to use the notetaking shortcut</string>
+
+ <!---
+ The action to make the lock screen shortcut for the notes app to be available for the user to
+ use. This is shown as the action button in the dialog listing the requirements. When all
+ requirements are met, the app can be accessed through a shortcut button on the lock screen.
+ [CHAR LIMIT=NONE] -->
+ <string name="keyguard_affordance_enablement_dialog_notes_app_action">Select app</string>
+
<!--
Error message shown when a shortcut must be pressed and held to activate it, usually shown when
the user tried to tap the shortcut or held it for too short a time. [CHAR LIMIT=32].
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java
index 016d573..4a66562 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java
@@ -230,7 +230,7 @@
private ClassLoader getParentClassLoader(ClassLoader baseClassLoader) {
return new PluginManagerImpl.ClassLoaderFilter(
- baseClassLoader, "com.android.systemui.plugin");
+ baseClassLoader, "com.android.systemui.log", "com.android.systemui.plugin");
}
/** Returns class loader specific for the given plugin. */
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
index 2f9f5b2..1e668b8 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
@@ -248,19 +248,23 @@
// This allows plugins to include any libraries or copied code they want by only including
// classes from the plugin library.
static class ClassLoaderFilter extends ClassLoader {
- private final String mPackage;
+ private final String[] mPackages;
private final ClassLoader mBase;
- public ClassLoaderFilter(ClassLoader base, String pkg) {
+ ClassLoaderFilter(ClassLoader base, String... pkgs) {
super(ClassLoader.getSystemClassLoader());
mBase = base;
- mPackage = pkg;
+ mPackages = pkgs;
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
- if (!name.startsWith(mPackage)) super.loadClass(name, resolve);
- return mBase.loadClass(name);
+ for (String pkg : mPackages) {
+ if (name.startsWith(pkg)) {
+ return mBase.loadClass(name);
+ }
+ }
+ return super.loadClass(name, resolve);
}
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
index 362d7a9..7cf3121 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
@@ -68,7 +68,7 @@
onActivityLaunchOnSecondaryDisplayRerouted();
}
- default void onTaskProfileLocked(RunningTaskInfo taskInfo) { }
+ default void onTaskProfileLocked(RunningTaskInfo taskInfo, int userId) { }
default void onTaskCreated(int taskId, ComponentName componentName) { }
default void onTaskRemoved(int taskId) { }
default void onTaskMovedToFront(int taskId) { }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
index dd52cfb..c613afb 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
@@ -262,8 +262,8 @@
}
@Override
- public void onTaskProfileLocked(RunningTaskInfo taskInfo) {
- mHandler.obtainMessage(ON_TASK_PROFILE_LOCKED, taskInfo).sendToTarget();
+ public void onTaskProfileLocked(RunningTaskInfo taskInfo, int userId) {
+ mHandler.obtainMessage(ON_TASK_PROFILE_LOCKED, userId, 0, taskInfo).sendToTarget();
}
@Override
@@ -418,8 +418,9 @@
}
case ON_TASK_PROFILE_LOCKED: {
final RunningTaskInfo info = (RunningTaskInfo) msg.obj;
+ final int userId = msg.arg1;
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
- mTaskStackListeners.get(i).onTaskProfileLocked(info);
+ mTaskStackListeners.get(i).onTaskProfileLocked(info, userId);
}
break;
}
diff --git a/packages/SystemUI/src-debug/com/android/systemui/log/DebugLogger.kt b/packages/SystemUI/src-debug/com/android/systemui/log/DebugLogger.kt
new file mode 100644
index 0000000..af29b05
--- /dev/null
+++ b/packages/SystemUI/src-debug/com/android/systemui/log/DebugLogger.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2023 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.log
+
+import android.os.Build
+import android.util.Log
+import android.util.Log.LOG_ID_MAIN
+
+/**
+ * A simplified debug logger built as a wrapper around Android's [Log]. Internal for development.
+ *
+ * The main advantages are:
+ * - Sensible defaults, automatically retrieving the class name from the call-site (i.e., tag);
+ * - The messages are purged from source on release builds (keep in mind they are visible on AOSP);
+ * - Lazily evaluate Strings for zero impact in production builds or when disabled;
+ *
+ * Usage example:
+ * ```kotlin
+ * // Logging a message:
+ * debugLog { "message" }
+ *
+ * // Logging an error:
+ * debugLog(error = exception) { "message" }
+ *
+ * // Logging the current stack trace, for debugging:
+ * debugLog(error = Throwable()) { "message" }
+ * ```
+ */
+object DebugLogger {
+
+ /**
+ * Log a debug message, with sensible defaults.
+ *
+ * For example:
+ * ```kotlin
+ * val one = 1
+ * debugLog { "message#$one" }
+ * ```
+ *
+ * The output will be: `D/NoteTaskController: message#1`
+ *
+ * Beware, the [debugLog] content is **REMOVED FROM SOURCE AND BINARY** in Release builds.
+ *
+ * @param enabled: whether or not the message should be logged. By default, it is
+ * [Build.IS_DEBUGGABLE].
+ * @param priority: type of this log. By default, it is [Log.DEBUG].
+ * @param tag: identifies the source of a log. By default, it is the receiver's simple name.
+ * @param error: a [Throwable] to log.
+ * @param message: a lazily evaluated message you wish to log.
+ */
+ inline fun Any.debugLog(
+ enabled: Boolean = Build.IS_DEBUGGABLE,
+ priority: Int = Log.DEBUG,
+ tag: String = this::class.simpleName.orEmpty(),
+ error: Throwable? = null,
+ message: () -> String,
+ ) {
+ if (enabled) {
+ if (error == null) {
+ Log.println(priority, tag, message())
+ } else {
+ Log.printlns(LOG_ID_MAIN, priority, tag, message(), error)
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src-release/com/android/systemui/log/DebugLogger.kt b/packages/SystemUI/src-release/com/android/systemui/log/DebugLogger.kt
new file mode 100644
index 0000000..2764a1f
--- /dev/null
+++ b/packages/SystemUI/src-release/com/android/systemui/log/DebugLogger.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2023 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.log
+
+import android.os.Build
+import android.util.Log
+
+/** An empty logger for release builds. */
+object DebugLogger {
+
+ @JvmName("logcatMessage")
+ inline fun Any.debugLog(
+ enabled: Boolean = Build.IS_DEBUGGABLE,
+ priority: Int = Log.DEBUG,
+ tag: String = this::class.simpleName.orEmpty(),
+ error: Throwable? = null,
+ message: () -> String,
+ ) {
+ // no-op.
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 9573913..1f1d3b6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -522,6 +522,14 @@
FACE_AUTH_TRIGGERED_TRUST_DISABLED);
}
+ mLogger.logTrustChanged(wasTrusted, enabled, userId);
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onTrustChanged(userId);
+ }
+ }
+
if (enabled) {
String message = null;
if (KeyguardUpdateMonitor.getCurrentUser() == userId
@@ -560,14 +568,6 @@
}
}
}
-
- mLogger.logTrustChanged(wasTrusted, enabled, userId);
- for (int i = 0; i < mCallbacks.size(); i++) {
- KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
- if (cb != null) {
- cb.onTrustChanged(userId);
- }
- }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
index 4b5c50f..5499d2c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
@@ -19,7 +19,6 @@
import android.annotation.RawRes
import android.content.Context
import android.content.Context.FINGERPRINT_SERVICE
-import android.content.res.Configuration
import android.hardware.fingerprint.FingerprintManager
import android.view.DisplayInfo
import android.view.Surface
@@ -35,21 +34,18 @@
import com.android.systemui.biometrics.AuthBiometricView.STATE_HELP
import com.android.systemui.biometrics.AuthBiometricView.STATE_IDLE
import com.android.systemui.biometrics.AuthBiometricView.STATE_PENDING_CONFIRMATION
-import com.android.systemui.unfold.compat.ScreenSizeFoldProvider
-import com.android.systemui.unfold.updates.FoldProvider
/** Fingerprint only icon animator for BiometricPrompt. */
open class AuthBiometricFingerprintIconController(
context: Context,
iconView: LottieAnimationView,
protected val iconViewOverlay: LottieAnimationView
-) : AuthIconController(context, iconView), FoldProvider.FoldCallback {
+) : AuthIconController(context, iconView) {
- private var isDeviceFolded: Boolean = false
private val isSideFps: Boolean
private val isReverseDefaultRotation =
context.resources.getBoolean(com.android.internal.R.bool.config_reverseDefaultRotation)
- private val screenSizeFoldProvider: ScreenSizeFoldProvider = ScreenSizeFoldProvider(context)
+
var iconLayoutParamSize: Pair<Int, Int> = Pair(1, 1)
set(value) {
if (field == value) {
@@ -77,20 +73,16 @@
if (isSideFps && getRotationFromDefault(displayInfo.rotation) == Surface.ROTATION_180) {
iconView.rotation = 180f
}
- screenSizeFoldProvider.registerCallback(this, context.mainExecutor)
- screenSizeFoldProvider.onConfigurationChange(context.resources.configuration)
}
private fun updateIconSideFps(@BiometricState lastState: Int, @BiometricState newState: Int) {
val displayInfo = DisplayInfo()
context.display?.getDisplayInfo(displayInfo)
val rotation = getRotationFromDefault(displayInfo.rotation)
- val iconAnimation = getSideFpsAnimationForTransition(rotation)
val iconViewOverlayAnimation =
getSideFpsOverlayAnimationForTransition(lastState, newState, rotation) ?: return
if (!(lastState == STATE_AUTHENTICATING_ANIMATING_IN && newState == STATE_AUTHENTICATING)) {
- iconView.setAnimation(iconAnimation)
iconViewOverlay.setAnimation(iconViewOverlayAnimation)
}
@@ -132,10 +124,6 @@
LottieColorUtils.applyDynamicColors(context, iconView)
}
- override fun onConfigurationChanged(newConfig: Configuration) {
- screenSizeFoldProvider.onConfigurationChange(newConfig)
- }
-
override fun updateIcon(@BiometricState lastState: Int, @BiometricState newState: Int) {
if (isSideFps) {
updateIconSideFps(lastState, newState)
@@ -230,25 +218,6 @@
if (isReverseDefaultRotation) (rotation + 1) % 4 else rotation
@RawRes
- private fun getSideFpsAnimationForTransition(rotation: Int): Int = when (rotation) {
- Surface.ROTATION_90 -> if (isDeviceFolded) {
- R.raw.biometricprompt_folded_base_topleft
- } else {
- R.raw.biometricprompt_portrait_base_topleft
- }
- Surface.ROTATION_270 -> if (isDeviceFolded) {
- R.raw.biometricprompt_folded_base_bottomright
- } else {
- R.raw.biometricprompt_portrait_base_bottomright
- }
- else -> if (isDeviceFolded) {
- R.raw.biometricprompt_folded_base_default
- } else {
- R.raw.biometricprompt_landscape_base
- }
- }
-
- @RawRes
private fun getSideFpsOverlayAnimationForTransition(
@BiometricState oldState: Int,
@BiometricState newState: Int,
@@ -357,8 +326,4 @@
)
}
}
-
- override fun onFoldUpdated(isFolded: Boolean) {
- isDeviceFolded = isFolded
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index e04dd06..f330c34 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -124,6 +124,7 @@
protected final int mTextColorHint;
private AuthPanelController mPanelController;
+
private PromptInfo mPromptInfo;
private boolean mRequireConfirmation;
private int mUserId;
@@ -266,11 +267,9 @@
/** Create the controller for managing the icons transitions during the prompt.*/
@NonNull
protected abstract AuthIconController createIconController();
-
void setPanelController(AuthPanelController panelController) {
mPanelController = panelController;
}
-
void setPromptInfo(PromptInfo promptInfo) {
mPromptInfo = promptInfo;
}
@@ -463,9 +462,16 @@
return false;
}
+ /**
+ * Updates mIconView animation on updates to fold state, device rotation, or rear display mode
+ * @param animation new asset to use for iconw
+ */
+ public void updateIconViewAnimation(int animation) {
+ mIconView.setAnimation(animation);
+ }
+
public void updateState(@BiometricState int newState) {
Log.v(TAG, "newState: " + newState);
-
mIconController.updateState(mState, newState);
switch (newState) {
@@ -625,7 +631,6 @@
public void restoreState(@Nullable Bundle savedState) {
mSavedState = savedState;
}
-
private void setTextOrHide(TextView view, CharSequence charSequence) {
if (TextUtils.isEmpty(charSequence)) {
view.setVisibility(View.GONE);
@@ -658,7 +663,6 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- mIconController.onConfigurationChanged(newConfig);
if (mSavedState != null) {
updateState(mSavedState.getInt(AuthDialog.KEY_BIOMETRIC_STATE));
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index aeebb01..b386bc9 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -67,6 +67,8 @@
import com.android.systemui.biometrics.AuthController.ScaleFactorProvider;
import com.android.systemui.biometrics.domain.interactor.BiometricPromptCredentialInteractor;
import com.android.systemui.biometrics.ui.CredentialView;
+import com.android.systemui.biometrics.ui.binder.AuthBiometricFingerprintViewBinder;
+import com.android.systemui.biometrics.ui.viewmodel.AuthBiometricFingerprintViewModel;
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.keyguard.WakefulnessLifecycle;
@@ -126,6 +128,8 @@
// TODO: these should be migrated out once ready
private final Provider<BiometricPromptCredentialInteractor> mBiometricPromptInteractor;
+ private final Provider<AuthBiometricFingerprintViewModel>
+ mAuthBiometricFingerprintViewModelProvider;
private final Provider<CredentialViewModel> mCredentialViewModelProvider;
@VisibleForTesting final BiometricCallback mBiometricCallback;
@@ -241,12 +245,14 @@
@NonNull LockPatternUtils lockPatternUtils,
@NonNull InteractionJankMonitor jankMonitor,
@NonNull Provider<BiometricPromptCredentialInteractor> biometricPromptInteractor,
+ @NonNull Provider<AuthBiometricFingerprintViewModel>
+ authBiometricFingerprintViewModelProvider,
@NonNull Provider<CredentialViewModel> credentialViewModelProvider) {
mConfig.mSensorIds = sensorIds;
return new AuthContainerView(mConfig, fpProps, faceProps, wakefulnessLifecycle,
panelInteractionDetector, userManager, lockPatternUtils, jankMonitor,
- biometricPromptInteractor, credentialViewModelProvider,
- new Handler(Looper.getMainLooper()), bgExecutor);
+ biometricPromptInteractor, authBiometricFingerprintViewModelProvider,
+ credentialViewModelProvider, new Handler(Looper.getMainLooper()), bgExecutor);
}
}
@@ -339,6 +345,8 @@
@NonNull LockPatternUtils lockPatternUtils,
@NonNull InteractionJankMonitor jankMonitor,
@NonNull Provider<BiometricPromptCredentialInteractor> biometricPromptInteractor,
+ @NonNull Provider<AuthBiometricFingerprintViewModel>
+ authBiometricFingerprintViewModelProvider,
@NonNull Provider<CredentialViewModel> credentialViewModelProvider,
@NonNull Handler mainHandler,
@NonNull @Background DelayableExecutor bgExecutor) {
@@ -368,6 +376,7 @@
mBackgroundExecutor = bgExecutor;
mInteractionJankMonitor = jankMonitor;
mBiometricPromptInteractor = biometricPromptInteractor;
+ mAuthBiometricFingerprintViewModelProvider = authBiometricFingerprintViewModelProvider;
mCredentialViewModelProvider = credentialViewModelProvider;
// Inflate biometric view only if necessary.
@@ -386,6 +395,9 @@
fingerprintAndFaceView.updateOverrideIconLayoutParamsSize();
fingerprintAndFaceView.setFaceClass3(
faceProperties.sensorStrength == STRENGTH_STRONG);
+ final AuthBiometricFingerprintViewModel fpAndFaceViewModel =
+ mAuthBiometricFingerprintViewModelProvider.get();
+ AuthBiometricFingerprintViewBinder.bind(fingerprintAndFaceView, fpAndFaceViewModel);
mBiometricView = fingerprintAndFaceView;
} else if (fpProperties != null) {
final AuthBiometricFingerprintView fpView =
@@ -394,6 +406,9 @@
fpView.setSensorProperties(fpProperties);
fpView.setScaleFactorProvider(config.mScaleProvider);
fpView.updateOverrideIconLayoutParamsSize();
+ final AuthBiometricFingerprintViewModel fpViewModel =
+ mAuthBiometricFingerprintViewModelProvider.get();
+ AuthBiometricFingerprintViewBinder.bind(fpView, fpViewModel);
mBiometricView = fpView;
} else if (faceProperties != null) {
mBiometricView = (AuthBiometricFaceView) layoutInflater.inflate(
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 6eb3c70..3579e8c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -73,6 +73,7 @@
import com.android.systemui.CoreStartable;
import com.android.systemui.biometrics.domain.interactor.BiometricPromptCredentialInteractor;
import com.android.systemui.biometrics.domain.interactor.LogContextInteractor;
+import com.android.systemui.biometrics.ui.viewmodel.AuthBiometricFingerprintViewModel;
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
@@ -127,6 +128,9 @@
// TODO: these should be migrated out once ready
@NonNull private final Provider<BiometricPromptCredentialInteractor> mBiometricPromptInteractor;
+
+ @NonNull private final Provider<AuthBiometricFingerprintViewModel>
+ mAuthBiometricFingerprintViewModelProvider;
@NonNull private final Provider<CredentialViewModel> mCredentialViewModelProvider;
@NonNull private final LogContextInteractor mLogContextInteractor;
@@ -722,7 +726,6 @@
}
onDialogDismissed(reason);
}
-
@Inject
public AuthController(Context context,
Execution execution,
@@ -741,6 +744,8 @@
@NonNull UdfpsLogger udfpsLogger,
@NonNull LogContextInteractor logContextInteractor,
@NonNull Provider<BiometricPromptCredentialInteractor> biometricPromptInteractor,
+ @NonNull Provider<AuthBiometricFingerprintViewModel>
+ authBiometricFingerprintViewModelProvider,
@NonNull Provider<CredentialViewModel> credentialViewModelProvider,
@NonNull InteractionJankMonitor jankMonitor,
@Main Handler handler,
@@ -771,6 +776,7 @@
mLogContextInteractor = logContextInteractor;
mBiometricPromptInteractor = biometricPromptInteractor;
+ mAuthBiometricFingerprintViewModelProvider = authBiometricFingerprintViewModelProvider;
mCredentialViewModelProvider = credentialViewModelProvider;
mOrientationListener = new BiometricDisplayListener(
@@ -1299,7 +1305,7 @@
.build(bgExecutor, sensorIds, mFpProps, mFaceProps, wakefulnessLifecycle,
panelInteractionDetector, userManager, lockPatternUtils,
mInteractionJankMonitor, mBiometricPromptInteractor,
- mCredentialViewModelProvider);
+ mAuthBiometricFingerprintViewModelProvider, mCredentialViewModelProvider);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthIconController.kt
index d6ad4da..f5f4640 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthIconController.kt
@@ -18,7 +18,6 @@
import android.annotation.DrawableRes
import android.content.Context
-import android.content.res.Configuration
import android.graphics.drawable.Animatable2
import android.graphics.drawable.AnimatedVectorDrawable
import android.graphics.drawable.Drawable
@@ -94,8 +93,6 @@
/** Called during [onAnimationEnd] if the controller is not [deactivated]. */
open fun handleAnimationEnd(drawable: Drawable) {}
- open fun onConfigurationChanged(newConfig: Configuration) {}
-
// TODO(b/251476085): Migrate this to an extension at the appropriate level?
/** Load the given [rawResources] immediately so they are cached for use in the [context]. */
protected fun cacheLottieAssetsInContext(context: Context, vararg rawResources: Int) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
index 4319f01..962140f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
@@ -55,6 +55,7 @@
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.Dumpable
import com.android.systemui.R
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
@@ -84,6 +85,7 @@
private val activityTaskManager: ActivityTaskManager,
overviewProxyService: OverviewProxyService,
displayManager: DisplayManager,
+ private val displayStateInteractor: DisplayStateInteractor,
@Main private val mainExecutor: DelayableExecutor,
@Main private val handler: Handler,
private val alternateBouncerInteractor: AlternateBouncerInteractor,
@@ -203,14 +205,16 @@
request: SideFpsUiRequestSource,
@BiometricOverlayConstants.ShowReason reason: Int = BiometricOverlayConstants.REASON_UNKNOWN
) {
- requests.add(request)
- mainExecutor.execute {
- if (overlayView == null) {
- traceSection("SideFpsController#show(request=${request.name}, reason=$reason") {
- createOverlayForDisplay(reason)
+ if (!displayStateInteractor.isInRearDisplayMode.value) {
+ requests.add(request)
+ mainExecutor.execute {
+ if (overlayView == null) {
+ traceSection("SideFpsController#show(request=${request.name}, reason=$reason") {
+ createOverlayForDisplay(reason)
+ }
+ } else {
+ Log.v(TAG, "overlay already shown")
}
- } else {
- Log.v(TAG, "overlay already shown")
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
index f0b9f67..c831663 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
@@ -21,8 +21,12 @@
import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepositoryImpl
import com.android.systemui.biometrics.data.repository.PromptRepository
import com.android.systemui.biometrics.data.repository.PromptRepositoryImpl
+import com.android.systemui.biometrics.data.repository.RearDisplayStateRepository
+import com.android.systemui.biometrics.data.repository.RearDisplayStateRepositoryImpl
import com.android.systemui.biometrics.domain.interactor.CredentialInteractor
import com.android.systemui.biometrics.domain.interactor.CredentialInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
import com.android.systemui.biometrics.domain.interactor.LogContextInteractor
import com.android.systemui.biometrics.domain.interactor.LogContextInteractorImpl
import com.android.systemui.dagger.SysUISingleton
@@ -45,6 +49,9 @@
@SysUISingleton
fun fingerprintRepository(impl: FingerprintPropertyRepositoryImpl):
FingerprintPropertyRepository
+ @Binds
+ @SysUISingleton
+ fun rearDisplayStateRepository(impl: RearDisplayStateRepositoryImpl): RearDisplayStateRepository
@Binds
@SysUISingleton
@@ -52,6 +59,10 @@
@Binds
@SysUISingleton
+ fun providesDisplayStateInteractor(impl: DisplayStateInteractorImpl): DisplayStateInteractor
+
+ @Binds
+ @SysUISingleton
fun bindsLogContextInteractor(impl: LogContextInteractorImpl): LogContextInteractor
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/RearDisplayStateRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/RearDisplayStateRepository.kt
new file mode 100644
index 0000000..d17d961
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/RearDisplayStateRepository.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2023 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.biometrics.data.repository
+
+import android.content.Context
+import android.hardware.devicestate.DeviceStateManager
+import com.android.internal.util.ArrayUtils
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Main
+import java.util.concurrent.Executor
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.stateIn
+
+/** Provide current rear display state. */
+interface RearDisplayStateRepository {
+ /** Provides the current rear display state. */
+ val isInRearDisplayMode: StateFlow<Boolean>
+}
+
+@SysUISingleton
+class RearDisplayStateRepositoryImpl
+@Inject
+constructor(
+ @Application applicationScope: CoroutineScope,
+ @Application context: Context,
+ deviceStateManager: DeviceStateManager,
+ @Main mainExecutor: Executor
+) : RearDisplayStateRepository {
+ override val isInRearDisplayMode: StateFlow<Boolean> =
+ conflatedCallbackFlow {
+ val sendRearDisplayStateUpdate = { state: Boolean ->
+ trySendWithFailureLogging(
+ state,
+ TAG,
+ "Error sending rear display state update to $state"
+ )
+ }
+
+ val callback =
+ DeviceStateManager.DeviceStateCallback { state ->
+ val isInRearDisplayMode =
+ ArrayUtils.contains(
+ context.resources.getIntArray(
+ com.android.internal.R.array.config_rearDisplayDeviceStates
+ ),
+ state
+ )
+ sendRearDisplayStateUpdate(isInRearDisplayMode)
+ }
+
+ sendRearDisplayStateUpdate(false)
+ deviceStateManager.registerCallback(mainExecutor, callback)
+ awaitClose { deviceStateManager.unregisterCallback(callback) }
+ }
+ .stateIn(
+ applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = false,
+ )
+
+ companion object {
+ const val TAG = "RearDisplayStateRepositoryImpl"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractor.kt
new file mode 100644
index 0000000..c935aa2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractor.kt
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2023 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.biometrics.domain.interactor
+
+import android.content.Context
+import android.content.res.Configuration
+import com.android.systemui.biometrics.data.repository.RearDisplayStateRepository
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.unfold.compat.ScreenSizeFoldProvider
+import com.android.systemui.unfold.updates.FoldProvider
+import java.util.concurrent.Executor
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.stateIn
+
+/** Aggregates display state information. */
+interface DisplayStateInteractor {
+
+ /** Whether the device is currently in rear display mode. */
+ val isInRearDisplayMode: StateFlow<Boolean>
+
+ /** Whether the device is currently folded. */
+ val isFolded: Flow<Boolean>
+
+ /** Called on configuration changes, used to keep the display state in sync */
+ fun onConfigurationChanged(newConfig: Configuration)
+}
+
+/** Encapsulates logic for interacting with the display state. */
+class DisplayStateInteractorImpl
+@Inject
+constructor(
+ @Application applicationScope: CoroutineScope,
+ @Application context: Context,
+ @Main mainExecutor: Executor,
+ rearDisplayStateRepository: RearDisplayStateRepository,
+) : DisplayStateInteractor {
+ private var screenSizeFoldProvider: ScreenSizeFoldProvider = ScreenSizeFoldProvider(context)
+
+ fun setScreenSizeFoldProvider(foldProvider: ScreenSizeFoldProvider) {
+ screenSizeFoldProvider = foldProvider
+ }
+
+ override val isFolded: Flow<Boolean> =
+ conflatedCallbackFlow {
+ val sendFoldStateUpdate = { state: Boolean ->
+ trySendWithFailureLogging(
+ state,
+ TAG,
+ "Error sending fold state update to $state"
+ )
+ }
+
+ val callback =
+ object : FoldProvider.FoldCallback {
+ override fun onFoldUpdated(isFolded: Boolean) {
+ sendFoldStateUpdate(isFolded)
+ }
+ }
+ sendFoldStateUpdate(false)
+ screenSizeFoldProvider.registerCallback(callback, mainExecutor)
+ awaitClose { screenSizeFoldProvider.unregisterCallback(callback) }
+ }
+ .stateIn(
+ applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = false,
+ )
+
+ override val isInRearDisplayMode: StateFlow<Boolean> =
+ rearDisplayStateRepository.isInRearDisplayMode
+
+ override fun onConfigurationChanged(newConfig: Configuration) {
+ screenSizeFoldProvider.onConfigurationChange(newConfig)
+ }
+
+ companion object {
+ private const val TAG = "DisplayStateInteractor"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/AuthBiometricFingerprintViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/AuthBiometricFingerprintViewBinder.kt
new file mode 100644
index 0000000..e776ab4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/AuthBiometricFingerprintViewBinder.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 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.biometrics.ui.binder
+
+import android.view.Surface
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.biometrics.AuthBiometricFingerprintView
+import com.android.systemui.biometrics.ui.viewmodel.AuthBiometricFingerprintViewModel
+import com.android.systemui.lifecycle.repeatWhenAttached
+import kotlinx.coroutines.launch
+
+object AuthBiometricFingerprintViewBinder {
+
+ /** Binds a [AuthBiometricFingerprintView] to a [AuthBiometricFingerprintViewModel]. */
+ @JvmStatic
+ fun bind(view: AuthBiometricFingerprintView, viewModel: AuthBiometricFingerprintViewModel) {
+ view.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ viewModel.onConfigurationChanged(view.context.resources.configuration)
+ viewModel.setRotation(view.context.display?.orientation ?: Surface.ROTATION_0)
+ launch {
+ viewModel.iconAsset.collect { iconAsset ->
+ view.updateIconViewAnimation(iconAsset)
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/AuthBiometricFingerprintViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/AuthBiometricFingerprintViewModel.kt
new file mode 100644
index 0000000..617d80c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/AuthBiometricFingerprintViewModel.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2023 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.biometrics.ui.viewmodel
+
+import android.annotation.RawRes
+import android.content.res.Configuration
+import android.view.Surface
+import com.android.systemui.R
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+
+/** Models UI of AuthBiometricFingerprintView to support rear display state changes. */
+class AuthBiometricFingerprintViewModel
+@Inject
+constructor(private val interactor: DisplayStateInteractor) {
+ /** Current device rotation. */
+ private var rotation: Int = Surface.ROTATION_0
+
+ /** Current AuthBiometricFingerprintView asset. */
+ val iconAsset: Flow<Int> =
+ combine(interactor.isFolded, interactor.isInRearDisplayMode) {
+ isFolded: Boolean,
+ isInRearDisplayMode: Boolean ->
+ getSideFpsAnimationAsset(isFolded, isInRearDisplayMode)
+ }
+
+ @RawRes
+ private fun getSideFpsAnimationAsset(
+ isDeviceFolded: Boolean,
+ isInRearDisplayMode: Boolean,
+ ): Int =
+ when (rotation) {
+ Surface.ROTATION_90 ->
+ if (isInRearDisplayMode) {
+ R.raw.biometricprompt_rear_portrait_reverse_base
+ } else if (isDeviceFolded) {
+ R.raw.biometricprompt_folded_base_topleft
+ } else {
+ R.raw.biometricprompt_portrait_base_topleft
+ }
+ Surface.ROTATION_270 ->
+ if (isInRearDisplayMode) {
+ R.raw.biometricprompt_rear_portrait_base
+ } else if (isDeviceFolded) {
+ R.raw.biometricprompt_folded_base_bottomright
+ } else {
+ R.raw.biometricprompt_portrait_base_bottomright
+ }
+ else ->
+ if (isInRearDisplayMode) {
+ R.raw.biometricprompt_rear_landscape_base
+ } else if (isDeviceFolded) {
+ R.raw.biometricprompt_folded_base_default
+ } else {
+ R.raw.biometricprompt_landscape_base
+ }
+ }
+
+ /** Called on configuration changes */
+ fun onConfigurationChanged(newConfig: Configuration) {
+ interactor.onConfigurationChanged(newConfig)
+ }
+
+ fun setRotation(newRotation: Int) {
+ rotation = newRotation
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardImageLoader.kt b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardImageLoader.kt
new file mode 100644
index 0000000..0542e13
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardImageLoader.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 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.clipboardoverlay
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.net.Uri
+import android.util.Log
+import android.util.Size
+import com.android.systemui.R
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import java.io.IOException
+import java.util.function.Consumer
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import kotlinx.coroutines.withTimeoutOrNull
+
+class ClipboardImageLoader
+@Inject
+constructor(
+ private val context: Context,
+ @Background private val bgDispatcher: CoroutineDispatcher,
+ @Application private val mainScope: CoroutineScope
+) {
+ private val TAG: String = "ClipboardImageLoader"
+
+ suspend fun load(uri: Uri, timeoutMs: Long = 300) =
+ withTimeoutOrNull(timeoutMs) {
+ withContext(bgDispatcher) {
+ try {
+ val size = context.resources.getDimensionPixelSize(R.dimen.overlay_x_scale)
+ context.contentResolver.loadThumbnail(uri, Size(size, size * 4), null)
+ } catch (e: IOException) {
+ Log.e(TAG, "Thumbnail loading failed!", e)
+ null
+ }
+ }
+ }
+
+ fun loadAsync(uri: Uri, callback: Consumer<Bitmap?>) {
+ mainScope.launch { callback.accept(load(uri)) }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index 0aeab10..757ebf4 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -32,6 +32,7 @@
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SWIPE_DISMISSED;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_TAP_OUTSIDE;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_TIMED_OUT;
+import static com.android.systemui.flags.Flags.CLIPBOARD_IMAGE_TIMEOUT;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -90,6 +91,7 @@
private final ClipboardOverlayUtils mClipboardUtils;
private final FeatureFlags mFeatureFlags;
private final Executor mBgExecutor;
+ private final ClipboardImageLoader mClipboardImageLoader;
private final ClipboardOverlayView mView;
@@ -109,6 +111,7 @@
private Runnable mOnUiUpdate;
+ private boolean mShowingUi;
private boolean mIsMinimized;
private ClipboardModel mClipboardModel;
@@ -175,9 +178,11 @@
FeatureFlags featureFlags,
ClipboardOverlayUtils clipboardUtils,
@Background Executor bgExecutor,
+ ClipboardImageLoader clipboardImageLoader,
UiEventLogger uiEventLogger) {
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
+ mClipboardImageLoader = clipboardImageLoader;
mClipboardLogger = new ClipboardLogger(uiEventLogger);
@@ -260,21 +265,42 @@
boolean shouldAnimate = !model.dataMatches(mClipboardModel) || wasExiting;
mClipboardModel = model;
mClipboardLogger.setClipSource(mClipboardModel.getSource());
- if (shouldAnimate) {
- reset();
- mClipboardLogger.setClipSource(mClipboardModel.getSource());
- if (shouldShowMinimized(mWindow.getWindowInsets())) {
- mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_SHOWN_MINIMIZED);
- mIsMinimized = true;
- mView.setMinimized(true);
- } else {
- mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_SHOWN_EXPANDED);
+ if (mFeatureFlags.isEnabled(CLIPBOARD_IMAGE_TIMEOUT)) {
+ if (shouldAnimate) {
+ reset();
+ mClipboardLogger.setClipSource(mClipboardModel.getSource());
+ if (shouldShowMinimized(mWindow.getWindowInsets())) {
+ mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_SHOWN_MINIMIZED);
+ mIsMinimized = true;
+ mView.setMinimized(true);
+ } else {
+ mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_SHOWN_EXPANDED);
+ setExpandedView(this::animateIn);
+ }
+ mView.announceForAccessibility(
+ getAccessibilityAnnouncement(mClipboardModel.getType()));
+ } else if (!mIsMinimized) {
+ setExpandedView(() -> {
+ });
+ }
+ } else {
+ if (shouldAnimate) {
+ reset();
+ mClipboardLogger.setClipSource(mClipboardModel.getSource());
+ if (shouldShowMinimized(mWindow.getWindowInsets())) {
+ mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_SHOWN_MINIMIZED);
+ mIsMinimized = true;
+ mView.setMinimized(true);
+ } else {
+ mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_SHOWN_EXPANDED);
+ setExpandedView();
+ animateIn();
+ }
+ mView.announceForAccessibility(
+ getAccessibilityAnnouncement(mClipboardModel.getType()));
+ } else if (!mIsMinimized) {
setExpandedView();
}
- animateIn();
- mView.announceForAccessibility(getAccessibilityAnnouncement(mClipboardModel.getType()));
- } else if (!mIsMinimized) {
- setExpandedView();
}
if (mClipboardModel.isRemote()) {
mTimeoutHandler.cancelTimeout();
@@ -285,6 +311,58 @@
}
}
+ private void setExpandedView(Runnable onViewReady) {
+ final ClipboardModel model = mClipboardModel;
+ mView.setMinimized(false);
+ switch (model.getType()) {
+ case TEXT:
+ if (model.isRemote() || DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_SHOW_ACTIONS, false)) {
+ if (model.getTextLinks() != null) {
+ classifyText(model);
+ }
+ }
+ if (model.isSensitive()) {
+ mView.showTextPreview(mContext.getString(R.string.clipboard_asterisks), true);
+ } else {
+ mView.showTextPreview(model.getText().toString(), false);
+ }
+ mView.setEditAccessibilityAction(true);
+ mOnPreviewTapped = this::editText;
+ onViewReady.run();
+ break;
+ case IMAGE:
+ mView.setEditAccessibilityAction(true);
+ mOnPreviewTapped = () -> editImage(model.getUri());
+ if (model.isSensitive()) {
+ mView.showImagePreview(null);
+ onViewReady.run();
+ } else {
+ mClipboardImageLoader.loadAsync(model.getUri(), (bitmap) -> mView.post(() -> {
+ if (bitmap == null) {
+ mView.showDefaultTextPreview();
+ } else {
+ mView.showImagePreview(bitmap);
+ }
+ onViewReady.run();
+ }));
+ }
+ break;
+ case URI:
+ case OTHER:
+ mView.showDefaultTextPreview();
+ onViewReady.run();
+ break;
+ }
+ if (!model.isRemote()) {
+ maybeShowRemoteCopy(model.getClipData());
+ }
+ if (model.getType() != ClipboardModel.Type.OTHER) {
+ mOnShareTapped = () -> shareContent(model.getClipData());
+ mView.showShareChip();
+ }
+ }
+
private void setExpandedView() {
final ClipboardModel model = mClipboardModel;
mView.setMinimized(false);
@@ -350,8 +428,12 @@
mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_EXPANDED_FROM_MINIMIZED);
mIsMinimized = false;
}
- setExpandedView();
- animateIn();
+ if (mFeatureFlags.isEnabled(CLIPBOARD_IMAGE_TIMEOUT)) {
+ setExpandedView(() -> animateIn());
+ } else {
+ setExpandedView();
+ animateIn();
+ }
}
});
mEnterAnimator.start();
@@ -412,7 +494,8 @@
mInputMonitor.getInputChannel(), Looper.getMainLooper()) {
@Override
public void onInputEvent(InputEvent event) {
- if (event instanceof MotionEvent) {
+ if ((!mFeatureFlags.isEnabled(CLIPBOARD_IMAGE_TIMEOUT) || mShowingUi)
+ && event instanceof MotionEvent) {
MotionEvent motionEvent = (MotionEvent) event;
if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
if (!mView.isInTouchRegion(
@@ -452,6 +535,12 @@
mEnterAnimator = mView.getEnterAnimation();
mEnterAnimator.addListener(new AnimatorListenerAdapter() {
@Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ mShowingUi = true;
+ }
+
+ @Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
if (mOnUiUpdate != null) {
@@ -518,6 +607,7 @@
mOnRemoteCopyTapped = null;
mOnShareTapped = null;
mOnPreviewTapped = null;
+ mShowingUi = false;
mView.reset();
mTimeoutHandler.cancelTimeout();
mClipboardLogger.reset();
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
index 5d608c3..7cbd1f5 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
@@ -16,9 +16,11 @@
package com.android.systemui.controls.ui
+import android.app.Activity
import android.app.ActivityOptions
import android.app.ActivityTaskManager
import android.app.ActivityTaskManager.INVALID_TASK_ID
+import android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
import android.app.Dialog
import android.app.PendingIntent
import android.content.ComponentName
@@ -96,7 +98,9 @@
activityContext,
0 /* enterResId */,
0 /* exitResId */
- )
+ ).setPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED)
+ options.isPendingIntentBackgroundActivityLaunchAllowedByPermission = true
+
taskView.startActivity(
pendingIntent,
fillInIntent,
@@ -214,6 +218,12 @@
if (!isShowing()) return
taskView.release()
+ val isActivityFinishing =
+ (activityContext as? Activity)?.let { it.isFinishing || it.isDestroyed }
+ if (isActivityFinishing == true) {
+ // Don't dismiss the dialog if the activity is finishing, it will get removed
+ return
+ }
super.dismiss()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 78994c4..6ca409f 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -61,6 +61,9 @@
// TODO(b/254512538): Tracking Bug
val INSTANT_VOICE_REPLY = unreleasedFlag(111, "instant_voice_reply")
+ // TODO(b/279735475): Tracking Bug
+ @JvmField val NEW_LIGHT_BAR_LOGIC = unreleasedFlag(279735475, "new_light_bar_logic")
+
/**
* This flag is server-controlled and should stay as [unreleasedFlag] since we never want to
* enable it on release builds.
@@ -203,11 +206,6 @@
)
/** Whether to inflate the bouncer view on a background thread. */
- // TODO(b/272091103): Tracking Bug
- @JvmField
- val ASYNC_INFLATE_BOUNCER = releasedFlag(229, "async_inflate_bouncer")
-
- /** Whether to inflate the bouncer view on a background thread. */
// TODO(b/273341787): Tracking Bug
@JvmField
val PREVENT_BYPASS_KEYGUARD = releasedFlag(230, "prevent_bypass_keyguard")
@@ -222,12 +220,22 @@
val LOCK_SCREEN_LONG_PRESS_DIRECT_TO_WPP =
unreleasedFlag(232, "lock_screen_long_press_directly_opens_wallpaper_picker")
+ /** Whether to run the new udfps keyguard refactor code. */
+ // TODO(b/279440316): Tracking bug.
+ @JvmField
+ val REFACTOR_UDFPS_KEYGUARD_VIEWS = unreleasedFlag(233, "refactor_udfps_keyguard_views")
+
/** Provide new auth messages on the bouncer. */
// TODO(b/277961132): Tracking bug.
@JvmField
val REVAMPED_BOUNCER_MESSAGES =
unreleasedFlag(234, "revamped_bouncer_messages")
+ /** Whether to delay showing bouncer UI when face auth or active unlock are enrolled. */
+ // TODO(b/279794160): Tracking bug.
+ @JvmField
+ val DELAY_BOUNCER = unreleasedFlag(235, "delay_bouncer")
+
// 300 - power menu
// TODO(b/254512600): Tracking Bug
@JvmField val POWER_MENU_LITE = releasedFlag(300, "power_menu_lite")
@@ -266,7 +274,7 @@
)
@JvmField
- val QS_PIPELINE_NEW_HOST = unreleasedFlag(504, "qs_pipeline_new_host", teamfood = false)
+ val QS_PIPELINE_NEW_HOST = unreleasedFlag(504, "qs_pipeline_new_host", teamfood = true)
// TODO(b/278068252): Tracking Bug
@JvmField
@@ -383,7 +391,7 @@
val MEDIA_TAP_TO_TRANSFER_DISMISS_GESTURE = releasedFlag(912, "media_ttt_dismiss_gesture")
// TODO(b/266157412): Tracking Bug
- val MEDIA_RETAIN_SESSIONS = releasedFlag(913, "media_retain_sessions")
+ val MEDIA_RETAIN_SESSIONS = unreleasedFlag(913, "media_retain_sessions")
// TODO(b/266739309): Tracking Bug
@JvmField
@@ -393,10 +401,10 @@
val MEDIA_RESUME_PROGRESS = releasedFlag(915, "media_resume_progress")
// TODO(b/267166152) : Tracking Bug
- val MEDIA_RETAIN_RECOMMENDATIONS = releasedFlag(916, "media_retain_recommendations")
+ val MEDIA_RETAIN_RECOMMENDATIONS = unreleasedFlag(916, "media_retain_recommendations")
// TODO(b/270437894): Tracking Bug
- val MEDIA_REMOTE_RESUME = releasedFlag(917, "media_remote_resume")
+ val MEDIA_REMOTE_RESUME = unreleasedFlag(917, "media_remote_resume")
// 1000 - dock
val SIMULATE_DOCK_THROUGH_CHARGING = releasedFlag(1000, "simulate_dock_through_charging")
@@ -592,6 +600,8 @@
// 1700 - clipboard
@JvmField val CLIPBOARD_REMOTE_BEHAVIOR = releasedFlag(1701, "clipboard_remote_behavior")
+ // TODO(b/278714186) Tracking Bug
+ @JvmField val CLIPBOARD_IMAGE_TIMEOUT = unreleasedFlag(1702, "clipboard_image_timeout")
// 1800 - shade container
// TODO(b/265944639): Tracking Bug
@@ -615,12 +625,14 @@
// TODO(b/269132640): Tracking Bug
@JvmField
val APP_PANELS_REMOVE_APPS_ALLOWED =
- unreleasedFlag(2003, "app_panels_remove_apps_allowed", teamfood = true)
+ releasedFlag(2003, "app_panels_remove_apps_allowed")
- // 2200 - udfps
+ // 2200 - biometrics (udfps, sfps, BiometricPrompt, etc.)
// TODO(b/259264861): Tracking Bug
@JvmField val UDFPS_NEW_TOUCH_DETECTION = releasedFlag(2200, "udfps_new_touch_detection")
@JvmField val UDFPS_ELLIPSE_DETECTION = releasedFlag(2201, "udfps_ellipse_detection")
+ // TODO(b/278622168): Tracking Bug
+ @JvmField val BIOMETRIC_BP_STRONG = unreleasedFlag(2202, "biometric_bp_strong")
// 2300 - stylus
@JvmField val TRACK_STYLUS_EVER_USED = releasedFlag(2300, "track_stylus_ever_used")
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index d3b6fc2..f64ed60 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -128,6 +128,7 @@
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.phone.CentralSurfaces;
+import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -240,6 +241,7 @@
private final ScreenshotHelper mScreenshotHelper;
private final SysuiColorExtractor mSysuiColorExtractor;
private final IStatusBarService mStatusBarService;
+ protected final LightBarController mLightBarController;
protected final NotificationShadeWindowController mNotificationShadeWindowController;
private final IWindowManager mIWindowManager;
private final Executor mBackgroundExecutor;
@@ -349,6 +351,7 @@
MetricsLogger metricsLogger,
SysuiColorExtractor colorExtractor,
IStatusBarService statusBarService,
+ LightBarController lightBarController,
NotificationShadeWindowController notificationShadeWindowController,
IWindowManager iWindowManager,
@Background Executor backgroundExecutor,
@@ -381,6 +384,7 @@
mUiEventLogger = uiEventLogger;
mSysuiColorExtractor = colorExtractor;
mStatusBarService = statusBarService;
+ mLightBarController = lightBarController;
mNotificationShadeWindowController = notificationShadeWindowController;
mIWindowManager = iWindowManager;
mBackgroundExecutor = backgroundExecutor;
@@ -694,6 +698,7 @@
ActionsDialogLite dialog = new ActionsDialogLite(mContext,
com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActionsLite,
mAdapter, mOverflowAdapter, mSysuiColorExtractor, mStatusBarService,
+ mLightBarController,
mNotificationShadeWindowController, this::onRefresh, mKeyguardShowing,
mPowerAdapter, mUiEventLogger, mCentralSurfacesOptional, mKeyguardUpdateMonitor,
mLockPatternUtils);
@@ -2192,6 +2197,7 @@
protected final SysuiColorExtractor mColorExtractor;
private boolean mKeyguardShowing;
protected float mScrimAlpha;
+ protected final LightBarController mLightBarController;
protected final NotificationShadeWindowController mNotificationShadeWindowController;
private ListPopupWindow mOverflowPopup;
private Dialog mPowerOptionsDialog;
@@ -2267,6 +2273,7 @@
ActionsDialogLite(Context context, int themeRes, MyAdapter adapter,
MyOverflowAdapter overflowAdapter,
SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
+ LightBarController lightBarController,
NotificationShadeWindowController notificationShadeWindowController,
Runnable onRefreshCallback, boolean keyguardShowing,
MyPowerOptionsAdapter powerAdapter, UiEventLogger uiEventLogger,
@@ -2282,6 +2289,7 @@
mPowerOptionsAdapter = powerAdapter;
mColorExtractor = sysuiColorExtractor;
mStatusBarService = statusBarService;
+ mLightBarController = lightBarController;
mNotificationShadeWindowController = notificationShadeWindowController;
mOnRefreshCallback = onRefreshCallback;
mKeyguardShowing = keyguardShowing;
@@ -2474,6 +2482,7 @@
@Override
protected void start() {
mGlobalActionsLayout.updateList();
+ mLightBarController.setGlobalActionsVisible(true);
if (mBackgroundDrawable instanceof ScrimDrawable) {
mColorExtractor.addOnColorsChangedListener(this);
@@ -2504,6 +2513,7 @@
@Override
protected void stop() {
+ mLightBarController.setGlobalActionsVisible(false);
mColorExtractor.removeOnColorsChangedListener(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
index b92499e..b7ba201 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
@@ -56,11 +56,11 @@
tscl.registerTaskStackListener(mLockListener);
}
- private void startWorkChallengeInTask(ActivityManager.RunningTaskInfo info) {
+ private void startWorkChallengeInTask(ActivityManager.RunningTaskInfo info, int userId) {
String packageName = info.baseActivity != null ? info.baseActivity.getPackageName() : "";
Intent intent = new Intent(KeyguardManager.ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER)
.setComponent(new ComponentName(mContext, WorkLockActivity.class))
- .putExtra(Intent.EXTRA_USER_ID, info.userId)
+ .putExtra(Intent.EXTRA_USER_ID, userId)
.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
@@ -76,10 +76,11 @@
} else {
// Starting the activity inside the task failed. We can't be sure why, so to be
// safe just remove the whole task if it still exists.
+ Log.w(TAG, "Failed to start work lock activity, will remove task=" + info.taskId);
try {
mIatm.removeTask(info.taskId);
} catch (RemoteException e) {
- Log.w(TAG, "Failed to get description for task=" + info.taskId);
+ Log.e(TAG, "Failed to remove task=" + info.taskId);
}
}
}
@@ -112,8 +113,8 @@
private final TaskStackChangeListener mLockListener = new TaskStackChangeListener() {
@Override
- public void onTaskProfileLocked(ActivityManager.RunningTaskInfo info) {
- startWorkChallengeInTask(info);
+ public void onTaskProfileLocked(ActivityManager.RunningTaskInfo info, int userId) {
+ startWorkChallengeInTask(info, userId);
}
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
index 6bbc6f6..c1aefc7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
@@ -112,8 +112,6 @@
viewModel.isShowing.collect { isShowing ->
view.visibility = if (isShowing) View.VISIBLE else View.INVISIBLE
if (isShowing) {
- // Reset Security Container entirely.
- view.visibility = View.VISIBLE
securityContainerController.reinflateViewFlipper {
// Reset Security Container entirely.
securityContainerController.onBouncerVisibilityChanged(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index a98a7d8..951f0bd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -21,6 +21,7 @@
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import android.graphics.Rect
import android.hardware.display.DisplayManager
import android.os.Bundle
import android.os.IBinder
@@ -33,6 +34,7 @@
import com.android.keyguard.ClockEventController
import com.android.keyguard.KeyguardClockSwitch
import com.android.systemui.R
+import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
@@ -61,6 +63,7 @@
private val clockRegistry: ClockRegistry,
private val broadcastDispatcher: BroadcastDispatcher,
private val lockscreenSmartspaceController: LockscreenSmartspaceController,
+ private val udfpsOverlayInteractor: UdfpsOverlayInteractor,
@Assisted bundle: Bundle,
) {
@@ -112,7 +115,9 @@
setUpBottomArea(rootView)
- setupSmartspace(rootView)
+ setUpSmartspace(rootView)
+
+ setUpUdfps(rootView)
setUpClock(rootView)
@@ -169,49 +174,53 @@
/**
* This sets up and shows a non-interactive smart space
*
- * The top padding is as follows:
- * Status bar height + clock top margin + keyguard smart space top offset
+ * The top padding is as follows: Status bar height + clock top margin + keyguard smart space
+ * top offset
*
- * The start padding is as follows:
- * Clock padding start + Below clock padding start
+ * The start padding is as follows: Clock padding start + Below clock padding start
*
- * The end padding is as follows:
- * Below clock padding end
+ * The end padding is as follows: Below clock padding end
*/
- private fun setupSmartspace(parentView: ViewGroup) {
- if (!lockscreenSmartspaceController.isEnabled() ||
- !lockscreenSmartspaceController.isDateWeatherDecoupled()) {
+ private fun setUpSmartspace(parentView: ViewGroup) {
+ if (
+ !lockscreenSmartspaceController.isEnabled() ||
+ !lockscreenSmartspaceController.isDateWeatherDecoupled()
+ ) {
return
}
smartSpaceView = lockscreenSmartspaceController.buildAndConnectDateView(parentView)
- val topPadding: Int = with(context.resources) {
- getDimensionPixelSize(R.dimen.status_bar_header_height_keyguard) +
+ val topPadding: Int =
+ with(context.resources) {
+ getDimensionPixelSize(R.dimen.status_bar_header_height_keyguard) +
getDimensionPixelSize(R.dimen.keyguard_smartspace_top_offset) +
getDimensionPixelSize(R.dimen.keyguard_clock_top_margin)
- }
+ }
- val startPadding: Int = with(context.resources) {
- getDimensionPixelSize(R.dimen.clock_padding_start) +
+ val startPadding: Int =
+ with(context.resources) {
+ getDimensionPixelSize(R.dimen.clock_padding_start) +
getDimensionPixelSize(R.dimen.below_clock_padding_start)
- }
+ }
- val endPadding: Int = context.resources
- .getDimensionPixelSize(R.dimen.below_clock_padding_end)
+ val endPadding: Int =
+ context.resources.getDimensionPixelSize(R.dimen.below_clock_padding_end)
smartSpaceView?.let {
it.setPaddingRelative(startPadding, topPadding, endPadding, 0)
it.isClickable = false
parentView.addView(
- it,
- FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.MATCH_PARENT,
- FrameLayout.LayoutParams.WRAP_CONTENT,
- ),
+ it,
+ FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.WRAP_CONTENT,
+ ),
)
}
+
+ smartSpaceView?.alpha = if (shouldHighlightSelectedAffordance) DIM_ALPHA else 1.0f
}
private fun setUpBottomArea(parentView: ViewGroup) {
@@ -234,6 +243,33 @@
)
}
+ private fun setUpUdfps(parentView: ViewGroup) {
+ val sensorBounds = udfpsOverlayInteractor.udfpsOverlayParams.value.sensorBounds
+
+ // If sensorBounds are default rect, then there is no UDFPS
+ if (sensorBounds == Rect()) {
+ return
+ }
+
+ // Place the UDFPS view in the proper sensor location
+ val fingerprintLayoutParams =
+ FrameLayout.LayoutParams(sensorBounds.width(), sensorBounds.height())
+ fingerprintLayoutParams.setMarginsRelative(
+ sensorBounds.left,
+ sensorBounds.top,
+ sensorBounds.right,
+ sensorBounds.bottom
+ )
+ val finger =
+ LayoutInflater.from(context)
+ .inflate(
+ R.layout.udfps_keyguard_view_internal,
+ parentView,
+ false,
+ ) as View
+ parentView.addView(finger, fingerprintLayoutParams)
+ }
+
private fun setUpClock(parentView: ViewGroup) {
val clockChangeListener =
object : ClockRegistry.ClockChangeListener {
@@ -266,8 +302,6 @@
disposables.add(DisposableHandle { broadcastDispatcher.unregisterReceiver(receiver) })
onClockChanged(parentView)
-
- updateSmartspaceWithSetupClock()
}
private fun onClockChanged(parentView: ViewGroup) {
@@ -281,33 +315,22 @@
?.onTargetRegionChanged(KeyguardClockSwitch.getLargeClockRegion(parentView))
clockView?.let { parentView.removeView(it) }
- clockView = largeClock?.view?.apply {
- if (shouldHighlightSelectedAffordance) {
- alpha = DIM_ALPHA
+ clockView =
+ largeClock?.view?.apply {
+ if (shouldHighlightSelectedAffordance) {
+ alpha = DIM_ALPHA
+ }
+ parentView.addView(this)
+ visibility = View.VISIBLE
}
- parentView.addView(this)
- visibility = View.VISIBLE
- }
} else {
clockView?.visibility = View.GONE
}
- }
- /**
- * Updates smart space after clock is set up. Used to show or hide smartspace with the right
- * opacity based on the clock after setup.
- */
- private fun updateSmartspaceWithSetupClock() {
+ // Hide smart space if the clock has weather display; otherwise show it
val hasCustomWeatherDataDisplay =
- clockController
- .clock
- ?.largeClock
- ?.config
- ?.hasCustomWeatherDataDisplay == true
-
+ clockController.clock?.largeClock?.config?.hasCustomWeatherDataDisplay == true
hideSmartspace(hasCustomWeatherDataDisplay)
-
- smartSpaceView?.alpha = if (shouldHighlightSelectedAffordance) DIM_ALPHA else 1.0f
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableChange.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableChange.kt
index 42fdd68..592044e 100644
--- a/packages/SystemUI/src/com/android/systemui/log/table/TableChange.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/table/TableChange.kt
@@ -27,19 +27,27 @@
*/
data class TableChange(
var timestamp: Long = 0,
- var columnPrefix: String = "",
- var columnName: String = "",
- var isInitial: Boolean = false,
- var type: DataType = DataType.EMPTY,
- var bool: Boolean = false,
- var int: Int? = null,
- var str: String? = null,
+ private var columnPrefix: String = "",
+ private var columnName: String = "",
+ private var isInitial: Boolean = false,
+ private var type: DataType = DataType.EMPTY,
+ private var bool: Boolean = false,
+ private var int: Int? = null,
+ private var str: String? = null,
) {
+ init {
+ // Truncate any strings that were passed into the constructor. [reset] and [set] will take
+ // care of the rest of the truncation.
+ this.columnPrefix = columnPrefix.take(MAX_STRING_LENGTH)
+ this.columnName = columnName.take(MAX_STRING_LENGTH)
+ this.str = str?.take(MAX_STRING_LENGTH)
+ }
+
/** Resets to default values so that the object can be recycled. */
fun reset(timestamp: Long, columnPrefix: String, columnName: String, isInitial: Boolean) {
this.timestamp = timestamp
- this.columnPrefix = columnPrefix
- this.columnName = columnName
+ this.columnPrefix = columnPrefix.take(MAX_STRING_LENGTH)
+ this.columnName = columnName.take(MAX_STRING_LENGTH)
this.isInitial = isInitial
this.type = DataType.EMPTY
this.bool = false
@@ -50,7 +58,7 @@
/** Sets this to store a string change. */
fun set(value: String?) {
type = DataType.STRING
- str = value
+ str = value?.take(MAX_STRING_LENGTH)
}
/** Sets this to store a boolean change. */
@@ -89,6 +97,8 @@
}
}
+ fun getColumnName() = columnName
+
fun getVal(): String {
val value =
when (type) {
@@ -109,5 +119,8 @@
companion object {
@VisibleForTesting const val IS_INITIAL_PREFIX = "**"
+ // Don't allow any strings larger than this length so that we have a hard upper limit on the
+ // size of the data stored by the buffer.
+ @VisibleForTesting const val MAX_STRING_LENGTH = 500
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
index 9d883cc..8babfc9 100644
--- a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
@@ -291,7 +291,7 @@
private fun echoToDesiredEndpoints(change: TableChange) {
if (
logcatEchoTracker.isBufferLoggable(bufferName = name, LogLevel.DEBUG) ||
- logcatEchoTracker.isTagLoggable(change.columnName, LogLevel.DEBUG)
+ logcatEchoTracker.isTagLoggable(change.getColumnName(), LogLevel.DEBUG)
) {
if (change.hasData()) {
localLogcat.d(name, change.logcatRepresentation())
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
index 9997730..fa42114 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
@@ -43,7 +43,6 @@
import android.net.Uri
import android.os.Parcelable
import android.os.Process
-import android.os.RemoteException
import android.os.UserHandle
import android.provider.Settings
import android.service.notification.StatusBarNotification
@@ -53,7 +52,6 @@
import android.util.Pair as APair
import androidx.media.utils.MediaConstants
import com.android.internal.logging.InstanceId
-import com.android.internal.statusbar.IStatusBarService
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.Dumpable
import com.android.systemui.R
@@ -139,8 +137,6 @@
expiryTimeMs = 0,
)
-const val MEDIA_TITLE_ERROR_MESSAGE = "Invalid media data: title is null or blank."
-
fun isMediaNotification(sbn: StatusBarNotification): Boolean {
return sbn.notification.isMediaNotification()
}
@@ -185,7 +181,6 @@
private val logger: MediaUiEventLogger,
private val smartspaceManager: SmartspaceManager,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
- private val statusBarService: IStatusBarService,
) : Dumpable, BcSmartspaceDataPlugin.SmartspaceTargetListener {
companion object {
@@ -257,7 +252,6 @@
mediaFlags: MediaFlags,
logger: MediaUiEventLogger,
smartspaceManager: SmartspaceManager,
- statusBarService: IStatusBarService,
keyguardUpdateMonitor: KeyguardUpdateMonitor,
) : this(
context,
@@ -283,7 +277,6 @@
logger,
smartspaceManager,
keyguardUpdateMonitor,
- statusBarService,
)
private val appChangeReceiver =
@@ -385,21 +378,21 @@
fun onNotificationAdded(key: String, sbn: StatusBarNotification) {
if (useQsMediaPlayer && isMediaNotification(sbn)) {
- var isNewlyActiveEntry = false
+ var logEvent = false
Assert.isMainThread()
val oldKey = findExistingEntry(key, sbn.packageName)
if (oldKey == null) {
val instanceId = logger.getNewInstanceId()
val temp = LOADING.copy(packageName = sbn.packageName, instanceId = instanceId)
mediaEntries.put(key, temp)
- isNewlyActiveEntry = true
+ logEvent = true
} else if (oldKey != key) {
// Resume -> active conversion; move to new key
val oldData = mediaEntries.remove(oldKey)!!
- isNewlyActiveEntry = true
+ logEvent = true
mediaEntries.put(key, oldData)
}
- loadMediaData(key, sbn, oldKey, isNewlyActiveEntry)
+ loadMediaData(key, sbn, oldKey, logEvent)
} else {
onNotificationRemoved(key)
}
@@ -482,9 +475,9 @@
key: String,
sbn: StatusBarNotification,
oldKey: String?,
- isNewlyActiveEntry: Boolean = false,
+ logEvent: Boolean = false
) {
- backgroundExecutor.execute { loadMediaDataInBg(key, sbn, oldKey, isNewlyActiveEntry) }
+ backgroundExecutor.execute { loadMediaDataInBg(key, sbn, oldKey, logEvent) }
}
/** Add a listener for changes in this class */
@@ -608,11 +601,9 @@
}
}
- private fun removeEntry(key: String, logEvent: Boolean = true) {
+ private fun removeEntry(key: String) {
mediaEntries.remove(key)?.let {
- if (logEvent) {
- logger.logMediaRemoved(it.appUid, it.packageName, it.instanceId)
- }
+ logger.logMediaRemoved(it.appUid, it.packageName, it.instanceId)
}
notifyMediaDataRemoved(key)
}
@@ -760,7 +751,7 @@
key: String,
sbn: StatusBarNotification,
oldKey: String?,
- isNewlyActiveEntry: Boolean = false,
+ logEvent: Boolean = false
) {
val token =
sbn.notification.extras.getParcelable(
@@ -774,34 +765,6 @@
val metadata = mediaController.metadata
val notif: Notification = sbn.notification
- // Song name
- var song: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE)
- if (song == null) {
- song = metadata?.getString(MediaMetadata.METADATA_KEY_TITLE)
- }
- if (song == null) {
- song = HybridGroupManager.resolveTitle(notif)
- }
- // Media data must have a title.
- if (song.isNullOrBlank()) {
- try {
- statusBarService.onNotificationError(
- sbn.packageName,
- sbn.tag,
- sbn.id,
- sbn.uid,
- sbn.initialPid,
- MEDIA_TITLE_ERROR_MESSAGE,
- sbn.user.identifier
- )
- } catch (e: RemoteException) {
- Log.e(TAG, "cancelNotification failed: $e")
- }
- // Only add log for media removed if active media is updated with invalid title.
- foregroundExecutor.execute { removeEntry(key, !isNewlyActiveEntry) }
- return
- }
-
val appInfo =
notif.extras.getParcelable(
Notification.EXTRA_BUILDER_APPLICATION_INFO,
@@ -830,6 +793,15 @@
// App Icon
val smallIcon = sbn.notification.smallIcon
+ // Song name
+ var song: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE)
+ if (song == null) {
+ song = metadata?.getString(MediaMetadata.METADATA_KEY_TITLE)
+ }
+ if (song == null) {
+ song = HybridGroupManager.resolveTitle(notif)
+ }
+
// Explicit Indicator
var isExplicit = false
if (mediaFlags.isExplicitIndicatorEnabled()) {
@@ -901,7 +873,7 @@
val instanceId = currentEntry?.instanceId ?: logger.getNewInstanceId()
val appUid = appInfo?.uid ?: Process.INVALID_UID
- if (isNewlyActiveEntry) {
+ if (logEvent) {
logSingleVsMultipleMediaAdded(appUid, sbn.packageName, instanceId)
logger.logActiveMediaAdded(appUid, sbn.packageName, instanceId, playbackLocation)
} else if (playbackLocation != currentEntry?.playbackLocation) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 41e3e6d..9a1efc3 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -15,6 +15,8 @@
*/
package com.android.systemui.navigationbar.gestural;
+import static android.view.InputDevice.SOURCE_MOUSE;
+import static android.view.InputDevice.SOURCE_TOUCHPAD;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
import static com.android.systemui.classifier.Classifier.BACK_GESTURE;
@@ -937,10 +939,12 @@
mMLResults = 0;
mLogGesture = false;
mInRejectedExclusion = false;
- boolean isWithinInsets = isWithinInsets((int) ev.getX(), (int) ev.getY());
// Trackpad back gestures don't have zones, so we don't need to check if the down event
- // is within insets.
+ // is within insets. Also we don't allow back for button press from the trackpad, and
+ // yet we do with a mouse.
+ boolean isWithinInsets = isWithinInsets((int) ev.getX(), (int) ev.getY());
mAllowGesture = !mDisabledForQuickstep && mIsBackGestureAllowed
+ && !isButtonPressFromTrackpad(ev)
&& (isTrackpadMultiFingerSwipe || isWithinInsets)
&& !mGestureBlockingActivityRunning
&& !QuickStepContract.isBackGestureDisabled(mSysUiFlags)
@@ -1047,6 +1051,11 @@
mProtoTracer.scheduleFrameUpdate();
}
+ private boolean isButtonPressFromTrackpad(MotionEvent ev) {
+ int sources = InputManager.getInstance().getInputDevice(ev.getDeviceId()).getSources();
+ return (sources & (SOURCE_MOUSE | SOURCE_TOUCHPAD)) == sources && ev.getButtonState() != 0;
+ }
+
private void dispatchToBackAnimation(MotionEvent event) {
if (mBackAnimation != null) {
mVelocityTracker.addMovement(event);
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/LaunchNotesRoleSettingsTrampolineActivity.kt b/packages/SystemUI/src/com/android/systemui/notetask/LaunchNotesRoleSettingsTrampolineActivity.kt
new file mode 100644
index 0000000..c209a00
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/notetask/LaunchNotesRoleSettingsTrampolineActivity.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2023 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.notetask
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
+import javax.inject.Inject
+
+/**
+ * An internal proxy activity that starts the notes role setting.
+ *
+ * This activity is introduced mainly for the error handling of the notes app lock screen shortcut
+ * picker, which only supports package + action but not extras. See
+ * [KeyguardQuickAffordanceConfig.PickerScreenState.Disabled.actionComponentName].
+ */
+class LaunchNotesRoleSettingsTrampolineActivity
+@Inject
+constructor(
+ private val controller: NoteTaskController,
+) : ComponentActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ val entryPoint =
+ if (intent?.action == ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE) {
+ NoteTaskEntryPoint.QUICK_AFFORDANCE
+ } else {
+ null
+ }
+ controller.startNotesRoleSetting(this, entryPoint)
+ finish()
+ }
+
+ companion object {
+ const val ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE =
+ "com.android.systemui.action.MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
index d4052f5..7e9b346 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
@@ -31,15 +31,14 @@
import android.content.pm.PackageManager
import android.content.pm.ShortcutManager
import android.graphics.drawable.Icon
-import android.os.Build
import android.os.UserHandle
import android.os.UserManager
-import android.util.Log
import android.widget.Toast
import androidx.annotation.VisibleForTesting
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.devicepolicy.areKeyguardShortcutsDisabled
+import com.android.systemui.log.DebugLogger.debugLog
import com.android.systemui.notetask.NoteTaskRoleManagerExt.createNoteShortcutInfoAsUser
import com.android.systemui.notetask.NoteTaskRoleManagerExt.getDefaultRoleHolderAsUser
import com.android.systemui.notetask.shortcut.LaunchNoteTaskManagedProfileProxyActivity
@@ -92,10 +91,10 @@
if (info.launchMode != NoteTaskLaunchMode.AppBubble) return
if (isExpanding) {
- logDebug { "onBubbleExpandChanged - expanding: $info" }
+ debugLog { "onBubbleExpandChanged - expanding: $info" }
eventLogger.logNoteTaskOpened(info)
} else {
- logDebug { "onBubbleExpandChanged - collapsing: $info" }
+ debugLog { "onBubbleExpandChanged - collapsing: $info" }
eventLogger.logNoteTaskClosed(info)
}
}
@@ -112,6 +111,43 @@
)
}
+ /** Starts the notes role setting. */
+ fun startNotesRoleSetting(activityContext: Context, entryPoint: NoteTaskEntryPoint?) {
+ val user =
+ if (entryPoint == null) {
+ userTracker.userHandle
+ } else {
+ getUserForHandlingNotesTaking(entryPoint)
+ }
+ activityContext.startActivityAsUser(
+ Intent(Intent.ACTION_MANAGE_DEFAULT_APP).apply {
+ putExtra(Intent.EXTRA_ROLE_NAME, ROLE_NOTES)
+ },
+ user
+ )
+ }
+
+ /**
+ * Returns the [UserHandle] of an android user that should handle the notes taking [entryPoint].
+ *
+ * On company owned personally enabled (COPE) devices, if the given [entryPoint] is in the
+ * [FORCE_WORK_NOTE_APPS_ENTRY_POINTS_ON_COPE_DEVICES] list, the default notes app in the work
+ * profile user will always be launched.
+ *
+ * On non managed devices or devices with other management modes, the current [UserHandle] is
+ * returned.
+ */
+ fun getUserForHandlingNotesTaking(entryPoint: NoteTaskEntryPoint): UserHandle =
+ if (
+ entryPoint in FORCE_WORK_NOTE_APPS_ENTRY_POINTS_ON_COPE_DEVICES &&
+ devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile
+ ) {
+ userTracker.userProfiles.firstOrNull { userManager.isManagedProfile(it.id) }?.userHandle
+ ?: userTracker.userHandle
+ } else {
+ userTracker.userHandle
+ }
+
/**
* Shows a note task. How the task is shown will depend on when the method is invoked.
*
@@ -122,30 +158,13 @@
* bubble is already opened.
*
* That will let users open other apps in full screen, and take contextual notes.
- *
- * On company owned personally enabled (COPE) devices, if the given [entryPoint] is in the
- * [FORCE_WORK_NOTE_APPS_ENTRY_POINTS_ON_COPE_DEVICES] list, the default notes app in the work
- * profile user will always be launched.
*/
fun showNoteTask(
entryPoint: NoteTaskEntryPoint,
) {
if (!isEnabled) return
- val user: UserHandle =
- if (
- entryPoint in FORCE_WORK_NOTE_APPS_ENTRY_POINTS_ON_COPE_DEVICES &&
- devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile
- ) {
- userTracker.userProfiles
- .firstOrNull { userManager.isManagedProfile(it.id) }
- ?.userHandle
- ?: userTracker.userHandle
- } else {
- userTracker.userHandle
- }
-
- showNoteTaskAsUser(entryPoint, user)
+ showNoteTaskAsUser(entryPoint, getUserForHandlingNotesTaking(entryPoint))
}
/** A variant of [showNoteTask] which launches note task in the given [user]. */
@@ -168,14 +187,14 @@
isKeyguardLocked &&
devicePolicyManager.areKeyguardShortcutsDisabled(userId = user.identifier)
) {
- logDebug { "Enterprise policy disallows launching note app when the screen is locked." }
+ debugLog { "Enterprise policy disallows launching note app when the screen is locked." }
return
}
val info = resolver.resolveInfo(entryPoint, isKeyguardLocked, user)
if (info == null) {
- logDebug { "Default notes app isn't set" }
+ debugLog { "Default notes app isn't set" }
showNoDefaultNotesAppToast()
return
}
@@ -184,7 +203,7 @@
try {
// TODO(b/266686199): We should handle when app not available. For now, we log.
- logDebug { "onShowNoteTask - start: $info on user#${user.identifier}" }
+ debugLog { "onShowNoteTask - start: $info on user#${user.identifier}" }
when (info.launchMode) {
is NoteTaskLaunchMode.AppBubble -> {
val intent = createNoteTaskIntent(info)
@@ -192,7 +211,7 @@
Icon.createWithResource(context, R.drawable.ic_note_task_shortcut_widget)
bubbles.showOrHideAppBubble(intent, user, icon)
// App bubble logging happens on `onBubbleExpandChanged`.
- logDebug { "onShowNoteTask - opened as app bubble: $info" }
+ debugLog { "onShowNoteTask - opened as app bubble: $info" }
}
is NoteTaskLaunchMode.Activity -> {
if (activityManager.isInForeground(info.packageName)) {
@@ -200,20 +219,20 @@
val intent = createHomeIntent()
context.startActivityAsUser(intent, user)
eventLogger.logNoteTaskClosed(info)
- logDebug { "onShowNoteTask - closed as activity: $info" }
+ debugLog { "onShowNoteTask - closed as activity: $info" }
} else {
val intent = createNoteTaskIntent(info)
context.startActivityAsUser(intent, user)
eventLogger.logNoteTaskOpened(info)
- logDebug { "onShowNoteTask - opened as activity: $info" }
+ debugLog { "onShowNoteTask - opened as activity: $info" }
}
}
}
- logDebug { "onShowNoteTask - success: $info" }
+ debugLog { "onShowNoteTask - success: $info" }
} catch (e: ActivityNotFoundException) {
- logDebug { "onShowNoteTask - failed: $info" }
+ debugLog { "onShowNoteTask - failed: $info" }
}
- logDebug { "onShowNoteTask - completed: $info" }
+ debugLog { "onShowNoteTask - completed: $info" }
}
@VisibleForTesting
@@ -253,7 +272,7 @@
PackageManager.DONT_KILL_APP,
)
- logDebug { "setNoteTaskShortcutEnabled - completed: $isEnabled" }
+ debugLog { "setNoteTaskShortcutEnabled - completed: $isEnabled" }
}
/**
@@ -352,11 +371,6 @@
}
}
-/** [Log.println] a [Log.DEBUG] message, only when [Build.IS_DEBUGGABLE]. */
-private inline fun Any.logDebug(message: () -> String) {
- if (Build.IS_DEBUGGABLE) Log.d(this::class.java.simpleName.orEmpty(), message())
-}
-
/** Creates an [Intent] which forces the current app to background by calling home. */
private fun createHomeIntent(): Intent =
Intent(Intent.ACTION_MAIN).apply {
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
index 2c62ffd..4d5173a 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
@@ -45,6 +45,10 @@
@[Binds IntoMap ClassKey(LaunchNoteTaskManagedProfileProxyActivity::class)]
fun LaunchNoteTaskManagedProfileProxyActivity.bindNoteTaskLauncherProxyActivity(): Activity
+ @[Binds IntoMap ClassKey(LaunchNotesRoleSettingsTrampolineActivity::class)]
+ fun LaunchNotesRoleSettingsTrampolineActivity.bindLaunchNotesRoleSettingsTrampolineActivity():
+ Activity
+
companion object {
@[Provides NoteTaskEnabledKey]
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
index 2da5b76..444407c 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
@@ -16,9 +16,12 @@
package com.android.systemui.notetask.quickaffordance
+import android.app.role.OnRoleHoldersChangedListener
+import android.app.role.RoleManager
import android.content.Context
import android.hardware.input.InputSettings
import android.os.Build
+import android.os.UserHandle
import android.os.UserManager
import android.util.Log
import com.android.keyguard.KeyguardUpdateMonitor
@@ -27,17 +30,22 @@
import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyguard.data.quickaffordance.BuiltInKeyguardQuickAffordanceKeys
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.LockScreenState
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnTriggeredResult
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.PickerScreenState
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
+import com.android.systemui.notetask.LaunchNotesRoleSettingsTrampolineActivity.Companion.ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE
import com.android.systemui.notetask.NoteTaskController
import com.android.systemui.notetask.NoteTaskEnabledKey
-import com.android.systemui.notetask.NoteTaskEntryPoint
+import com.android.systemui.notetask.NoteTaskEntryPoint.QUICK_AFFORDANCE
+import com.android.systemui.notetask.NoteTaskInfoResolver
+import com.android.systemui.shared.customization.data.content.CustomizationProviderContract.LockScreenQuickAffordances.AffordanceTable.COMPONENT_NAME_SEPARATOR
import com.android.systemui.stylus.StylusManager
import dagger.Lazy
+import java.util.concurrent.Executor
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.channels.trySendBlocking
@@ -49,13 +57,16 @@
class NoteTaskQuickAffordanceConfig
@Inject
constructor(
- context: Context,
+ private val context: Context,
private val controller: NoteTaskController,
+ private val noteTaskInfoResolver: NoteTaskInfoResolver,
private val stylusManager: StylusManager,
+ private val roleManager: RoleManager,
private val keyguardMonitor: KeyguardUpdateMonitor,
private val userManager: UserManager,
private val lazyRepository: Lazy<KeyguardQuickAffordanceRepository>,
@NoteTaskEnabledKey private val isEnabled: Boolean,
+ @Background private val backgroundExecutor: Executor,
) : KeyguardQuickAffordanceConfig {
override val key = BuiltInKeyguardQuickAffordanceKeys.CREATE_NOTE
@@ -73,15 +84,24 @@
val configSelectedFlow = repository.createConfigSelectedFlow(key)
val stylusEverUsedFlow = stylusManager.createStylusEverUsedFlow(context)
val userUnlockedFlow = userManager.createUserUnlockedFlow(keyguardMonitor)
- combine(userUnlockedFlow, stylusEverUsedFlow, configSelectedFlow) {
+ val defaultNotesAppFlow =
+ roleManager.createNotesRoleFlow(backgroundExecutor, controller, noteTaskInfoResolver)
+ combine(userUnlockedFlow, stylusEverUsedFlow, configSelectedFlow, defaultNotesAppFlow) {
isUserUnlocked,
isStylusEverUsed,
- isConfigSelected ->
+ isConfigSelected,
+ isDefaultNotesAppSet ->
logDebug { "lockScreenState:isUserUnlocked=$isUserUnlocked" }
logDebug { "lockScreenState:isStylusEverUsed=$isStylusEverUsed" }
logDebug { "lockScreenState:isConfigSelected=$isConfigSelected" }
+ logDebug { "lockScreenState:isDefaultNotesAppSet=$isDefaultNotesAppSet" }
- if (isEnabled && isUserUnlocked && (isConfigSelected || isStylusEverUsed)) {
+ if (
+ isEnabled &&
+ isUserUnlocked &&
+ isDefaultNotesAppSet &&
+ (isConfigSelected || isStylusEverUsed)
+ ) {
val contentDescription = ContentDescription.Resource(pickerNameResourceId)
val icon = Icon.Resource(pickerIconResourceId, contentDescription)
LockScreenState.Visible(icon)
@@ -92,15 +112,34 @@
.onEach { state -> logDebug { "lockScreenState=$state" } }
}
- override suspend fun getPickerScreenState() =
- if (isEnabled) {
- PickerScreenState.Default()
- } else {
- PickerScreenState.UnavailableOnDevice
+ override suspend fun getPickerScreenState(): PickerScreenState {
+ val isDefaultNotesAppSet =
+ noteTaskInfoResolver.resolveInfo(
+ QUICK_AFFORDANCE,
+ user = controller.getUserForHandlingNotesTaking(QUICK_AFFORDANCE)
+ ) != null
+ return when {
+ isEnabled && isDefaultNotesAppSet -> PickerScreenState.Default()
+ isEnabled -> {
+ PickerScreenState.Disabled(
+ listOf(
+ context.getString(
+ R.string.keyguard_affordance_enablement_dialog_notes_app_instruction
+ )
+ ),
+ context.getString(
+ R.string.keyguard_affordance_enablement_dialog_notes_app_action
+ ),
+ "${context.packageName}$COMPONENT_NAME_SEPARATOR" +
+ "$ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE",
+ )
+ }
+ else -> PickerScreenState.UnavailableOnDevice
}
+ }
override fun onTriggered(expandable: Expandable?): OnTriggeredResult {
- controller.showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
+ controller.showNoteTask(entryPoint = QUICK_AFFORDANCE)
return OnTriggeredResult.Handled
}
}
@@ -129,6 +168,27 @@
awaitClose { unregisterCallback(callback) }
}
+private fun RoleManager.createNotesRoleFlow(
+ executor: Executor,
+ noteTaskController: NoteTaskController,
+ noteTaskInfoResolver: NoteTaskInfoResolver,
+) = callbackFlow {
+ fun isDefaultNotesAppSetForUser() =
+ noteTaskInfoResolver.resolveInfo(
+ QUICK_AFFORDANCE,
+ user = noteTaskController.getUserForHandlingNotesTaking(QUICK_AFFORDANCE)
+ ) != null
+
+ trySendBlocking(isDefaultNotesAppSetForUser())
+ val callback = OnRoleHoldersChangedListener { roleName, _ ->
+ if (roleName == RoleManager.ROLE_NOTES) {
+ trySendBlocking(isDefaultNotesAppSetForUser())
+ }
+ }
+ addOnRoleHoldersChangedListenerAsUser(executor, callback, UserHandle.ALL)
+ awaitClose { removeOnRoleHoldersChangedListenerAsUser(callback, UserHandle.ALL) }
+}
+
private fun KeyguardQuickAffordanceRepository.createConfigSelectedFlow(key: String) =
selections.map { selected ->
selected.values.flatten().any { selectedConfig -> selectedConfig.key == key }
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt b/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt
index 0f38d32..8ca13b9 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt
@@ -18,12 +18,11 @@
import android.content.Context
import android.content.Intent
-import android.os.Build
import android.os.Bundle
import android.os.UserHandle
import android.os.UserManager
-import android.util.Log
import androidx.activity.ComponentActivity
+import com.android.systemui.log.DebugLogger.debugLog
import com.android.systemui.notetask.NoteTaskController
import com.android.systemui.notetask.NoteTaskEntryPoint
import com.android.systemui.settings.UserTracker
@@ -68,7 +67,7 @@
val mainUser: UserHandle? = userManager.mainUser
if (userManager.isManagedProfile) {
if (mainUser == null) {
- logDebug { "Can't find the main user. Skipping the notes app launch." }
+ debugLog { "Can't find the main user. Skipping the notes app launch." }
} else {
controller.startNoteTaskProxyActivityForUser(mainUser)
}
@@ -89,8 +88,3 @@
}
}
}
-
-/** [Log.println] a [Log.DEBUG] message, only when [Build.IS_DEBUGGABLE]. */
-private inline fun Any.logDebug(message: () -> String) {
- if (Build.IS_DEBUGGABLE) Log.d(this::class.java.simpleName.orEmpty(), message())
-}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
index 79167f2..166ba9f 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
@@ -15,6 +15,7 @@
package com.android.systemui.privacy
import android.content.Context
+import android.content.res.Configuration
import android.util.AttributeSet
import android.view.Gravity.CENTER_VERTICAL
import android.view.Gravity.END
@@ -102,6 +103,11 @@
R.string.ongoing_privacy_chip_content_multiple_apps, typesText)
}
+ override fun onConfigurationChanged(newConfig: Configuration?) {
+ super.onConfigurationChanged(newConfig)
+ updateResources()
+ }
+
private fun updateResources() {
iconMargin = context.resources
.getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_margin)
@@ -110,8 +116,11 @@
iconColor =
Utils.getColorAttrDefaultColor(context, com.android.internal.R.attr.colorPrimary)
+ val height = context.resources
+ .getDimensionPixelSize(R.dimen.ongoing_appops_chip_height)
val padding = context.resources
.getDimensionPixelSize(R.dimen.ongoing_appops_chip_side_padding)
+ iconsContainer.layoutParams.height = height
iconsContainer.setPaddingRelative(padding, 0, padding, 0)
iconsContainer.background = context.getDrawable(R.drawable.statusbar_privacy_chip_bg)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index b7f9f6b..1afc885 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -38,7 +38,9 @@
*/
public class QSContainerImpl extends FrameLayout implements Dumpable {
+ private int mFancyClippingLeftInset;
private int mFancyClippingTop;
+ private int mFancyClippingRightInset;
private int mFancyClippingBottom;
private final float[] mFancyClippingRadii = new float[] {0, 0, 0, 0, 0, 0, 0, 0};
private final Path mFancyClippingPath = new Path();
@@ -53,6 +55,7 @@
private boolean mQsDisabled;
private int mContentHorizontalPadding = -1;
private boolean mClippingEnabled;
+ private boolean mIsFullWidth;
public QSContainerImpl(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -237,7 +240,8 @@
/**
* Clip QS bottom using a concave shape.
*/
- public void setFancyClipping(int top, int bottom, int radius, boolean enabled) {
+ public void setFancyClipping(int leftInset, int top, int rightInset, int bottom, int radius,
+ boolean enabled, boolean fullWidth) {
boolean updatePath = false;
if (mFancyClippingRadii[0] != radius) {
mFancyClippingRadii[0] = radius;
@@ -246,10 +250,18 @@
mFancyClippingRadii[3] = radius;
updatePath = true;
}
+ if (mFancyClippingLeftInset != leftInset) {
+ mFancyClippingLeftInset = leftInset;
+ updatePath = true;
+ }
if (mFancyClippingTop != top) {
mFancyClippingTop = top;
updatePath = true;
}
+ if (mFancyClippingRightInset != rightInset) {
+ mFancyClippingRightInset = rightInset;
+ updatePath = true;
+ }
if (mFancyClippingBottom != bottom) {
mFancyClippingBottom = bottom;
updatePath = true;
@@ -258,6 +270,10 @@
mClippingEnabled = enabled;
updatePath = true;
}
+ if (mIsFullWidth != fullWidth) {
+ mIsFullWidth = fullWidth;
+ updatePath = true;
+ }
if (updatePath) {
updateClippingPath();
@@ -281,15 +297,21 @@
return;
}
- mFancyClippingPath.addRoundRect(0, mFancyClippingTop, getWidth(),
+ int clippingLeft = mIsFullWidth ? -mFancyClippingLeftInset : 0;
+ int clippingRight = mIsFullWidth ? getWidth() + mFancyClippingRightInset : getWidth();
+ mFancyClippingPath.addRoundRect(clippingLeft, mFancyClippingTop, clippingRight,
mFancyClippingBottom, mFancyClippingRadii, Path.Direction.CW);
invalidate();
}
@Override
public void dump(PrintWriter pw, String[] args) {
- pw.println(getClass().getSimpleName() + " updateClippingPath: top("
- + mFancyClippingTop + ") bottom(" + mFancyClippingBottom + ") mClippingEnabled("
- + mClippingEnabled + ")");
+ pw.println(getClass().getSimpleName() + " updateClippingPath: "
+ + "leftInset(" + mFancyClippingLeftInset + ") "
+ + "top(" + mFancyClippingTop + ") "
+ + "rightInset(" + mFancyClippingRightInset + ") "
+ + "bottom(" + mFancyClippingBottom + ") "
+ + "mClippingEnabled(" + mClippingEnabled + ") "
+ + "mIsFullWidth(" + mIsFullWidth + ")");
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index d806afa..fd3f701 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -18,9 +18,10 @@
import static com.android.systemui.media.dagger.MediaModule.QS_PANEL;
import static com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL;
-import static com.android.systemui.statusbar.disableflags.DisableFlagsLogger.DisableState;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED;
+import static com.android.systemui.statusbar.disableflags.DisableFlagsLogger.DisableState;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.res.Configuration;
@@ -395,9 +396,11 @@
}
@Override
- public void setFancyClipping(int top, int bottom, int cornerRadius, boolean visible) {
+ public void setFancyClipping(int leftInset, int top, int rightInset, int bottom,
+ int cornerRadius, boolean visible, boolean fullWidth) {
if (getView() instanceof QSContainerImpl) {
- ((QSContainerImpl) getView()).setFancyClipping(top, bottom, cornerRadius, visible);
+ ((QSContainerImpl) getView()).setFancyClipping(leftInset, top, rightInset, bottom,
+ cornerRadius, visible, fullWidth);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
index 0bce1f7..b70b94b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
@@ -719,7 +719,8 @@
String name = vpnName != null ? vpnName : vpnNameWorkProfile;
String namedVp = mDpm.getResources().getString(
QS_DIALOG_MANAGEMENT_NAMED_VPN,
- () -> mContext.getString(R.string.monitoring_description_named_vpn, name),
+ () -> mContext.getString(
+ R.string.monitoring_description_managed_device_named_vpn, name),
name);
message.append(namedVp);
}
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 4a31998..b806683 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -385,6 +385,11 @@
super.onInitializeAccessibilityNodeInfo(info)
// Clear selected state so it is not announce by talkback.
info.isSelected = false
+ info.text = if (TextUtils.isEmpty(secondaryLabel.text)) {
+ "${label.text}"
+ } else {
+ "${label.text}, ${secondaryLabel.text}"
+ }
if (lastDisabledByPolicy) {
info.addAction(
AccessibilityNodeInfo.AccessibilityAction(
@@ -402,12 +407,6 @@
accessibilityClass
}
if (Switch::class.java.name == accessibilityClass) {
- val label = resources.getString(
- if (tileState) R.string.switch_bar_on else R.string.switch_bar_off)
- // Set the text here for tests in
- // android.platform.test.scenario.sysui.quicksettings. Can be removed when
- // UiObject2 has a new getStateDescription() API and tests are updated.
- info.text = label
info.isChecked = tileState
info.isCheckable = true
if (isLongClickable) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index 7f7f8ad6..2d9f7dd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -68,6 +68,7 @@
private final SensorPrivacyManager mPrivacyManager;
private final BatteryController mBatteryController;
private final SettingObserver mSetting;
+ private final boolean mAllowRotationResolver;
@Inject
public RotationLockTile(
@@ -105,6 +106,8 @@
}
};
mBatteryController.observe(getLifecycle(), this);
+ mAllowRotationResolver = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_allowRotationResolver);
}
@Override
@@ -145,7 +148,7 @@
final boolean powerSave = mBatteryController.isPowerSave();
final boolean cameraLocked = mPrivacyManager.isSensorPrivacyEnabled(CAMERA);
- final boolean cameraRotation =
+ final boolean cameraRotation = mAllowRotationResolver &&
!powerSave && !cameraLocked && hasSufficientPermission(mContext)
&& mController.isCameraRotationEnabled();
state.value = !rotationLocked;
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/BaseScreenSharePermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/BaseScreenSharePermissionDialog.kt
index f63bf07..b340043 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/BaseScreenSharePermissionDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/BaseScreenSharePermissionDialog.kt
@@ -57,8 +57,8 @@
setContentView(R.layout.screen_share_dialog)
dialogTitle = findViewById(R.id.screen_share_dialog_title)
warning = findViewById(R.id.text_warning)
- startButton = findViewById(R.id.button_start)
- cancelButton = findViewById(R.id.button_cancel)
+ startButton = findViewById(android.R.id.button1)
+ cancelButton = findViewById(android.R.id.button2)
updateIcon()
initScreenShareOptions()
createOptionsView(getOptionsViewLayoutId())
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 69008cc..84f358c 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -33,6 +33,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
@@ -60,11 +61,10 @@
public static final int REQUEST_CODE = 2;
private static final int USER_ID_NOT_SPECIFIED = -1;
- private static final int NOTIFICATION_RECORDING_ID = 4274;
- private static final int NOTIFICATION_PROCESSING_ID = 4275;
- private static final int NOTIFICATION_VIEW_ID = 4273;
+ private static final int NOTIF_BASE_ID = 4273;
private static final String TAG = "RecordingService";
private static final String CHANNEL_ID = "screen_record";
+ private static final String GROUP_KEY = "screen_record_saved";
private static final String EXTRA_RESULT_CODE = "extra_resultCode";
private static final String EXTRA_PATH = "extra_path";
private static final String EXTRA_AUDIO_SOURCE = "extra_useAudio";
@@ -89,6 +89,7 @@
private final UiEventLogger mUiEventLogger;
private final NotificationManager mNotificationManager;
private final UserContextProvider mUserContextTracker;
+ private int mNotificationId = NOTIF_BASE_ID;
@Inject
public RecordingService(RecordingController controller, @LongRunning Executor executor,
@@ -134,14 +135,23 @@
}
String action = intent.getAction();
Log.d(TAG, "onStartCommand " + action);
+ NotificationChannel channel = new NotificationChannel(
+ CHANNEL_ID,
+ getString(R.string.screenrecord_title),
+ NotificationManager.IMPORTANCE_DEFAULT);
+ channel.setDescription(getString(R.string.screenrecord_channel_description));
+ channel.enableVibration(true);
+ mNotificationManager.createNotificationChannel(channel);
int currentUserId = mUserContextTracker.getUserContext().getUserId();
UserHandle currentUser = new UserHandle(currentUserId);
switch (action) {
case ACTION_START:
+ // Get a unique ID for this recording's notifications
+ mNotificationId = NOTIF_BASE_ID + (int) SystemClock.uptimeMillis();
mAudioSource = ScreenRecordingAudioSource
.values()[intent.getIntExtra(EXTRA_AUDIO_SOURCE, 0)];
- Log.d(TAG, "recording with audio source" + mAudioSource);
+ Log.d(TAG, "recording with audio source " + mAudioSource);
mShowTaps = intent.getBooleanExtra(EXTRA_SHOW_TAPS, false);
MediaProjectionCaptureTarget captureTarget =
intent.getParcelableExtra(EXTRA_CAPTURE_TARGET,
@@ -169,7 +179,7 @@
} else {
updateState(false);
createErrorNotification();
- stopForeground(true);
+ stopForeground(STOP_FOREGROUND_DETACH);
stopSelf();
return Service.START_NOT_STICKY;
}
@@ -200,7 +210,7 @@
startActivity(Intent.createChooser(shareIntent, shareLabel)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
// Remove notification
- mNotificationManager.cancelAsUser(null, NOTIFICATION_VIEW_ID, currentUser);
+ mNotificationManager.cancelAsUser(null, mNotificationId, currentUser);
return false;
}, false, false);
@@ -260,14 +270,6 @@
@VisibleForTesting
protected void createErrorNotification() {
Resources res = getResources();
- NotificationChannel channel = new NotificationChannel(
- CHANNEL_ID,
- getString(R.string.screenrecord_title),
- NotificationManager.IMPORTANCE_DEFAULT);
- channel.setDescription(getString(R.string.screenrecord_channel_description));
- channel.enableVibration(true);
- mNotificationManager.createNotificationChannel(channel);
-
Bundle extras = new Bundle();
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
res.getString(R.string.screenrecord_title));
@@ -277,7 +279,7 @@
.setSmallIcon(R.drawable.ic_screenrecord)
.setContentTitle(notificationTitle)
.addExtras(extras);
- startForeground(NOTIFICATION_RECORDING_ID, builder.build());
+ startForeground(mNotificationId, builder.build());
}
@VisibleForTesting
@@ -288,14 +290,6 @@
@VisibleForTesting
protected void createRecordingNotification() {
Resources res = getResources();
- NotificationChannel channel = new NotificationChannel(
- CHANNEL_ID,
- getString(R.string.screenrecord_title),
- NotificationManager.IMPORTANCE_DEFAULT);
- channel.setDescription(getString(R.string.screenrecord_channel_description));
- channel.enableVibration(true);
- mNotificationManager.createNotificationChannel(channel);
-
Bundle extras = new Bundle();
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
res.getString(R.string.screenrecord_title));
@@ -323,7 +317,7 @@
.setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_IMMEDIATE)
.addAction(stopAction)
.addExtras(extras);
- startForeground(NOTIFICATION_RECORDING_ID, builder.build());
+ startForeground(mNotificationId, builder.build());
}
@VisibleForTesting
@@ -337,11 +331,12 @@
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
res.getString(R.string.screenrecord_title));
- Notification.Builder builder = new Notification.Builder(getApplicationContext(), CHANNEL_ID)
+ Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID)
.setContentTitle(notificationTitle)
.setContentText(
getResources().getString(R.string.screenrecord_background_processing_label))
.setSmallIcon(R.drawable.ic_screenrecord)
+ .setGroup(GROUP_KEY)
.addExtras(extras);
return builder.build();
}
@@ -378,6 +373,7 @@
PendingIntent.FLAG_IMMUTABLE))
.addAction(shareAction)
.setAutoCancel(true)
+ .setGroup(GROUP_KEY)
.addExtras(extras);
// Add thumbnail if available
@@ -391,6 +387,24 @@
return builder.build();
}
+ /**
+ * Adds a group notification so that save notifications from multiple recordings are
+ * grouped together, and the foreground service recording notification is not
+ */
+ private void postGroupNotification(UserHandle currentUser) {
+ Bundle extras = new Bundle();
+ extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
+ getResources().getString(R.string.screenrecord_title));
+ Notification groupNotif = new Notification.Builder(this, CHANNEL_ID)
+ .setSmallIcon(R.drawable.ic_screenrecord)
+ .setContentTitle(getResources().getString(R.string.screenrecord_save_title))
+ .setGroup(GROUP_KEY)
+ .setGroupSummary(true)
+ .setExtras(extras)
+ .build();
+ mNotificationManager.notifyAsUser(TAG, NOTIF_BASE_ID, groupNotif, currentUser);
+ }
+
private void stopService() {
stopService(USER_ID_NOT_SPECIFIED);
}
@@ -423,27 +437,26 @@
Log.e(TAG, "stopRecording called, but recorder was null");
}
updateState(false);
+ stopForeground(STOP_FOREGROUND_DETACH);
stopSelf();
}
private void saveRecording(int userId) {
UserHandle currentUser = new UserHandle(userId);
- mNotificationManager.notifyAsUser(null, NOTIFICATION_PROCESSING_ID,
+ mNotificationManager.notifyAsUser(null, mNotificationId,
createProcessingNotification(), currentUser);
mLongExecutor.execute(() -> {
try {
Log.d(TAG, "saving recording");
Notification notification = createSaveNotification(getRecorder().save());
- if (!mController.isRecording()) {
- mNotificationManager.notifyAsUser(null, NOTIFICATION_VIEW_ID, notification,
- currentUser);
- }
+ postGroupNotification(currentUser);
+ mNotificationManager.notifyAsUser(null, mNotificationId, notification,
+ currentUser);
} catch (IOException e) {
Log.e(TAG, "Error saving screen recording: " + e.getMessage());
showErrorToast(R.string.screenrecord_delete_error);
- } finally {
- mNotificationManager.cancelAsUser(null, NOTIFICATION_PROCESSING_ID, currentUser);
+ mNotificationManager.cancelAsUser(null, mNotificationId, currentUser);
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 5117915..137a99ef 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -4474,7 +4474,7 @@
mDisplayTopInset = combinedInsets.top;
mDisplayRightInset = combinedInsets.right;
mDisplayLeftInset = combinedInsets.left;
- mQsController.setDisplayInsets(mDisplayRightInset, mDisplayLeftInset);
+ mQsController.setDisplayInsets(mDisplayLeftInset, mDisplayRightInset);
mNavigationBarBottomHeight = insets.getStableInsetBottom();
updateMaxHeadsUpTranslation();
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
index 4012736..a1fa8fb 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
@@ -85,11 +85,13 @@
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
+import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
+import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.LargeScreenUtils;
@@ -116,6 +118,7 @@
private final PulseExpansionHandler mPulseExpansionHandler;
private final ShadeExpansionStateManager mShadeExpansionStateManager;
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ private final LightBarController mLightBarController;
private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
private final NotificationShadeDepthController mDepthController;
@@ -135,6 +138,7 @@
private final LockscreenGestureLogger mLockscreenGestureLogger;
private final ShadeLogger mShadeLog;
private final KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor;
+ private final CastController mCastController;
private final FeatureFlags mFeatureFlags;
private final InteractionJankMonitor mInteractionJankMonitor;
private final ShadeRepository mShadeRepository;
@@ -302,6 +306,7 @@
NotificationRemoteInputManager remoteInputManager,
ShadeExpansionStateManager shadeExpansionStateManager,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+ LightBarController lightBarController,
NotificationStackScrollLayoutController notificationStackScrollLayoutController,
LockscreenShadeTransitionController lockscreenShadeTransitionController,
NotificationShadeDepthController notificationShadeDepthController,
@@ -324,7 +329,8 @@
InteractionJankMonitor interactionJankMonitor,
ShadeLogger shadeLog,
KeyguardFaceAuthInteractor keyguardFaceAuthInteractor,
- ShadeRepository shadeRepository
+ ShadeRepository shadeRepository,
+ CastController castController
) {
mPanelViewControllerLazy = panelViewControllerLazy;
mPanelView = panelView;
@@ -343,6 +349,7 @@
mRemoteInputManager = remoteInputManager;
mShadeExpansionStateManager = shadeExpansionStateManager;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+ mLightBarController = lightBarController;
mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
mDepthController = notificationShadeDepthController;
@@ -364,6 +371,7 @@
mMetricsLogger = metricsLogger;
mShadeLog = shadeLog;
mKeyguardFaceAuthInteractor = keyguardFaceAuthInteractor;
+ mCastController = castController;
mFeatureFlags = featureFlags;
mInteractionJankMonitor = interactionJankMonitor;
mShadeRepository = shadeRepository;
@@ -879,7 +887,9 @@
}
void setOverScrollAmount(int overExpansion) {
- mQs.setOverScrollAmount(overExpansion);
+ if (mQs != null) {
+ mQs.setOverScrollAmount(overExpansion);
+ }
}
private void setOverScrolling(boolean overscrolling) {
@@ -1014,6 +1024,9 @@
mShadeHeaderController.setShadeExpandedFraction(shadeExpandedFraction);
mShadeHeaderController.setQsExpandedFraction(qsExpansionFraction);
mShadeHeaderController.setQsVisible(mVisible);
+
+ // Update the light bar
+ mLightBarController.setQsExpanded(mFullyExpanded);
}
float getLockscreenShadeDragProgress() {
@@ -1188,7 +1201,9 @@
mLastClipBounds.set(left, top, right, bottom);
if (mIsFullWidth) {
clipStatusView = qsVisible;
- float screenCornerRadius = mRecordingController.isRecording() ? 0 : mScreenCornerRadius;
+ float screenCornerRadius =
+ mRecordingController.isRecording() || mCastController.hasConnectedCastDevice()
+ ? 0 : mScreenCornerRadius;
radius = (int) MathUtils.lerp(screenCornerRadius, mScrimCornerRadius,
Math.min(top / (float) mScrimCornerRadius, 1f));
mScrimController.setNotificationBottomRadius(radius);
@@ -1217,10 +1232,13 @@
mVisible = qsVisible;
mQs.setQsVisible(qsVisible);
mQs.setFancyClipping(
+ mDisplayLeftInset,
clipTop,
+ mDisplayRightInset,
clipBottom,
radius,
- qsVisible && !mSplitShadeEnabled);
+ qsVisible && !mSplitShadeEnabled,
+ mIsFullWidth);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
index 07b6869..b6970ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
@@ -20,6 +20,7 @@
import android.content.res.Resources
import android.os.SystemProperties
import android.os.Trace
+import android.os.Trace.TRACE_TAG_APP
import android.util.IndentingPrintWriter
import android.util.MathUtils
import android.view.CrossWindowBlurListeners
@@ -43,8 +44,8 @@
) : Dumpable {
val minBlurRadius = resources.getDimensionPixelSize(R.dimen.min_window_blur_radius)
val maxBlurRadius = resources.getDimensionPixelSize(R.dimen.max_window_blur_radius)
- private val traceCookie = System.identityHashCode(this)
private var lastAppliedBlur = 0
+ private var earlyWakeupEnabled = false
init {
dumpManager.registerDumpable(javaClass.name, this)
@@ -72,6 +73,26 @@
}
/**
+ * This method should be called before [applyBlur] so that, if needed, we can set the
+ * early-wakeup flag in SurfaceFlinger.
+ */
+ fun prepareBlur(viewRootImpl: ViewRootImpl?, radius: Int) {
+ if (viewRootImpl == null || !viewRootImpl.surfaceControl.isValid ||
+ !supportsBlursOnWindows() || earlyWakeupEnabled
+ ) {
+ return
+ }
+ if (lastAppliedBlur == 0 && radius != 0) {
+ Trace.asyncTraceForTrackBegin(TRACE_TAG_APP, TRACK_NAME, EARLY_WAKEUP_SLICE_NAME, 0)
+ earlyWakeupEnabled = true
+ createTransaction().use {
+ it.setEarlyWakeupStart()
+ it.apply()
+ }
+ }
+ }
+
+ /**
* Applies background blurs to a {@link ViewRootImpl}.
*
* @param viewRootImpl The window root.
@@ -85,14 +106,20 @@
createTransaction().use {
if (supportsBlursOnWindows()) {
it.setBackgroundBlurRadius(viewRootImpl.surfaceControl, radius)
- if (lastAppliedBlur == 0 && radius != 0) {
- Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_APP, TRACK_NAME,
- EARLY_WAKEUP_SLICE_NAME, traceCookie)
+ if (!earlyWakeupEnabled && lastAppliedBlur == 0 && radius != 0) {
+ Trace.asyncTraceForTrackBegin(
+ TRACE_TAG_APP,
+ TRACK_NAME,
+ EARLY_WAKEUP_SLICE_NAME,
+ 0
+ )
it.setEarlyWakeupStart()
+ earlyWakeupEnabled = true
}
- if (lastAppliedBlur != 0 && radius == 0) {
+ if (earlyWakeupEnabled && lastAppliedBlur != 0 && radius == 0) {
it.setEarlyWakeupEnd()
- Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_APP, TRACK_NAME, traceCookie)
+ Trace.asyncTraceForTrackEnd(TRACE_TAG_APP, TRACK_NAME, 0)
+ earlyWakeupEnabled = false
}
lastAppliedBlur = radius
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java
index 505f45d..dcd9dc3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java
@@ -52,7 +52,6 @@
mActivatableNotificationViewController = activatableNotificationViewController;
mKeyguardBypassController = keyguardBypassController;
mStatusBarStateController = statusBarStateController;
- mView.useRoundnessSourceTypes(true);
mView.setSensitiveRevealAnimEndabled(featureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM));
mOnAttachStateChangeListener = new View.OnAttachStateChangeListener() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index 8dc7842..a3bd247 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -189,12 +189,7 @@
scheduleUpdate()
}
- /**
- * Callback that updates the window blur value and is called only once per frame.
- */
- @VisibleForTesting
- val updateBlurCallback = Choreographer.FrameCallback {
- updateScheduled = false
+ private fun computeBlurAndZoomOut(): Pair<Int, Float> {
val animationRadius = MathUtils.constrain(shadeAnimation.radius,
blurUtils.minBlurRadius.toFloat(), blurUtils.maxBlurRadius.toFloat())
val expansionRadius = blurUtils.blurRadiusOfRatio(
@@ -232,6 +227,16 @@
// Brightness slider removes blur, but doesn't affect zooms
blur = (blur * (1f - brightnessMirrorSpring.ratio)).toInt()
+ return Pair(blur, zoomOut)
+ }
+
+ /**
+ * Callback that updates the window blur value and is called only once per frame.
+ */
+ @VisibleForTesting
+ val updateBlurCallback = Choreographer.FrameCallback {
+ updateScheduled = false
+ val (blur, zoomOut) = computeBlurAndZoomOut()
val opaque = scrimsVisible && !blursDisabledForAppLaunch
Trace.traceCounter(Trace.TRACE_TAG_APP, "shade_blur_radius", blur)
blurUtils.applyBlur(root.viewRootImpl, blur, opaque)
@@ -441,6 +446,8 @@
return
}
updateScheduled = true
+ val (blur, _) = computeBlurAndZoomOut()
+ blurUtils.prepareBlur(root.viewRootImpl, blur)
choreographer.postFrameCallback(updateBlurCallback)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 7eb63da..49c7950 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -44,7 +44,6 @@
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
-import com.android.systemui.statusbar.notification.LegacySourceType;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.SourceType;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
@@ -128,13 +127,6 @@
setClipToPadding(false);
mShelfIcons.setIsStaticLayout(false);
requestRoundness(/* top = */ 1f, /* bottom = */ 1f, BASE_VALUE, /* animate = */ false);
-
- if (!mUseRoundnessSourceTypes) {
- // Setting this to first in section to get the clipping to the top roundness correct.
- // This value determines the way we are clipping to the top roundness of the overall
- // shade
- setFirstInSection(true);
- }
updateResources();
}
@@ -569,17 +561,8 @@
* mAmbientState.getExpansionFraction();
final float cornerAnimationTop = shelfStart - cornerAnimationDistance;
- final SourceType sourceType;
- if (mUseRoundnessSourceTypes) {
- sourceType = SHELF_SCROLL;
- } else {
- sourceType = LegacySourceType.OnScroll;
- }
-
final float topValue;
- if (!mUseRoundnessSourceTypes && anv.isFirstInSection()) {
- topValue = 1f;
- } else if (viewStart >= cornerAnimationTop) {
+ if (viewStart >= cornerAnimationTop) {
// Round top corners within animation bounds
topValue = MathUtils.saturate(
(viewStart - cornerAnimationTop) / cornerAnimationDistance);
@@ -588,12 +571,10 @@
// Reset top and bottom corners outside of animation bounds.
topValue = 0f;
}
- anv.requestTopRoundness(topValue, sourceType, /* animate = */ false);
+ anv.requestTopRoundness(topValue, SHELF_SCROLL, /* animate = */ false);
final float bottomValue;
- if (!mUseRoundnessSourceTypes && anv.isLastInSection()) {
- bottomValue = 1f;
- } else if (viewEnd >= cornerAnimationTop) {
+ if (viewEnd >= cornerAnimationTop) {
// Round bottom corners within animation bounds
bottomValue = MathUtils.saturate(
(viewEnd - cornerAnimationTop) / cornerAnimationDistance);
@@ -602,7 +583,7 @@
// Reset top and bottom corners outside of animation bounds.
bottomValue = 0f;
}
- anv.requestBottomRoundness(bottomValue, sourceType, /* animate = */ false);
+ anv.requestBottomRoundness(bottomValue, SHELF_SCROLL, /* animate = */ false);
}
private boolean isViewAffectedBySwipe(ExpandableView expandableView) {
@@ -1100,15 +1081,6 @@
child.requestRoundnessReset(SHELF_SCROLL);
}
- /**
- * This method resets the OnScroll roundness of a view to 0f
- * <p>
- * Note: This should be the only class that handles roundness {@code SourceType.OnScroll}
- */
- public static void resetLegacyOnScrollRoundness(ExpandableView expandableView) {
- expandableView.requestRoundnessReset(LegacySourceType.OnScroll);
- }
-
@Override
public void dump(PrintWriter pwOriginal, String[] args) {
IndentingPrintWriter pw = DumpUtilsKt.asIndenting(pwOriginal);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index 976924a..821a172 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -87,13 +87,8 @@
bypassController.isPulseExpanding = value
if (changed) {
if (value) {
- val topEntry = headsUpManager.topEntry
- topEntry?.let {
- roundnessManager.setTrackingHeadsUp(it.row)
- }
lockscreenShadeTransitionController.onPulseExpansionStarted()
} else {
- roundnessManager.setTrackingHeadsUp(null)
if (!leavingLockscreen) {
bypassController.maybePerformPendingUnlock()
pulseExpandAbortListener?.run()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 7755003..129c859 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -26,6 +26,7 @@
import android.app.ActivityManager;
import android.app.Notification;
import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
@@ -75,9 +76,9 @@
*/
private static final float DARK_ALPHA_BOOST = 0.67f;
/**
- * Status icons are currently drawn with the intention of being 17dp tall, but we
- * want to scale them (in a way that doesn't require an asset dump) down 2dp. So
- * 17dp * (15 / 17) = 15dp, the new height. After the first call to {@link #reloadDimens} all
+ * Status icons are currently drawn with the intention of being 17sp tall, but we
+ * want to scale them (in a way that doesn't require an asset dump) down 2sp. So
+ * 17sp * (15 / 17) = 15sp, the new height. After the first call to {@link #reloadDimens} all
* values will be in px.
*/
private float mSystemIconDesiredHeight = 15f;
@@ -144,7 +145,7 @@
private String mNumberText;
private StatusBarNotification mNotification;
private final boolean mBlocked;
- private int mDensity;
+ private Configuration mConfiguration;
private boolean mNightMode;
private float mIconScale = 1.0f;
private final Paint mDotPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@@ -198,9 +199,8 @@
mNumberPain.setAntiAlias(true);
setNotification(sbn);
setScaleType(ScaleType.CENTER);
- mDensity = context.getResources().getDisplayMetrics().densityDpi;
- Configuration configuration = context.getResources().getConfiguration();
- mNightMode = (configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK)
+ mConfiguration = new Configuration(context.getResources().getConfiguration());
+ mNightMode = (mConfiguration.uiMode & Configuration.UI_MODE_NIGHT_MASK)
== Configuration.UI_MODE_NIGHT_YES;
initializeDecorColor();
reloadDimens();
@@ -214,7 +214,7 @@
mAlwaysScaleIcon = true;
reloadDimens();
maybeUpdateIconScaleDimens();
- mDensity = context.getResources().getDisplayMetrics().densityDpi;
+ mConfiguration = new Configuration(context.getResources().getConfiguration());
}
/** Should always be preceded by {@link #reloadDimens()} */
@@ -231,12 +231,17 @@
private void updateIconScaleForNotifications() {
final float imageBounds = mIncreasedSize ?
mStatusBarIconDrawingSizeIncreased : mStatusBarIconDrawingSize;
- final int outerBounds = mStatusBarIconSize;
- mIconScale = imageBounds / (float)outerBounds;
+ float iconHeight = getIconHeight();
+ if (iconHeight != 0) {
+ mIconScale = imageBounds / iconHeight;
+ } else {
+ final int outerBounds = mStatusBarIconSize;
+ mIconScale = imageBounds / (float) outerBounds;
+ }
updatePivot();
}
- // Makes sure that all icons are scaled to the same height (15dp). If we cannot get a height
+ // Makes sure that all icons are scaled to the same height (15sp). If we cannot get a height
// for the icon, it uses the default SCALE (15f / 17f) which is the old behavior
private void updateIconScaleForSystemIcons() {
float iconHeight = getIconHeight();
@@ -267,12 +272,10 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- int density = newConfig.densityDpi;
- if (density != mDensity) {
- mDensity = density;
- reloadDimens();
- updateDrawable();
- maybeUpdateIconScaleDimens();
+ final int configDiff = newConfig.diff(mConfiguration);
+ mConfiguration.setTo(newConfig);
+ if ((configDiff & (ActivityInfo.CONFIG_DENSITY | ActivityInfo.CONFIG_FONT_SCALE)) != 0) {
+ updateIconDimens();
}
boolean nightMode = (newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
== Configuration.UI_MODE_NIGHT_YES;
@@ -282,6 +285,15 @@
}
}
+ /**
+ * Update the icon dimens and drawable with current resources
+ */
+ public void updateIconDimens() {
+ reloadDimens();
+ updateDrawable();
+ maybeUpdateIconScaleDimens();
+ }
+
private void reloadDimens() {
boolean applyRadius = mDotRadius == mStaticDotRadius;
Resources res = getResources();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt
index 76ff97d..212f2c215 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt
@@ -448,10 +448,3 @@
}
}
}
-
-@Deprecated("Use SourceType.from() instead", ReplaceWith("SourceType.from()"))
-enum class LegacySourceType : SourceType {
- DefaultValue,
- OnDismissAnimation,
- OnScroll,
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 766ad88..66d4c3a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -110,7 +110,6 @@
protected Point mTargetPoint;
private boolean mDismissed;
private boolean mRefocusOnDismiss;
- protected boolean mUseRoundnessSourceTypes;
public ActivatableNotificationView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -709,18 +708,10 @@
mTouchHandler = touchHandler;
}
- /**
- * Enable the support for rounded corner based on the SourceType
- * @param enabled true if is supported
- */
- public void useRoundnessSourceTypes(boolean enabled) {
- mUseRoundnessSourceTypes = enabled;
- }
-
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- if (mUseRoundnessSourceTypes && !mOnDetachResetRoundness.isEmpty()) {
+ if (!mOnDetachResetRoundness.isEmpty()) {
for (SourceType sourceType : mOnDetachResetRoundness) {
requestRoundnessReset(sourceType);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index e468a59..5978133 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -87,7 +87,6 @@
import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
import com.android.systemui.statusbar.notification.FeedbackIcon;
import com.android.systemui.statusbar.notification.LaunchAnimationParameters;
-import com.android.systemui.statusbar.notification.LegacySourceType;
import com.android.systemui.statusbar.notification.NotificationFadeAware;
import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorController;
import com.android.systemui.statusbar.notification.NotificationUtils;
@@ -866,9 +865,6 @@
}
onAttachedChildrenCountChanged();
row.setIsChildInGroup(false, null);
- if (!mUseRoundnessSourceTypes) {
- row.requestBottomRoundness(0.0f, LegacySourceType.DefaultValue, /* animate = */ false);
- }
}
/**
@@ -884,10 +880,6 @@
if (child.keepInParentForDismissAnimation()) {
mChildrenContainer.removeNotification(child);
child.setIsChildInGroup(false, null);
- if (!mUseRoundnessSourceTypes) {
- LegacySourceType sourceType = LegacySourceType.DefaultValue;
- child.requestBottomRoundness(0f, sourceType, /* animate = */ false);
- }
child.setKeepInParentForDismissAnimation(false);
logKeepInParentChildDetached(child);
childCountChanged = true;
@@ -942,9 +934,7 @@
mNotificationParent.updateBackgroundForGroupState();
}
updateBackgroundClipping();
- if (mUseRoundnessSourceTypes) {
- updateBaseRoundness();
- }
+ updateBaseRoundness();
}
@Override
@@ -1054,15 +1044,13 @@
if (isAboveShelf() != wasAboveShelf) {
mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
}
- if (mUseRoundnessSourceTypes) {
- if (pinned) {
- // Should be animated if someone explicitly set it to 0 and the row is shown.
- boolean animated = mAnimatePinnedRoundness && isShown();
- requestRoundness(/* top = */ 1f, /* bottom = */ 1f, PINNED, animated);
- } else {
- requestRoundnessReset(PINNED);
- mAnimatePinnedRoundness = true;
- }
+ if (pinned) {
+ // Should be animated if someone explicitly set it to 0 and the row is shown.
+ boolean animated = mAnimatePinnedRoundness && isShown();
+ requestRoundness(/* top = */ 1f, /* bottom = */ 1f, PINNED, animated);
+ } else {
+ requestRoundnessReset(PINNED);
+ mAnimatePinnedRoundness = true;
}
}
@@ -1879,7 +1867,6 @@
mChildrenContainer.setIsLowPriority(mIsLowPriority);
mChildrenContainer.setContainingNotification(ExpandableNotificationRow.this);
mChildrenContainer.onNotificationUpdated();
- mChildrenContainer.useRoundnessSourceTypes(mUseRoundnessSourceTypes);
mTranslateableViews.add(mChildrenContainer);
});
@@ -2308,24 +2295,6 @@
mBackgroundNormal.setExpandAnimationSize(params.getWidth(), actualHeight);
}
- @Override
- public float getTopRoundness() {
- if (!mUseRoundnessSourceTypes && mExpandAnimationRunning) {
- return mTopRoundnessDuringLaunchAnimation;
- }
-
- return super.getTopRoundness();
- }
-
- @Override
- public float getBottomRoundness() {
- if (!mUseRoundnessSourceTypes && mExpandAnimationRunning) {
- return mBottomRoundnessDuringLaunchAnimation;
- }
-
- return super.getBottomRoundness();
- }
-
public void setExpandAnimationRunning(boolean expandAnimationRunning) {
if (expandAnimationRunning) {
setAboveShelf(true);
@@ -3481,18 +3450,11 @@
private void applyChildrenRoundness() {
if (mIsSummaryWithChildren) {
- if (mUseRoundnessSourceTypes) {
- mChildrenContainer.requestRoundness(
- /* top = */ getTopRoundness(),
- /* bottom = */ getBottomRoundness(),
- /* sourceType = */ FROM_PARENT,
- /* animate = */ false);
- } else {
- mChildrenContainer.requestBottomRoundness(
- getBottomRoundness(),
- LegacySourceType.DefaultValue,
- /* animate = */ false);
- }
+ mChildrenContainer.requestRoundness(
+ /* top = */ getTopRoundness(),
+ /* bottom = */ getBottomRoundness(),
+ /* sourceType = */ FROM_PARENT,
+ /* animate = */ false);
}
}
@@ -3709,24 +3671,10 @@
}
}
- /**
- * Enable the support for rounded corner based on the SourceType
- * @param enabled true if is supported
- */
- @Override
- public void useRoundnessSourceTypes(boolean enabled) {
- super.useRoundnessSourceTypes(enabled);
- if (mChildrenContainer != null) {
- mChildrenContainer.useRoundnessSourceTypes(mUseRoundnessSourceTypes);
- }
- }
-
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- if (mUseRoundnessSourceTypes) {
- updateBaseRoundness();
- }
+ updateBaseRoundness();
}
/** Set whether this notification may show a snooze action. */
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 19c612e..1acc9f9 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
@@ -261,7 +261,6 @@
mStatusBarStateController.removeCallback(mStatusBarStateListener);
}
});
- mView.useRoundnessSourceTypes(true);
}
private final StatusBarStateController.StateListener mStatusBarStateListener =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
index 9a777ea..2c59c2e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
@@ -72,7 +72,6 @@
private View mFeedbackIcon;
private boolean mIsLowPriority;
private boolean mTransformLowPriorityTitle;
- private boolean mUseRoundnessSourceTypes;
private RoundnessChangedListener mRoundnessChangedListener;
protected NotificationHeaderViewWrapper(Context ctx, View view, ExpandableNotificationRow row) {
@@ -122,7 +121,7 @@
@Override
public void applyRoundnessAndInvalidate() {
- if (mUseRoundnessSourceTypes && mRoundnessChangedListener != null) {
+ if (mRoundnessChangedListener != null) {
// We cannot apply the rounded corner to this View, so our parents (in drawChild()) will
// clip our canvas. So we should invalidate our parent.
mRoundnessChangedListener.applyRoundnessAndInvalidate();
@@ -377,15 +376,6 @@
}
/**
- * Enable the support for rounded corner based on the SourceType
- *
- * @param enabled true if is supported
- */
- public void useRoundnessSourceTypes(boolean enabled) {
- mUseRoundnessSourceTypes = enabled;
- }
-
- /**
* Interface that handle the Roundness changes
*/
public interface RoundnessChangedListener {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
index 8106715..12956ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
@@ -81,7 +81,6 @@
ActivatableNotificationViewBinder.bind(viewModel, shelf, falsingManager)
shelf.apply {
setRefactorFlagEnabled(true)
- useRoundnessSourceTypes(true)
setSensitiveRevealAnimEndabled(featureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM))
// TODO(278765923): Replace with eventual NotificationIconContainerViewBinder#bind()
notificationIconAreaController.setShelfIcons(shelfIcons)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 160a230..d18757d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -45,9 +45,7 @@
import com.android.systemui.R;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.NotificationGroupingUtil;
-import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.notification.FeedbackIcon;
-import com.android.systemui.statusbar.notification.LegacySourceType;
import com.android.systemui.statusbar.notification.NotificationFadeAware;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.Roundable;
@@ -133,7 +131,6 @@
private int mUntruncatedChildCount;
private boolean mContainingNotificationIsFaded = false;
private RoundableState mRoundableState;
- private boolean mUseRoundnessSourceTypes;
public NotificationChildrenContainer(Context context) {
this(context, null);
@@ -328,13 +325,6 @@
row.setContentTransformationAmount(0, false /* isLastChild */);
row.setNotificationFaded(mContainingNotificationIsFaded);
- if (!mUseRoundnessSourceTypes) {
- // This is a workaround, the NotificationShelf should be the owner of `OnScroll`
- // roundness.
- // Here we should reset the `OnScroll` roundness only on top-level rows.
- NotificationShelf.resetLegacyOnScrollRoundness(row);
- }
-
// It doesn't make sense to keep old animations around, lets cancel them!
ExpandableViewState viewState = row.getViewState();
if (viewState != null) {
@@ -342,9 +332,7 @@
row.cancelAppearDrawing();
}
- if (mUseRoundnessSourceTypes) {
- applyRoundnessAndInvalidate();
- }
+ applyRoundnessAndInvalidate();
}
private void ensureRemovedFromTransientContainer(View v) {
@@ -379,10 +367,8 @@
mGroupingUtil.restoreChildNotification(row);
}
- if (mUseRoundnessSourceTypes) {
- row.requestRoundnessReset(FROM_PARENT, /* animate = */ false);
- applyRoundnessAndInvalidate();
- }
+ row.requestRoundnessReset(FROM_PARENT, /* animate = */ false);
+ applyRoundnessAndInvalidate();
}
/**
@@ -409,10 +395,7 @@
getContext(),
mNotificationHeader,
mContainingNotification);
- mNotificationHeaderWrapper.useRoundnessSourceTypes(mUseRoundnessSourceTypes);
- if (mUseRoundnessSourceTypes) {
- mNotificationHeaderWrapper.setOnRoundnessChangedListener(this::invalidate);
- }
+ mNotificationHeaderWrapper.setOnRoundnessChangedListener(this::invalidate);
addView(mNotificationHeader, 0);
invalidate();
} else {
@@ -450,12 +433,7 @@
getContext(),
mNotificationHeaderLowPriority,
mContainingNotification);
- mNotificationHeaderWrapperLowPriority.useRoundnessSourceTypes(
- mUseRoundnessSourceTypes
- );
- if (mUseRoundnessSourceTypes) {
- mNotificationHeaderWrapper.setOnRoundnessChangedListener(this::invalidate);
- }
+ mNotificationHeaderWrapper.setOnRoundnessChangedListener(this::invalidate);
addView(mNotificationHeaderLowPriority, 0);
invalidate();
} else {
@@ -891,7 +869,7 @@
isCanvasChanged = true;
canvas.save();
- if (mUseRoundnessSourceTypes && translation != 0f) {
+ if (translation != 0f) {
clipPath.offset(translation, 0f);
canvas.clipPath(clipPath);
clipPath.offset(-translation, 0f);
@@ -1444,40 +1422,30 @@
@Override
public void applyRoundnessAndInvalidate() {
boolean last = true;
- if (mUseRoundnessSourceTypes) {
- if (mNotificationHeaderWrapper != null) {
- mNotificationHeaderWrapper.requestTopRoundness(
- /* value = */ getTopRoundness(),
- /* sourceType = */ FROM_PARENT,
- /* animate = */ false
- );
- }
- if (mNotificationHeaderWrapperLowPriority != null) {
- mNotificationHeaderWrapperLowPriority.requestTopRoundness(
- /* value = */ getTopRoundness(),
- /* sourceType = */ FROM_PARENT,
- /* animate = */ false
- );
- }
+ if (mNotificationHeaderWrapper != null) {
+ mNotificationHeaderWrapper.requestTopRoundness(
+ /* value = */ getTopRoundness(),
+ /* sourceType = */ FROM_PARENT,
+ /* animate = */ false
+ );
+ }
+ if (mNotificationHeaderWrapperLowPriority != null) {
+ mNotificationHeaderWrapperLowPriority.requestTopRoundness(
+ /* value = */ getTopRoundness(),
+ /* sourceType = */ FROM_PARENT,
+ /* animate = */ false
+ );
}
for (int i = mAttachedChildren.size() - 1; i >= 0; i--) {
ExpandableNotificationRow child = mAttachedChildren.get(i);
if (child.getVisibility() == View.GONE) {
continue;
}
- if (mUseRoundnessSourceTypes) {
- child.requestRoundness(
- /* top = */ 0f,
- /* bottom = */ last ? getBottomRoundness() : 0f,
- /* sourceType = */ FROM_PARENT,
- /* animate = */ false);
- } else {
- child.requestRoundness(
- /* top = */ 0f,
- /* bottom = */ last ? getBottomRoundness() : 0f,
- LegacySourceType.DefaultValue,
- /* animate = */ isShown());
- }
+ child.requestRoundness(
+ /* top = */ 0f,
+ /* bottom = */ last ? getBottomRoundness() : 0f,
+ /* sourceType = */ FROM_PARENT,
+ /* animate = */ false);
last = false;
}
Roundable.super.applyRoundnessAndInvalidate();
@@ -1537,15 +1505,6 @@
return mNotificationHeaderWrapper;
}
- /**
- * Enable the support for rounded corner based on the SourceType
- *
- * @param enabled true if is supported
- */
- public void useRoundnessSourceTypes(boolean enabled) {
- mUseRoundnessSourceTypes = enabled;
- }
-
public String debugString() {
return TAG + " { "
+ "visibility: " + getVisibility()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
index b6aec83ae..fa1843e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
@@ -16,22 +16,13 @@
package com.android.systemui.statusbar.notification.stack;
-import android.content.res.Resources;
-import android.util.MathUtils;
-
import androidx.annotation.NonNull;
import com.android.systemui.Dumpable;
-import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.statusbar.notification.LegacySourceType;
-import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
import com.android.systemui.statusbar.notification.Roundable;
import com.android.systemui.statusbar.notification.SourceType;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.logging.NotificationRoundnessLogger;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import java.io.PrintWriter;
@@ -48,63 +39,27 @@
private static final String TAG = "NotificationRoundnessManager";
private static final SourceType DISMISS_ANIMATION = SourceType.from("DismissAnimation");
- private final ExpandableView[] mFirstInSectionViews;
- private final ExpandableView[] mLastInSectionViews;
- private final ExpandableView[] mTmpFirstInSectionViews;
- private final ExpandableView[] mTmpLastInSectionViews;
- private final NotificationRoundnessLogger mNotifLogger;
private final DumpManager mDumpManager;
- private boolean mExpanded;
private HashSet<ExpandableView> mAnimatedChildren;
- private Runnable mRoundingChangedCallback;
- private ExpandableNotificationRow mTrackedHeadsUp;
- private float mAppearFraction;
private boolean mRoundForPulsingViews;
private boolean mIsClearAllInProgress;
private ExpandableView mSwipedView = null;
private Roundable mViewBeforeSwipedView = null;
private Roundable mViewAfterSwipedView = null;
- private boolean mUseRoundnessSourceTypes;
@Inject
- NotificationRoundnessManager(
- NotificationSectionsFeatureManager sectionsFeatureManager,
- NotificationRoundnessLogger notifLogger,
- DumpManager dumpManager) {
- int numberOfSections = sectionsFeatureManager.getNumberOfBuckets();
- mFirstInSectionViews = new ExpandableView[numberOfSections];
- mLastInSectionViews = new ExpandableView[numberOfSections];
- mTmpFirstInSectionViews = new ExpandableView[numberOfSections];
- mTmpLastInSectionViews = new ExpandableView[numberOfSections];
- mNotifLogger = notifLogger;
+ NotificationRoundnessManager(DumpManager dumpManager) {
mDumpManager = dumpManager;
- mUseRoundnessSourceTypes = true;
-
mDumpManager.registerDumpable(TAG, this);
}
@Override
public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
- pw.println("mFirstInSectionViews: length=" + mFirstInSectionViews.length);
- pw.println(dumpViews(mFirstInSectionViews));
- pw.println("mLastInSectionViews: length=" + mLastInSectionViews.length);
- pw.println(dumpViews(mFirstInSectionViews));
- if (mTrackedHeadsUp != null) {
- pw.println("trackedHeadsUp=" + mTrackedHeadsUp.getEntry());
- }
pw.println("roundForPulsingViews=" + mRoundForPulsingViews);
pw.println("isClearAllInProgress=" + mIsClearAllInProgress);
}
- public void updateView(ExpandableView view, boolean animate) {
- if (mUseRoundnessSourceTypes) return;
- boolean changed = updateViewWithoutCallback(view, animate);
- if (changed) {
- mRoundingChangedCallback.run();
- }
- }
-
public boolean isViewAffectedBySwipe(ExpandableView expandableView) {
return expandableView != null
&& (expandableView == mSwipedView
@@ -112,58 +67,6 @@
|| expandableView == mViewAfterSwipedView);
}
- boolean updateViewWithoutCallback(
- ExpandableView view,
- boolean animate) {
- if (mUseRoundnessSourceTypes) return false;
- if (view == null
- || view == mViewBeforeSwipedView
- || view == mViewAfterSwipedView) {
- return false;
- }
-
- final boolean isTopChanged = view.requestTopRoundness(
- getRoundnessDefaultValue(view, true /* top */),
- LegacySourceType.DefaultValue,
- animate);
-
- final boolean isBottomChanged = view.requestBottomRoundness(
- getRoundnessDefaultValue(view, /* top = */ false),
- LegacySourceType.DefaultValue,
- animate);
-
- final boolean isFirstInSection = isFirstInSection(view);
- final boolean isLastInSection = isLastInSection(view);
-
- view.setFirstInSection(isFirstInSection);
- view.setLastInSection(isLastInSection);
-
- mNotifLogger.onCornersUpdated(view, isFirstInSection,
- isLastInSection, isTopChanged, isBottomChanged);
-
- return (isFirstInSection || isLastInSection) && (isTopChanged || isBottomChanged);
- }
-
- private boolean isFirstInSection(ExpandableView view) {
- if (mUseRoundnessSourceTypes) return false;
- for (int i = 0; i < mFirstInSectionViews.length; i++) {
- if (view == mFirstInSectionViews[i]) {
- return true;
- }
- }
- return false;
- }
-
- private boolean isLastInSection(ExpandableView view) {
- if (mUseRoundnessSourceTypes) return false;
- for (int i = mLastInSectionViews.length - 1; i >= 0; i--) {
- if (view == mLastInSectionViews[i]) {
- return true;
- }
- }
- return false;
- }
-
void setViewsAffectedBySwipe(
Roundable viewBefore,
ExpandableView viewSwiped,
@@ -177,34 +80,27 @@
if (mSwipedView != null) oldViews.add(mSwipedView);
if (mViewAfterSwipedView != null) oldViews.add(mViewAfterSwipedView);
- final SourceType source;
- if (mUseRoundnessSourceTypes) {
- source = DISMISS_ANIMATION;
- } else {
- source = LegacySourceType.OnDismissAnimation;
- }
-
mViewBeforeSwipedView = viewBefore;
if (viewBefore != null) {
oldViews.remove(viewBefore);
- viewBefore.requestRoundness(/* top = */ 0f, /* bottom = */ 1f, source);
+ viewBefore.requestRoundness(/* top = */ 0f, /* bottom = */ 1f, DISMISS_ANIMATION);
}
mSwipedView = viewSwiped;
if (viewSwiped != null) {
oldViews.remove(viewSwiped);
- viewSwiped.requestRoundness(/* top = */ 1f, /* bottom = */ 1f, source);
+ viewSwiped.requestRoundness(/* top = */ 1f, /* bottom = */ 1f, DISMISS_ANIMATION);
}
mViewAfterSwipedView = viewAfter;
if (viewAfter != null) {
oldViews.remove(viewAfter);
- viewAfter.requestRoundness(/* top = */ 1f, /* bottom = */ 0f, source);
+ viewAfter.requestRoundness(/* top = */ 1f, /* bottom = */ 0f, DISMISS_ANIMATION);
}
// After setting the current Views, reset the views that are still present in the set.
for (Roundable oldView : oldViews) {
- oldView.requestRoundnessReset(source);
+ oldView.requestRoundnessReset(DISMISS_ANIMATION);
}
}
@@ -226,143 +122,6 @@
return mRoundForPulsingViews;
}
- private float getRoundnessDefaultValue(Roundable view, boolean top) {
- if (mUseRoundnessSourceTypes) return 0f;
-
- if (view == null) {
- return 0f;
- }
- if (view == mViewBeforeSwipedView
- || view == mSwipedView
- || view == mViewAfterSwipedView) {
- return 1f;
- }
- if (view instanceof ExpandableNotificationRow
- && ((ExpandableNotificationRow) view).canViewBeCleared()
- && mIsClearAllInProgress) {
- return 1.0f;
- }
- if (view instanceof ExpandableView) {
- ExpandableView expandableView = (ExpandableView) view;
- if ((expandableView.isPinned()
- || (expandableView.isHeadsUpAnimatingAway()) && !mExpanded)) {
- return 1.0f;
- }
- if (isFirstInSection(expandableView) && top) {
- return 1.0f;
- }
- if (isLastInSection(expandableView) && !top) {
- return 1.0f;
- }
-
- if (view == mTrackedHeadsUp) {
- // If we're pushing up on a headsup the appear fraction is < 0 and it needs to
- // still be rounded.
- return MathUtils.saturate(1.0f - mAppearFraction);
- }
- if (expandableView.showingPulsing() && mRoundForPulsingViews) {
- return 1.0f;
- }
- if (expandableView.isChildInGroup()) {
- return 0f;
- }
- final Resources resources = expandableView.getResources();
- return resources.getDimension(R.dimen.notification_corner_radius_small)
- / resources.getDimension(R.dimen.notification_corner_radius);
- }
- return 0f;
- }
-
- public void setExpanded(float expandedHeight, float appearFraction) {
- if (mUseRoundnessSourceTypes) return;
- mExpanded = expandedHeight != 0.0f;
- mAppearFraction = appearFraction;
- if (mTrackedHeadsUp != null) {
- updateView(mTrackedHeadsUp, false /* animate */);
- }
- }
-
- public void updateRoundedChildren(NotificationSection[] sections) {
- if (mUseRoundnessSourceTypes) return;
- boolean anyChanged = false;
- for (int i = 0; i < sections.length; i++) {
- mTmpFirstInSectionViews[i] = mFirstInSectionViews[i];
- mTmpLastInSectionViews[i] = mLastInSectionViews[i];
- mFirstInSectionViews[i] = sections[i].getFirstVisibleChild();
- mLastInSectionViews[i] = sections[i].getLastVisibleChild();
- }
- anyChanged |= handleRemovedOldViews(sections, mTmpFirstInSectionViews, true);
- anyChanged |= handleRemovedOldViews(sections, mTmpLastInSectionViews, false);
- anyChanged |= handleAddedNewViews(sections, mTmpFirstInSectionViews, true);
- anyChanged |= handleAddedNewViews(sections, mTmpLastInSectionViews, false);
- if (anyChanged) {
- mRoundingChangedCallback.run();
- }
-
- mNotifLogger.onSectionCornersUpdated(sections, anyChanged);
- }
-
- private boolean handleRemovedOldViews(
- NotificationSection[] sections,
- ExpandableView[] oldViews,
- boolean first) {
- if (mUseRoundnessSourceTypes) return false;
- boolean anyChanged = false;
- for (ExpandableView oldView : oldViews) {
- if (oldView != null) {
- boolean isStillPresent = false;
- boolean adjacentSectionChanged = false;
- for (NotificationSection section : sections) {
- ExpandableView newView =
- (first ? section.getFirstVisibleChild()
- : section.getLastVisibleChild());
- if (newView == oldView) {
- isStillPresent = true;
- if (oldView.isFirstInSection() != isFirstInSection(oldView)
- || oldView.isLastInSection() != isLastInSection(oldView)) {
- adjacentSectionChanged = true;
- }
- break;
- }
- }
- if (!isStillPresent || adjacentSectionChanged) {
- anyChanged = true;
- if (!oldView.isRemoved()) {
- updateViewWithoutCallback(oldView, oldView.isShown());
- }
- }
- }
- }
- return anyChanged;
- }
-
- private boolean handleAddedNewViews(
- NotificationSection[] sections,
- ExpandableView[] oldViews,
- boolean first) {
- if (mUseRoundnessSourceTypes) return false;
- boolean anyChanged = false;
- for (NotificationSection section : sections) {
- ExpandableView newView =
- (first ? section.getFirstVisibleChild() : section.getLastVisibleChild());
- if (newView != null) {
- boolean wasAlreadyPresent = false;
- for (ExpandableView oldView : oldViews) {
- if (oldView == newView) {
- wasAlreadyPresent = true;
- break;
- }
- }
- if (!wasAlreadyPresent) {
- anyChanged = true;
- updateViewWithoutCallback(newView,
- newView.isShown() && !mAnimatedChildren.contains(newView));
- }
- }
- }
- return anyChanged;
- }
-
public void setAnimatedChildren(HashSet<ExpandableView> animatedChildren) {
mAnimatedChildren = animatedChildren;
}
@@ -376,51 +135,7 @@
return mAnimatedChildren.contains(view);
}
- public void setOnRoundingChangedCallback(Runnable roundingChangedCallback) {
- mRoundingChangedCallback = roundingChangedCallback;
- }
-
- public void setTrackingHeadsUp(ExpandableNotificationRow row) {
- ExpandableNotificationRow previous = mTrackedHeadsUp;
- mTrackedHeadsUp = row;
- if (previous != null) {
- updateView(previous, true /* animate */);
- }
- }
-
public void setShouldRoundPulsingViews(boolean shouldRoundPulsingViews) {
mRoundForPulsingViews = shouldRoundPulsingViews;
}
-
- private String dumpViews(ExpandableView[] views) {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < views.length; i++) {
- if (views[i] == null) continue;
-
- sb.append("\t")
- .append("[").append(i).append("] ")
- .append("isPinned=").append(views[i].isPinned()).append(" ")
- .append("isFirstInSection=").append(views[i].isFirstInSection()).append(" ")
- .append("isLastInSection=").append(views[i].isLastInSection()).append(" ");
-
- if (views[i] instanceof ExpandableNotificationRow) {
- sb.append("entry=");
- dumpEntry(((ExpandableNotificationRow) views[i]).getEntry(), sb);
- }
-
- sb.append("\n");
- }
- return sb.toString();
- }
-
- private void dumpEntry(NotificationEntry entry, StringBuilder sb) {
- sb.append("NotificationEntry{key=").append(entry.getKey()).append(" ");
-
- if (entry.getSection() != null) {
- sb.append(" section=")
- .append(entry.getSection().getLabel());
- }
-
- sb.append("}");
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index 57b6dbc..fd064ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -52,8 +52,6 @@
@SilentHeader private val silentHeaderController: SectionHeaderController
) : SectionProvider {
- private val useRoundnessSourceTypes = true
-
private val configurationListener = object : ConfigurationController.ConfigurationListener {
override fun onLocaleListChanged() {
reinflateViews()
@@ -193,35 +191,33 @@
isSectionChanged || changed
}
- if (useRoundnessSourceTypes) {
- val newFirstChildren = sections.mapNotNull { it.firstVisibleChild }
- val newLastChildren = sections.mapNotNull { it.lastVisibleChild }
+ val newFirstChildren = sections.mapNotNull { it.firstVisibleChild }
+ val newLastChildren = sections.mapNotNull { it.lastVisibleChild }
- // Update the roundness of Views that weren't already in the first/last position
- newFirstChildren.forEach { firstChild ->
- val wasFirstChild = oldFirstChildren.remove(firstChild)
- if (!wasFirstChild) {
- val notAnimatedChild = !notificationRoundnessManager.isAnimatedChild(firstChild)
- val animated = firstChild.isShown && notAnimatedChild
- firstChild.requestTopRoundness(1f, SECTION, animated)
- }
+ // Update the roundness of Views that weren't already in the first/last position
+ newFirstChildren.forEach { firstChild ->
+ val wasFirstChild = oldFirstChildren.remove(firstChild)
+ if (!wasFirstChild) {
+ val notAnimatedChild = !notificationRoundnessManager.isAnimatedChild(firstChild)
+ val animated = firstChild.isShown && notAnimatedChild
+ firstChild.requestTopRoundness(1f, SECTION, animated)
}
- newLastChildren.forEach { lastChild ->
- val wasLastChild = oldLastChildren.remove(lastChild)
- if (!wasLastChild) {
- val notAnimatedChild = !notificationRoundnessManager.isAnimatedChild(lastChild)
- val animated = lastChild.isShown && notAnimatedChild
- lastChild.requestBottomRoundness(1f, SECTION, animated)
- }
+ }
+ newLastChildren.forEach { lastChild ->
+ val wasLastChild = oldLastChildren.remove(lastChild)
+ if (!wasLastChild) {
+ val notAnimatedChild = !notificationRoundnessManager.isAnimatedChild(lastChild)
+ val animated = lastChild.isShown && notAnimatedChild
+ lastChild.requestBottomRoundness(1f, SECTION, animated)
}
+ }
- // The Views left in the set are no longer in the first/last position
- oldFirstChildren.forEach { noMoreFirstChild ->
- noMoreFirstChild.requestTopRoundness(0f, SECTION)
- }
- oldLastChildren.forEach { noMoreLastChild ->
- noMoreLastChild.requestBottomRoundness(0f, SECTION)
- }
+ // The Views left in the set are no longer in the first/last position
+ oldFirstChildren.forEach { noMoreFirstChild ->
+ noMoreFirstChild.requestTopRoundness(0f, SECTION)
+ }
+ oldLastChildren.forEach { noMoreLastChild ->
+ noMoreLastChild.requestBottomRoundness(0f, SECTION)
}
if (DEBUG) {
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 abcb825..edff877 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
@@ -200,7 +200,6 @@
private Set<Integer> mDebugTextUsedYPositions;
private final boolean mDebugRemoveAnimation;
private final boolean mSimplifiedAppearFraction;
- private final boolean mUseRoundnessSourceTypes;
private final boolean mSensitiveRevealAnimEndabled;
private boolean mAnimatedInsets;
@@ -625,7 +624,6 @@
mDebugLines = featureFlags.isEnabled(Flags.NSSL_DEBUG_LINES);
mDebugRemoveAnimation = featureFlags.isEnabled(Flags.NSSL_DEBUG_REMOVE_ANIMATION);
mSimplifiedAppearFraction = featureFlags.isEnabled(Flags.SIMPLIFIED_APPEAR_FRACTION);
- mUseRoundnessSourceTypes = true;
mSensitiveRevealAnimEndabled = featureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM);
setAnimatedInsetsEnabled(featureFlags.isEnabled(Flags.ANIMATED_NOTIFICATION_SHADE_INSETS));
mSectionsManager = Dependency.get(NotificationSectionsManager.class);
@@ -3134,10 +3132,6 @@
mAnimateNextSectionBoundsChange = false;
}
mAmbientState.setLastVisibleBackgroundChild(lastChild);
- if (!mUseRoundnessSourceTypes) {
- // TODO: Refactor SectionManager and put the RoundnessManager there.
- mController.getNotificationRoundnessManager().updateRoundedChildren(mSections);
- }
mAnimateBottomOnLayout = false;
invalidate();
}
@@ -3584,9 +3578,7 @@
@ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM)
protected StackScrollAlgorithm createStackScrollAlgorithm(Context context) {
- StackScrollAlgorithm stackScrollAlgorithm = new StackScrollAlgorithm(context, this);
- stackScrollAlgorithm.useRoundnessSourceTypes(mUseRoundnessSourceTypes);
- return stackScrollAlgorithm;
+ return new StackScrollAlgorithm(context, this);
}
/**
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 d96a2cd..7b046d6 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
@@ -192,7 +192,6 @@
private int mBarState;
private HeadsUpAppearanceController mHeadsUpAppearanceController;
private final FeatureFlags mFeatureFlags;
- private final boolean mUseRoundnessSourceTypes;
private final NotificationTargetsHelper mNotificationTargetsHelper;
private final SecureSettings mSecureSettings;
private final NotificationDismissibilityProvider mDismissibilityProvider;
@@ -591,36 +590,12 @@
}
@Override
- public void onHeadsUpPinned(NotificationEntry entry) {
- if (!mUseRoundnessSourceTypes) {
- mNotificationRoundnessManager.updateView(
- entry.getRow(),
- /* animate = */ false);
- }
- }
-
- @Override
- public void onHeadsUpUnPinned(NotificationEntry entry) {
- if (!mUseRoundnessSourceTypes) {
- ExpandableNotificationRow row = entry.getRow();
- // update the roundedness posted, because we might be animating away the
- // headsup soon, so no need to set the roundedness to 0 and then back to 1.
- row.post(() -> mNotificationRoundnessManager.updateView(row,
- true /* animate */));
- }
- }
-
- @Override
public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
long numEntries = mHeadsUpManager.getAllEntries().count();
NotificationEntry topEntry = mHeadsUpManager.getTopEntry();
mView.setNumHeadsUp(numEntries);
mView.setTopHeadsUpEntry(topEntry);
generateHeadsUpAnimation(entry, isHeadsUp);
- if (!mUseRoundnessSourceTypes) {
- ExpandableNotificationRow row = entry.getRow();
- mNotificationRoundnessManager.updateView(row, true /* animate */);
- }
}
};
@@ -720,7 +695,6 @@
mShadeController = shadeController;
mNotifIconAreaController = notifIconAreaController;
mFeatureFlags = featureFlags;
- mUseRoundnessSourceTypes = true;
mNotificationTargetsHelper = notificationTargetsHelper;
mSecureSettings = secureSettings;
mDismissibilityProvider = dismissibilityProvider;
@@ -788,11 +762,6 @@
mLockscreenUserManager.addUserChangedListener(mLockscreenUserChangeListener);
- if (!mUseRoundnessSourceTypes) {
- mNotificationRoundnessManager.setOnRoundingChangedCallback(mView::invalidate);
- mView.addOnExpandedHeightChangedListener(mNotificationRoundnessManager::setExpanded);
- }
-
mVisibilityLocationProviderDelegator.setDelegate(this::isInVisibleLocation);
mTunerService.addTunable(
@@ -958,7 +927,6 @@
public void setTrackingHeadsUp(ExpandableNotificationRow expandableNotificationRow) {
mView.setTrackingHeadsUp(expandableNotificationRow);
- mNotificationRoundnessManager.setTrackingHeadsUp(expandableNotificationRow);
}
public void wakeUpFromPulse() {
@@ -1776,9 +1744,6 @@
@Override
public void bindRow(ExpandableNotificationRow row) {
row.setHeadsUpAnimatingAwayListener(animatingAway -> {
- if (!mUseRoundnessSourceTypes) {
- mNotificationRoundnessManager.updateView(row, false);
- }
NotificationEntry entry = row.getEntry();
mHeadsUpAppearanceController.updateHeader(entry);
mHeadsUpAppearanceController.updateHeadsUpAndPulsingRoundness(entry);
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 2d0a6cf..993c3801 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
@@ -68,7 +68,6 @@
private boolean mIsExpanded;
private boolean mPulsing;
private final NotificationRoundnessManager mNotificationRoundnessManager;
- private final boolean mUseRoundnessSourceTypes;
NotificationSwipeHelper(
Resources resources,
@@ -80,7 +79,6 @@
NotificationRoundnessManager notificationRoundnessManager) {
super(callback, resources, viewConfiguration, falsingManager, featureFlags);
mNotificationRoundnessManager = notificationRoundnessManager;
- mUseRoundnessSourceTypes = true;
mMenuListener = menuListener;
mCallback = callback;
mFalsingCheck = () -> resetExposedMenuView(true /* animate */, true /* force */);
@@ -322,8 +320,7 @@
protected void prepareDismissAnimation(View view, Animator anim) {
super.prepareDismissAnimation(view, anim);
- if (mUseRoundnessSourceTypes
- && view instanceof ExpandableNotificationRow
+ if (view instanceof ExpandableNotificationRow
&& mNotificationRoundnessManager.isClearAllInProgress()) {
ExpandableNotificationRow row = (ExpandableNotificationRow) view;
anim.addListener(new AnimatorListenerAdapter() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt
index cd0c1b1..02662f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt
@@ -4,7 +4,6 @@
import androidx.core.view.isVisible
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.statusbar.notification.Roundable
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView
@@ -20,7 +19,6 @@
constructor(
featureFlags: FeatureFlags,
) {
- private val useRoundnessSourceTypes = true
/**
* This method looks for views that can be rounded (and implement [Roundable]) during a
@@ -48,10 +46,6 @@
if (notificationParent != null && childrenContainer != null) {
// We are inside a notification group
- if (!useRoundnessSourceTypes) {
- return RoundableTargets(null, null, null)
- }
-
val visibleGroupChildren = childrenContainer.attachedChildren.filter { it.isVisible }
val indexOfParentSwipedView = visibleGroupChildren.indexOf(viewSwiped)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 3060473..92d767a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -34,7 +34,6 @@
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.NotificationShelf;
-import com.android.systemui.statusbar.notification.LegacySourceType;
import com.android.systemui.statusbar.notification.SourceType;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -75,7 +74,6 @@
private float mQuickQsOffsetHeight;
private float mSmallCornerRadius;
private float mLargeCornerRadius;
- private boolean mUseRoundnessSourceTypes;
public StackScrollAlgorithm(
Context context,
@@ -836,12 +834,8 @@
row.isLastInSection() ? 1f : (mSmallCornerRadius / mLargeCornerRadius);
final float bottomValue = computeCornerRoundnessForPinnedHun(mHostView.getHeight(),
ambientState.getStackY(), getMaxAllowedChildHeight(row), originalCornerRadius);
- if (mUseRoundnessSourceTypes) {
- row.requestBottomRoundness(bottomValue, STACK_SCROLL_ALGO);
- row.addOnDetachResetRoundness(STACK_SCROLL_ALGO);
- } else {
- row.requestBottomRoundness(bottomValue, LegacySourceType.OnScroll);
- }
+ row.requestBottomRoundness(bottomValue, STACK_SCROLL_ALGO);
+ row.addOnDetachResetRoundness(STACK_SCROLL_ALGO);
}
@VisibleForTesting
@@ -979,14 +973,6 @@
this.mIsExpanded = isExpanded;
}
- /**
- * Enable the support for rounded corner based on the SourceType
- * @param enabled true if is supported
- */
- public void useRoundnessSourceTypes(boolean enabled) {
- mUseRoundnessSourceTypes = enabled;
- }
-
public static class StackScrollAlgorithmState {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 0c4821c..f15dcc3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -76,7 +76,6 @@
private final DarkIconDispatcher mDarkIconDispatcher;
private final ShadeViewController mShadeViewController;
private final NotificationRoundnessManager mNotificationRoundnessManager;
- private final boolean mUseRoundnessSourceTypes;
private final Consumer<ExpandableNotificationRow>
mSetTrackingHeadsUp = this::setTrackingHeadsUp;
private final BiConsumer<Float, Float> mSetExpandedHeight = this::setAppearFraction;
@@ -124,7 +123,6 @@
super(headsUpStatusBarView);
mNotificationIconAreaController = notificationIconAreaController;
mNotificationRoundnessManager = notificationRoundnessManager;
- mUseRoundnessSourceTypes = true;
mHeadsUpManager = headsUpManager;
// We may be mid-HUN-expansion when this controller is re-created (for example, if the user
@@ -405,21 +403,19 @@
* @param entry target notification
*/
public void updateHeadsUpAndPulsingRoundness(NotificationEntry entry) {
- if (mUseRoundnessSourceTypes) {
- ExpandableNotificationRow row = entry.getRow();
- boolean isTrackedChild = row == mTrackedChild;
- if (row.isPinned() || row.isHeadsUpAnimatingAway() || isTrackedChild) {
- float roundness = MathUtils.saturate(1f - mAppearFraction);
- row.requestRoundness(roundness, roundness, HEADS_UP);
+ ExpandableNotificationRow row = entry.getRow();
+ boolean isTrackedChild = row == mTrackedChild;
+ if (row.isPinned() || row.isHeadsUpAnimatingAway() || isTrackedChild) {
+ float roundness = MathUtils.saturate(1f - mAppearFraction);
+ row.requestRoundness(roundness, roundness, HEADS_UP);
+ } else {
+ row.requestRoundnessReset(HEADS_UP);
+ }
+ if (mNotificationRoundnessManager.shouldRoundNotificationPulsing()) {
+ if (row.showingPulsing()) {
+ row.requestRoundness(/* top = */ 1f, /* bottom = */ 1f, PULSING);
} else {
- row.requestRoundnessReset(HEADS_UP);
- }
- if (mNotificationRoundnessManager.shouldRoundNotificationPulsing()) {
- if (row.showingPulsing()) {
- row.requestRoundness(/* top = */ 1f, /* bottom = */ 1f, PULSING);
- } else {
- row.requestRoundnessReset(PULSING);
- }
+ row.requestRoundnessReset(PULSING);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
index 534edb9..a058bf8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
@@ -25,6 +25,7 @@
import android.annotation.ColorInt;
import android.content.Context;
import android.graphics.Rect;
+import android.util.Log;
import android.view.InsetsFlags;
import android.view.ViewDebug;
import android.view.WindowInsetsController.Appearance;
@@ -35,13 +36,17 @@
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.util.Compile;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Date;
import javax.inject.Inject;
@@ -51,10 +56,14 @@
@SysUISingleton
public class LightBarController implements BatteryController.BatteryStateChangeCallback, Dumpable {
+ private static final String TAG = "LightBarController";
+ private static final boolean DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG);
+
private static final float NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD = 0.1f;
private final SysuiDarkIconDispatcher mStatusBarIconController;
private final BatteryController mBatteryController;
+ private final boolean mUseNewLightBarLogic;
private BiometricUnlockController mBiometricUnlockController;
private LightBarTransitionsController mNavigationBarController;
@@ -67,13 +76,17 @@
private final int mLightIconColor;
/**
- * Whether the navigation bar should be light factoring in already how much alpha the scrim has
+ * Whether the navigation bar should be light factoring in already how much alpha the scrim has.
+ * "Light" refers to the background color of the navigation bar, so when this is true,
+ * it's referring to a state where the navigation bar icons are tinted dark.
*/
private boolean mNavigationLight;
/**
- * Whether the flags indicate that a light status bar is requested. This doesn't factor in the
- * scrim alpha yet.
+ * Whether the flags indicate that a light navigation bar is requested.
+ * "Light" refers to the background color of the navigation bar, so when this is true,
+ * it's referring to a state where the navigation bar icons would be tinted dark.
+ * This doesn't factor in the scrim alpha yet.
*/
private boolean mHasLightNavigationBar;
@@ -82,22 +95,34 @@
* {@link #mNavigationLight} {@code false}.
*/
private boolean mForceDarkForScrim;
+ /**
+ * {@code true} if {@link #mHasLightNavigationBar} should be ignored and forcefully make
+ * {@link #mNavigationLight} {@code true}.
+ */
+ private boolean mForceLightForScrim;
private boolean mQsCustomizing;
+ private boolean mQsExpanded;
+ private boolean mGlobalActionsVisible;
private boolean mDirectReplying;
private boolean mNavbarColorManagedByIme;
private boolean mIsCustomizingForBackNav;
+ private String mLastSetScrimStateLog;
+ private String mLastNavigationBarAppearanceChangedLog;
+
@Inject
public LightBarController(
Context ctx,
DarkIconDispatcher darkIconDispatcher,
BatteryController batteryController,
NavigationModeController navModeController,
+ FeatureFlags featureFlags,
DumpManager dumpManager,
DisplayTracker displayTracker) {
+ mUseNewLightBarLogic = featureFlags.isEnabled(Flags.NEW_LIGHT_BAR_LOGIC);
mDarkIconColor = ctx.getColor(R.color.dark_mode_icon_color_single_tone);
mLightIconColor = ctx.getColor(R.color.light_mode_icon_color_single_tone);
mStatusBarIconController = (SysuiDarkIconDispatcher) darkIconDispatcher;
@@ -159,9 +184,42 @@
final boolean last = mNavigationLight;
mHasLightNavigationBar = isLight(appearance, navigationBarMode,
APPEARANCE_LIGHT_NAVIGATION_BARS);
- mNavigationLight = mHasLightNavigationBar
- && (mDirectReplying && mNavbarColorManagedByIme || !mForceDarkForScrim)
- && !mQsCustomizing;
+ if (mUseNewLightBarLogic) {
+ final boolean ignoreScrimForce = mDirectReplying && mNavbarColorManagedByIme;
+ final boolean darkForScrim = mForceDarkForScrim && !ignoreScrimForce;
+ final boolean lightForScrim = mForceLightForScrim && !ignoreScrimForce;
+ final boolean darkForQs = mQsCustomizing || mQsExpanded || mGlobalActionsVisible;
+ mNavigationLight =
+ ((mHasLightNavigationBar && !darkForScrim) || lightForScrim) && !darkForQs;
+ mLastNavigationBarAppearanceChangedLog = "onNavigationBarAppearanceChanged()"
+ + " appearance=" + appearance
+ + " nbModeChanged=" + nbModeChanged
+ + " navigationBarMode=" + navigationBarMode
+ + " navbarColorManagedByIme=" + navbarColorManagedByIme
+ + " mHasLightNavigationBar=" + mHasLightNavigationBar
+ + " ignoreScrimForce=" + ignoreScrimForce
+ + " darkForScrim=" + darkForScrim
+ + " lightForScrim=" + lightForScrim
+ + " darkForQs=" + darkForQs
+ + " mNavigationLight=" + mNavigationLight
+ + " last=" + last
+ + " timestamp=" + new Date();
+ if (DEBUG) Log.d(TAG, mLastNavigationBarAppearanceChangedLog);
+ } else {
+ mNavigationLight = mHasLightNavigationBar
+ && (mDirectReplying && mNavbarColorManagedByIme || !mForceDarkForScrim)
+ && !mQsCustomizing;
+ mLastNavigationBarAppearanceChangedLog = "onNavigationBarAppearanceChanged()"
+ + " appearance=" + appearance
+ + " nbModeChanged=" + nbModeChanged
+ + " navigationBarMode=" + navigationBarMode
+ + " navbarColorManagedByIme=" + navbarColorManagedByIme
+ + " mHasLightNavigationBar=" + mHasLightNavigationBar
+ + " mNavigationLight=" + mNavigationLight
+ + " last=" + last
+ + " timestamp=" + new Date();
+ if (DEBUG) Log.d(TAG, mLastNavigationBarAppearanceChangedLog);
+ }
if (mNavigationLight != last) {
updateNavigation();
}
@@ -188,6 +246,20 @@
reevaluate();
}
+ /** Set if Quick Settings is fully expanded, which affects notification scrim visibility */
+ public void setQsExpanded(boolean expanded) {
+ if (mQsExpanded == expanded) return;
+ mQsExpanded = expanded;
+ reevaluate();
+ }
+
+ /** Set if Global Actions dialog is visible, which requires dark mode (light buttons) */
+ public void setGlobalActionsVisible(boolean visible) {
+ if (mGlobalActionsVisible == visible) return;
+ mGlobalActionsVisible = visible;
+ reevaluate();
+ }
+
/**
* Controls the light status bar temporarily for back navigation.
* @param appearance the custmoized appearance.
@@ -225,16 +297,52 @@
public void setScrimState(ScrimState scrimState, float scrimBehindAlpha,
GradientColors scrimInFrontColor) {
- boolean forceDarkForScrimLast = mForceDarkForScrim;
- // For BOUNCER/BOUNCER_SCRIMMED cases, we assume that alpha is always below threshold.
- // This enables IMEs to control the navigation bar color.
- // For other cases, scrim should be able to veto the light navigation bar.
- mForceDarkForScrim = scrimState != ScrimState.BOUNCER
- && scrimState != ScrimState.BOUNCER_SCRIMMED
- && scrimBehindAlpha >= NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD
- && !scrimInFrontColor.supportsDarkText();
- if (mHasLightNavigationBar && (mForceDarkForScrim != forceDarkForScrimLast)) {
- reevaluate();
+ if (mUseNewLightBarLogic) {
+ boolean forceDarkForScrimLast = mForceDarkForScrim;
+ boolean forceLightForScrimLast = mForceLightForScrim;
+ final boolean forceForScrim =
+ scrimBehindAlpha >= NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD;
+ final boolean scrimColorIsLight = scrimInFrontColor.supportsDarkText();
+
+ mForceDarkForScrim = forceForScrim && !scrimColorIsLight;
+ mForceLightForScrim = forceForScrim && scrimColorIsLight;
+ if (mHasLightNavigationBar) {
+ if (mForceDarkForScrim != forceDarkForScrimLast) reevaluate();
+ } else {
+ if (mForceLightForScrim != forceLightForScrimLast) reevaluate();
+ }
+ mLastSetScrimStateLog = "setScrimState()"
+ + " scrimState=" + scrimState
+ + " scrimBehindAlpha=" + scrimBehindAlpha
+ + " scrimInFrontColor=" + scrimInFrontColor
+ + " forceForScrim=" + forceForScrim
+ + " scrimColorIsLight=" + scrimColorIsLight
+ + " mHasLightNavigationBar=" + mHasLightNavigationBar
+ + " mForceDarkForScrim=" + mForceDarkForScrim
+ + " mForceLightForScrim=" + mForceLightForScrim
+ + " timestamp=" + new Date();
+ if (DEBUG) Log.d(TAG, mLastSetScrimStateLog);
+ } else {
+ boolean forceDarkForScrimLast = mForceDarkForScrim;
+ // For BOUNCER/BOUNCER_SCRIMMED cases, we assume that alpha is always below threshold.
+ // This enables IMEs to control the navigation bar color.
+ // For other cases, scrim should be able to veto the light navigation bar.
+ // NOTE: this was also wrong for S and has been removed in the new logic.
+ mForceDarkForScrim = scrimState != ScrimState.BOUNCER
+ && scrimState != ScrimState.BOUNCER_SCRIMMED
+ && scrimBehindAlpha >= NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD
+ && !scrimInFrontColor.supportsDarkText();
+ if (mHasLightNavigationBar && (mForceDarkForScrim != forceDarkForScrimLast)) {
+ reevaluate();
+ }
+ mLastSetScrimStateLog = "setScrimState()"
+ + " scrimState=" + scrimState
+ + " scrimBehindAlpha=" + scrimBehindAlpha
+ + " scrimInFrontColor=" + scrimInFrontColor
+ + " mHasLightNavigationBar=" + mHasLightNavigationBar
+ + " mForceDarkForScrim=" + mForceDarkForScrim
+ + " timestamp=" + new Date();
+ if (DEBUG) Log.d(TAG, mLastSetScrimStateLog);
}
}
@@ -309,16 +417,24 @@
pw.print(mAppearanceRegions[i].toString()); pw.print(" isLight="); pw.println(isLight);
}
- pw.print(" mNavigationLight="); pw.print(mNavigationLight);
+ pw.print(" mNavigationLight="); pw.println(mNavigationLight);
pw.print(" mHasLightNavigationBar="); pw.println(mHasLightNavigationBar);
-
+ pw.println();
pw.print(" mStatusBarMode="); pw.print(mStatusBarMode);
pw.print(" mNavigationBarMode="); pw.println(mNavigationBarMode);
-
- pw.print(" mForceDarkForScrim="); pw.print(mForceDarkForScrim);
- pw.print(" mQsCustomizing="); pw.print(mQsCustomizing);
+ pw.println();
+ pw.print(" mForceDarkForScrim="); pw.println(mForceDarkForScrim);
+ pw.print(" mForceLightForScrim="); pw.println(mForceLightForScrim);
+ pw.println();
+ pw.print(" mQsCustomizing="); pw.println(mQsCustomizing);
+ pw.print(" mQsExpanded="); pw.println(mQsExpanded);
+ pw.print(" mGlobalActionsVisible="); pw.println(mGlobalActionsVisible);
pw.print(" mDirectReplying="); pw.println(mDirectReplying);
pw.print(" mNavbarColorManagedByIme="); pw.println(mNavbarColorManagedByIme);
+ pw.println();
+ pw.println(" Recent Calculation Logs:");
+ pw.print(" "); pw.println(mLastSetScrimStateLog);
+ pw.print(" "); pw.println(mLastNavigationBarAppearanceChangedLog);
pw.println();
@@ -344,6 +460,7 @@
private final DarkIconDispatcher mDarkIconDispatcher;
private final BatteryController mBatteryController;
private final NavigationModeController mNavModeController;
+ private final FeatureFlags mFeatureFlags;
private final DumpManager mDumpManager;
private final DisplayTracker mDisplayTracker;
@@ -352,12 +469,14 @@
DarkIconDispatcher darkIconDispatcher,
BatteryController batteryController,
NavigationModeController navModeController,
+ FeatureFlags featureFlags,
DumpManager dumpManager,
DisplayTracker displayTracker) {
mDarkIconDispatcher = darkIconDispatcher;
mBatteryController = batteryController;
mNavModeController = navModeController;
+ mFeatureFlags = featureFlags;
mDumpManager = dumpManager;
mDisplayTracker = displayTracker;
}
@@ -365,7 +484,7 @@
/** Create an {@link LightBarController} */
public LightBarController create(Context context) {
return new LightBarController(context, mDarkIconDispatcher, mBatteryController,
- mNavModeController, mDumpManager, mDisplayTracker);
+ mNavModeController, mFeatureFlags, mDumpManager, mDisplayTracker);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 006a029d..b9a12e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -306,7 +306,7 @@
public void applyIconStates() {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
- ViewState childState = mIconStates.get(child);
+ IconState childState = mIconStates.get(child);
if (childState != null) {
childState.applyToView(child);
}
@@ -339,6 +339,7 @@
}
}
if (child instanceof StatusBarIconView) {
+ ((StatusBarIconView) child).updateIconDimens();
((StatusBarIconView) child).setDozing(mDozing, false, 0);
}
}
@@ -447,9 +448,14 @@
@VisibleForTesting
boolean isOverflowing(boolean isLastChild, float translationX, float layoutEnd,
float iconSize) {
- // Layout end, as used here, does not include padding end.
- final float overflowX = isLastChild ? layoutEnd : layoutEnd - iconSize;
- return translationX >= overflowX;
+ if (isLastChild) {
+ return translationX + iconSize > layoutEnd;
+ } else {
+ // If the child is not the last child, we need to ensure that we have room for the next
+ // icon and the dot. The dot could be as large as an icon, so verify that we have room
+ // for 2 icons.
+ return translationX + iconSize * 2f > layoutEnd;
+ }
}
/**
@@ -489,10 +495,7 @@
// First icon to overflow.
if (firstOverflowIndex == -1 && isOverflowing) {
firstOverflowIndex = i;
- mVisualOverflowStart = layoutEnd - mIconSize;
- if (forceOverflow || mIsStaticLayout) {
- mVisualOverflowStart = Math.min(translationX, mVisualOverflowStart);
- }
+ mVisualOverflowStart = translationX;
}
final float drawingScale = mOnLockScreen && view instanceof StatusBarIconView
? ((StatusBarIconView) view).getIconScaleIncreased()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 51c56a0..fdb772b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -42,6 +42,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.internal.graphics.ColorUtils;
+import com.android.internal.util.ContrastColorUtil;
import com.android.internal.util.function.TriConsumer;
import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.keyguard.KeyguardUpdateMonitor;
@@ -249,6 +250,7 @@
private final TriConsumer<ScrimState, Float, GradientColors> mScrimStateListener;
private final LargeScreenShadeInterpolator mLargeScreenShadeInterpolator;
private final FeatureFlags mFeatureFlags;
+ private final boolean mUseNewLightBarLogic;
private Consumer<Integer> mScrimVisibleListener;
private boolean mBlankScreen;
private boolean mScreenBlankingCallbackCalled;
@@ -306,6 +308,7 @@
mScrimStateListener = lightBarController::setScrimState;
mLargeScreenShadeInterpolator = largeScreenShadeInterpolator;
mFeatureFlags = featureFlags;
+ mUseNewLightBarLogic = featureFlags.isEnabled(Flags.NEW_LIGHT_BAR_LOGIC);
mDefaultScrimAlpha = BUSY_SCRIM_ALPHA;
mKeyguardStateController = keyguardStateController;
@@ -1159,7 +1162,13 @@
if (mClipsQsScrim && mQsBottomVisible) {
alpha = mNotificationsAlpha;
}
- mScrimStateListener.accept(mState, alpha, mScrimInFront.getColors());
+ if (mUseNewLightBarLogic) {
+ mScrimStateListener.accept(mState, alpha, mColors);
+ } else {
+ // NOTE: This wasn't wrong, but it implied that each scrim might have different colors,
+ // when in fact they all share the same GradientColors instance, which we own.
+ mScrimStateListener.accept(mState, alpha, mScrimInFront.getColors());
+ }
}
private void dispatchScrimsVisible() {
@@ -1487,8 +1496,15 @@
int accent = Utils.getColorAccent(mScrimBehind.getContext()).getDefaultColor();
mColors.setMainColor(background);
mColors.setSecondaryColor(accent);
- mColors.setSupportsDarkText(
- ColorUtils.calculateContrast(mColors.getMainColor(), Color.WHITE) > 4.5);
+ if (mUseNewLightBarLogic) {
+ final boolean isBackgroundLight = !ContrastColorUtil.isColorDark(background);
+ mColors.setSupportsDarkText(isBackgroundLight);
+ } else {
+ // NOTE: This was totally backward, but LightBarController was flipping it back.
+ // There may be other consumers of this which would struggle though
+ mColors.setSupportsDarkText(
+ ColorUtils.calculateContrast(mColors.getMainColor(), Color.WHITE) > 4.5);
+ }
mNeedsDrawableColorUpdate = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index a8a834f..678873c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -203,8 +203,7 @@
@Override
protected LayoutParams onCreateLayoutParams() {
- LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
+ LinearLayout.LayoutParams lp = super.onCreateLayoutParams();
lp.setMargins(mIconHPadding, 0, mIconHPadding, 0);
return lp;
}
@@ -370,7 +369,7 @@
private final MobileIconsViewModel mMobileIconsViewModel;
protected final Context mContext;
- protected final int mIconSize;
+ protected int mIconSize;
// Whether or not these icons show up in dumpsys
protected boolean mShouldLog = false;
private StatusBarIconController mController;
@@ -395,10 +394,10 @@
mStatusBarPipelineFlags = statusBarPipelineFlags;
mMobileContextProvider = mobileContextProvider;
mContext = group.getContext();
- mIconSize = mContext.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.status_bar_icon_size);
mLocation = location;
+ reloadDimens();
+
if (statusBarPipelineFlags.runNewMobileIconsBackend()) {
// This starts the flow for the new pipeline, and will notify us of changes if
// {@link StatusBarPipelineFlags#useNewMobileIcons} is also true.
@@ -609,13 +608,9 @@
mGroup.removeAllViews();
}
- protected void onDensityOrFontScaleChanged() {
- for (int i = 0; i < mGroup.getChildCount(); i++) {
- View child = mGroup.getChildAt(i);
- LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
- child.setLayoutParams(lp);
- }
+ protected void reloadDimens() {
+ mIconSize = mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_icon_size);
}
private void setHeightAndCenter(ImageView imageView, int height) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index 3a18423..80d5651 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -109,6 +109,7 @@
}
group.setController(this);
+ group.reloadDimens();
mIconGroups.add(group);
List<Slot> allSlots = mStatusBarIconList.getSlots();
for (int i = 0; i < allSlots.size(); i++) {
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 26c1767..ddbfd43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -22,6 +22,8 @@
import android.annotation.Nullable;
import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
@@ -72,13 +74,16 @@
// Any ignored icon will never be added as a child
private ArrayList<String> mIgnoredSlots = new ArrayList<>();
+ private Configuration mConfiguration;
+
public StatusIconContainer(Context context) {
this(context, null);
}
public StatusIconContainer(Context context, AttributeSet attrs) {
super(context, attrs);
- initDimens();
+ mConfiguration = new Configuration(context.getResources().getConfiguration());
+ reloadDimens();
setWillNotDraw(!DEBUG_OVERFLOW);
}
@@ -95,7 +100,7 @@
return mShouldRestrictIcons;
}
- private void initDimens() {
+ private void reloadDimens() {
// This is the same value that StatusBarIconView uses
mIconDotFrameWidth = getResources().getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_icon_size);
@@ -211,6 +216,16 @@
child.setTag(R.id.status_bar_view_state_tag, null);
}
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ final int configDiff = newConfig.diff(mConfiguration);
+ mConfiguration.setTo(newConfig);
+ if ((configDiff & (ActivityInfo.CONFIG_DENSITY | ActivityInfo.CONFIG_FONT_SCALE)) != 0) {
+ reloadDimens();
+ }
+ }
+
/**
* Add a name of an icon slot to be ignored. It will not show up nor be measured
* @param slotName name of the icon as it exists in
@@ -348,13 +363,17 @@
int totalVisible = mLayoutStates.size();
int maxVisible = totalVisible <= MAX_ICONS ? MAX_ICONS : MAX_ICONS - 1;
- mUnderflowStart = 0;
+ // Init mUnderflowStart value with the offset to let the dot be placed next to battery icon.
+ // It to prevent if the underflow happens at rightest(totalVisible - 1) child then break the
+ // for loop with mUnderflowStart staying 0(initial value), causing the dot be placed at the
+ // leftest side.
+ mUnderflowStart = (int) Math.max(contentStart, width - getPaddingEnd() - mUnderflowWidth);
int visible = 0;
int firstUnderflowIndex = -1;
for (int i = totalVisible - 1; i >= 0; i--) {
StatusIconState state = mLayoutStates.get(i);
// Allow room for underflow if we found we need it in onMeasure
- if (mNeedsUnderflow && (state.getXTranslation() < (contentStart + mUnderflowWidth))
+ if ((mNeedsUnderflow && (state.getXTranslation() < (contentStart + mUnderflowWidth)))
|| (mShouldRestrictIcons && (visible >= maxVisible))) {
firstUnderflowIndex = i;
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
index 98cde2a..abedd3220 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
@@ -28,6 +28,11 @@
void startCasting(CastDevice device);
void stopCasting(CastDevice device);
+ /**
+ * @return whether we have a connected device.
+ */
+ boolean hasConnectedCastDevice();
+
public interface Callback {
void onCastDevicesChanged();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
index 7290a1a..f7b601b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
@@ -217,6 +217,12 @@
}
}
+ @Override
+ public boolean hasConnectedCastDevice() {
+ return getCastDevices().stream().anyMatch(
+ castDevice -> castDevice.state == CastDevice.STATE_CONNECTED);
+ }
+
private void setProjection(MediaProjectionInfo projection, boolean started) {
boolean changed = false;
final MediaProjectionInfo oldProjection = mProjection;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt
index aa502bc..f61f3b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt
@@ -34,6 +34,8 @@
private val halfFoldedStates =
context.resources.getIntArray(R.array.config_halfFoldedDeviceStates)
private val unfoldedStates = context.resources.getIntArray(R.array.config_openDeviceStates)
+ private val rearDisplayStates =
+ context.resources.getIntArray(R.array.config_rearDisplayDeviceStates)
fun logListeningChange(listening: Boolean) {
logBuffer.log(TAG, VERBOSE, { bool1 = listening }, { "setListening: $bool1" })
@@ -122,6 +124,7 @@
in foldedStates -> "Folded"
in unfoldedStates -> "Unfolded"
in halfFoldedStates -> "Half-Folded"
+ in rearDisplayStates -> "Rear display"
-1 -> "Uninitialized"
else -> "Unknown"
}
diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
index 412b315..27aaa68 100644
--- a/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
@@ -22,7 +22,6 @@
import android.hardware.BatteryState
import android.hardware.input.InputManager
import android.hardware.input.InputSettings
-import android.os.Build
import android.os.Handler
import android.util.ArrayMap
import android.util.Log
@@ -35,6 +34,7 @@
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.log.DebugLogger.debugLog
import com.android.systemui.shared.hardware.hasInputDevice
import com.android.systemui.shared.hardware.isInternalStylusSource
import java.util.concurrent.CopyOnWriteArrayList
@@ -81,7 +81,7 @@
fun startListener() {
handler.post {
if (hasStarted) return@post
- logDebug { "Listener has started." }
+ debugLog { "Listener has started." }
hasStarted = true
isInUsiSession =
@@ -109,7 +109,7 @@
val device: InputDevice = inputManager.getInputDevice(deviceId) ?: return
if (!device.supportsSource(InputDevice.SOURCE_STYLUS)) return
- logDebug {
+ debugLog {
"Stylus InputDevice added: $deviceId ${device.name}, " +
"External: ${device.isExternal}"
}
@@ -134,7 +134,7 @@
val device: InputDevice = inputManager.getInputDevice(deviceId) ?: return
if (!device.supportsSource(InputDevice.SOURCE_STYLUS)) return
- logDebug { "Stylus InputDevice changed: $deviceId ${device.name}" }
+ debugLog { "Stylus InputDevice changed: $deviceId ${device.name}" }
val currAddress: String? = device.bluetoothAddress
val prevAddress: String? = inputDeviceAddressMap[deviceId]
@@ -155,7 +155,7 @@
if (!hasStarted) return
if (!inputDeviceAddressMap.contains(deviceId)) return
- logDebug { "Stylus InputDevice removed: $deviceId" }
+ debugLog { "Stylus InputDevice removed: $deviceId" }
unregisterBatteryListener(deviceId)
@@ -180,7 +180,7 @@
val isCharging = String(value) == "true"
- logDebug {
+ debugLog {
"Charging state metadata changed for device $inputDeviceId " +
"${device.address}: $isCharging"
}
@@ -199,7 +199,7 @@
handler.post {
if (!hasStarted) return@post
- logDebug {
+ debugLog {
"Battery state changed for $deviceId. " +
"batteryState present: ${batteryState.isPresent}, " +
"capacity: ${batteryState.capacity}"
@@ -247,7 +247,7 @@
if (!featureFlags.isEnabled(Flags.TRACK_STYLUS_EVER_USED)) return
if (InputSettings.isStylusEverUsed(context)) return
- logDebug { "Stylus used for the first time." }
+ debugLog { "Stylus used for the first time." }
InputSettings.setStylusEverUsed(context, true)
executeStylusCallbacks { cb -> cb.onStylusFirstUsed() }
}
@@ -264,7 +264,7 @@
val hasBtConnection = if (inputDeviceBtSessionIdMap.isEmpty()) 0 else 1
if (batteryStateValid && usiSessionId == null) {
- logDebug { "USI battery newly present, entering new USI session: $deviceId" }
+ debugLog { "USI battery newly present, entering new USI session: $deviceId" }
usiSessionId = instanceIdSequence.newInstanceId()
uiEventLogger.logWithInstanceIdAndPosition(
StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_FIRST_DETECTED,
@@ -274,7 +274,7 @@
hasBtConnection,
)
} else if (!batteryStateValid && usiSessionId != null) {
- logDebug { "USI battery newly absent, exiting USI session: $deviceId" }
+ debugLog { "USI battery newly absent, exiting USI session: $deviceId" }
uiEventLogger.logWithInstanceIdAndPosition(
StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_REMOVED,
0,
@@ -291,7 +291,7 @@
btAddress: String,
btConnected: Boolean
) {
- logDebug {
+ debugLog {
"Bluetooth stylus ${if (btConnected) "connected" else "disconnected"}:" +
" $deviceId $btAddress"
}
@@ -386,9 +386,3 @@
val TAG = StylusManager::class.simpleName.orEmpty()
}
}
-
-private inline fun logDebug(message: () -> String) {
- if (Build.IS_DEBUGGABLE) {
- Log.d(StylusManager.TAG, message())
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt
index 21b0efa..6eddd9e 100644
--- a/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt
+++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt
@@ -26,7 +26,6 @@
import android.content.IntentFilter
import android.hardware.BatteryState
import android.hardware.input.InputManager
-import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.UserHandle
@@ -40,6 +39,7 @@
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.log.DebugLogger.debugLog
import com.android.systemui.shared.hardware.hasInputDevice
import com.android.systemui.shared.hardware.isAnyStylusSource
import com.android.systemui.util.NotificationChannels
@@ -110,7 +110,7 @@
inputDeviceId = deviceId
batteryCapacity = batteryState.capacity
- logDebug {
+ debugLog {
"Updating notification battery state to $batteryCapacity " +
"for InputDevice $deviceId."
}
@@ -130,14 +130,14 @@
handler.post updateSuppressed@{
if (suppressed == suppress) return@updateSuppressed
- logDebug { "Updating notification suppression to $suppress." }
+ debugLog { "Updating notification suppression to $suppress." }
suppressed = suppress
refresh()
}
}
private fun hideNotification() {
- logDebug { "Cancelling USI low battery notification." }
+ debugLog { "Cancelling USI low battery notification." }
instanceId = null
notificationManager.cancel(USI_NOTIFICATION_ID)
}
@@ -160,7 +160,7 @@
.setAutoCancel(true)
.build()
- logDebug { "Show or update USI low battery notification at $batteryCapacity." }
+ debugLog { "Show or update USI low battery notification at $batteryCapacity." }
logUiEvent(StylusUiEvent.STYLUS_LOW_BATTERY_NOTIFICATION_SHOWN)
notificationManager.notify(USI_NOTIFICATION_ID, notification)
}
@@ -188,12 +188,12 @@
override fun onReceive(context: Context, intent: Intent) {
when (intent.action) {
ACTION_DISMISSED_LOW_BATTERY -> {
- logDebug { "USI low battery notification dismissed." }
+ debugLog { "USI low battery notification dismissed." }
logUiEvent(StylusUiEvent.STYLUS_LOW_BATTERY_NOTIFICATION_DISMISSED)
updateSuppression(true)
}
ACTION_CLICKED_LOW_BATTERY -> {
- logDebug { "USI low battery notification clicked." }
+ debugLog { "USI low battery notification clicked." }
logUiEvent(StylusUiEvent.STYLUS_LOW_BATTERY_NOTIFICATION_CLICKED)
updateSuppression(true)
if (inputDeviceId == null) return
@@ -263,9 +263,3 @@
@VisibleForTesting const val KEY_SETTINGS_FRAGMENT_ARGS = ":settings:show_fragment_args"
}
}
-
-private inline fun logDebug(message: () -> String) {
- if (Build.IS_DEBUGGABLE) {
- Log.d(StylusUsiPowerUI.TAG, message())
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt b/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
index 6026d2c..f0fa779 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
+++ b/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.android.systemui.theme
import android.util.Pair
@@ -24,68 +25,73 @@
@JvmField
val ALL_DYNAMIC_COLORS_MAPPED: List<Pair<String, DynamicColor>> =
arrayListOf(
- Pair.create("primary_container", MDC.primaryContainer),
- Pair.create("on_primary_container", MDC.onPrimaryContainer),
- Pair.create("primary", MDC.primary),
- Pair.create("on_primary", MDC.onPrimary),
- Pair.create("secondary_container", MDC.secondaryContainer),
- Pair.create("on_secondary_container", MDC.onSecondaryContainer),
- Pair.create("secondary", MDC.secondary),
- Pair.create("on_secondary", MDC.onSecondary),
- Pair.create("tertiary_container", MDC.tertiaryContainer),
- Pair.create("on_tertiary_container", MDC.onTertiaryContainer),
- Pair.create("tertiary", MDC.tertiary),
- Pair.create("on_tertiary", MDC.onTertiary),
- Pair.create("background", MDC.background),
- Pair.create("on_background", MDC.onBackground),
- Pair.create("surface", MDC.surface),
- Pair.create("on_surface", MDC.onSurface),
- Pair.create("surface_container_low", MDC.surfaceContainerLow),
- Pair.create("surface_container_lowest", MDC.surfaceContainerLowest),
- Pair.create("surface_container", MDC.surfaceContainer),
- Pair.create("surface_container_high", MDC.surfaceContainerHigh),
- Pair.create("surface_container_highest", MDC.surfaceContainerHighest),
- Pair.create("surface_bright", MDC.surfaceBright),
- Pair.create("surface_dim", MDC.surfaceDim),
- Pair.create("surface_variant", MDC.surfaceVariant),
- Pair.create("on_surface_variant", MDC.onSurfaceVariant),
- Pair.create("outline", MDC.outline),
- Pair.create("outline_variant", MDC.outlineVariant),
- Pair.create("error", MDC.error),
- Pair.create("on_error", MDC.onError),
- Pair.create("error_container", MDC.errorContainer),
- Pair.create("on_error_container", MDC.onErrorContainer),
- Pair.create("primary_fixed", MDC.primaryFixed),
- Pair.create("primary_fixed_dim", MDC.primaryFixedDim),
- Pair.create("on_primary_fixed", MDC.onPrimaryFixed),
- Pair.create("on_primary_fixed_variant", MDC.onPrimaryFixedVariant),
- Pair.create("secondary_fixed", MDC.secondaryFixed),
- Pair.create("secondary_fixed_dim", MDC.secondaryFixedDim),
- Pair.create("on_secondary_fixed", MDC.onSecondaryFixed),
- Pair.create("on_secondary_fixed_variant", MDC.onSecondaryFixedVariant),
- Pair.create("tertiary_fixed", MDC.tertiaryFixed),
- Pair.create("tertiary_fixed_dim", MDC.tertiaryFixedDim),
- Pair.create("on_tertiary_fixed", MDC.onTertiaryFixed),
- Pair.create("on_tertiary_fixed_variant", MDC.onTertiaryFixedVariant),
- Pair.create("control_activated", MDC.controlActivated),
- Pair.create("control_normal", MDC.controlNormal),
- Pair.create("control_highlight", MDC.controlHighlight),
- Pair.create("text_primary_inverse", MDC.textPrimaryInverse),
+ Pair.create("primary_container", MDC.primaryContainer()),
+ Pair.create("on_primary_container", MDC.onPrimaryContainer()),
+ Pair.create("primary", MDC.primary()),
+ Pair.create("on_primary", MDC.onPrimary()),
+ Pair.create("secondary_container", MDC.secondaryContainer()),
+ Pair.create("on_secondary_container", MDC.onSecondaryContainer()),
+ Pair.create("secondary", MDC.secondary()),
+ Pair.create("on_secondary", MDC.onSecondary()),
+ Pair.create("tertiary_container", MDC.tertiaryContainer()),
+ Pair.create("on_tertiary_container", MDC.onTertiaryContainer()),
+ Pair.create("tertiary", MDC.tertiary()),
+ Pair.create("on_tertiary", MDC.onTertiary()),
+ Pair.create("background", MDC.background()),
+ Pair.create("on_background", MDC.onBackground()),
+ Pair.create("surface", MDC.surface()),
+ Pair.create("on_surface", MDC.onSurface()),
+ Pair.create("surface_container_low", MDC.surfaceContainerLow()),
+ Pair.create("surface_container_lowest", MDC.surfaceContainerLowest()),
+ Pair.create("surface_container", MDC.surfaceContainer()),
+ Pair.create("surface_container_high", MDC.surfaceContainerHigh()),
+ Pair.create("surface_container_highest", MDC.surfaceContainerHighest()),
+ Pair.create("surface_bright", MDC.surfaceBright()),
+ Pair.create("surface_dim", MDC.surfaceDim()),
+ Pair.create("surface_variant", MDC.surfaceVariant()),
+ Pair.create("on_surface_variant", MDC.onSurfaceVariant()),
+ Pair.create("outline", MDC.outline()),
+ Pair.create("error", MDC.error()),
+ Pair.create("on_error", MDC.onError()),
+ Pair.create("error_container", MDC.errorContainer()),
+ Pair.create("on_error_container", MDC.onErrorContainer()),
+ Pair.create("primary_fixed", MDC.primaryFixed()),
+ Pair.create("primary_fixed_dim", MDC.primaryFixedDim()),
+ Pair.create("on_primary_fixed", MDC.onPrimaryFixed()),
+ Pair.create("on_primary_fixed_variant", MDC.onPrimaryFixedVariant()),
+ Pair.create("secondary_fixed", MDC.secondaryFixed()),
+ Pair.create("secondary_fixed_dim", MDC.secondaryFixedDim()),
+ Pair.create("on_secondary_fixed", MDC.onSecondaryFixed()),
+ Pair.create("on_secondary_fixed_variant", MDC.onSecondaryFixedVariant()),
+ Pair.create("tertiary_fixed", MDC.tertiaryFixed()),
+ Pair.create("tertiary_fixed_dim", MDC.tertiaryFixedDim()),
+ Pair.create("on_tertiary_fixed", MDC.onTertiaryFixed()),
+ Pair.create("on_tertiary_fixed_variant", MDC.onTertiaryFixedVariant()),
+ Pair.create("control_activated", MDC.controlActivated()),
+ Pair.create("control_normal", MDC.controlNormal()),
+ Pair.create("control_highlight", MDC.controlHighlight()),
+ Pair.create("text_primary_inverse", MDC.textPrimaryInverse()),
Pair.create(
"text_secondary_and_tertiary_inverse",
- MDC.textSecondaryAndTertiaryInverse
+ MDC.textSecondaryAndTertiaryInverse()
),
- Pair.create("text_primary_inverse_disable_only", MDC.textPrimaryInverseDisableOnly),
+ Pair.create(
+ "text_primary_inverse_disable_only",
+ MDC.textPrimaryInverseDisableOnly()
+ ),
Pair.create(
"text_secondary_and_tertiary_inverse_disabled",
- MDC.textSecondaryAndTertiaryInverseDisabled
+ MDC.textSecondaryAndTertiaryInverseDisabled()
),
- Pair.create("text_hint_inverse", MDC.textHintInverse),
- Pair.create("palette_key_color_primary", MDC.primaryPaletteKeyColor),
- Pair.create("palette_key_color_secondary", MDC.secondaryPaletteKeyColor),
- Pair.create("palette_key_color_tertiary", MDC.tertiaryPaletteKeyColor),
- Pair.create("palette_key_color_neutral", MDC.neutralPaletteKeyColor),
- Pair.create("palette_key_color_neutral_variant", MDC.neutralVariantPaletteKeyColor)
+ Pair.create("text_hint_inverse", MDC.textHintInverse()),
+ Pair.create("palette_key_color_primary", MDC.primaryPaletteKeyColor()),
+ Pair.create("palette_key_color_secondary", MDC.secondaryPaletteKeyColor()),
+ Pair.create("palette_key_color_tertiary", MDC.tertiaryPaletteKeyColor()),
+ Pair.create("palette_key_color_neutral", MDC.neutralPaletteKeyColor()),
+ Pair.create(
+ "palette_key_color_neutral_variant",
+ MDC.neutralVariantPaletteKeyColor()
+ )
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index faae8df..43d15bc 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.android.systemui.theme;
import static android.util.TypedValue.TYPE_INT_COLOR_ARGB8;
@@ -659,9 +660,9 @@
&& res.getColor(android.R.color.system_neutral2_500, theme)
== mColorScheme.getNeutral2().getS500()
&& res.getColor(android.R.color.system_primary_container_dark, theme)
- == MaterialDynamicColors.primaryContainer.getArgb(mDynamicSchemeDark)
+ == MaterialDynamicColors.primaryContainer().getArgb(mDynamicSchemeDark)
&& res.getColor(android.R.color.system_primary_container_light, theme)
- == MaterialDynamicColors.primaryContainer.getArgb(mDynamicSchemeLight))) {
+ == MaterialDynamicColors.primaryContainer().getArgb(mDynamicSchemeLight))) {
return false;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index b3e7cb0..e60f9b6 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -33,6 +33,7 @@
import android.graphics.Rect;
import android.inputmethodservice.InputMethodService;
import android.os.IBinder;
+import android.view.Display;
import android.view.KeyEvent;
import androidx.annotation.NonNull;
@@ -347,12 +348,16 @@
void initDesktopMode(DesktopMode desktopMode) {
desktopMode.addVisibleTasksListener(
new DesktopModeTaskRepository.VisibleTasksListener() {
- @Override
- public void onVisibilityChanged(boolean hasFreeformTasks) {
- mSysUiState.setFlag(SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE, hasFreeformTasks)
- .commitUpdate(mDisplayTracker.getDefaultDisplayId());
- }
- }, mSysUiMainExecutor);
+ @Override
+ public void onVisibilityChanged(int displayId, boolean hasFreeformTasks) {
+ if (displayId == Display.DEFAULT_DISPLAY) {
+ mSysUiState.setFlag(SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE,
+ hasFreeformTasks)
+ .commitUpdate(mDisplayTracker.getDefaultDisplayId());
+ }
+ // TODO(b/278084491): update sysui state for changes on other displays
+ }
+ }, mSysUiMainExecutor);
}
@Override
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index e2b568c..080be6d 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -196,6 +196,17 @@
android:exported="false"
android:permission="com.android.systemui.permission.SELF"
android:excludeFromRecents="true" />
+
+ <activity
+ android:name="com.android.systemui.notetask.LaunchNotesRoleSettingsTrampolineActivity"
+ android:exported="false"
+ android:permission="com.android.systemui.permission.SELF"
+ android:excludeFromRecents="true" >
+ <intent-filter>
+ <action android:name="com.android.systemui.action.MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
</application>
<instrumentation android:name="android.testing.TestableInstrumentation"
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index f4df26d..8a05a37 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -682,8 +682,7 @@
}
@Test
- public void testReinflateViewFlipper_asyncBouncerFlagOn() {
- when(mFeatureFlags.isEnabled(Flags.ASYNC_INFLATE_BOUNCER)).thenReturn(true);
+ public void testReinflateViewFlipper() {
KeyguardSecurityViewFlipperController.OnViewInflatedCallback onViewInflatedCallback =
controller -> {
};
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 2962c14..ddd9a08 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -151,7 +151,9 @@
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
+import org.mockito.InOrder;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
import org.mockito.internal.util.reflection.FieldSetter;
@@ -2737,6 +2739,36 @@
verifyFingerprintAuthenticateCall();
}
+ @Test
+ public void onTrustChangedCallbacksCalledBeforeOnTrustGrantedForCurrentUserCallback() {
+ // GIVEN device is interactive
+ deviceIsInteractive();
+
+ // GIVEN callback is registered
+ KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
+ mKeyguardUpdateMonitor.registerCallback(callback);
+
+ // WHEN onTrustChanged enabled=true
+ mKeyguardUpdateMonitor.onTrustChanged(
+ true /* enabled */,
+ true /* newlyUnlocked */,
+ getCurrentUser() /* userId */,
+ TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD /* flags */,
+ null /* trustGrantedMessages */);
+
+ // THEN onTrustChanged is called FIRST
+ final InOrder inOrder = Mockito.inOrder(callback);
+ inOrder.verify(callback).onTrustChanged(eq(getCurrentUser()));
+
+ // AND THEN onTrustGrantedForCurrentUser callback called
+ inOrder.verify(callback).onTrustGrantedForCurrentUser(
+ eq(true) /* dismissKeyguard */,
+ eq(true) /* newlyUnlocked */,
+ eq(new TrustGrantFlags(TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD)),
+ eq(null) /* message */
+ );
+ }
+
private void verifyFingerprintAuthenticateNeverCalled() {
verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), any());
verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index a20875b..6e37ee7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -40,14 +40,19 @@
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.data.repository.FakePromptRepository
+import com.android.systemui.biometrics.data.repository.FakeRearDisplayStateRepository
import com.android.systemui.biometrics.domain.interactor.FakeCredentialInteractor
import com.android.systemui.biometrics.domain.interactor.BiometricPromptCredentialInteractor
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
+import com.android.systemui.biometrics.ui.viewmodel.AuthBiometricFingerprintViewModel
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
import org.junit.After
import org.junit.Ignore
import org.junit.Rule
@@ -87,13 +92,26 @@
@Mock
lateinit var interactionJankMonitor: InteractionJankMonitor
+ private val testScope = TestScope(StandardTestDispatcher())
+ private val fakeExecutor = FakeExecutor(FakeSystemClock())
private val biometricPromptRepository = FakePromptRepository()
+ private val rearDisplayStateRepository = FakeRearDisplayStateRepository()
private val credentialInteractor = FakeCredentialInteractor()
private val bpCredentialInteractor = BiometricPromptCredentialInteractor(
Dispatchers.Main.immediate,
biometricPromptRepository,
credentialInteractor
)
+ private val displayStateInteractor = DisplayStateInteractorImpl(
+ testScope.backgroundScope,
+ mContext,
+ fakeExecutor,
+ rearDisplayStateRepository
+ )
+
+ private val authBiometricFingerprintViewModel = AuthBiometricFingerprintViewModel(
+ displayStateInteractor
+ )
private val credentialViewModel = CredentialViewModel(mContext, bpCredentialInteractor)
private var authContainer: TestAuthContainerView? = null
@@ -469,9 +487,10 @@
lockPatternUtils,
interactionJankMonitor,
{ bpCredentialInteractor },
+ { authBiometricFingerprintViewModel },
{ credentialViewModel },
Handler(TestableLooper.get(this).looper),
- FakeExecutor(FakeSystemClock())
+ fakeExecutor
) {
override fun postOnAnimation(runnable: Runnable) {
runnable.run()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 4f24b3a..a326cc7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -93,6 +93,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.domain.interactor.BiometricPromptCredentialInteractor;
import com.android.systemui.biometrics.domain.interactor.LogContextInteractor;
+import com.android.systemui.biometrics.ui.viewmodel.AuthBiometricFingerprintViewModel;
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.statusbar.CommandQueue;
@@ -172,6 +173,8 @@
@Mock
private BiometricPromptCredentialInteractor mBiometricPromptCredentialInteractor;
@Mock
+ private AuthBiometricFingerprintViewModel mAuthBiometricFingerprintViewModel;
+ @Mock
private CredentialViewModel mCredentialViewModel;
@Mock
private UdfpsUtils mUdfpsUtils;
@@ -995,8 +998,9 @@
() -> mSideFpsController, mDisplayManager, mWakefulnessLifecycle,
mPanelInteractionDetector, mUserManager, mLockPatternUtils, mUdfpsLogger,
mLogContextInteractor, () -> mBiometricPromptCredentialInteractor,
- () -> mCredentialViewModel, mInteractionJankMonitor, mHandler,
- mBackgroundExecutor, mVibratorHelper, mUdfpsUtils);
+ () -> mAuthBiometricFingerprintViewModel, () -> mCredentialViewModel,
+ mInteractionJankMonitor, mHandler, mBackgroundExecutor, mVibratorHelper,
+ mUdfpsUtils);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
index e6334cf..40d9009 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
@@ -55,6 +55,9 @@
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.SysuiTestableContext
+import com.android.systemui.biometrics.data.repository.FakeRearDisplayStateRepository
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
@@ -66,7 +69,9 @@
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestCoroutineScope
+import kotlinx.coroutines.test.TestScope
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -90,6 +95,8 @@
private const val DISPLAY_ID = 2
private const val SENSOR_ID = 1
+private const val REAR_DISPLAY_MODE_DEVICE_STATE = 3
+
@SmallTest
@RoboPilotTest
@RunWith(AndroidJUnit4::class)
@@ -112,7 +119,12 @@
private lateinit var keyguardBouncerRepository: FakeKeyguardBouncerRepository
private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
+ private lateinit var displayStateInteractor: DisplayStateInteractor
+
private val executor = FakeExecutor(FakeSystemClock())
+ private val rearDisplayStateRepository = FakeRearDisplayStateRepository()
+ private val testScope = TestScope(StandardTestDispatcher())
+
private lateinit var overlayController: ISidefpsController
private lateinit var sideFpsController: SideFpsController
@@ -142,6 +154,13 @@
FakeDeviceEntryFingerprintAuthRepository(),
FakeSystemClock(),
)
+ displayStateInteractor =
+ DisplayStateInteractorImpl(
+ testScope.backgroundScope,
+ context,
+ executor,
+ rearDisplayStateRepository
+ )
context.addMockSystemService(DisplayManager::class.java, displayManager)
context.addMockSystemService(WindowManager::class.java, windowManager)
@@ -168,6 +187,7 @@
isReverseDefaultRotation: Boolean = false,
initInfo: DisplayInfo.() -> Unit = {},
windowInsets: WindowInsets = insetsForSmallNavbar(),
+ inRearDisplayMode: Boolean = false,
block: () -> Unit
) {
this.deviceConfig = deviceConfig
@@ -228,6 +248,13 @@
isReverseDefaultRotation
)
+ val rearDisplayDeviceStates =
+ if (inRearDisplayMode) intArrayOf(REAR_DISPLAY_MODE_DEVICE_STATE) else intArrayOf()
+ sideFpsControllerContext.orCreateTestableResources.addOverride(
+ com.android.internal.R.array.config_rearDisplayDeviceStates,
+ rearDisplayDeviceStates
+ )
+
sideFpsController =
SideFpsController(
sideFpsControllerContext,
@@ -237,12 +264,14 @@
activityTaskManager,
overviewProxyService,
displayManager,
+ displayStateInteractor,
executor,
handler,
alternateBouncerInteractor,
TestCoroutineScope(),
- dumpManager,
+ dumpManager
)
+ rearDisplayStateRepository.setIsInRearDisplayMode(inRearDisplayMode)
overlayController =
ArgumentCaptor.forClass(ISidefpsController::class.java)
@@ -584,10 +613,62 @@
verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true)
}
+ @Test
+ fun verifiesSfpsIndicatorNotAddedInRearDisplayMode_0() =
+ testWithDisplay(
+ deviceConfig = DeviceConfig.Y_ALIGNED,
+ isReverseDefaultRotation = false,
+ { rotation = Surface.ROTATION_0 },
+ inRearDisplayMode = true,
+ ) {
+ verifySfpsIndicator_notAdded_InRearDisplayMode()
+ }
+
+ @Test
+ fun verifiesSfpsIndicatorNotAddedInRearDisplayMode_90() =
+ testWithDisplay(
+ deviceConfig = DeviceConfig.Y_ALIGNED,
+ isReverseDefaultRotation = false,
+ { rotation = Surface.ROTATION_90 },
+ inRearDisplayMode = true,
+ ) {
+ verifySfpsIndicator_notAdded_InRearDisplayMode()
+ }
+
+ @Test
+ fun verifiesSfpsIndicatorNotAddedInRearDisplayMode_180() =
+ testWithDisplay(
+ deviceConfig = DeviceConfig.Y_ALIGNED,
+ isReverseDefaultRotation = false,
+ { rotation = Surface.ROTATION_180 },
+ inRearDisplayMode = true,
+ ) {
+ verifySfpsIndicator_notAdded_InRearDisplayMode()
+ }
+
+ @Test
+ fun verifiesSfpsIndicatorNotAddedInRearDisplayMode_270() =
+ testWithDisplay(
+ deviceConfig = DeviceConfig.Y_ALIGNED,
+ isReverseDefaultRotation = false,
+ { rotation = Surface.ROTATION_270 },
+ inRearDisplayMode = true,
+ ) {
+ verifySfpsIndicator_notAdded_InRearDisplayMode()
+ }
+
private fun verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible: Boolean) {
sideFpsController.overlayOffsets = sensorLocation
}
+ private fun verifySfpsIndicator_notAdded_InRearDisplayMode() {
+ sideFpsController.overlayOffsets = sensorLocation
+ overlayController.show(SENSOR_ID, REASON_UNKNOWN)
+ executor.runAllReady()
+
+ verify(windowManager, never()).addView(any(), any())
+ }
+
fun alternateBouncerVisibility_showAndHideSideFpsUI() = testWithDisplay {
// WHEN alternate bouncer is visible
keyguardBouncerRepository.setAlternateVisible(true)
@@ -624,7 +705,7 @@
* in other rotations have been omitted.
*/
@Test
- fun verifiesIndicatorPlacementForXAlignedSensor_0() {
+ fun verifiesIndicatorPlacementForXAlignedSensor_0() =
testWithDisplay(
deviceConfig = DeviceConfig.X_ALIGNED,
isReverseDefaultRotation = false,
@@ -641,7 +722,6 @@
assertThat(overlayViewParamsCaptor.value.x).isEqualTo(sensorLocation.sensorLocationX)
assertThat(overlayViewParamsCaptor.value.y).isEqualTo(0)
}
- }
/**
* {@link SideFpsController#updateOverlayParams} calculates indicator placement for ROTATION_270
@@ -650,7 +730,7 @@
* correctly, tests for indicator placement in other rotations have been omitted.
*/
@Test
- fun verifiesIndicatorPlacementForXAlignedSensor_InReverseDefaultRotation_270() {
+ fun verifiesIndicatorPlacementForXAlignedSensor_InReverseDefaultRotation_270() =
testWithDisplay(
deviceConfig = DeviceConfig.X_ALIGNED,
isReverseDefaultRotation = true,
@@ -667,7 +747,6 @@
assertThat(overlayViewParamsCaptor.value.x).isEqualTo(sensorLocation.sensorLocationX)
assertThat(overlayViewParamsCaptor.value.y).isEqualTo(0)
}
- }
/**
* {@link SideFpsController#updateOverlayParams} calculates indicator placement for ROTATION_0,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/RearDisplayStateRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/RearDisplayStateRepositoryTest.kt
new file mode 100644
index 0000000..dfe8d36
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/RearDisplayStateRepositoryTest.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2023 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.keyguard.data.repository
+
+import android.hardware.devicestate.DeviceStateManager
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.RearDisplayStateRepository
+import com.android.systemui.biometrics.data.repository.RearDisplayStateRepositoryImpl
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.withArgCaptor
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+private const val NORMAL_DISPLAY_MODE_DEVICE_STATE = 2
+private const val REAR_DISPLAY_MODE_DEVICE_STATE = 3
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class RearDisplayStateRepositoryTest : SysuiTestCase() {
+ @JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule()
+ @Mock private lateinit var deviceStateManager: DeviceStateManager
+ private lateinit var underTest: RearDisplayStateRepository
+
+ private val testScope = TestScope(StandardTestDispatcher())
+ private val fakeExecutor = FakeExecutor(FakeSystemClock())
+
+ @Captor
+ private lateinit var callbackCaptor: ArgumentCaptor<DeviceStateManager.DeviceStateCallback>
+
+ @Before
+ fun setUp() {
+ val rearDisplayDeviceStates = intArrayOf(REAR_DISPLAY_MODE_DEVICE_STATE)
+ mContext.orCreateTestableResources.addOverride(
+ com.android.internal.R.array.config_rearDisplayDeviceStates,
+ rearDisplayDeviceStates
+ )
+
+ underTest =
+ RearDisplayStateRepositoryImpl(
+ testScope.backgroundScope,
+ mContext,
+ deviceStateManager,
+ fakeExecutor
+ )
+ }
+
+ @Test
+ fun updatesIsInRearDisplayMode_whenRearDisplayStateChanges() =
+ testScope.runTest {
+ val isInRearDisplayMode = collectLastValue(underTest.isInRearDisplayMode)
+ runCurrent()
+
+ val callback = deviceStateManager.captureCallback()
+
+ callback.onStateChanged(NORMAL_DISPLAY_MODE_DEVICE_STATE)
+ assertThat(isInRearDisplayMode()).isFalse()
+
+ callback.onStateChanged(REAR_DISPLAY_MODE_DEVICE_STATE)
+ assertThat(isInRearDisplayMode()).isTrue()
+ }
+}
+
+private fun DeviceStateManager.captureCallback() =
+ withArgCaptor<DeviceStateManager.DeviceStateCallback> {
+ verify(this@captureCallback).registerCallback(any(), capture())
+ }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractorImplTest.kt
new file mode 100644
index 0000000..2217c5c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractorImplTest.kt
@@ -0,0 +1,84 @@
+package com.android.systemui.biometrics.domain.interactor
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeRearDisplayStateRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.unfold.compat.ScreenSizeFoldProvider
+import com.android.systemui.unfold.updates.FoldProvider
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.withArgCaptor
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class DisplayStateInteractorImplTest : SysuiTestCase() {
+
+ @JvmField @Rule var mockitoRule = MockitoJUnit.rule()
+
+ private val fakeExecutor = FakeExecutor(FakeSystemClock())
+ private val testScope = TestScope(StandardTestDispatcher())
+ private val rearDisplayStateRepository = FakeRearDisplayStateRepository()
+
+ @Mock private lateinit var screenSizeFoldProvider: ScreenSizeFoldProvider
+ private lateinit var interactor: DisplayStateInteractorImpl
+
+ @Before
+ fun setup() {
+ interactor =
+ DisplayStateInteractorImpl(
+ testScope.backgroundScope,
+ mContext,
+ fakeExecutor,
+ rearDisplayStateRepository
+ )
+ interactor.setScreenSizeFoldProvider(screenSizeFoldProvider)
+ }
+
+ @Test
+ fun isInRearDisplayModeChanges() =
+ testScope.runTest {
+ val isInRearDisplayMode = collectLastValue(interactor.isInRearDisplayMode)
+
+ rearDisplayStateRepository.setIsInRearDisplayMode(false)
+ assertThat(isInRearDisplayMode()).isFalse()
+
+ rearDisplayStateRepository.setIsInRearDisplayMode(true)
+ assertThat(isInRearDisplayMode()).isTrue()
+ }
+
+ @Test
+ fun isFoldedChanges() =
+ testScope.runTest {
+ val isFolded = collectLastValue(interactor.isFolded)
+ runCurrent()
+ val callback = screenSizeFoldProvider.captureCallback()
+
+ callback.onFoldUpdated(isFolded = true)
+ assertThat(isFolded()).isTrue()
+
+ callback.onFoldUpdated(isFolded = false)
+ assertThat(isFolded()).isFalse()
+ }
+}
+
+private fun FoldProvider.captureCallback() =
+ withArgCaptor<FoldProvider.FoldCallback> {
+ verify(this@captureCallback).registerCallback(capture(), any())
+ }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/AuthBiometricFingerprintViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/AuthBiometricFingerprintViewModelTest.kt
new file mode 100644
index 0000000..0c210e5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/AuthBiometricFingerprintViewModelTest.kt
@@ -0,0 +1,69 @@
+package com.android.systemui.biometrics.ui.viewmodel
+
+import android.content.res.Configuration
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeRearDisplayStateRepository
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class AuthBiometricFingerprintViewModelTest : SysuiTestCase() {
+
+ private val rearDisplayStateRepository = FakeRearDisplayStateRepository()
+ private val testScope = TestScope(StandardTestDispatcher())
+ private val fakeExecutor = FakeExecutor(FakeSystemClock())
+
+ private lateinit var interactor: DisplayStateInteractor
+ private lateinit var viewModel: AuthBiometricFingerprintViewModel
+
+ @Before
+ fun setup() {
+ interactor =
+ DisplayStateInteractorImpl(
+ testScope.backgroundScope,
+ mContext,
+ fakeExecutor,
+ rearDisplayStateRepository
+ )
+ viewModel = AuthBiometricFingerprintViewModel(interactor)
+ }
+
+ @Test
+ fun iconUpdates_onConfigurationChanged() {
+ testScope.runTest {
+ runCurrent()
+ val testConfig = Configuration()
+ val folded = INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP - 1
+ val unfolded = INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP + 1
+ val currentIcon = collectLastValue(viewModel.iconAsset)
+
+ testConfig.smallestScreenWidthDp = folded
+ viewModel.onConfigurationChanged(testConfig)
+ val foldedIcon = currentIcon()
+
+ testConfig.smallestScreenWidthDp = unfolded
+ viewModel.onConfigurationChanged(testConfig)
+ val unfoldedIcon = currentIcon()
+
+ assertThat(foldedIcon).isNotEqualTo(unfoldedIcon)
+ }
+ }
+}
+
+internal const val INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP = 600
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardImageLoaderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardImageLoaderTest.kt
new file mode 100644
index 0000000..21516d49
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardImageLoaderTest.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2023 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.clipboardoverlay
+
+import android.content.ContentResolver
+import android.content.Context
+import android.net.Uri
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.whenever
+import java.io.IOException
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Assert.assertNull
+import org.junit.Before
+import org.junit.Test
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+class ClipboardImageLoaderTest : SysuiTestCase() {
+ @Mock private lateinit var mockContext: Context
+
+ @Mock private lateinit var mockContentResolver: ContentResolver
+
+ private lateinit var clipboardImageLoader: ClipboardImageLoader
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ }
+
+ @Test
+ @Throws(IOException::class)
+ fun test_imageLoadSuccess() = runTest {
+ val testDispatcher = StandardTestDispatcher(this.testScheduler)
+ clipboardImageLoader =
+ ClipboardImageLoader(mockContext, testDispatcher, CoroutineScope(testDispatcher))
+ val testUri = Uri.parse("testUri")
+ whenever(mockContext.contentResolver).thenReturn(mockContentResolver)
+ whenever(mockContext.resources).thenReturn(context.resources)
+
+ clipboardImageLoader.load(testUri)
+
+ verify(mockContentResolver).loadThumbnail(eq(testUri), any(), any())
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ @Throws(IOException::class)
+ fun test_imageLoadFailure() = runTest {
+ val testDispatcher = StandardTestDispatcher(this.testScheduler)
+ clipboardImageLoader =
+ ClipboardImageLoader(mockContext, testDispatcher, CoroutineScope(testDispatcher))
+ val testUri = Uri.parse("testUri")
+ whenever(mockContext.contentResolver).thenReturn(mockContentResolver)
+ whenever(mockContext.resources).thenReturn(context.resources)
+
+ val res = clipboardImageLoader.load(testUri)
+
+ verify(mockContentResolver).loadThumbnail(eq(testUri), any(), any())
+ assertNull(res)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
index fe5fa1f..39fb7b4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
@@ -25,6 +25,7 @@
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SHOWN_EXPANDED;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SHOWN_MINIMIZED;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SWIPE_DISMISSED;
+import static com.android.systemui.flags.Flags.CLIPBOARD_IMAGE_TIMEOUT;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -90,6 +91,8 @@
@Mock
private ClipboardOverlayUtils mClipboardUtils;
@Mock
+ private ClipboardImageLoader mClipboardImageLoader;
+ @Mock
private UiEventLogger mUiEventLogger;
private FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
private FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
@@ -120,6 +123,7 @@
mSampleClipData = new ClipData("Test", new String[]{"text/plain"},
new ClipData.Item("Test Item"));
+ mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, true); // turned off for legacy tests
mOverlayController = new ClipboardOverlayController(
mContext,
@@ -131,6 +135,7 @@
mFeatureFlags,
mClipboardUtils,
mExecutor,
+ mClipboardImageLoader,
mUiEventLogger);
verify(mClipboardOverlayView).setCallbacks(mOverlayCallbacksCaptor.capture());
mCallbacks = mOverlayCallbacksCaptor.getValue();
@@ -142,6 +147,69 @@
}
@Test
+ public void test_setClipData_invalidImageData_legacy() {
+ ClipData clipData = new ClipData("", new String[]{"image/png"},
+ new ClipData.Item(Uri.parse("")));
+ mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
+
+ mOverlayController.setClipData(clipData, "");
+
+ verify(mClipboardOverlayView, times(1)).showDefaultTextPreview();
+ verify(mClipboardOverlayView, times(1)).showShareChip();
+ verify(mClipboardOverlayView, times(1)).getEnterAnimation();
+ }
+
+ @Test
+ public void test_setClipData_nonImageUri_legacy() {
+ ClipData clipData = new ClipData("", new String[]{"resource/png"},
+ new ClipData.Item(Uri.parse("")));
+ mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
+
+ mOverlayController.setClipData(clipData, "");
+
+ verify(mClipboardOverlayView, times(1)).showDefaultTextPreview();
+ verify(mClipboardOverlayView, times(1)).showShareChip();
+ verify(mClipboardOverlayView, times(1)).getEnterAnimation();
+ }
+
+ @Test
+ public void test_setClipData_textData_legacy() {
+ mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
+ mOverlayController.setClipData(mSampleClipData, "abc");
+
+ verify(mClipboardOverlayView, times(1)).showTextPreview("Test Item", false);
+ verify(mUiEventLogger, times(1)).log(CLIPBOARD_OVERLAY_SHOWN_EXPANDED, 0, "abc");
+ verify(mClipboardOverlayView, times(1)).showShareChip();
+ verify(mClipboardOverlayView, times(1)).getEnterAnimation();
+ }
+
+ @Test
+ public void test_setClipData_sensitiveTextData_legacy() {
+ mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
+ ClipDescription description = mSampleClipData.getDescription();
+ PersistableBundle b = new PersistableBundle();
+ b.putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true);
+ description.setExtras(b);
+ ClipData data = new ClipData(description, mSampleClipData.getItemAt(0));
+ mOverlayController.setClipData(data, "");
+
+ verify(mClipboardOverlayView, times(1)).showTextPreview("••••••", true);
+ verify(mClipboardOverlayView, times(1)).showShareChip();
+ verify(mClipboardOverlayView, times(1)).getEnterAnimation();
+ }
+
+ @Test
+ public void test_setClipData_repeatedCalls_legacy() {
+ when(mAnimator.isRunning()).thenReturn(true);
+ mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
+
+ mOverlayController.setClipData(mSampleClipData, "");
+ mOverlayController.setClipData(mSampleClipData, "");
+
+ verify(mClipboardOverlayView, times(1)).getEnterAnimation();
+ }
+
+ @Test
public void test_setClipData_invalidImageData() {
ClipData clipData = new ClipData("", new String[]{"image/png"},
new ClipData.Item(Uri.parse("")));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt
index c3506e8..5414259 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.controls.ui
+import android.app.ActivityOptions
import android.app.PendingIntent
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
@@ -24,7 +25,10 @@
import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.capture
import com.android.wm.shell.taskview.TaskView
+import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -69,6 +73,25 @@
verify(taskView).startActivity(eq(pendingIntent), any(), any(), any())
}
+ @Test
+ fun testActivityOptionsAllowBal() {
+ // GIVEN the dialog is created with a PendingIntent
+ val dialog = createDialog(pendingIntent)
+
+ // WHEN the TaskView is initialized
+ dialog.stateCallback.onInitialized()
+
+ val optionsCaptor = argumentCaptor<ActivityOptions>()
+
+ // THEN the ActivityOptions have the correct flags
+ verify(taskView).startActivity(any(), any(), capture(optionsCaptor), any())
+
+ assertThat(optionsCaptor.value.pendingIntentBackgroundActivityStartMode)
+ .isEqualTo(ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED)
+ assertThat(optionsCaptor.value.isPendingIntentBackgroundActivityLaunchAllowedByPermission)
+ .isTrue()
+ }
+
private fun createDialog(pendingIntent: PendingIntent): DetailDialog {
return DetailDialog(
mContext,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
index 8795ac0..c9ee1e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
@@ -70,6 +70,7 @@
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.phone.CentralSurfaces;
+import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.telephony.TelephonyListenerManager;
@@ -115,6 +116,7 @@
@Mock private MetricsLogger mMetricsLogger;
@Mock private SysuiColorExtractor mColorExtractor;
@Mock private IStatusBarService mStatusBarService;
+ @Mock private LightBarController mLightBarController;
@Mock private NotificationShadeWindowController mNotificationShadeWindowController;
@Mock private IWindowManager mWindowManager;
@Mock private Executor mBackgroundExecutor;
@@ -166,6 +168,7 @@
mMetricsLogger,
mColorExtractor,
mStatusBarService,
+ mLightBarController,
mNotificationShadeWindowController,
mWindowManager,
mBackgroundExecutor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
index b9cfc65..e981d62 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
@@ -25,13 +25,11 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.IActivityTaskManager;
import android.app.IApplicationThread;
import android.app.ProfilerInfo;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
@@ -59,13 +57,14 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
public class WorkLockActivityControllerTest extends SysuiTestCase {
- private static final int USER_ID = 333;
+ private static final int TASK_USER_ID = 333;
+ private static final int PROFILE_USER_ID = 555;
private static final int TASK_ID = 444;
private static final ActivityManager.RunningTaskInfo TASK_INFO =
new ActivityManager.RunningTaskInfo();
static {
- TASK_INFO.userId = USER_ID;
+ TASK_INFO.userId = TASK_USER_ID;
TASK_INFO.taskId = TASK_ID;
}
@@ -101,10 +100,10 @@
setActivityStartCode(TASK_ID, true /*taskOverlay*/, ActivityManager.START_SUCCESS);
// And the controller receives a message saying the profile is locked,
- mTaskStackListener.onTaskProfileLocked(TASK_INFO);
+ mTaskStackListener.onTaskProfileLocked(TASK_INFO, PROFILE_USER_ID);
// The overlay should start and the task the activity started in should not be removed.
- verifyStartActivity(TASK_ID, true /*taskOverlay*/);
+ verifyStartActivity(TASK_ID, true /*taskOverlay*/, PROFILE_USER_ID);
verify(mIActivityTaskManager, never()).removeTask(anyInt() /*taskId*/);
}
@@ -114,11 +113,11 @@
setActivityStartCode(TASK_ID, true /*taskOverlay*/, ActivityManager.START_CLASS_NOT_FOUND);
// And the controller receives a message saying the profile is locked,
- mTaskStackListener.onTaskProfileLocked(TASK_INFO);
+ mTaskStackListener.onTaskProfileLocked(TASK_INFO, PROFILE_USER_ID);
// The task the activity started in should be removed to prevent the locked task from
// being shown.
- verifyStartActivity(TASK_ID, true /*taskOverlay*/);
+ verifyStartActivity(TASK_ID, true /*taskOverlay*/, PROFILE_USER_ID);
verify(mIActivityTaskManager).removeTask(TASK_ID);
}
@@ -141,12 +140,13 @@
eq(ActivityManager.getCurrentUser()));
}
- private void verifyStartActivity(int taskId, boolean taskOverlay) throws Exception {
+ private void verifyStartActivity(int taskId, boolean taskOverlay, int profileUserId)
+ throws Exception {
verify(mIActivityTaskManager).startActivityAsUser(
eq((IApplicationThread) null),
eq((String) null),
eq((String) null),
- any(Intent.class),
+ argThat(hasUserId(profileUserId)),
eq((String) null),
eq((IBinder) null),
eq((String) null),
@@ -157,24 +157,15 @@
eq(ActivityManager.getCurrentUser()));
}
- private static ArgumentMatcher<Intent> hasComponent(final Context context,
- final Class<? extends Activity> activityClass) {
- return new ArgumentMatcher<Intent>() {
- @Override
- public boolean matches(Intent intent) {
- return new ComponentName(context, activityClass).equals(intent.getComponent());
- }
- };
+ private static ArgumentMatcher<Intent> hasUserId(int userId) {
+ return intent -> intent.getIntExtra(Intent.EXTRA_USER_ID, -1) == userId;
}
private static ArgumentMatcher<Bundle> hasOptions(final int taskId, final boolean overlay) {
- return new ArgumentMatcher<Bundle>() {
- @Override
- public boolean matches(Bundle item) {
- final ActivityOptions options = ActivityOptions.fromBundle(item);
- return (options.getLaunchTaskId() == taskId)
- && (options.getTaskOverlay() == overlay);
- }
+ return item -> {
+ final ActivityOptions options = ActivityOptions.fromBundle(item);
+ return (options.getLaunchTaskId() == taskId)
+ && (options.getTaskOverlay() == overlay);
};
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt
index a003e1d..43e430f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt
@@ -19,7 +19,9 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.table.TableChange.Companion.IS_INITIAL_PREFIX
+import com.android.systemui.log.table.TableChange.Companion.MAX_STRING_LENGTH
import com.google.common.truth.Truth.assertThat
+import junit.framework.Assert.assertTrue
import org.junit.Test
@SmallTest
@@ -326,4 +328,152 @@
assertThat(underTest.getVal()).doesNotContain(IS_INITIAL_PREFIX)
}
+
+ @Test
+ fun constructor_columnAndValueTooLong_truncated() {
+ val underTest =
+ TableChange(
+ columnPrefix = "P".repeat(MAX_STRING_LENGTH + 10),
+ columnName = "N".repeat(MAX_STRING_LENGTH + 10),
+ type = TableChange.DataType.STRING,
+ str = "V".repeat(MAX_STRING_LENGTH + 10),
+ )
+
+ assertThat(underTest.getName()).contains("P".repeat(MAX_STRING_LENGTH))
+ assertThat(underTest.getName()).doesNotContain("P".repeat(MAX_STRING_LENGTH + 1))
+ assertThat(underTest.getName()).contains("N".repeat(MAX_STRING_LENGTH))
+ assertThat(underTest.getName()).doesNotContain("N".repeat(MAX_STRING_LENGTH + 1))
+ assertThat(underTest.getVal()).isEqualTo("V".repeat(MAX_STRING_LENGTH))
+ }
+
+ @Test
+ fun constructor_columnNameNotTooLong_noReallocation() {
+ val inputColumnName = "fakeName"
+ val inputValue = "fakeValue"
+ val underTest =
+ TableChange(
+ columnPrefix = "",
+ columnName = inputColumnName,
+ type = TableChange.DataType.STRING,
+ str = inputValue,
+ )
+
+ // Use referential equality to verify we didn't reallocate a new string when the string is
+ // *not* too long.
+ assertTrue(underTest.getColumnName() === inputColumnName)
+ }
+
+ @Test
+ fun reset_columnPrefixTooLong_truncated() {
+ val underTest = TableChange()
+
+ underTest.reset(
+ timestamp = 1L,
+ columnPrefix = "P".repeat(MAX_STRING_LENGTH + 10),
+ columnName = "name",
+ isInitial = false,
+ )
+
+ assertThat(underTest.getName()).contains("P".repeat(MAX_STRING_LENGTH))
+ assertThat(underTest.getName()).doesNotContain("P".repeat(MAX_STRING_LENGTH + 1))
+ }
+
+ @Test
+ fun reset_columnNameTooLong_truncated() {
+ val underTest = TableChange()
+
+ underTest.reset(
+ timestamp = 1L,
+ columnPrefix = "prefix",
+ columnName = "N".repeat(MAX_STRING_LENGTH + 10),
+ isInitial = false,
+ )
+
+ assertThat(underTest.getName()).contains("N".repeat(MAX_STRING_LENGTH))
+ assertThat(underTest.getName()).doesNotContain("N".repeat(MAX_STRING_LENGTH + 1))
+ }
+
+ @Test
+ fun reset_columnNameNotTooLong_noReallocation() {
+ val underTest = TableChange()
+ val shortColumnName = "shortColumnName"
+
+ underTest.reset(
+ timestamp = 1L,
+ columnPrefix = "prefix",
+ columnName = shortColumnName,
+ isInitial = false,
+ )
+
+ // Use referential equality to verify we didn't reallocate a new string when the string is
+ // *not* too long.
+ assertTrue(underTest.getColumnName() === shortColumnName)
+ }
+
+ @Test
+ fun setString_valueTooLong_truncated() {
+ val underTest = TableChange()
+
+ underTest.set("V".repeat(MAX_STRING_LENGTH + 1))
+
+ assertThat(underTest.getVal()).isEqualTo("V".repeat(MAX_STRING_LENGTH))
+ }
+
+ @Test
+ fun updateTo_newColumnPrefixTooLong_truncated() {
+ val underTest = TableChange(columnPrefix = "fakePrefix", columnName = "fakeName")
+ underTest.set(42)
+
+ val new =
+ TableChange(
+ columnPrefix = "P".repeat(MAX_STRING_LENGTH + 10),
+ columnName = "name",
+ )
+ underTest.updateTo(new)
+
+ assertThat(underTest.getName()).contains("P".repeat(MAX_STRING_LENGTH))
+ assertThat(underTest.getName()).doesNotContain("P".repeat(MAX_STRING_LENGTH + 1))
+ }
+
+ @Test
+ fun updateTo_newColumnNameTooLong_truncated() {
+ val underTest = TableChange(columnPrefix = "fakePrefix", columnName = "fakeName")
+ underTest.set(42)
+
+ val new =
+ TableChange(
+ columnPrefix = "prefix",
+ columnName = "N".repeat(MAX_STRING_LENGTH + 10),
+ )
+ underTest.updateTo(new)
+
+ assertThat(underTest.getName()).contains("N".repeat(MAX_STRING_LENGTH))
+ assertThat(underTest.getName()).doesNotContain("N".repeat(MAX_STRING_LENGTH + 1))
+ }
+
+ @Test
+ fun updateTo_columnNameNotTooLong_noReallocation() {
+ val underTest = TableChange()
+ val shortColumnName = "shortColumnName"
+ val new = TableChange(columnPrefix = "prefix", columnName = shortColumnName)
+
+ underTest.updateTo(new)
+
+ // Use referential equality to verify we didn't reallocate a new string when the string is
+ // *not* too long.
+ assertTrue(underTest.getColumnName() === shortColumnName)
+ }
+
+ @Test
+ fun updateTo_newValTooLong_truncated() {
+ val underTest = TableChange(columnPrefix = "fakePrefix", columnName = "fakeName")
+ underTest.set("value")
+
+ val new = TableChange()
+ new.set("V".repeat(MAX_STRING_LENGTH + 10))
+
+ underTest.updateTo(new)
+
+ assertThat(underTest.getVal()).isEqualTo("V".repeat(MAX_STRING_LENGTH))
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt
index a2b2322..f867fc7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt
@@ -19,6 +19,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.table.TableChange.Companion.IS_INITIAL_PREFIX
+import com.android.systemui.log.table.TableChange.Companion.MAX_STRING_LENGTH
import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.plugins.log.LogcatEchoTracker
import com.android.systemui.util.mockito.any
@@ -576,6 +577,112 @@
}
@Test
+ fun dumpChanges_tooLongColumnPrefix_viaLogChange_truncated() {
+ underTest.logChange(
+ prefix = "P".repeat(MAX_STRING_LENGTH + 10),
+ columnName = "name",
+ value = true,
+ )
+
+ val dumpedString = dumpChanges()
+
+ assertThat(dumpedString).contains("P".repeat(MAX_STRING_LENGTH))
+ assertThat(dumpedString).doesNotContain("P".repeat(MAX_STRING_LENGTH + 1))
+ }
+
+ @Test
+ fun dumpChanges_tooLongColumnPrefix_viaLogDiffs_truncated() {
+ val prevDiffable = object : TestDiffable() {}
+ val nextDiffable =
+ object : TestDiffable() {
+ override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+ row.logChange("status", "value")
+ }
+ }
+
+ // WHEN the column prefix is too large
+ underTest.logDiffs(
+ columnPrefix = "P".repeat(MAX_STRING_LENGTH + 10),
+ prevDiffable,
+ nextDiffable,
+ )
+
+ val dumpedString = dumpChanges()
+
+ // THEN it's truncated to the max length
+ assertThat(dumpedString).contains("P".repeat(MAX_STRING_LENGTH))
+ assertThat(dumpedString).doesNotContain("P".repeat(MAX_STRING_LENGTH + 1))
+ }
+
+ @Test
+ fun dumpChanges_tooLongColumnName_viaLogChange_truncated() {
+ underTest.logChange(
+ prefix = "prefix",
+ columnName = "N".repeat(MAX_STRING_LENGTH + 10),
+ value = 10,
+ )
+
+ val dumpedString = dumpChanges()
+
+ assertThat(dumpedString).contains("N".repeat(MAX_STRING_LENGTH))
+ assertThat(dumpedString).doesNotContain("N".repeat(MAX_STRING_LENGTH + 1))
+ }
+
+ @Test
+ fun dumpChanges_tooLongColumnName_viaLogDiffs_truncated() {
+ val prevDiffable = object : TestDiffable() {}
+ val nextDiffable =
+ object : TestDiffable() {
+ override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+ // WHEN the column name is too large
+ row.logChange(columnName = "N".repeat(MAX_STRING_LENGTH + 10), "value")
+ }
+ }
+
+ underTest.logDiffs(columnPrefix = "prefix", prevDiffable, nextDiffable)
+
+ val dumpedString = dumpChanges()
+
+ // THEN it's truncated to the max length
+ assertThat(dumpedString).contains("N".repeat(MAX_STRING_LENGTH))
+ assertThat(dumpedString).doesNotContain("N".repeat(MAX_STRING_LENGTH + 1))
+ }
+
+ @Test
+ fun dumpChanges_tooLongValue_viaLogChange_truncated() {
+ underTest.logChange(
+ prefix = "prefix",
+ columnName = "name",
+ value = "V".repeat(MAX_STRING_LENGTH + 10),
+ )
+
+ val dumpedString = dumpChanges()
+
+ assertThat(dumpedString).contains("V".repeat(MAX_STRING_LENGTH))
+ assertThat(dumpedString).doesNotContain("V".repeat(MAX_STRING_LENGTH + 1))
+ }
+
+ @Test
+ fun dumpChanges_tooLongValue_viaLogDiffs_truncated() {
+ val prevDiffable = object : TestDiffable() {}
+ val nextDiffable =
+ object : TestDiffable() {
+ override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+ // WHEN the value is too large
+ row.logChange("columnName", value = "V".repeat(MAX_STRING_LENGTH + 10))
+ }
+ }
+
+ underTest.logDiffs(columnPrefix = "prefix", prevDiffable, nextDiffable)
+
+ val dumpedString = dumpChanges()
+
+ // THEN it's truncated to the max length
+ assertThat(dumpedString).contains("V".repeat(MAX_STRING_LENGTH))
+ assertThat(dumpedString).doesNotContain("V".repeat(MAX_STRING_LENGTH + 1))
+ }
+
+ @Test
fun dumpChanges_rotatesIfBufferIsFull() {
lateinit var valToDump: String
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
index 0a1db60..d428db7b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
@@ -40,7 +40,6 @@
import androidx.media.utils.MediaConstants
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
-import com.android.internal.statusbar.IStatusBarService
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.InstanceIdSequenceFake
import com.android.systemui.R
@@ -131,7 +130,6 @@
@Mock lateinit var activityStarter: ActivityStarter
@Mock lateinit var smartspaceManager: SmartspaceManager
@Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
- @Mock lateinit var statusBarService: IStatusBarService
lateinit var smartspaceMediaDataProvider: SmartspaceMediaDataProvider
@Mock lateinit var mediaSmartspaceTarget: SmartspaceTarget
@Mock private lateinit var mediaRecommendationItem: SmartspaceAction
@@ -194,8 +192,7 @@
mediaFlags = mediaFlags,
logger = logger,
smartspaceManager = smartspaceManager,
- keyguardUpdateMonitor = keyguardUpdateMonitor,
- statusBarService = statusBarService,
+ keyguardUpdateMonitor = keyguardUpdateMonitor
)
verify(tunerService)
.addTunable(capture(tunableCaptor), eq(Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION))
@@ -520,136 +517,19 @@
}
@Test
- fun testOnNotificationAdded_emptyTitle_notLoaded() {
- // GIVEN that the manager has a notification with an empty title.
+ fun testOnNotificationRemoved_emptyTitle_notConverted() {
+ // GIVEN that the manager has a notification with a resume action and empty title.
whenever(controller.metadata)
.thenReturn(
metadataBuilder
.putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_EMPTY_TITLE)
.build()
)
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
-
- assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
- assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
- verify(statusBarService)
- .onNotificationError(
- eq(PACKAGE_NAME),
- eq(mediaNotification.tag),
- eq(mediaNotification.id),
- eq(mediaNotification.uid),
- eq(mediaNotification.initialPid),
- eq(MEDIA_TITLE_ERROR_MESSAGE),
- eq(mediaNotification.user.identifier)
- )
- verify(listener, never())
- .onMediaDataLoaded(
- eq(KEY),
- eq(null),
- capture(mediaDataCaptor),
- eq(true),
- eq(0),
- eq(false)
- )
- verify(logger, never()).logResumeMediaAdded(anyInt(), eq(PACKAGE_NAME), any())
- verify(logger, never()).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), any())
- }
-
- @Test
- fun testOnNotificationAdded_blankTitle_notLoaded() {
- // GIVEN that the manager has a notification with a blank title.
- whenever(controller.metadata)
- .thenReturn(
- metadataBuilder
- .putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_BLANK_TITLE)
- .build()
- )
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
-
- assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
- assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
- verify(statusBarService)
- .onNotificationError(
- eq(PACKAGE_NAME),
- eq(mediaNotification.tag),
- eq(mediaNotification.id),
- eq(mediaNotification.uid),
- eq(mediaNotification.initialPid),
- eq(MEDIA_TITLE_ERROR_MESSAGE),
- eq(mediaNotification.user.identifier)
- )
- verify(listener, never())
- .onMediaDataLoaded(
- eq(KEY),
- eq(null),
- capture(mediaDataCaptor),
- eq(true),
- eq(0),
- eq(false)
- )
- verify(logger, never()).logResumeMediaAdded(anyInt(), eq(PACKAGE_NAME), any())
- verify(logger, never()).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), any())
- }
-
- @Test
- fun testOnNotificationUpdated_invalidTitle_logMediaRemoved() {
- addNotificationAndLoad()
- val data = mediaDataCaptor.value
-
- verify(listener)
- .onMediaDataLoaded(
- eq(KEY),
- eq(null),
- capture(mediaDataCaptor),
- eq(true),
- eq(0),
- eq(false)
- )
-
- reset(listener)
- whenever(controller.metadata)
- .thenReturn(
- metadataBuilder
- .putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_BLANK_TITLE)
- .build()
- )
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
- assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
- assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
- verify(statusBarService)
- .onNotificationError(
- eq(PACKAGE_NAME),
- eq(mediaNotification.tag),
- eq(mediaNotification.id),
- eq(mediaNotification.uid),
- eq(mediaNotification.initialPid),
- eq(MEDIA_TITLE_ERROR_MESSAGE),
- eq(mediaNotification.user.identifier)
- )
- verify(listener, never())
- .onMediaDataLoaded(
- eq(KEY),
- eq(null),
- capture(mediaDataCaptor),
- eq(true),
- eq(0),
- eq(false)
- )
- verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
- }
-
- @Test
- fun testOnNotificationRemoved_emptyTitle_notConverted() {
- // GIVEN that the manager has a notification with a resume action and empty title.
addNotificationAndLoad()
val data = mediaDataCaptor.value
val instanceId = data.instanceId
assertThat(data.resumption).isFalse()
- mediaDataManager.onMediaDataLoaded(
- KEY,
- null,
- data.copy(song = SESSION_EMPTY_TITLE, resumeAction = Runnable {})
- )
+ mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
// WHEN the notification is removed
reset(listener)
@@ -674,15 +554,17 @@
@Test
fun testOnNotificationRemoved_blankTitle_notConverted() {
// GIVEN that the manager has a notification with a resume action and blank title.
+ whenever(controller.metadata)
+ .thenReturn(
+ metadataBuilder
+ .putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_BLANK_TITLE)
+ .build()
+ )
addNotificationAndLoad()
val data = mediaDataCaptor.value
val instanceId = data.instanceId
assertThat(data.resumption).isFalse()
- mediaDataManager.onMediaDataLoaded(
- KEY,
- null,
- data.copy(song = SESSION_BLANK_TITLE, resumeAction = Runnable {})
- )
+ mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
// WHEN the notification is removed
reset(listener)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/DynamicColorTest.java b/packages/SystemUI/tests/src/com/android/systemui/monet/DynamicColorTest.java
index fb5197e..4ce32d2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/monet/DynamicColorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/monet/DynamicColorTest.java
@@ -17,18 +17,16 @@
package com.android.systemui.monet;
import static com.android.systemui.monet.utils.ArgbSubject.assertThat;
-
import static org.junit.Assert.assertTrue;
-
import androidx.test.filters.SmallTest;
-import com.android.systemui.SysuiTestCase;
import com.android.systemui.monet.contrast.Contrast;
import com.android.systemui.monet.dynamiccolor.DynamicColor;
import com.android.systemui.monet.dynamiccolor.MaterialDynamicColors;
import com.android.systemui.monet.dynamiccolor.ToneDeltaConstraint;
import com.android.systemui.monet.dynamiccolor.TonePolarity;
+import com.android.systemui.SysuiTestCase;
import com.android.systemui.monet.hct.Hct;
import com.android.systemui.monet.scheme.DynamicScheme;
import com.android.systemui.monet.scheme.SchemeContent;
@@ -36,182 +34,174 @@
import com.android.systemui.monet.scheme.SchemeMonochrome;
import com.android.systemui.monet.scheme.SchemeTonalSpot;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+@Ignore("b/279581953")
@SmallTest
@RunWith(JUnit4.class)
-public final class DynamicColorTest extends SysuiTestCase {
+public final class DynamicColorTest extends SysuiTestCase{
- @Test
- public void fromArgbNoBackground_doesntChangeForContrast() {
- final int blueArgb = 0xff0000ff;
- final DynamicColor dynamicColor = DynamicColor.fromArgb(blueArgb);
+ private final MaterialDynamicColors dynamicColors = new MaterialDynamicColors();
- final SchemeTonalSpot standardContrast = new SchemeTonalSpot(Hct.fromInt(blueArgb), false,
- 0.0);
- assertThat(dynamicColor.getArgb(standardContrast)).isSameColorAs(blueArgb);
+ @Test
+ public void fromArgbNoBackground_doesntChangeForContrast() {
+ final int blueArgb = 0xff0000ff;
+ final DynamicColor dynamicColor = DynamicColor.fromArgb(blueArgb);
- final SchemeTonalSpot minContrast = new SchemeTonalSpot(Hct.fromInt(blueArgb), false, -1.0);
- assertThat(dynamicColor.getArgb(minContrast)).isSameColorAs(blueArgb);
+ final SchemeTonalSpot standardContrast = new SchemeTonalSpot(Hct.fromInt(blueArgb), false, 0.0);
+ assertThat(dynamicColor.getArgb(standardContrast)).isSameColorAs(blueArgb);
- final SchemeTonalSpot maxContrast = new SchemeTonalSpot(Hct.fromInt(blueArgb), false, 1.0);
- assertThat(dynamicColor.getArgb(maxContrast)).isSameColorAs(blueArgb);
- }
+ final SchemeTonalSpot minContrast = new SchemeTonalSpot(Hct.fromInt(blueArgb), false, -1.0);
+ assertThat(dynamicColor.getArgb(minContrast)).isSameColorAs(blueArgb);
- @Test
- public void toneDeltaConstraintNoPreference_evaluatesCorrectly() {
- final int blueArgb = 0xff0000ff;
- final int redArgb = 0xffff0000;
- final DynamicColor otherDynamicColor = DynamicColor.fromArgb(redArgb);
- final DynamicColor dynamicColor =
- DynamicColor.fromArgb(
- blueArgb,
- (s) -> 30.0,
- null,
- (s) -> new ToneDeltaConstraint(30, otherDynamicColor,
- TonePolarity.NO_PREFERENCE));
- final SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(blueArgb), false, 0.0);
- assertThat(dynamicColor.getArgb(scheme)).isSameColorAs(0xff0000ef);
- }
+ final SchemeTonalSpot maxContrast = new SchemeTonalSpot(Hct.fromInt(blueArgb), false, 1.0);
+ assertThat(dynamicColor.getArgb(maxContrast)).isSameColorAs(blueArgb);
+ }
- @Test
- public void dynamicColor_withOpacity() {
- final DynamicColor dynamicColor =
- new DynamicColor(
- s -> 0.0,
- s -> 0.0,
- s -> s.isDark ? 100.0 : 0.0,
- s -> s.isDark ? 0.20 : 0.12,
- null,
- scheme ->
- DynamicColor.toneMinContrastDefault(
- (s) -> s.isDark ? 100.0 : 0.0, null, scheme, null),
- scheme ->
- DynamicColor.toneMaxContrastDefault(
- (s) -> s.isDark ? 100.0 : 0.0, null, scheme, null),
- null);
- final SchemeTonalSpot lightScheme = new SchemeTonalSpot(Hct.fromInt(0xff4285f4), false,
- 0.0);
- assertThat(dynamicColor.getArgb(lightScheme)).isSameColorAs(0x1f000000);
+ @Test
+ public void toneDeltaConstraintNoPreference_evaluatesCorrectly() {
+ final int blueArgb = 0xff0000ff;
+ final int redArgb = 0xffff0000;
+ final DynamicColor otherDynamicColor = DynamicColor.fromArgb(redArgb);
+ final DynamicColor dynamicColor =
+ DynamicColor.fromArgb(
+ blueArgb,
+ (s) -> 30.0,
+ null,
+ (s) -> new ToneDeltaConstraint(30, otherDynamicColor, TonePolarity.NO_PREFERENCE));
+ final SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(blueArgb), false, 0.0);
+ assertThat(dynamicColor.getArgb(scheme)).isSameColorAs(0xff0000ef);
+ }
- final SchemeTonalSpot darkScheme = new SchemeTonalSpot(Hct.fromInt(0xff4285f4), true, 0.0);
- assertThat(dynamicColor.getArgb(darkScheme)).isSameColorAs(0x33ffffff);
- }
+ @Test
+ public void dynamicColor_withOpacity() {
+ final DynamicColor dynamicColor =
+ new DynamicColor(
+ s -> 0.0,
+ s -> 0.0,
+ s -> s.isDark ? 100.0 : 0.0,
+ s -> s.isDark ? 0.20 : 0.12,
+ null,
+ scheme ->
+ DynamicColor.toneMinContrastDefault(
+ (s) -> s.isDark ? 100.0 : 0.0, null, scheme, null),
+ scheme ->
+ DynamicColor.toneMaxContrastDefault(
+ (s) -> s.isDark ? 100.0 : 0.0, null, scheme, null),
+ null);
+ final SchemeTonalSpot lightScheme = new SchemeTonalSpot(Hct.fromInt(0xff4285f4), false, 0.0);
+ assertThat(dynamicColor.getArgb(lightScheme)).isSameColorAs(0x1f000000);
- @Test
- public void respectsContrast() {
- final Hct[] seedColors =
- new Hct[]{
- Hct.fromInt(0xFFFF0000),
- Hct.fromInt(0xFFFFFF00),
- Hct.fromInt(0xFF00FF00),
- Hct.fromInt(0xFF0000FF)
- };
+ final SchemeTonalSpot darkScheme = new SchemeTonalSpot(Hct.fromInt(0xff4285f4), true, 0.0);
+ assertThat(dynamicColor.getArgb(darkScheme)).isSameColorAs(0x33ffffff);
+ }
- final double[] contrastLevels = {-1.0, -0.5, 0.0, 0.5, 1.0};
+ @Test
+ public void respectsContrast() {
+ final Hct[] seedColors =
+ new Hct[] {
+ Hct.fromInt(0xFFFF0000),
+ Hct.fromInt(0xFFFFFF00),
+ Hct.fromInt(0xFF00FF00),
+ Hct.fromInt(0xFF0000FF)
+ };
- for (Hct seedColor : seedColors) {
- for (double contrastLevel : contrastLevels) {
- for (boolean isDark : new boolean[]{false, true}) {
- final DynamicScheme[] schemes =
- new DynamicScheme[]{
- new SchemeContent(seedColor, isDark, contrastLevel),
- new SchemeMonochrome(seedColor, isDark, contrastLevel),
- new SchemeTonalSpot(seedColor, isDark, contrastLevel),
- new SchemeFidelity(seedColor, isDark, contrastLevel)
- };
- for (final DynamicScheme scheme : schemes) {
- assertTrue(
- pairSatisfiesContrast(
- scheme, MaterialDynamicColors.onPrimary,
- MaterialDynamicColors.primary));
- assertTrue(
- pairSatisfiesContrast(
- scheme,
- MaterialDynamicColors.onPrimaryContainer,
- MaterialDynamicColors.primaryContainer));
- assertTrue(
- pairSatisfiesContrast(
- scheme, MaterialDynamicColors.onSecondary,
- MaterialDynamicColors.secondary));
- assertTrue(
- pairSatisfiesContrast(
- scheme,
- MaterialDynamicColors.onSecondaryContainer,
- MaterialDynamicColors.secondaryContainer));
- assertTrue(
- pairSatisfiesContrast(
- scheme, MaterialDynamicColors.onTertiary,
- MaterialDynamicColors.tertiary));
- assertTrue(
- pairSatisfiesContrast(
- scheme,
- MaterialDynamicColors.onTertiaryContainer,
- MaterialDynamicColors.tertiaryContainer));
- assertTrue(
- pairSatisfiesContrast(
- scheme, MaterialDynamicColors.onError,
- MaterialDynamicColors.error));
- assertTrue(
- pairSatisfiesContrast(
- scheme,
- MaterialDynamicColors.onErrorContainer,
- MaterialDynamicColors.errorContainer));
- assertTrue(
- pairSatisfiesContrast(
- scheme, MaterialDynamicColors.onBackground,
- MaterialDynamicColors.background));
- assertTrue(
- pairSatisfiesContrast(
- scheme,
- MaterialDynamicColors.onSurfaceVariant,
- MaterialDynamicColors.surfaceVariant));
- assertTrue(
- pairSatisfiesContrast(
- scheme,
- MaterialDynamicColors.onSurfaceInverse,
- MaterialDynamicColors.surfaceInverse));
- }
- }
- }
+ final double[] contrastLevels = {-1.0, -0.5, 0.0, 0.5, 1.0};
+
+ for (Hct seedColor : seedColors) {
+ for (double contrastLevel : contrastLevels) {
+ for (boolean isDark : new boolean[] {false, true}) {
+ final DynamicScheme[] schemes =
+ new DynamicScheme[] {
+ new SchemeContent(seedColor, isDark, contrastLevel),
+ new SchemeMonochrome(seedColor, isDark, contrastLevel),
+ new SchemeTonalSpot(seedColor, isDark, contrastLevel),
+ new SchemeFidelity(seedColor, isDark, contrastLevel)
+ };
+ for (final DynamicScheme scheme : schemes) {
+ assertTrue(
+ pairSatisfiesContrast(scheme, dynamicColors.onPrimary(), dynamicColors.primary()));
+ assertTrue(
+ pairSatisfiesContrast(
+ scheme, dynamicColors.onPrimaryContainer(), dynamicColors.primaryContainer()));
+ assertTrue(
+ pairSatisfiesContrast(
+ scheme, dynamicColors.onSecondary(), dynamicColors.secondary()));
+ assertTrue(
+ pairSatisfiesContrast(
+ scheme,
+ dynamicColors.onSecondaryContainer(),
+ dynamicColors.secondaryContainer()));
+ assertTrue(
+ pairSatisfiesContrast(
+ scheme, dynamicColors.onTertiary(), dynamicColors.tertiary()));
+ assertTrue(
+ pairSatisfiesContrast(
+ scheme,
+ dynamicColors.onTertiaryContainer(),
+ dynamicColors.tertiaryContainer()));
+ assertTrue(
+ pairSatisfiesContrast(scheme, dynamicColors.onError(), dynamicColors.error()));
+ assertTrue(
+ pairSatisfiesContrast(
+ scheme, dynamicColors.onErrorContainer(), dynamicColors.errorContainer()));
+ assertTrue(
+ pairSatisfiesContrast(
+ scheme, dynamicColors.onBackground(), dynamicColors.background()));
+ assertTrue(
+ pairSatisfiesContrast(
+ scheme, dynamicColors.onSurfaceVariant(), dynamicColors.surfaceVariant()));
+ assertTrue(
+ pairSatisfiesContrast(
+ scheme, dynamicColors.inverseOnSurface(), dynamicColors.inverseSurface()));
+ }
}
+ }
}
+ }
- @Test
- public void valuesAreCorrect() {
- // Checks that the values of certain dynamic colors match Dart results.
- assertThat(
- MaterialDynamicColors.onPrimaryContainer.getArgb(
- new SchemeFidelity(Hct.fromInt(0xFFFF0000), false, 0.5)))
- .isSameColorAs(0xFFFFE5E1);
- assertThat(
- MaterialDynamicColors.onSecondaryContainer.getArgb(
- new SchemeContent(Hct.fromInt(0xFF0000FF), false, 0.5)))
- .isSameColorAs(0xFFFFFCFF);
- assertThat(
- MaterialDynamicColors.onTertiaryContainer.getArgb(
- new SchemeContent(Hct.fromInt(0xFFFFFF00), true, -0.5)))
- .isSameColorAs(0xFF616600);
- assertThat(
- MaterialDynamicColors.surfaceInverse.getArgb(
- new SchemeContent(Hct.fromInt(0xFF0000FF), false, 0.0)))
- .isSameColorAs(0xFF464652);
- assertThat(
- MaterialDynamicColors.primaryInverse.getArgb(
- new SchemeContent(Hct.fromInt(0xFFFF0000), false, -0.5)))
- .isSameColorAs(0xFFFF8C7A);
- assertThat(
- MaterialDynamicColors.outlineVariant.getArgb(
- new SchemeContent(Hct.fromInt(0xFFFFFF00), true, 0.0)))
- .isSameColorAs(0xFF484831);
- }
+ @Test
+ public void valuesAreCorrect() {
+ // Checks that the values of certain dynamic colors match Dart results.
+ assertThat(
+ dynamicColors
+ .onPrimaryContainer()
+ .getArgb(new SchemeFidelity(Hct.fromInt(0xFFFF0000), false, 0.5)))
+ .isSameColorAs(0xFFFFE5E1);
+ assertThat(
+ dynamicColors
+ .onSecondaryContainer()
+ .getArgb(new SchemeContent(Hct.fromInt(0xFF0000FF), false, 0.5)))
+ .isSameColorAs(0xFFFFFCFF);
+ assertThat(
+ dynamicColors
+ .onTertiaryContainer()
+ .getArgb(new SchemeContent(Hct.fromInt(0xFFFFFF00), true, -0.5)))
+ .isSameColorAs(0xFF616600);
+ assertThat(
+ dynamicColors
+ .inverseSurface()
+ .getArgb(new SchemeContent(Hct.fromInt(0xFF0000FF), false, 0.0)))
+ .isSameColorAs(0xFF2F2F3B);
+ assertThat(
+ dynamicColors
+ .inversePrimary()
+ .getArgb(new SchemeContent(Hct.fromInt(0xFFFF0000), false, -0.5)))
+ .isSameColorAs(0xFFFF907F);
+ assertThat(
+ dynamicColors
+ .outlineVariant()
+ .getArgb(new SchemeContent(Hct.fromInt(0xFFFFFF00), true, 0.0)))
+ .isSameColorAs(0xFF484831);
+ }
- private boolean pairSatisfiesContrast(DynamicScheme scheme, DynamicColor fg, DynamicColor bg) {
- double fgTone = fg.getHct(scheme).getTone();
- double bgTone = bg.getHct(scheme).getTone();
- double minimumRequirement = scheme.contrastLevel >= 0.0 ? 4.5 : 3.0;
- return Contrast.ratioOfTones(fgTone, bgTone) >= minimumRequirement;
- }
+ private boolean pairSatisfiesContrast(DynamicScheme scheme, DynamicColor fg, DynamicColor bg) {
+ double fgTone = fg.getHct(scheme).getTone();
+ double bgTone = bg.getHct(scheme).getTone();
+ double minimumRequirement = scheme.contrastLevel >= 0.0 ? 4.5 : 3.0;
+ return Contrast.ratioOfTones(fgTone, bgTone) >= minimumRequirement;
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeContentTest.java b/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeContentTest.java
index 1ddfc4d..704aed8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeContentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeContentTest.java
@@ -25,246 +25,229 @@
import com.android.systemui.monet.hct.Hct;
import com.android.systemui.monet.scheme.SchemeContent;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+@Ignore("b/279581953")
@SmallTest
@RunWith(JUnit4.class)
public final class SchemeContentTest extends SysuiTestCase {
+ private final MaterialDynamicColors dynamicColors = new MaterialDynamicColors();
+
@Test
public void testKeyColors() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.primaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff080CFF);
- assertThat(MaterialDynamicColors.secondaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.secondaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff656DD3);
- assertThat(MaterialDynamicColors.tertiaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.tertiaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff81009F);
- assertThat(MaterialDynamicColors.neutralPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.neutralPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff767684);
- assertThat(MaterialDynamicColors.neutralVariantPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.neutralVariantPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff757589);
}
@Test
public void lightTheme_minContrast_primary() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xFF1218FF);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xFF1218FF);
}
@Test
public void lightTheme_standardContrast_primary() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xFF0001C3);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xFF0001C3);
}
@Test
public void lightTheme_maxContrast_primary() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xFF000181);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xFF000181);
}
@Test
public void lightTheme_minContrast_primaryContainer() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xFF5660FF);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xFF5660FF);
}
@Test
public void lightTheme_standardContrast_primaryContainer() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xFF2D36FF);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xFF2D36FF);
}
@Test
public void lightTheme_maxContrast_primaryContainer() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xFF0000E3);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xFF0000E3);
}
@Test
public void lightTheme_minContrast_tertiaryContainer() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.tertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xFFB042CC);
+ assertThat(dynamicColors.tertiaryContainer().getArgb(scheme)).isSameColorAs(0xFFB042CC);
}
@Test
public void lightTheme_standardContrast_tertiaryContainer() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.tertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xFF9221AF);
+ assertThat(dynamicColors.tertiaryContainer().getArgb(scheme)).isSameColorAs(0xFF9221AF);
}
@Test
public void lightTheme_maxContrast_tertiaryContainer() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.tertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xFF73008E);
+ assertThat(dynamicColors.tertiaryContainer().getArgb(scheme)).isSameColorAs(0xFF73008E);
}
@Test
public void lightTheme_minContrast_objectionableTertiaryContainerLightens() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF850096), false, -1.0);
- assertThat(MaterialDynamicColors.tertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xFFD03A71);
+ assertThat(dynamicColors.tertiaryContainer().getArgb(scheme)).isSameColorAs(0xFFD03A71);
}
@Test
public void lightTheme_standardContrast_objectionableTertiaryContainerLightens() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF850096), false, 0.0);
- assertThat(MaterialDynamicColors.tertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xFFAC1B57);
+ assertThat(dynamicColors.tertiaryContainer().getArgb(scheme)).isSameColorAs(0xFFAC1B57);
}
@Test
public void lightTheme_maxContrast_objectionableTertiaryContainerDarkens() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF850096), false, 1.0);
- assertThat(MaterialDynamicColors.tertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xFF870040);
+ assertThat(dynamicColors.tertiaryContainer().getArgb(scheme)).isSameColorAs(0xFF870040);
}
@Test
public void lightTheme_minContrast_onPrimaryContainer() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xFFCBCDFF);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xFFCBCDFF);
}
@Test
public void lightTheme_standardContrast_onPrimaryContainer() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xFFCECFFF);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xFFCECFFF);
}
@Test
public void lightTheme_maxContrast_onPrimaryContainer() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xFFD6D6FF);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xFFD6D6FF);
}
@Test
public void lightTheme_minContrast_surface() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), false, -1);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xFFFBF8FF);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xFFFBF8FF);
}
@Test
public void lightTheme_standardContrast_surface() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xFFFBF8FF);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xFFFBF8FF);
}
@Test
public void lightTheme_maxContrast_surface() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xFFFBF8FF);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xFFFBF8FF);
}
@Test
public void darkTheme_minContrast_primary() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xFF5660FF);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xFF5660FF);
}
@Test
public void darkTheme_standardContrast_primary() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xFFBEC2FF);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xFFBEC2FF);
}
@Test
public void darkTheme_maxContrast_primary() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xFFF6F4FF);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xFFF6F4FF);
}
@Test
public void darkTheme_minContrast_primaryContainer() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xFF0000E6);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xFF0000E6);
}
@Test
public void darkTheme_standardContrast_primaryContainer() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xFF0000E6);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xFF0000E6);
}
@Test
public void darkTheme_maxContrast_primaryContainer() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xFFC4C6FF);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xFFC4C6FF);
}
@Test
public void darkTheme_minContrast_onPrimaryContainer() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xFF7A83FF);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xFF7A83FF);
}
@Test
public void darkTheme_standardContrast_onPrimaryContainer() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xFFA4AAFF);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xFFA4AAFF);
}
@Test
public void darkTheme_maxContrast_onPrimaryContainer() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xFF0001C6);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xFF0001C6);
}
@Test
public void darkTheme_minContrast_onTertiaryContainer() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xFFCF60EA);
+ assertThat(dynamicColors.onTertiaryContainer().getArgb(scheme)).isSameColorAs(0xFFCF60EA);
}
@Test
public void darkTheme_standardContrast_onTertiaryContainer() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xFFEB8CFF);
+ assertThat(dynamicColors.onTertiaryContainer().getArgb(scheme)).isSameColorAs(0xFFEB8CFF);
}
@Test
public void darkTheme_maxContrast_onTertiaryContainer() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xFF63007B);
+ assertThat(dynamicColors.onTertiaryContainer().getArgb(scheme)).isSameColorAs(0xFF63007B);
}
@Test
public void darkTheme_minContrast_surface() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xFF12121D);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xFF12121D);
}
@Test
public void darkTheme_standardContrast_surface() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xFF12121D);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xFF12121D);
}
@Test
public void darkTheme_maxContrast_surface() {
SchemeContent scheme = new SchemeContent(Hct.fromInt(0xFF0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xFF12121D);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xFF12121D);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeExpressiveTest.java b/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeExpressiveTest.java
index 31e8711..32a589d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeExpressiveTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeExpressiveTest.java
@@ -25,183 +25,175 @@
import com.android.systemui.monet.hct.Hct;
import com.android.systemui.monet.scheme.SchemeExpressive;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+@Ignore("b/279581953")
@SmallTest
@RunWith(JUnit4.class)
public final class SchemeExpressiveTest extends SysuiTestCase {
+ private final MaterialDynamicColors dynamicColors = new MaterialDynamicColors();
+
@Test
public void testKeyColors() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.primaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff35855F);
- assertThat(MaterialDynamicColors.secondaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.secondaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff8C6D8C);
- assertThat(MaterialDynamicColors.tertiaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.tertiaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff806EA1);
- assertThat(MaterialDynamicColors.neutralPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.neutralPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff79757F);
- assertThat(MaterialDynamicColors.neutralVariantPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.neutralVariantPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff7A7585);
}
@Test
public void lightTheme_minContrast_primary() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff32835D);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xffad603c);
}
@Test
public void lightTheme_standardContrast_primary() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff146C48);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff924b28);
}
@Test
public void lightTheme_maxContrast_primary() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff002818);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff401400);
}
@Test
public void lightTheme_minContrast_primaryContainer() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffA2F4C6);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xffffdbcc);
}
@Test
public void lightTheme_standardContrast_primaryContainer() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffA2F4C6);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xffffdbcc);
}
@Test
public void lightTheme_maxContrast_primaryContainer() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff004D31);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xff6f3010);
}
@Test
public void lightTheme_minContrast_onPrimaryContainer() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff1e724e);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xff99512e);
}
@Test
public void lightTheme_standardContrast_onPrimaryContainer() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff002112);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xff351000);
}
@Test
public void lightTheme_maxContrast_onPrimaryContainer() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff9aebbe);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xffffd0bc);
}
@Test
public void lightTheme_minContrast_surface() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xfffdf7ff);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xfffbf8ff);
}
@Test
public void lightTheme_standardContrast_surface() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xfffdf7ff);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xfffbf8ff);
}
@Test
public void lightTheme_maxContrast_surface() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xfffdf7ff);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xfffbf8ff);
}
@Test
public void darkTheme_minContrast_primary() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff32835d);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xffad603c);
}
@Test
public void darkTheme_standardContrast_primary() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff87d7ab);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xffffb595);
}
@Test
public void darkTheme_maxContrast_primary() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xffd5ffe4);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xfffff3ee);
}
@Test
public void darkTheme_minContrast_primaryContainer() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff005234);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xff743413);
}
@Test
public void darkTheme_standardContrast_primaryContainer() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff005234);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xff743413);
}
@Test
public void darkTheme_maxContrast_primaryContainer() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff8bdbaf);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xffffbb9e);
}
@Test
public void darkTheme_minContrast_onPrimaryContainer() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff76c59b);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xfff99f75);
}
@Test
public void darkTheme_standardContrast_onPrimaryContainer() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffa2f4c6);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xffffdbcc);
}
@Test
public void darkTheme_maxContrast_onPrimaryContainer() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff004229);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xff622706);
}
@Test
public void darkTheme_minContrast_surface() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xff14121a);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xff12131a);
}
@Test
public void darkTheme_standardContrast_surface() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xff14121a);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xff12131a);
}
@Test
public void darkTheme_maxContrast_surface() {
SchemeExpressive scheme = new SchemeExpressive(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xff14121a);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xff12131a);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeFidelityTest.java b/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeFidelityTest.java
index 511f83b..6844a92 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeFidelityTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeFidelityTest.java
@@ -25,245 +25,230 @@
import com.android.systemui.monet.hct.Hct;
import com.android.systemui.monet.scheme.SchemeFidelity;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+@Ignore("b/279581953")
@SmallTest
@RunWith(JUnit4.class)
public final class SchemeFidelityTest extends SysuiTestCase {
+
+ private final MaterialDynamicColors dynamicColors = new MaterialDynamicColors();
+
@Test
public void testKeyColors() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.primaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff080CFF);
- assertThat(MaterialDynamicColors.secondaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.secondaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff656DD3);
- assertThat(MaterialDynamicColors.tertiaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.tertiaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff9D0002);
- assertThat(MaterialDynamicColors.neutralPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.neutralPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff767684);
- assertThat(MaterialDynamicColors.neutralVariantPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.neutralVariantPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff757589);
}
@Test
public void lightTheme_minContrast_primary() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff1218ff);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff1218ff);
}
@Test
public void lightTheme_standardContrast_primary() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff0001c3);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff0001c3);
}
@Test
public void lightTheme_maxContrast_primary() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff000181);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff000181);
}
@Test
public void lightTheme_minContrast_primaryContainer() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff5660ff);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xff5660ff);
}
@Test
public void lightTheme_standardContrast_primaryContainer() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff2d36ff);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xff2d36ff);
}
@Test
public void lightTheme_maxContrast_primaryContainer() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff0000e3);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xff0000e3);
}
@Test
public void lightTheme_minContrast_tertiaryContainer() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.tertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffd93628);
+ assertThat(dynamicColors.tertiaryContainer().getArgb(scheme)).isSameColorAs(0xffd93628);
}
@Test
public void lightTheme_standardContrast_tertiaryContainer() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.tertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffb31910);
+ assertThat(dynamicColors.tertiaryContainer().getArgb(scheme)).isSameColorAs(0xffb31910);
}
@Test
public void lightTheme_maxContrast_tertiaryContainer() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.tertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff8c0002);
+ assertThat(dynamicColors.tertiaryContainer().getArgb(scheme)).isSameColorAs(0xff8c0002);
}
@Test
public void lightTheme_minContrast_objectionableTertiaryContainerLightens() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff850096), false, -1.0);
- assertThat(MaterialDynamicColors.tertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffbcac5a);
+ assertThat(dynamicColors.tertiaryContainer().getArgb(scheme)).isSameColorAs(0xffbcac5a);
}
@Test
public void lightTheme_standardContrast_objectionableTertiaryContainerLightens() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff850096), false, 0.0);
- assertThat(MaterialDynamicColors.tertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffbcac5a);
+ assertThat(dynamicColors.tertiaryContainer().getArgb(scheme)).isSameColorAs(0xffbcac5a);
}
@Test
public void lightTheme_maxContrast_objectionableTertiaryContainerDarkens() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff850096), false, 1.0);
- assertThat(MaterialDynamicColors.tertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff4d4300);
+ assertThat(dynamicColors.tertiaryContainer().getArgb(scheme)).isSameColorAs(0xff4d4300);
}
@Test
public void lightTheme_minContrast_onPrimaryContainer() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffcbcdff);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xffcbcdff);
}
@Test
public void lightTheme_standardContrast_onPrimaryContainer() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffcecfff);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xffcecfff);
}
@Test
public void lightTheme_maxContrast_onPrimaryContainer() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffd6d6ff);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xffd6d6ff);
}
@Test
public void lightTheme_minContrast_surface() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xfffbf8ff);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xfffbf8ff);
}
@Test
public void lightTheme_standardContrast_surface() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xfffbf8ff);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xfffbf8ff);
}
@Test
public void lightTheme_maxContrast_surface() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xfffbf8ff);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xfffbf8ff);
}
@Test
public void darkTheme_minContrast_primary() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff5660ff);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff5660ff);
}
@Test
public void darkTheme_standardContrast_primary() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xffbec2ff);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xffbec2ff);
}
@Test
public void darkTheme_maxContrast_primary() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xfff6f4ff);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xfff6f4ff);
}
@Test
public void darkTheme_minContrast_primaryContainer() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff0000e6);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xff0000e6);
}
@Test
public void darkTheme_standardContrast_primaryContainer() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff0000e6);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xff0000e6);
}
@Test
public void darkTheme_maxContrast_primaryContainer() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffc4c6ff);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xffc4c6ff);
}
@Test
public void darkTheme_minContrast_onPrimaryContainer() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff7a83ff);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xff7a83ff);
}
@Test
public void darkTheme_standardContrast_onPrimaryContainer() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffa4aaff);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xffa4aaff);
}
@Test
public void darkTheme_maxContrast_onPrimaryContainer() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff0001c6);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xff0001c6);
}
@Test
public void darkTheme_minContrast_onTertiaryContainer() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xfffe513e);
+ assertThat(dynamicColors.onTertiaryContainer().getArgb(scheme)).isSameColorAs(0xfffe513e);
}
@Test
public void darkTheme_standardContrast_onTertiaryContainer() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffFF9181);
+ assertThat(dynamicColors.onTertiaryContainer().getArgb(scheme)).isSameColorAs(0xffFF9181);
}
@Test
public void darkTheme_maxContrast_onTertiaryContainer() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff790001);
+ assertThat(dynamicColors.onTertiaryContainer().getArgb(scheme)).isSameColorAs(0xff790001);
}
@Test
public void darkTheme_minContrast_surface() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xff12121d);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xff12121d);
}
@Test
public void darkTheme_standardContrast_surface() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xff12121d);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xff12121d);
}
@Test
public void darkTheme_maxContrast_surface() {
SchemeFidelity scheme = new SchemeFidelity(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xff12121d);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xff12121d);
}
+
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeFruitSaladTest.java b/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeFruitSaladTest.java
index 4cf14d5..4bca2c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeFruitSaladTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeFruitSaladTest.java
@@ -25,226 +25,230 @@
import com.android.systemui.monet.hct.Hct;
import com.android.systemui.monet.scheme.SchemeFruitSalad;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+@Ignore("b/279581953")
@SmallTest
@RunWith(JUnit4.class)
public final class SchemeFruitSaladTest extends SysuiTestCase {
+ private final MaterialDynamicColors dynamicColors = new MaterialDynamicColors();
+
@Test
public void testKeyColors() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.primaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff0091C0);
- assertThat(MaterialDynamicColors.secondaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.secondaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff3A7E9E);
- assertThat(MaterialDynamicColors.tertiaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.tertiaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff6E72AC);
- assertThat(MaterialDynamicColors.neutralPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.neutralPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff777682);
- assertThat(MaterialDynamicColors.neutralVariantPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.neutralVariantPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff75758B);
}
@Test
public void lightTheme_minContrast_primary() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff007ea7);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff007ea7);
}
@Test
public void lightTheme_standardContrast_primary() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff006688);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff006688);
}
@Test
public void lightTheme_maxContrast_primary() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff002635);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff002635);
}
@Test
public void lightTheme_minContrast_primaryContainer() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(
0xffC2E8FF);
}
@Test
public void lightTheme_standardContrast_primaryContainer() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(
0xffC2E8FF);
}
@Test
public void lightTheme_maxContrast_primaryContainer() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(
0xff004862);
}
@Test
public void lightTheme_minContrast_tertiaryContainer() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.tertiaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.tertiaryContainer().getArgb(scheme)).isSameColorAs(
0xffE0E0FF);
}
@Test
public void lightTheme_standardContrast_tertiaryContainer() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.tertiaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.tertiaryContainer().getArgb(scheme)).isSameColorAs(
0xffE0E0FF);
}
@Test
public void lightTheme_maxContrast_tertiaryContainer() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.tertiaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.tertiaryContainer().getArgb(scheme)).isSameColorAs(
0xFF3A3E74);
}
@Test
public void lightTheme_minContrast_onPrimaryContainer() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(
0xff006C90);
}
@Test
public void lightTheme_standardContrast_onPrimaryContainer() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(
0xff001E2B);
}
@Test
public void lightTheme_maxContrast_onPrimaryContainer() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(
0xffACE1FF);
}
@Test
public void lightTheme_minContrast_surface() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xfffbf8ff);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xfffbf8ff);
}
@Test
public void lightTheme_standardContrast_surface() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xfffbf8ff);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xfffbf8ff);
}
@Test
public void lightTheme_maxContrast_surface() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xfffbf8ff);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xfffbf8ff);
}
@Test
public void darkTheme_minContrast_primary() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff007EA7);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff007EA7);
}
@Test
public void darkTheme_standardContrast_primary() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xFF76D1FF);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xFF76D1FF);
}
@Test
public void darkTheme_maxContrast_primary() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xFFECF7FF);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xFFECF7FF);
}
@Test
public void darkTheme_minContrast_primaryContainer() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(
0xFF004D67);
}
@Test
public void darkTheme_standardContrast_primaryContainer() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(
0xFF004D67);
}
@Test
public void darkTheme_maxContrast_primaryContainer() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(
0xFF83D5FF);
}
@Test
public void darkTheme_minContrast_onPrimaryContainer() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(
0xff55C0F2);
}
@Test
public void darkTheme_standardContrast_onPrimaryContainer() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(
0xffC2E8FF);
}
@Test
public void darkTheme_maxContrast_onPrimaryContainer() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(
0xff003E54);
}
@Test
public void darkTheme_minContrast_onTertiaryContainer() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.onTertiaryContainer().getArgb(scheme)).isSameColorAs(
0xffADB0EF);
}
@Test
public void darkTheme_standardContrast_onTertiaryContainer() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.onTertiaryContainer().getArgb(scheme)).isSameColorAs(
0xffe0e0ff);
}
@Test
public void darkTheme_maxContrast_onTertiaryContainer() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.onTertiaryContainer().getArgb(scheme)).isSameColorAs(
0xff30346A);
}
@Test
public void darkTheme_minContrast_surface() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xff12131c);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xff12131c);
}
@Test
public void darkTheme_standardContrast_surface() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xff12131c);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xff12131c);
}
@Test
public void darkTheme_maxContrast_surface() {
SchemeFruitSalad scheme = new SchemeFruitSalad(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xff12131c);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xff12131c);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeMonochromeTest.java b/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeMonochromeTest.java
index 3eca4dc..d511422 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeMonochromeTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeMonochromeTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.monet;
+import static com.google.common.truth.Truth.assertThat;
import static com.android.systemui.monet.utils.ArgbSubject.assertThat;
import androidx.test.filters.SmallTest;
@@ -25,204 +26,227 @@
import com.android.systemui.monet.hct.Hct;
import com.android.systemui.monet.scheme.SchemeMonochrome;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+@Ignore("b/279581953")
@SmallTest
@RunWith(JUnit4.class)
public final class SchemeMonochromeTest extends SysuiTestCase {
+ private final MaterialDynamicColors dynamicColors = new MaterialDynamicColors();
+
@Test
public void testKeyColors() {
SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.primaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff070707);
- assertThat(MaterialDynamicColors.secondaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.secondaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff070707);
- assertThat(MaterialDynamicColors.tertiaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.tertiaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff070707);
- assertThat(MaterialDynamicColors.neutralPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.neutralPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff070707);
- assertThat(MaterialDynamicColors.neutralVariantPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.neutralVariantPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff070707);
}
@Test
public void lightTheme_minContrast_primary() {
- SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff747474);
+ SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), false, -1);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff3c3c3c);
}
@Test
public void lightTheme_standardContrast_primary() {
SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff5e5e5e);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff000000);
}
@Test
public void lightTheme_maxContrast_primary() {
- SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff222222);
+ SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), false, 1);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff000000);
}
@Test
public void lightTheme_minContrast_primaryContainer() {
- SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffe2e2e2);
+ SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), false, -1);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xff5f5f5f);
}
@Test
public void lightTheme_standardContrast_primaryContainer() {
SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffe2e2e2);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xff3b3b3b);
}
@Test
public void lightTheme_maxContrast_primaryContainer() {
- SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff434343);
+ SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), false, 1);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xff3a3a3a);
}
@Test
public void lightTheme_minContrast_onPrimaryContainer() {
- SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff646464);
+ SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), false, -1);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xffd9d9d9);
}
@Test
public void lightTheme_standardContrast_onPrimaryContainer() {
SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff1b1b1b);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xffffffff);
}
@Test
public void lightTheme_maxContrast_onPrimaryContainer() {
- SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffdadada);
+ SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), false, 1);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xffcdcdcd);
}
@Test
public void lightTheme_minContrast_surface() {
- SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xfff9f9f9);
+ SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), false, -1);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xfff9f9f9);
}
@Test
public void lightTheme_standardContrast_surface() {
SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xfff9f9f9);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xfff9f9f9);
}
@Test
public void lightTheme_maxContrast_surface() {
- SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xfff9f9f9);
+ SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), false, 1);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xfff9f9f9);
}
@Test
public void darkTheme_minContrast_primary() {
- SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff747474);
+ SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, -1);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xffcccccc);
}
@Test
public void darkTheme_standardContrast_primary() {
SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xffc6c6c6);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xffffffff);
}
@Test
public void darkTheme_maxContrast_primary() {
- SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xfff5f5f5);
+ SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, 1);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xffffffff);
}
@Test
public void darkTheme_minContrast_primaryContainer() {
- SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff474747);
+ SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, -1);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xffa3a3a3);
}
@Test
public void darkTheme_standardContrast_primaryContainer() {
SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff474747);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xffd4d4d4);
}
@Test
public void darkTheme_maxContrast_primaryContainer() {
- SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffcbcbcb);
+ SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, 1);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xffd5d5d5);
}
@Test
public void darkTheme_minContrast_onPrimaryContainer() {
- SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffb5b5b5);
+ SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, -1);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xff393939);
}
@Test
public void darkTheme_standardContrast_onPrimaryContainer() {
SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffe2e2e2);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xff000000);
}
@Test
public void darkTheme_maxContrast_onPrimaryContainer() {
- SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff393939);
+ SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, 1);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xff404040);
}
@Test
public void darkTheme_minContrast_onTertiaryContainer() {
- SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffb5b5b5);
+ SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, -1);
+ assertThat(dynamicColors.onTertiaryContainer().getArgb(scheme)).isSameColorAs(0xffd1d1d1);
}
@Test
public void darkTheme_standardContrast_onTertiaryContainer() {
SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffe2e2e2);
+ assertThat(dynamicColors.onTertiaryContainer().getArgb(scheme)).isSameColorAs(0xff000000);
}
@Test
public void darkTheme_maxContrast_onTertiaryContainer() {
- SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff393939);
+ SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, 1);
+ assertThat(dynamicColors.onTertiaryContainer().getArgb(scheme)).isSameColorAs(0xff393939);
}
@Test
public void darkTheme_minContrast_surface() {
- SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xff131313);
+ SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, -1);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xff131313);
}
@Test
public void darkTheme_standardContrast_surface() {
SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xff131313);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xff131313);
}
@Test
public void darkTheme_maxContrast_surface() {
- SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xff131313);
+ SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, 1);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xff131313);
+ }
+
+ @Test
+ public void darkTheme_monochromeSpec() {
+ SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), true, 0.0);
+ assertThat(dynamicColors.primary().getHct(scheme).getTone()).isWithin(1).of(100);
+ assertThat(dynamicColors.onPrimary().getHct(scheme).getTone()).isWithin(1).of(10);
+ assertThat(dynamicColors.primaryContainer().getHct(scheme).getTone()).isWithin(1).of(85);
+ assertThat(dynamicColors.onPrimaryContainer().getHct(scheme).getTone()).isWithin(1).of(0);
+ assertThat(dynamicColors.secondary().getHct(scheme).getTone()).isWithin(1).of(80);
+ assertThat(dynamicColors.onSecondary().getHct(scheme).getTone()).isWithin(1).of(10);
+ assertThat(dynamicColors.secondaryContainer().getHct(scheme).getTone()).isWithin(1).of(30);
+ assertThat(dynamicColors.onSecondaryContainer().getHct(scheme).getTone()).isWithin(1).of(90);
+ assertThat(dynamicColors.tertiary().getHct(scheme).getTone()).isWithin(1).of(90);
+ assertThat(dynamicColors.onTertiary().getHct(scheme).getTone()).isWithin(1).of(10);
+ assertThat(dynamicColors.tertiaryContainer().getHct(scheme).getTone()).isWithin(1).of(60);
+ assertThat(dynamicColors.onTertiaryContainer().getHct(scheme).getTone()).isWithin(1).of(0);
+ }
+
+ @Test
+ public void lightTheme_monochromeSpec() {
+ SchemeMonochrome scheme = new SchemeMonochrome(Hct.fromInt(0xff0000ff), false, 0.0);
+ assertThat(dynamicColors.primary().getHct(scheme).getTone()).isWithin(1).of(0);
+ assertThat(dynamicColors.onPrimary().getHct(scheme).getTone()).isWithin(1).of(90);
+ assertThat(dynamicColors.primaryContainer().getHct(scheme).getTone()).isWithin(1).of(25);
+ assertThat(dynamicColors.onPrimaryContainer().getHct(scheme).getTone()).isWithin(1).of(100);
+ assertThat(dynamicColors.secondary().getHct(scheme).getTone()).isWithin(1).of(40);
+ assertThat(dynamicColors.onSecondary().getHct(scheme).getTone()).isWithin(1).of(100);
+ assertThat(dynamicColors.secondaryContainer().getHct(scheme).getTone()).isWithin(1).of(85);
+ assertThat(dynamicColors.onSecondaryContainer().getHct(scheme).getTone()).isWithin(1).of(10);
+ assertThat(dynamicColors.tertiary().getHct(scheme).getTone()).isWithin(1).of(25);
+ assertThat(dynamicColors.onTertiary().getHct(scheme).getTone()).isWithin(1).of(90);
+ assertThat(dynamicColors.tertiaryContainer().getHct(scheme).getTone()).isWithin(1).of(49);
+ assertThat(dynamicColors.onTertiaryContainer().getHct(scheme).getTone()).isWithin(1).of(100);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeNeutralTest.java b/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeNeutralTest.java
index 71e9f4d..4f3fc7d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeNeutralTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeNeutralTest.java
@@ -25,204 +25,193 @@
import com.android.systemui.monet.hct.Hct;
import com.android.systemui.monet.scheme.SchemeNeutral;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+@Ignore("b/279581953")
@SmallTest
@RunWith(JUnit4.class)
public final class SchemeNeutralTest extends SysuiTestCase {
+ private final MaterialDynamicColors dynamicColors = new MaterialDynamicColors();
+
@Test
public void testKeyColors() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.primaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff767685);
- assertThat(MaterialDynamicColors.secondaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.secondaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff777680);
- assertThat(MaterialDynamicColors.tertiaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.tertiaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff75758B);
- assertThat(MaterialDynamicColors.neutralPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.neutralPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff787678);
- assertThat(MaterialDynamicColors.neutralVariantPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.neutralVariantPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff787678);
}
@Test
public void lightTheme_minContrast_primary() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff737383);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff737383);
}
@Test
public void lightTheme_standardContrast_primary() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff5d5d6c);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff5d5d6c);
}
@Test
public void lightTheme_maxContrast_primary() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff21212e);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff21212e);
}
@Test
public void lightTheme_minContrast_primaryContainer() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffe2e1f3);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xffe2e1f3);
}
@Test
public void lightTheme_standardContrast_primaryContainer() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffe2e1f3);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xffe2e1f3);
}
@Test
public void lightTheme_maxContrast_primaryContainer() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff414250);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xff414250);
}
@Test
public void lightTheme_minContrast_onPrimaryContainer() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff636372);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xff636372);
}
@Test
public void lightTheme_standardContrast_onPrimaryContainer() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff1a1b27);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xff1a1b27);
}
@Test
public void lightTheme_maxContrast_onPrimaryContainer() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffd9d8ea);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xffd9d8ea);
}
@Test
public void lightTheme_minContrast_surface() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xfffcf8fa);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xfffcf8fa);
}
@Test
public void lightTheme_standardContrast_surface() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xfffcf8fa);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xfffcf8fa);
}
@Test
public void lightTheme_maxContrast_surface() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xfffcf8fa);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xfffcf8fa);
}
@Test
public void darkTheme_minContrast_primary() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff737383);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff737383);
}
@Test
public void darkTheme_standardContrast_primary() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xffc6c5d6);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xffc6c5d6);
}
@Test
public void darkTheme_maxContrast_primary() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xfff6f4ff);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xfff6f4ff);
}
@Test
public void darkTheme_minContrast_primaryContainer() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff454654);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xff454654);
}
@Test
public void darkTheme_standardContrast_primaryContainer() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff454654);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xff454654);
}
@Test
public void darkTheme_maxContrast_primaryContainer() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffcac9da);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xffcac9da);
}
@Test
public void darkTheme_minContrast_onPrimaryContainer() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffb5b3c4);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xffb5b3c4);
}
@Test
public void darkTheme_standardContrast_onPrimaryContainer() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffe2e1f3);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xffe2e1f3);
}
@Test
public void darkTheme_maxContrast_onPrimaryContainer() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff373846);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xff373846);
}
@Test
public void darkTheme_minContrast_onTertiaryContainer() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffb3b3cb);
+ assertThat(dynamicColors.onTertiaryContainer().getArgb(scheme)).isSameColorAs(0xffb3b3cb);
}
@Test
public void darkTheme_standardContrast_onTertiaryContainer() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffe1e0f9);
+ assertThat(dynamicColors.onTertiaryContainer().getArgb(scheme)).isSameColorAs(0xffe1e0f9);
}
@Test
public void darkTheme_maxContrast_onTertiaryContainer() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff37374b);
+ assertThat(dynamicColors.onTertiaryContainer().getArgb(scheme)).isSameColorAs(0xff37374b);
}
@Test
public void darkTheme_minContrast_surface() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xff131315);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xff131315);
}
@Test
public void darkTheme_standardContrast_surface() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xff131315);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xff131315);
}
@Test
public void darkTheme_maxContrast_surface() {
SchemeNeutral scheme = new SchemeNeutral(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xff131315);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xff131315);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeRainbowTest.java b/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeRainbowTest.java
index cc6f044..ece3f9a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeRainbowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeRainbowTest.java
@@ -25,225 +25,229 @@
import com.android.systemui.monet.hct.Hct;
import com.android.systemui.monet.scheme.SchemeRainbow;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+@Ignore("b/279581953")
@SmallTest
@RunWith(JUnit4.class)
public final class SchemeRainbowTest extends SysuiTestCase {
+ private final MaterialDynamicColors dynamicColors = new MaterialDynamicColors();
+
@Test
public void testKeyColors() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.primaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff696FC4);
- assertThat(MaterialDynamicColors.secondaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.secondaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff75758B);
- assertThat(MaterialDynamicColors.tertiaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.tertiaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff936B84);
- assertThat(MaterialDynamicColors.neutralPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.neutralPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff070707);
- assertThat(MaterialDynamicColors.neutralVariantPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.neutralVariantPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff070707);
}
@Test
public void lightTheme_minContrast_primary() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff676DC1);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff676DC1);
}
@Test
public void lightTheme_standardContrast_primary() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff5056A9);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff5056A9);
}
@Test
public void lightTheme_maxContrast_primary() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff0F136A);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff0F136A);
}
@Test
public void lightTheme_minContrast_primaryContainer() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(
0xffE0E0FF);
}
@Test
public void lightTheme_standardContrast_primaryContainer() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(
0xffE0E0FF);
}
@Test
public void lightTheme_maxContrast_primaryContainer() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(
0xff34398B);
}
@Test
public void lightTheme_minContrast_tertiaryContainer() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.tertiaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.tertiaryContainer().getArgb(scheme)).isSameColorAs(
0xffffd8ee);
}
@Test
public void lightTheme_standardContrast_tertiaryContainer() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.tertiaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.tertiaryContainer().getArgb(scheme)).isSameColorAs(
0xffffd8ee);
}
@Test
public void lightTheme_maxContrast_tertiaryContainer() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.tertiaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.tertiaryContainer().getArgb(scheme)).isSameColorAs(
0xff5A384E);
}
@Test
public void lightTheme_minContrast_onPrimaryContainer() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(
0xff565CB0);
}
@Test
public void lightTheme_standardContrast_onPrimaryContainer() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(
0xff050865);
}
@Test
public void lightTheme_maxContrast_onPrimaryContainer() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(
0xffd6d6ff);
}
@Test
public void lightTheme_minContrast_surface() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xfff9f9f9);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xfff9f9f9);
}
@Test
public void lightTheme_standardContrast_surface() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xfff9f9f9);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xfff9f9f9);
}
@Test
public void lightTheme_maxContrast_surface() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xfff9f9f9);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xfff9f9f9);
}
@Test
public void darkTheme_minContrast_primary() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff676DC1);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff676DC1);
}
@Test
public void darkTheme_standardContrast_primary() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xffbec2ff);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xffbec2ff);
}
@Test
public void darkTheme_maxContrast_primary() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xfff6f4ff);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xfff6f4ff);
}
@Test
public void darkTheme_minContrast_primaryContainer() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(
0xff383E8F);
}
@Test
public void darkTheme_standardContrast_primaryContainer() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(
0xff383E8F);
}
@Test
public void darkTheme_maxContrast_primaryContainer() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(
0xffc4c6ff);
}
@Test
public void darkTheme_minContrast_onPrimaryContainer() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(
0xffa9afff);
}
@Test
public void darkTheme_standardContrast_onPrimaryContainer() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(
0xffe0e0ff);
}
@Test
public void darkTheme_maxContrast_onPrimaryContainer() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(
0xff292f81);
}
@Test
public void darkTheme_minContrast_onTertiaryContainer() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.onTertiaryContainer().getArgb(scheme)).isSameColorAs(
0xffd5a8c3);
}
@Test
public void darkTheme_standardContrast_onTertiaryContainer() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.onTertiaryContainer().getArgb(scheme)).isSameColorAs(
0xffffd8ee);
}
@Test
public void darkTheme_maxContrast_onTertiaryContainer() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)).isSameColorAs(
+ assertThat(dynamicColors.onTertiaryContainer().getArgb(scheme)).isSameColorAs(
0xff4f2e44);
}
@Test
public void darkTheme_minContrast_surface() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xff131313);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xff131313);
}
@Test
public void darkTheme_standardContrast_surface() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xff131313);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xff131313);
}
@Test
public void darkTheme_maxContrast_surface() {
SchemeRainbow scheme = new SchemeRainbow(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xff131313);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xff131313);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeTonalSpotTest.java b/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeTonalSpotTest.java
index e4880d9..01d199b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeTonalSpotTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeTonalSpotTest.java
@@ -25,348 +25,338 @@
import com.android.systemui.monet.hct.Hct;
import com.android.systemui.monet.scheme.SchemeTonalSpot;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+@Ignore("b/279581953")
@SmallTest
@RunWith(JUnit4.class)
public final class SchemeTonalSpotTest extends SysuiTestCase {
+ private final MaterialDynamicColors dynamicColors = new MaterialDynamicColors();
+
@Test
public void testKeyColors() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.primaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff6E72AC);
- assertThat(MaterialDynamicColors.secondaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.secondaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff75758B);
- assertThat(MaterialDynamicColors.tertiaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.tertiaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff936B84);
- assertThat(MaterialDynamicColors.neutralPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.neutralPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff78767A);
- assertThat(MaterialDynamicColors.neutralVariantPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.neutralVariantPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff777680);
}
+
@Test
public void lightTheme_minContrast_primary() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff6c70aa);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff6a6fb1);
}
@Test
public void lightTheme_standardContrast_primary() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff555992);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff545999);
}
@Test
public void lightTheme_maxContrast_primary() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff181c51);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff161a59);
}
@Test
public void lightTheme_minContrast_primaryContainer() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffe0e0ff);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xffe0e0ff);
}
@Test
public void lightTheme_standardContrast_primaryContainer() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffe0e0ff);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xffe0e0ff);
}
@Test
public void lightTheme_maxContrast_primaryContainer() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff3a3e74);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xff383c7c);
}
@Test
public void lightTheme_minContrast_onPrimaryContainer() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff5C5F98);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xff5a5fa0);
}
@Test
public void lightTheme_standardContrast_onPrimaryContainer() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff11144B);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xff0e1253);
}
@Test
public void lightTheme_maxContrast_onPrimaryContainer() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffd6d6ff);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xffd6d6ff);
}
@Test
public void lightTheme_minContrast_surface() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xffFCF8FD);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xfffbf8ff);
}
@Test
public void lightTheme_standardContrast_surface() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xffFCF8FD);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xfffbf8ff);
}
@Test
public void lightTheme_maxContrast_surface() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xffFCF8FD);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xfffbf8ff);
}
@Test
public void lightTheme_minContrast_onSurface() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.onSurface.getArgb(scheme)).isSameColorAs(0xff605E62);
+ assertThat(dynamicColors.onSurface().getArgb(scheme)).isSameColorAs(0xff5f5e65);
}
@Test
public void lightTheme_standardContrast_onSurface() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.onSurface.getArgb(scheme)).isSameColorAs(0xff1B1B1F);
+ assertThat(dynamicColors.onSurface().getArgb(scheme)).isSameColorAs(0xff1b1b21);
}
@Test
public void lightTheme_maxContrast_onSurface() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.onSurface.getArgb(scheme)).isSameColorAs(0xff1B1A1E);
+ assertThat(dynamicColors.onSurface().getArgb(scheme)).isSameColorAs(0xff1a1a20);
}
@Test
public void lightTheme_minContrast_onSecondary() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.onSecondary.getArgb(scheme)).isSameColorAs(0xffcfcfe7);
+ assertThat(dynamicColors.onSecondary().getArgb(scheme)).isSameColorAs(0xffcfcfe7);
}
@Test
public void lightTheme_standardContrast_onSecondary() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.onSecondary.getArgb(scheme)).isSameColorAs(0xffffffff);
+ assertThat(dynamicColors.onSecondary().getArgb(scheme)).isSameColorAs(0xffffffff);
}
@Test
public void lightTheme_maxContrast_onSecondary() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.onSecondary.getArgb(scheme)).isSameColorAs(0xffababc3);
+ assertThat(dynamicColors.onSecondary().getArgb(scheme)).isSameColorAs(0xffababc3);
}
@Test
public void lightTheme_minContrast_onTertiary() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.onTertiary.getArgb(scheme)).isSameColorAs(0xfff3c3df);
+ assertThat(dynamicColors.onTertiary().getArgb(scheme)).isSameColorAs(0xfff3c3df);
}
@Test
public void lightTheme_standardContrast_onTertiary() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.onTertiary.getArgb(scheme)).isSameColorAs(0xffffffff);
+ assertThat(dynamicColors.onTertiary().getArgb(scheme)).isSameColorAs(0xffffffff);
}
@Test
public void lightTheme_maxContrast_onTertiary() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.onTertiary.getArgb(scheme)).isSameColorAs(0xffcda0bb);
+ assertThat(dynamicColors.onTertiary().getArgb(scheme)).isSameColorAs(0xffcda0bb);
}
@Test
public void lightTheme_minContrast_onError() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.onError.getArgb(scheme)).isSameColorAs(0xffffc2bb);
+ assertThat(dynamicColors.onError().getArgb(scheme)).isSameColorAs(0xffffc2bb);
}
@Test
public void lightTheme_standardContrast_onError() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.onError.getArgb(scheme)).isSameColorAs(0xffffffff);
+ assertThat(dynamicColors.onError().getArgb(scheme)).isSameColorAs(0xffffffff);
}
@Test
public void lightTheme_maxContrast_onError() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.onError.getArgb(scheme)).isSameColorAs(0xffff8d80);
+ assertThat(dynamicColors.onError().getArgb(scheme)).isSameColorAs(0xffff8d80);
}
@Test
public void darkTheme_minContrast_primary() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff6C70AA);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff6a6fb1);
}
@Test
public void darkTheme_standardContrast_primary() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xffbec2ff);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xffbec2ff);
}
@Test
public void darkTheme_maxContrast_primary() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xfff6f4ff);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xfff6f4ff);
}
@Test
public void darkTheme_minContrast_primaryContainer() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff3E4278);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xff3c4180);
}
@Test
public void darkTheme_standardContrast_primaryContainer() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff3E4278);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xff3c4180);
}
@Test
public void darkTheme_maxContrast_primaryContainer() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffc4c6ff);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xffc4c6ff);
}
@Test
public void darkTheme_minContrast_onPrimaryContainer() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffadb0ef);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xffabaff7);
}
@Test
public void darkTheme_standardContrast_onPrimaryContainer() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffe0e0ff);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xffe0e0ff);
}
@Test
public void darkTheme_maxContrast_onPrimaryContainer() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff30346A);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xff2e3271);
}
@Test
public void darkTheme_minContrast_onTertiaryContainer() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffd5a8c3);
+ assertThat(dynamicColors.onTertiaryContainer().getArgb(scheme)).isSameColorAs(0xffd5a8c3);
}
@Test
public void darkTheme_standardContrast_onTertiaryContainer() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffffd8ee);
+ assertThat(dynamicColors.onTertiaryContainer().getArgb(scheme)).isSameColorAs(0xffffd8ee);
}
@Test
public void darkTheme_maxContrast_onTertiaryContainer() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff4f2e44);
+ assertThat(dynamicColors.onTertiaryContainer().getArgb(scheme)).isSameColorAs(0xff4f2e44);
}
@Test
public void darkTheme_minContrast_onSecondary() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.onSecondary.getArgb(scheme)).isSameColorAs(0xfffffbff);
+ assertThat(dynamicColors.onSecondary().getArgb(scheme)).isSameColorAs(0xfffffbff);
}
@Test
public void darkTheme_standardContrast_onSecondary() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.onSecondary.getArgb(scheme)).isSameColorAs(0xff2e2f42);
+ assertThat(dynamicColors.onSecondary().getArgb(scheme)).isSameColorAs(0xff2e2f42);
}
@Test
public void darkTheme_maxContrast_onSecondary() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.onSecondary.getArgb(scheme)).isSameColorAs(0xff505165);
+ assertThat(dynamicColors.onSecondary().getArgb(scheme)).isSameColorAs(0xff505165);
}
@Test
public void darkTheme_minContrast_onTertiary() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.onTertiary.getArgb(scheme)).isSameColorAs(0xfffffbff);
+ assertThat(dynamicColors.onTertiary().getArgb(scheme)).isSameColorAs(0xfffffbff);
}
@Test
public void darkTheme_standardContrast_onTertiary() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.onTertiary.getArgb(scheme)).isSameColorAs(0xff46263b);
+ assertThat(dynamicColors.onTertiary().getArgb(scheme)).isSameColorAs(0xff46263b);
}
@Test
public void darkTheme_maxContrast_onTertiary() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.onTertiary.getArgb(scheme)).isSameColorAs(0xff6b485f);
+ assertThat(dynamicColors.onTertiary().getArgb(scheme)).isSameColorAs(0xff6b485f);
}
@Test
public void darkTheme_minContrast_onError() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.onError.getArgb(scheme)).isSameColorAs(0xfffffbff);
+ assertThat(dynamicColors.onError().getArgb(scheme)).isSameColorAs(0xfffffbff);
}
@Test
public void darkTheme_standardContrast_onError() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.onError.getArgb(scheme)).isSameColorAs(0xff690005);
+ assertThat(dynamicColors.onError().getArgb(scheme)).isSameColorAs(0xff690005);
}
@Test
public void darkTheme_maxContrast_onError() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.onError.getArgb(scheme)).isSameColorAs(0xffa80710);
+ assertThat(dynamicColors.onError().getArgb(scheme)).isSameColorAs(0xffa80710);
}
@Test
public void darkTheme_minContrast_surface() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xff131316);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xff131318);
}
@Test
public void darkTheme_standardContrast_surface() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xff131316);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xff131318);
}
@Test
public void darkTheme_maxContrast_surface() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xff131316);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xff131318);
}
@Test
public void darkTheme_minContrast_onSurface() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.onSurface.getArgb(scheme)).isSameColorAs(0xffa4a2a6);
+ assertThat(dynamicColors.onSurface().getArgb(scheme)).isSameColorAs(0xffa4a2a9);
}
@Test
public void darkTheme_standardContrast_onSurface() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.onSurface.getArgb(scheme)).isSameColorAs(0xffe5e1e6);
+ assertThat(dynamicColors.onSurface().getArgb(scheme)).isSameColorAs(0xffe4e1e9);
}
@Test
public void darkTheme_maxContrast_onSurface() {
SchemeTonalSpot scheme = new SchemeTonalSpot(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.onSurface.getArgb(scheme)).isSameColorAs(0xffe6e2e7);
+ assertThat(dynamicColors.onSurface().getArgb(scheme)).isSameColorAs(0xffe5e2ea);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeVibrantTest.java b/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeVibrantTest.java
index e5963a2..0fb53eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeVibrantTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/monet/SchemeVibrantTest.java
@@ -25,204 +25,193 @@
import com.android.systemui.monet.hct.Hct;
import com.android.systemui.monet.scheme.SchemeVibrant;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+@Ignore("b/279581953")
@SmallTest
@RunWith(JUnit4.class)
public final class SchemeVibrantTest extends SysuiTestCase {
+ private final MaterialDynamicColors dynamicColors = new MaterialDynamicColors();
+
@Test
public void testKeyColors() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.primaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff080CFF);
- assertThat(MaterialDynamicColors.secondaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.secondaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff7B7296);
- assertThat(MaterialDynamicColors.tertiaryPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.tertiaryPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff886C9D);
- assertThat(MaterialDynamicColors.neutralPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.neutralPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff777682);
- assertThat(MaterialDynamicColors.neutralVariantPaletteKeyColor.getArgb(scheme))
+ assertThat(dynamicColors.neutralVariantPaletteKeyColor().getArgb(scheme))
.isSameColorAs(0xff767685);
}
@Test
public void lightTheme_minContrast_primary() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff5660ff);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff5660ff);
}
@Test
public void lightTheme_standardContrast_primary() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff343dff);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff343dff);
}
@Test
public void lightTheme_maxContrast_primary() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff000181);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff000181);
}
@Test
public void lightTheme_minContrast_primaryContainer() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffe0e0ff);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xffe0e0ff);
}
@Test
public void lightTheme_standardContrast_primaryContainer() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffe0e0ff);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xffe0e0ff);
}
@Test
public void lightTheme_maxContrast_primaryContainer() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff0000e3);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xff0000e3);
}
@Test
public void lightTheme_minContrast_onPrimaryContainer() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff3e47ff);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xff3e47ff);
}
@Test
public void lightTheme_standardContrast_onPrimaryContainer() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff00006e);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xff00006e);
}
@Test
public void lightTheme_maxContrast_onPrimaryContainer() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffd6d6ff);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xffd6d6ff);
}
@Test
public void lightTheme_minContrast_surface() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), false, -1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xfffbf8ff);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xfffbf8ff);
}
@Test
public void lightTheme_standardContrast_surface() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), false, 0.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xfffbf8ff);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xfffbf8ff);
}
@Test
public void lightTheme_maxContrast_surface() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), false, 1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xfffbf8ff);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xfffbf8ff);
}
@Test
public void darkTheme_minContrast_primary() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xff5660ff);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xff5660ff);
}
@Test
public void darkTheme_standardContrast_primary() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xffbec2ff);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xffbec2ff);
}
@Test
public void darkTheme_maxContrast_primary() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.primary.getArgb(scheme)).isSameColorAs(0xfff6f4ff);
+ assertThat(dynamicColors.primary().getArgb(scheme)).isSameColorAs(0xfff6f4ff);
}
@Test
public void darkTheme_minContrast_primaryContainer() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff0000ef);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xff0000ef);
}
@Test
public void darkTheme_standardContrast_primaryContainer() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff0000ef);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xff0000ef);
}
@Test
public void darkTheme_maxContrast_primaryContainer() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.primaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffc4c6ff);
+ assertThat(dynamicColors.primaryContainer().getArgb(scheme)).isSameColorAs(0xffc4c6ff);
}
@Test
public void darkTheme_minContrast_onPrimaryContainer() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffa9afff);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xffa9afff);
}
@Test
public void darkTheme_standardContrast_onPrimaryContainer() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffe0e0ff);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xffe0e0ff);
}
@Test
public void darkTheme_maxContrast_onPrimaryContainer() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff0001c6);
+ assertThat(dynamicColors.onPrimaryContainer().getArgb(scheme)).isSameColorAs(0xff0001c6);
}
@Test
public void darkTheme_minContrast_onTertiaryContainer() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xffc9a9df);
+ assertThat(dynamicColors.onTertiaryContainer().getArgb(scheme)).isSameColorAs(0xffc9a9df);
}
@Test
public void darkTheme_standardContrast_onTertiaryContainer() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xfff2daff);
+ assertThat(dynamicColors.onTertiaryContainer().getArgb(scheme)).isSameColorAs(0xfff2daff);
}
@Test
public void darkTheme_maxContrast_onTertiaryContainer() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)).isSameColorAs(
- 0xff472e5b);
+ assertThat(dynamicColors.onTertiaryContainer().getArgb(scheme)).isSameColorAs(0xff472e5b);
}
@Test
public void darkTheme_minContrast_surface() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), true, -1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xff12131C);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xff12131a);
}
@Test
public void darkTheme_standardContrast_surface() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), true, 0.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xff12131C);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xff12131a);
}
@Test
public void darkTheme_maxContrast_surface() {
SchemeVibrant scheme = new SchemeVibrant(Hct.fromInt(0xff0000ff), true, 1.0);
- assertThat(MaterialDynamicColors.surface.getArgb(scheme)).isSameColorAs(0xff12131C);
+ assertThat(dynamicColors.surface().getArgb(scheme)).isSameColorAs(0xff12131a);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/LaunchNotesRoleSettingsTrampolineActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/LaunchNotesRoleSettingsTrampolineActivityTest.kt
new file mode 100644
index 0000000..36b913f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/LaunchNotesRoleSettingsTrampolineActivityTest.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2023 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.notetask
+
+import android.content.Context
+import android.content.Intent
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import androidx.test.rule.ActivityTestRule
+import androidx.test.runner.intercepting.SingleActivityFactory
+import com.android.dx.mockito.inline.extended.ExtendedMockito.verify
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.notetask.LaunchNotesRoleSettingsTrampolineActivity.Companion.ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE
+import com.android.systemui.notetask.NoteTaskEntryPoint.QUICK_AFFORDANCE
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+@TestableLooper.RunWithLooper
+class LaunchNotesRoleSettingsTrampolineActivityTest : SysuiTestCase() {
+
+ @Mock lateinit var noteTaskController: NoteTaskController
+
+ @Rule
+ @JvmField
+ val activityRule =
+ ActivityTestRule<LaunchNotesRoleSettingsTrampolineActivity>(
+ /* activityFactory= */ object :
+ SingleActivityFactory<LaunchNotesRoleSettingsTrampolineActivity>(
+ LaunchNotesRoleSettingsTrampolineActivity::class.java
+ ) {
+ override fun create(intent: Intent?) =
+ LaunchNotesRoleSettingsTrampolineActivity(noteTaskController)
+ },
+ /* initialTouchMode= */ false,
+ /* launchActivity= */ false,
+ )
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ }
+
+ @After
+ fun tearDown() {
+ activityRule.finishActivity()
+ }
+
+ @Test
+ fun startActivity_noAction_shouldLaunchNotesRoleSettingTaskWithNullEntryPoint() {
+ activityRule.launchActivity(/* startIntent= */ null)
+
+ verify(noteTaskController).startNotesRoleSetting(any(Context::class.java), eq(null))
+ }
+
+ @Test
+ fun startActivity_quickAffordanceAction_shouldLaunchNotesRoleSettingTaskWithQuickAffordanceEntryPoint() { // ktlint-disable max-line-length
+ activityRule.launchActivity(Intent(ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE))
+
+ verify(noteTaskController)
+ .startNotesRoleSetting(any(Context::class.java), eq(QUICK_AFFORDANCE))
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
index 5dbcd33..5f89705 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
@@ -47,6 +47,9 @@
import com.android.systemui.notetask.NoteTaskController.Companion.EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE
import com.android.systemui.notetask.NoteTaskController.Companion.SETTINGS_CREATE_NOTE_TASK_SHORTCUT_COMPONENT
import com.android.systemui.notetask.NoteTaskController.Companion.SHORTCUT_ID
+import com.android.systemui.notetask.NoteTaskEntryPoint.APP_CLIPS
+import com.android.systemui.notetask.NoteTaskEntryPoint.QUICK_AFFORDANCE
+import com.android.systemui.notetask.NoteTaskEntryPoint.TAIL_BUTTON
import com.android.systemui.notetask.shortcut.LaunchNoteTaskActivity
import com.android.systemui.notetask.shortcut.LaunchNoteTaskManagedProfileProxyActivity
import com.android.systemui.settings.FakeUserTracker
@@ -493,7 +496,7 @@
)
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL)
- createNoteTaskController().showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
+ createNoteTaskController().showNoteTask(entryPoint = QUICK_AFFORDANCE)
verifyZeroInteractions(context, bubbles, eventLogger)
}
@@ -509,7 +512,7 @@
)
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL)
- createNoteTaskController().showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
+ createNoteTaskController().showNoteTask(entryPoint = QUICK_AFFORDANCE)
verifyZeroInteractions(context, bubbles, eventLogger)
}
@@ -525,7 +528,7 @@
)
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL)
- createNoteTaskController().showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
+ createNoteTaskController().showNoteTask(entryPoint = QUICK_AFFORDANCE)
verifyNoteTaskOpenInBubbleInUser(userTracker.userHandle)
}
@@ -541,7 +544,7 @@
)
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL)
- createNoteTaskController().showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
+ createNoteTaskController().showNoteTask(entryPoint = QUICK_AFFORDANCE)
verifyNoteTaskOpenInBubbleInUser(userTracker.userHandle)
}
@@ -553,7 +556,7 @@
whenever(devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile).thenReturn(true)
userTracker.set(listOf(mainUserInfo), mainAndWorkProfileUsers.indexOf(mainUserInfo))
- createNoteTaskController().showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
+ createNoteTaskController().showNoteTask(entryPoint = QUICK_AFFORDANCE)
verifyNoteTaskOpenInBubbleInUser(mainUserInfo.userHandle)
}
@@ -563,7 +566,7 @@
whenever(devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile).thenReturn(true)
userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
- createNoteTaskController().showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
+ createNoteTaskController().showNoteTask(entryPoint = QUICK_AFFORDANCE)
verifyNoteTaskOpenInBubbleInUser(workUserInfo.userHandle)
}
@@ -734,6 +737,129 @@
}
// endregion
+ // region getUserForHandlingNotesTaking
+ @Test
+ fun getUserForHandlingNotesTaking_cope_quickAffordance_shouldReturnWorkProfileUser() {
+ whenever(devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile).thenReturn(true)
+ userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
+
+ val user = createNoteTaskController().getUserForHandlingNotesTaking(QUICK_AFFORDANCE)
+
+ assertThat(user).isEqualTo(UserHandle.of(workUserInfo.id))
+ }
+
+ @Test
+ fun getUserForHandlingNotesTaking_cope_tailButton_shouldReturnWorkProfileUser() {
+ whenever(devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile).thenReturn(true)
+ userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
+
+ val user = createNoteTaskController().getUserForHandlingNotesTaking(TAIL_BUTTON)
+
+ assertThat(user).isEqualTo(UserHandle.of(workUserInfo.id))
+ }
+
+ @Test
+ fun getUserForHandlingNotesTaking_cope_appClip_shouldReturnCurrentUser() {
+ whenever(devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile).thenReturn(true)
+ userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
+
+ val user = createNoteTaskController().getUserForHandlingNotesTaking(APP_CLIPS)
+
+ assertThat(user).isEqualTo(UserHandle.of(mainUserInfo.id))
+ }
+
+ @Test
+ fun getUserForHandlingNotesTaking_noManagement_quickAffordance_shouldReturnCurrentUser() {
+ userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
+
+ val user = createNoteTaskController().getUserForHandlingNotesTaking(QUICK_AFFORDANCE)
+
+ assertThat(user).isEqualTo(UserHandle.of(mainUserInfo.id))
+ }
+
+ @Test
+ fun getUserForHandlingNotesTaking_noManagement_tailButton_shouldReturnCurrentUser() {
+ userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
+
+ val user = createNoteTaskController().getUserForHandlingNotesTaking(TAIL_BUTTON)
+
+ assertThat(user).isEqualTo(UserHandle.of(mainUserInfo.id))
+ }
+
+ @Test
+ fun getUserForHandlingNotesTaking_noManagement_appClip_shouldReturnCurrentUser() {
+ userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
+
+ val user = createNoteTaskController().getUserForHandlingNotesTaking(APP_CLIPS)
+
+ assertThat(user).isEqualTo(UserHandle.of(mainUserInfo.id))
+ }
+ // endregion
+
+ // startregion startNotesRoleSetting
+ @Test
+ fun startNotesRoleSetting_cope_quickAffordance_shouldStartNoteRoleIntentWithWorkProfileUser() {
+ whenever(devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile).thenReturn(true)
+ userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
+
+ createNoteTaskController().startNotesRoleSetting(context, QUICK_AFFORDANCE)
+
+ val intentCaptor = argumentCaptor<Intent>()
+ val userCaptor = argumentCaptor<UserHandle>()
+ verify(context).startActivityAsUser(capture(intentCaptor), capture(userCaptor))
+ intentCaptor.value.let { intent ->
+ assertThat(intent).hasAction(Intent.ACTION_MANAGE_DEFAULT_APP)
+ }
+ assertThat(userCaptor.value).isEqualTo(UserHandle.of(workUserInfo.id))
+ }
+
+ @Test
+ fun startNotesRoleSetting_cope_nullEntryPoint_shouldStartNoteRoleIntentWithCurrentUser() {
+ whenever(devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile).thenReturn(true)
+ userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
+
+ createNoteTaskController().startNotesRoleSetting(context, entryPoint = null)
+
+ val intentCaptor = argumentCaptor<Intent>()
+ val userCaptor = argumentCaptor<UserHandle>()
+ verify(context).startActivityAsUser(capture(intentCaptor), capture(userCaptor))
+ intentCaptor.value.let { intent ->
+ assertThat(intent).hasAction(Intent.ACTION_MANAGE_DEFAULT_APP)
+ }
+ assertThat(userCaptor.value).isEqualTo(UserHandle.of(mainUserInfo.id))
+ }
+
+ @Test
+ fun startNotesRoleSetting_noManagement_quickAffordance_shouldStartNoteRoleIntentWithCurrentUser() { // ktlint-disable max-line-length
+ userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
+
+ createNoteTaskController().startNotesRoleSetting(context, QUICK_AFFORDANCE)
+
+ val intentCaptor = argumentCaptor<Intent>()
+ val userCaptor = argumentCaptor<UserHandle>()
+ verify(context).startActivityAsUser(capture(intentCaptor), capture(userCaptor))
+ intentCaptor.value.let { intent ->
+ assertThat(intent).hasAction(Intent.ACTION_MANAGE_DEFAULT_APP)
+ }
+ assertThat(userCaptor.value).isEqualTo(UserHandle.of(mainUserInfo.id))
+ }
+
+ @Test
+ fun startNotesRoleSetting_noManagement_nullEntryPoint_shouldStartNoteRoleIntentWithCurrentUser() { // ktlint-disable max-line-length
+ userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
+
+ createNoteTaskController().startNotesRoleSetting(context, entryPoint = null)
+
+ val intentCaptor = argumentCaptor<Intent>()
+ val userCaptor = argumentCaptor<UserHandle>()
+ verify(context).startActivityAsUser(capture(intentCaptor), capture(userCaptor))
+ intentCaptor.value.let { intent ->
+ assertThat(intent).hasAction(Intent.ACTION_MANAGE_DEFAULT_APP)
+ }
+ assertThat(userCaptor.value).isEqualTo(UserHandle.of(mainUserInfo.id))
+ }
+ // endregion
+
private companion object {
const val NOTE_TASK_SHORT_LABEL = "Notetaking"
const val NOTE_TASK_ACTIVITY_NAME = "NoteTaskActivity"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
index 42ef2b5..4526580 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
@@ -18,7 +18,12 @@
package com.android.systemui.notetask.quickaffordance
+import android.app.role.RoleManager
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.ApplicationInfoFlags
import android.hardware.input.InputSettings
+import android.os.UserHandle
import android.os.UserManager
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
@@ -31,11 +36,18 @@
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.LockScreenState
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
+import com.android.systemui.notetask.LaunchNotesRoleSettingsTrampolineActivity.Companion.ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE
import com.android.systemui.notetask.NoteTaskController
import com.android.systemui.notetask.NoteTaskEntryPoint
+import com.android.systemui.notetask.NoteTaskInfoResolver
+import com.android.systemui.shared.customization.data.content.CustomizationProviderContract.LockScreenQuickAffordances.AffordanceTable.COMPONENT_NAME_SEPARATOR
import com.android.systemui.stylus.StylusManager
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
@@ -45,6 +57,7 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
+import org.mockito.Mockito.anyString
import org.mockito.Mockito.verify
import org.mockito.MockitoSession
import org.mockito.quality.Strictness
@@ -58,6 +71,8 @@
@Mock lateinit var stylusManager: StylusManager
@Mock lateinit var repository: KeyguardQuickAffordanceRepository
@Mock lateinit var userManager: UserManager
+ @Mock lateinit var roleManager: RoleManager
+ @Mock lateinit var packageManager: PackageManager
private lateinit var mockitoSession: MockitoSession
@@ -69,6 +84,23 @@
.mockStatic(InputSettings::class.java)
.strictness(Strictness.LENIENT)
.startMocking()
+
+ whenever(
+ packageManager.getApplicationInfoAsUser(
+ anyString(),
+ any(ApplicationInfoFlags::class.java),
+ any(UserHandle::class.java)
+ )
+ )
+ .thenReturn(ApplicationInfo())
+ whenever(controller.getUserForHandlingNotesTaking(any())).thenReturn(UserHandle.SYSTEM)
+ whenever(
+ roleManager.getRoleHoldersAsUser(
+ eq(RoleManager.ROLE_NOTES),
+ any(UserHandle::class.java)
+ )
+ )
+ .thenReturn(listOf("com.google.test.notes"))
}
@After
@@ -85,6 +117,9 @@
keyguardMonitor = mock(),
lazyRepository = { repository },
isEnabled = isEnabled,
+ backgroundExecutor = FakeExecutor(FakeSystemClock()),
+ roleManager = roleManager,
+ noteTaskInfoResolver = NoteTaskInfoResolver(roleManager, packageManager)
)
private fun createLockScreenStateVisible(): LockScreenState =
@@ -112,6 +147,27 @@
}
@Test
+ fun lockScreenState_stylusUsed_userUnlocked_isSelected_noDefaultNotesAppSet_shouldEmitHidden() =
+ runTest {
+ TestConfig()
+ .setStylusEverUsed(true)
+ .setUserUnlocked(true)
+ .setConfigSelections(mock<NoteTaskQuickAffordanceConfig>())
+ whenever(
+ roleManager.getRoleHoldersAsUser(
+ eq(RoleManager.ROLE_NOTES),
+ any(UserHandle::class.java)
+ )
+ )
+ .thenReturn(emptyList())
+
+ val underTest = createUnderTest()
+ val actual by collectLastValue(underTest.lockScreenState)
+
+ assertThat(actual).isEqualTo(LockScreenState.Hidden)
+ }
+
+ @Test
fun lockScreenState_stylusUnused_userUnlocked_isSelected_shouldEmitHidden() = runTest {
TestConfig()
.setStylusEverUsed(false)
@@ -217,6 +273,39 @@
verify(controller).showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
}
+ // region getPickerScreenState
+ @Test
+ fun getPickerScreenState_defaultNoteAppSet_shouldReturnDefault() = runTest {
+ val underTest = createUnderTest(isEnabled = true)
+
+ assertThat(underTest.getPickerScreenState())
+ .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.Default())
+ }
+
+ @Test
+ fun getPickerScreenState_nodefaultNoteAppSet_shouldReturnDisable() = runTest {
+ val underTest = createUnderTest(isEnabled = true)
+ whenever(
+ roleManager.getRoleHoldersAsUser(
+ eq(RoleManager.ROLE_NOTES),
+ any(UserHandle::class.java)
+ )
+ )
+ .thenReturn(emptyList())
+
+ assertThat(underTest.getPickerScreenState())
+ .isEqualTo(
+ KeyguardQuickAffordanceConfig.PickerScreenState.Disabled(
+ listOf("Select a default notes app to use the notetaking shortcut"),
+ actionText = "Select app",
+ actionComponentName =
+ "${context.packageName}$COMPONENT_NAME_SEPARATOR" +
+ "$ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE"
+ )
+ )
+ }
+ // endregion
+
private inner class TestConfig {
fun setStylusEverUsed(value: Boolean) = also {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
index 88d7e9c..2dc78a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
@@ -587,14 +587,14 @@
assertEquals(addLink(mContext.getString(R.string.monitoring_description_two_named_vpns,
VPN_PACKAGE, VPN_PACKAGE_2)),
mFooterUtils.getVpnMessage(false, true, VPN_PACKAGE, VPN_PACKAGE_2));
- assertEquals(addLink(mContext.getString(R.string.monitoring_description_named_vpn,
- VPN_PACKAGE)),
+ assertEquals(addLink(mContext.getString(
+ R.string.monitoring_description_managed_device_named_vpn, VPN_PACKAGE)),
mFooterUtils.getVpnMessage(true, false, VPN_PACKAGE, null));
assertEquals(addLink(mContext.getString(R.string.monitoring_description_named_vpn,
VPN_PACKAGE)),
mFooterUtils.getVpnMessage(false, false, VPN_PACKAGE, null));
- assertEquals(addLink(mContext.getString(R.string.monitoring_description_named_vpn,
- VPN_PACKAGE_2)),
+ assertEquals(addLink(mContext.getString(
+ R.string.monitoring_description_managed_device_named_vpn, VPN_PACKAGE_2)),
mFooterUtils.getVpnMessage(true, true, null, VPN_PACKAGE_2));
assertEquals(addLink(mContext.getString(
R.string.monitoring_description_managed_profile_named_vpn,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
index e106741..41545fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
@@ -30,6 +30,7 @@
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.testing.TestableResources;
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
@@ -94,14 +95,18 @@
private RotationLockController mController;
private TestableLooper mTestableLooper;
private RotationLockTile mLockTile;
+ private TestableResources mTestableResources;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mTestableLooper = TestableLooper.get(this);
+ mTestableResources = mContext.getOrCreateTestableResources();
when(mHost.getContext()).thenReturn(mContext);
when(mHost.getUserContext()).thenReturn(mContext);
+ mTestableResources.addOverride(com.android.internal.R.bool.config_allowRotationResolver,
+ true);
mController = new RotationLockControllerImpl(mRotationPolicyWrapper,
mDeviceStateRotationLockSettingController, DEFAULT_SETTINGS);
@@ -208,6 +213,32 @@
}
@Test
+ public void testSecondaryString_rotationResolverDisabled_isEmpty() {
+ mTestableResources.addOverride(com.android.internal.R.bool.config_allowRotationResolver,
+ false);
+ mLockTile = new RotationLockTile(
+ mHost,
+ mUiEventLogger,
+ mTestableLooper.getLooper(),
+ new Handler(mTestableLooper.getLooper()),
+ new FalsingManagerFake(),
+ mMetricsLogger,
+ mStatusBarStateController,
+ mActivityStarter,
+ mQSLogger,
+ mController,
+ mPrivacyManager,
+ mBatteryController,
+ new FakeSettings()
+ );
+
+ mLockTile.refreshState();
+ mTestableLooper.processAllMessages();
+
+ assertEquals("", mLockTile.getState().secondaryLabel.toString());
+ }
+
+ @Test
public void testIcon_whenDisabled_isOffState() {
QSTile.BooleanState state = new QSTile.BooleanState();
disableAutoRotation();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
index a1d78cb..7c30843b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
@@ -18,7 +18,6 @@
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
@@ -94,6 +93,7 @@
doReturn(mContext.getUserId()).when(mRecordingService).getUserId();
doReturn(mContext.getPackageName()).when(mRecordingService).getPackageName();
doReturn(mContext.getContentResolver()).when(mRecordingService).getContentResolver();
+ doReturn(mContext.getResources()).when(mRecordingService).getResources();
// Mock notifications
doNothing().when(mRecordingService).createRecordingNotification();
@@ -101,7 +101,7 @@
doReturn(mNotification).when(mRecordingService).createSaveNotification(any());
doNothing().when(mRecordingService).createErrorNotification();
doNothing().when(mRecordingService).showErrorToast(anyInt());
- doNothing().when(mRecordingService).stopForeground(anyBoolean());
+ doNothing().when(mRecordingService).stopForeground(anyInt());
doNothing().when(mRecordingService).startForeground(anyInt(), any());
doReturn(mScreenMediaRecorder).when(mRecordingService).getRecorder();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 1edc63c..9a8ec88 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -151,6 +151,7 @@
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
import com.android.systemui.statusbar.phone.KeyguardStatusBarViewController;
+import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.phone.ScrimController;
@@ -158,6 +159,7 @@
import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
import com.android.systemui.statusbar.phone.TapAgainViewController;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
+import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -239,6 +241,7 @@
@Mock protected KeyguardStatusBarViewComponent mKeyguardStatusBarViewComponent;
@Mock protected KeyguardClockSwitchController mKeyguardClockSwitchController;
@Mock protected KeyguardStatusBarViewController mKeyguardStatusBarViewController;
+ @Mock protected LightBarController mLightBarController;
@Mock protected NotificationStackScrollLayoutController
mNotificationStackScrollLayoutController;
@Mock protected NotificationShadeDepthController mNotificationShadeDepthController;
@@ -306,6 +309,7 @@
@Mock protected ActivityStarter mActivityStarter;
@Mock protected KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor;
@Mock protected ShadeRepository mShadeRepository;
+ @Mock private CastController mCastController;
protected final int mMaxUdfpsBurnInOffsetY = 5;
protected KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
@@ -653,6 +657,7 @@
mNotificationRemoteInputManager,
mShadeExpansionStateManager,
mStatusBarKeyguardViewManager,
+ mLightBarController,
mNotificationStackScrollLayoutController,
mLockscreenShadeTransitionController,
mNotificationShadeDepthController,
@@ -675,7 +680,8 @@
mInteractionJankMonitor,
mShadeLog,
mKeyguardFaceAuthInteractor,
- mShadeRepository
+ mShadeRepository,
+ mCastController
);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java
index 8a9161e..1cf3873 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java
@@ -83,10 +83,12 @@
import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
+import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
+import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import dagger.Lazy;
@@ -132,6 +134,7 @@
@Mock private PulseExpansionHandler mPulseExpansionHandler;
@Mock private NotificationRemoteInputManager mNotificationRemoteInputManager;
@Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ @Mock private LightBarController mLightBarController;
@Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
@Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
@Mock private NotificationShadeDepthController mNotificationShadeDepthController;
@@ -155,6 +158,7 @@
@Mock private ShadeLogger mShadeLogger;
@Mock private DumpManager mDumpManager;
@Mock private UiEventLogger mUiEventLogger;
+ @Mock private CastController mCastController;
private SysuiStatusBarStateController mStatusBarStateController;
@@ -221,6 +225,7 @@
mNotificationRemoteInputManager,
mShadeExpansionStateManager,
mStatusBarKeyguardViewManager,
+ mLightBarController,
mNotificationStackScrollLayoutController,
mLockscreenShadeTransitionController,
mNotificationShadeDepthController,
@@ -243,7 +248,8 @@
mInteractionJankMonitor,
mShadeLogger,
mock(KeyguardFaceAuthInteractor.class),
- mock(ShadeRepository.class)
+ mock(ShadeRepository.class),
+ mCastController
);
mFragmentListener = mQsController.getQsFragmentListener();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index beaf300..c49f179 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -356,6 +356,7 @@
@Test
fun ignoreShadeBlurUntilHidden_schedulesFrame() {
notificationShadeDepthController.blursDisabledForAppLaunch = true
+ verify(blurUtils).prepareBlur(any(), anyInt())
verify(choreographer)
.postFrameCallback(eq(notificationShadeDepthController.updateBlurCallback))
}
@@ -419,6 +420,7 @@
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(notificationShadeWindowController).setBackgroundBlurRadius(eq(0))
verify(wallpaperController).setNotificationShadeZoom(eq(1f))
+ verify(blurUtils).prepareBlur(any(), eq(0))
verify(blurUtils).applyBlur(eq(viewRootImpl), eq(0), eq(false))
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index 9186c35..4c83194 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -617,24 +617,9 @@
}
@Test
- public void applyRoundnessAndInv_should_be_immediately_applied_on_childrenContainer_legacy()
- throws Exception {
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
- group.useRoundnessSourceTypes(false);
- Assert.assertEquals(0f, group.getBottomRoundness(), 0.001f);
- Assert.assertEquals(0f, group.getChildrenContainer().getBottomRoundness(), 0.001f);
-
- group.requestBottomRoundness(1f, SourceType.from(""), false);
-
- Assert.assertEquals(1f, group.getBottomRoundness(), 0.001f);
- Assert.assertEquals(1f, group.getChildrenContainer().getBottomRoundness(), 0.001f);
- }
-
- @Test
public void applyRoundnessAndInvalidate_should_be_immediately_applied_on_childrenContainer()
throws Exception {
ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
- group.useRoundnessSourceTypes(true);
Assert.assertEquals(0f, group.getBottomRoundness(), 0.001f);
Assert.assertEquals(0f, group.getChildrenContainer().getBottomRoundness(), 0.001f);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
index e41929f..be976a1c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
@@ -25,7 +25,6 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.LegacySourceType;
import com.android.systemui.statusbar.notification.SourceType;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
@@ -158,55 +157,7 @@
}
@Test
- public void addNotification_shouldResetOnScrollRoundness() throws Exception {
- ExpandableNotificationRow row = mNotificationTestHelper.createRowWithRoundness(
- /* topRoundness = */ 1f,
- /* bottomRoundness = */ 1f,
- /* sourceType = */ LegacySourceType.OnScroll);
-
- mChildrenContainer.addNotification(row, 0);
-
- Assert.assertEquals(0f, row.getTopRoundness(), /* delta = */ 0f);
- Assert.assertEquals(0f, row.getBottomRoundness(), /* delta = */ 0f);
- }
-
- @Test
- public void addNotification_shouldNotResetOtherRoundness() throws Exception {
- ExpandableNotificationRow row1 = mNotificationTestHelper.createRowWithRoundness(
- /* topRoundness = */ 1f,
- /* bottomRoundness = */ 1f,
- /* sourceType = */ LegacySourceType.DefaultValue);
- ExpandableNotificationRow row2 = mNotificationTestHelper.createRowWithRoundness(
- /* topRoundness = */ 1f,
- /* bottomRoundness = */ 1f,
- /* sourceType = */ LegacySourceType.OnDismissAnimation);
-
- mChildrenContainer.addNotification(row1, 0);
- mChildrenContainer.addNotification(row2, 0);
-
- Assert.assertEquals(1f, row1.getTopRoundness(), /* delta = */ 0f);
- Assert.assertEquals(1f, row1.getBottomRoundness(), /* delta = */ 0f);
- Assert.assertEquals(1f, row2.getTopRoundness(), /* delta = */ 0f);
- Assert.assertEquals(1f, row2.getBottomRoundness(), /* delta = */ 0f);
- }
-
- @Test
- public void applyRoundnessAndInvalidate_should_be_immediately_applied_on_last_child_legacy() {
- mChildrenContainer.useRoundnessSourceTypes(false);
- List<ExpandableNotificationRow> children = mChildrenContainer.getAttachedChildren();
- ExpandableNotificationRow notificationRow = children.get(children.size() - 1);
- Assert.assertEquals(0f, mChildrenContainer.getBottomRoundness(), 0.001f);
- Assert.assertEquals(0f, notificationRow.getBottomRoundness(), 0.001f);
-
- mChildrenContainer.requestBottomRoundness(1f, SourceType.from(""), false);
-
- Assert.assertEquals(1f, mChildrenContainer.getBottomRoundness(), 0.001f);
- Assert.assertEquals(1f, notificationRow.getBottomRoundness(), 0.001f);
- }
-
- @Test
public void applyRoundnessAndInvalidate_should_be_immediately_applied_on_last_child() {
- mChildrenContainer.useRoundnessSourceTypes(true);
List<ExpandableNotificationRow> children = mChildrenContainer.getAttachedChildren();
ExpandableNotificationRow notificationRow = children.get(children.size() - 1);
Assert.assertEquals(0f, mChildrenContainer.getBottomRoundness(), 0.001f);
@@ -220,8 +171,6 @@
@Test
public void applyRoundnessAndInvalidate_should_be_immediately_applied_on_header() {
- mChildrenContainer.useRoundnessSourceTypes(true);
-
NotificationHeaderViewWrapper header = mChildrenContainer.getNotificationHeaderWrapper();
Assert.assertEquals(0f, header.getTopRoundness(), 0.001f);
@@ -232,7 +181,6 @@
@Test
public void applyRoundnessAndInvalidate_should_be_immediately_applied_on_headerLowPriority() {
- mChildrenContainer.useRoundnessSourceTypes(true);
mChildrenContainer.setIsLowPriority(true);
NotificationHeaderViewWrapper header = mChildrenContainer.getNotificationHeaderWrapper();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
index b1d3daa..05b70eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
@@ -12,7 +12,6 @@
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator
import com.android.systemui.statusbar.NotificationShelf
import com.android.systemui.statusbar.StatusBarIconView
-import com.android.systemui.statusbar.notification.LegacySourceType
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView
import com.android.systemui.statusbar.notification.row.NotificationTestHelper
@@ -359,39 +358,6 @@
)
}
- @Test
- fun resetOnScrollRoundness_shouldSetOnScrollTo0() {
- val row: ExpandableNotificationRow = notificationTestHelper.createRowWithRoundness(
- /* topRoundness = */ 1f,
- /* bottomRoundness = */ 1f,
- /* sourceType = */ LegacySourceType.OnScroll)
-
- NotificationShelf.resetLegacyOnScrollRoundness(row)
-
- assertEquals(0f, row.topRoundness)
- assertEquals(0f, row.bottomRoundness)
- }
-
- @Test
- fun resetOnScrollRoundness_shouldNotResetOtherRoundness() {
- val row1: ExpandableNotificationRow = notificationTestHelper.createRowWithRoundness(
- /* topRoundness = */ 1f,
- /* bottomRoundness = */ 1f,
- /* sourceType = */ LegacySourceType.DefaultValue)
- val row2: ExpandableNotificationRow = notificationTestHelper.createRowWithRoundness(
- /* topRoundness = */ 1f,
- /* bottomRoundness = */ 1f,
- /* sourceType = */ LegacySourceType.OnDismissAnimation)
-
- NotificationShelf.resetLegacyOnScrollRoundness(row1)
- NotificationShelf.resetLegacyOnScrollRoundness(row2)
-
- assertEquals(1f, row1.topRoundness)
- assertEquals(1f, row1.bottomRoundness)
- assertEquals(1f, row2.topRoundness)
- assertEquals(1f, row2.bottomRoundness)
- }
-
private fun setFractionToShade(fraction: Float) {
whenever(ambientState.fractionToShade).thenReturn(fraction)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
index 529519a..a501556 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
@@ -22,21 +22,31 @@
import static junit.framework.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.graphics.Color;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.annotation.ColorInt;
import androidx.test.filters.SmallTest;
+import com.android.internal.colorextraction.ColorExtractor.GradientColors;
+import com.android.internal.util.ContrastColorUtil;
import com.android.internal.view.AppearanceRegion;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FakeFeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -53,13 +63,25 @@
@TestableLooper.RunWithLooper
public class LightBarControllerTest extends SysuiTestCase {
+ private static final GradientColors COLORS_LIGHT = makeColors(Color.WHITE);
+ private static final GradientColors COLORS_DARK = makeColors(Color.BLACK);
+ private final FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
private LightBarTransitionsController mLightBarTransitionsController;
+ private LightBarTransitionsController mNavBarController;
private SysuiDarkIconDispatcher mStatusBarIconController;
private LightBarController mLightBarController;
+ /** Allow testing with NEW_LIGHT_BAR_LOGIC flag in different states */
+ protected boolean testNewLightBarLogic() {
+ return false;
+ }
+
@Before
public void setup() {
+ mFeatureFlags.set(Flags.NEW_LIGHT_BAR_LOGIC, testNewLightBarLogic());
mStatusBarIconController = mock(SysuiDarkIconDispatcher.class);
+ mNavBarController = mock(LightBarTransitionsController.class);
+ when(mNavBarController.supportsIconTintForNavMode(anyInt())).thenReturn(true);
mLightBarTransitionsController = mock(LightBarTransitionsController.class);
when(mStatusBarIconController.getTransitionsController()).thenReturn(
mLightBarTransitionsController);
@@ -68,10 +90,19 @@
mStatusBarIconController,
mock(BatteryController.class),
mock(NavigationModeController.class),
+ mFeatureFlags,
mock(DumpManager.class),
new FakeDisplayTracker(mContext));
}
+ private static GradientColors makeColors(@ColorInt int bgColor) {
+ GradientColors colors = new GradientColors();
+ colors.setMainColor(bgColor);
+ colors.setSecondaryColor(bgColor);
+ colors.setSupportsDarkText(!ContrastColorUtil.isColorDark(bgColor));
+ return colors;
+ }
+
@Test
public void testOnStatusBarAppearanceChanged_multipleStacks_allStacksLight() {
final Rect firstBounds = new Rect(0, 0, 1, 1);
@@ -177,4 +208,54 @@
false /* navbarColorManagedByIme */);
verify(mLightBarTransitionsController).setIconsDark(eq(false), anyBoolean());
}
+
+ @Test
+ public void validateNavBarChangesUpdateIcons() {
+ assumeTrue(testNewLightBarLogic()); // Only run in the new suite
+
+ // On the launcher in dark mode buttons are light
+ mLightBarController.setScrimState(ScrimState.UNLOCKED, 0f, COLORS_DARK);
+ mLightBarController.onNavigationBarAppearanceChanged(
+ 0, /* nbModeChanged = */ true,
+ MODE_TRANSPARENT, /* navbarColorManagedByIme = */ false);
+ verifyNavBarIconsUnchanged(); // no changes yet; not attached
+
+ // Initial state is set when controller is set
+ mLightBarController.setNavigationBar(mNavBarController);
+ verifyNavBarIconsDarkSetTo(false);
+
+ // Changing the color of the transparent scrim has no effect
+ mLightBarController.setScrimState(ScrimState.UNLOCKED, 0f, COLORS_LIGHT);
+ verifyNavBarIconsUnchanged(); // still light
+
+ // Showing the notification shade with white scrim requires dark icons
+ mLightBarController.setScrimState(ScrimState.UNLOCKED, 1f, COLORS_LIGHT);
+ verifyNavBarIconsDarkSetTo(true);
+
+ // Expanded QS always provides a black background, so icons become light again
+ mLightBarController.setQsExpanded(true);
+ verifyNavBarIconsDarkSetTo(false);
+
+ // Tapping the QS tile to change to dark theme has no effect in this state
+ mLightBarController.setScrimState(ScrimState.UNLOCKED, 1f, COLORS_DARK);
+ verifyNavBarIconsUnchanged(); // still light
+
+ // collapsing QS in dark mode doesn't affect button color
+ mLightBarController.setQsExpanded(false);
+ verifyNavBarIconsUnchanged(); // still light
+
+ // Closing the shade has no affect
+ mLightBarController.setScrimState(ScrimState.UNLOCKED, 0f, COLORS_DARK);
+ verifyNavBarIconsUnchanged(); // still light
+ }
+
+ private void verifyNavBarIconsUnchanged() {
+ verify(mNavBarController, never()).setIconsDark(anyBoolean(), anyBoolean());
+ }
+
+ private void verifyNavBarIconsDarkSetTo(boolean iconsDark) {
+ verify(mNavBarController).setIconsDark(eq(iconsDark), anyBoolean());
+ verify(mNavBarController, never()).setIconsDark(eq(!iconsDark), anyBoolean());
+ clearInvocations(mNavBarController);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerWithNewLogicTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerWithNewLogicTest.kt
new file mode 100644
index 0000000..d9c2cfa
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerWithNewLogicTest.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.phone
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.flags.Flags.NEW_LIGHT_BAR_LOGIC
+
+/**
+ * This file only needs to live as long as [NEW_LIGHT_BAR_LOGIC] does. When we delete that flag, we
+ * can roll this back into the old test.
+ */
+@SmallTest
+class LightBarControllerWithNewLogicTest : LightBarControllerTest() {
+ override fun testNewLightBarLogic(): Boolean = true
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
index b80b825..c282c1e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
@@ -21,6 +21,8 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.StatusBarIconView.STATE_DOT
+import com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
@@ -49,7 +51,7 @@
fun calculateWidthFor_oneIcon_widthForOneIcon() {
iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f)
- iconContainer.setIconSize(10);
+ iconContainer.setIconSize(10)
assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 1f),
/* actual= */ 30f)
@@ -59,7 +61,7 @@
fun calculateWidthFor_fourIcons_widthForFourIcons() {
iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f)
- iconContainer.setIconSize(10);
+ iconContainer.setIconSize(10)
assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 4f),
/* actual= */ 60f)
@@ -69,7 +71,7 @@
fun calculateWidthFor_fiveIcons_widthForFourIcons() {
iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f)
- iconContainer.setIconSize(10);
+ iconContainer.setIconSize(10)
assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 5f),
/* actual= */ 60f)
}
@@ -78,7 +80,7 @@
fun calculateIconXTranslations_shortShelfOneIcon_atCorrectXWithoutOverflowDot() {
iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f)
- iconContainer.setIconSize(10);
+ iconContainer.setIconSize(10)
val icon = mockStatusBarIcon()
iconContainer.addView(icon)
@@ -99,7 +101,7 @@
fun calculateIconXTranslations_shortShelfFourIcons_atCorrectXWithoutOverflowDot() {
iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f)
- iconContainer.setIconSize(10);
+ iconContainer.setIconSize(10)
val iconOne = mockStatusBarIcon()
val iconTwo = mockStatusBarIcon()
@@ -128,7 +130,7 @@
fun calculateIconXTranslations_shortShelfFiveIcons_atCorrectXWithOverflowDot() {
iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f)
- iconContainer.setIconSize(10);
+ iconContainer.setIconSize(10)
val iconOne = mockStatusBarIcon()
val iconTwo = mockStatusBarIcon()
@@ -154,6 +156,55 @@
}
@Test
+ fun calculateIconXTranslations_givenWidthEnoughForThreeIcons_atCorrectXWithoutOverflowDot() {
+ iconContainer.setActualPaddingStart(0f)
+ iconContainer.setActualPaddingEnd(0f)
+ iconContainer.setActualLayoutWidth(30)
+ iconContainer.setIconSize(10)
+
+ val iconOne = mockStatusBarIcon()
+ val iconTwo = mockStatusBarIcon()
+ val iconThree = mockStatusBarIcon()
+
+ iconContainer.addView(iconOne)
+ iconContainer.addView(iconTwo)
+ iconContainer.addView(iconThree)
+ assertEquals(3, iconContainer.childCount)
+
+ iconContainer.calculateIconXTranslations()
+ assertEquals(0f, iconContainer.getIconState(iconOne).xTranslation)
+ assertEquals(10f, iconContainer.getIconState(iconTwo).xTranslation)
+ assertEquals(20f, iconContainer.getIconState(iconThree).xTranslation)
+ assertFalse(iconContainer.areIconsOverflowing())
+ }
+
+ @Test
+ fun calculateIconXTranslations_givenWidthNotEnoughForFourIcons_atCorrectXWithOverflowDot() {
+ iconContainer.setActualPaddingStart(0f)
+ iconContainer.setActualPaddingEnd(0f)
+ iconContainer.setActualLayoutWidth(35)
+ iconContainer.setIconSize(10)
+
+ val iconOne = mockStatusBarIcon()
+ val iconTwo = mockStatusBarIcon()
+ val iconThree = mockStatusBarIcon()
+ val iconFour = mockStatusBarIcon()
+
+ iconContainer.addView(iconOne)
+ iconContainer.addView(iconTwo)
+ iconContainer.addView(iconThree)
+ iconContainer.addView(iconFour)
+ assertEquals(4, iconContainer.childCount)
+
+ iconContainer.calculateIconXTranslations()
+ assertEquals(0f, iconContainer.getIconState(iconOne).xTranslation)
+ assertEquals(10f, iconContainer.getIconState(iconTwo).xTranslation)
+ assertEquals(STATE_DOT, iconContainer.getIconState(iconThree).visibleState)
+ assertEquals(STATE_HIDDEN, iconContainer.getIconState(iconFour).visibleState)
+ assertTrue(iconContainer.areIconsOverflowing())
+ }
+
+ @Test
fun shouldForceOverflow_appearingAboveSpeedBump_true() {
val forceOverflow = iconContainer.shouldForceOverflow(
/* i= */ 1,
@@ -161,7 +212,7 @@
/* iconAppearAmount= */ 1f,
/* maxVisibleIcons= */ 5
)
- assertTrue(forceOverflow);
+ assertTrue(forceOverflow)
}
@Test
@@ -172,7 +223,7 @@
/* iconAppearAmount= */ 0f,
/* maxVisibleIcons= */ 5
)
- assertTrue(forceOverflow);
+ assertTrue(forceOverflow)
}
@Test
@@ -183,7 +234,7 @@
/* iconAppearAmount= */ 0f,
/* maxVisibleIcons= */ 5
)
- assertFalse(forceOverflow);
+ assertFalse(forceOverflow)
}
@Test
@@ -210,6 +261,17 @@
}
@Test
+ fun isOverflowing_lastChildXGreaterThanDotX_true() {
+ val isOverflowing = iconContainer.isOverflowing(
+ /* isLastChild= */ true,
+ /* translationX= */ 9f,
+ /* layoutEnd= */ 10f,
+ /* iconSize= */ 2f,
+ )
+ assertTrue(isOverflowing)
+ }
+
+ @Test
fun isOverflowing_lastChildXGreaterThanLayoutEnd_true() {
val isOverflowing = iconContainer.isOverflowing(
/* isLastChild= */ true,
@@ -253,7 +315,7 @@
assertTrue(isOverflowing)
}
- private fun mockStatusBarIcon() : StatusBarIconView {
+ private fun mockStatusBarIcon(): StatusBarIconView {
val iconView = mock(StatusBarIconView::class.java)
whenever(iconView.width).thenReturn(10)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastControllerImplTest.java
index db50163..b8e4306 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastControllerImplTest.java
@@ -1,6 +1,7 @@
package com.android.systemui.statusbar.policy;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -125,4 +126,20 @@
fail("Concurrent modification exception");
}
}
+
+ @Test
+ public void hasConnectedCastDevice_connected() {
+ CastController.CastDevice castDevice = new CastController.CastDevice();
+ castDevice.state = CastController.CastDevice.STATE_CONNECTED;
+ mController.startCasting(castDevice);
+ assertTrue(mController.hasConnectedCastDevice());
+ }
+
+ @Test
+ public void hasConnectedCastDevice_notConnected() {
+ CastController.CastDevice castDevice = new CastController.CastDevice();
+ castDevice.state = CastController.CastDevice.STATE_CONNECTING;
+ mController.startCasting(castDevice);
+ assertTrue(mController.hasConnectedCastDevice());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 1510ee8..47a86b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -380,7 +380,7 @@
mPositioner,
mock(DisplayController.class),
mOneHandedOptional,
- mock(DragAndDropController.class),
+ Optional.of(mock(DragAndDropController.class)),
syncExecutor,
mock(Handler.class),
mTaskViewTransitions,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
index c3bb771..14c3f3c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
@@ -69,7 +69,7 @@
BubblePositioner positioner,
DisplayController displayController,
Optional<OneHandedController> oneHandedOptional,
- DragAndDropController dragAndDropController,
+ Optional<DragAndDropController> dragAndDropController,
ShellExecutor shellMainExecutor,
Handler shellMainHandler,
TaskViewTransitions taskViewTransitions,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeRearDisplayStateRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeRearDisplayStateRepository.kt
new file mode 100644
index 0000000..fd91391
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeRearDisplayStateRepository.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.biometrics.data.repository
+
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeRearDisplayStateRepository : RearDisplayStateRepository {
+ private val _isInRearDisplayMode = MutableStateFlow<Boolean>(false)
+ override val isInRearDisplayMode: StateFlow<Boolean> = _isInRearDisplayMode.asStateFlow()
+
+ fun setIsInRearDisplayMode(isInRearDisplayMode: Boolean) {
+ _isInRearDisplayMode.value = isInRearDisplayMode
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeCastController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeCastController.java
index f6b24da..84ace7c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeCastController.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeCastController.java
@@ -51,4 +51,9 @@
public void stopCasting(CastDevice device) {
}
+
+ @Override
+ public boolean hasConnectedCastDevice() {
+ return false;
+ }
}
diff --git a/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java b/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java
deleted file mode 100644
index 715697d..0000000
--- a/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.autofill;
-
-import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
-
-import static com.android.server.autofill.Helper.sVerbose;
-
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.app.AppGlobals;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.ICancellationSignal;
-import android.os.RemoteException;
-import android.service.autofill.Dataset;
-import android.service.autofill.FillResponse;
-import android.service.autofill.IFillCallback;
-import android.service.autofill.SaveInfo;
-import android.text.TextUtils;
-import android.text.format.DateUtils;
-import android.util.Slog;
-import android.view.autofill.AutofillId;
-import android.view.autofill.IAutoFillManagerClient;
-import android.view.inputmethod.InlineSuggestionsRequest;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.infra.AndroidFuture;
-
-import java.util.List;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Maintains a client suggestions session with the
- * {@link android.view.autofill.AutofillRequestCallback} through the {@link IAutoFillManagerClient}.
- *
- */
-final class ClientSuggestionsSession {
-
- private static final String TAG = "ClientSuggestionsSession";
- private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 15 * DateUtils.SECOND_IN_MILLIS;
-
- private final int mSessionId;
- private final IAutoFillManagerClient mClient;
- private final Handler mHandler;
- private final ComponentName mComponentName;
-
- private final RemoteFillService.FillServiceCallbacks mCallbacks;
-
- private final Object mLock = new Object();
- @GuardedBy("mLock")
- private AndroidFuture<FillResponse> mPendingFillRequest;
- @GuardedBy("mLock")
- private int mPendingFillRequestId = INVALID_REQUEST_ID;
-
- ClientSuggestionsSession(int sessionId, IAutoFillManagerClient client, Handler handler,
- ComponentName componentName, RemoteFillService.FillServiceCallbacks callbacks) {
- mSessionId = sessionId;
- mClient = client;
- mHandler = handler;
- mComponentName = componentName;
- mCallbacks = callbacks;
- }
-
- void onFillRequest(int requestId, InlineSuggestionsRequest inlineRequest, int flags) {
- final AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>();
- final AtomicReference<AndroidFuture<FillResponse>> futureRef = new AtomicReference<>();
- final AndroidFuture<FillResponse> fillRequest = new AndroidFuture<>();
-
- mHandler.post(() -> {
- if (sVerbose) {
- Slog.v(TAG, "calling onFillRequest() for id=" + requestId);
- }
-
- try {
- mClient.requestFillFromClient(requestId, inlineRequest,
- new FillCallbackImpl(fillRequest, futureRef, cancellationSink));
- } catch (RemoteException e) {
- fillRequest.completeExceptionally(e);
- }
- });
-
- fillRequest.orTimeout(TIMEOUT_REMOTE_REQUEST_MILLIS, TimeUnit.MILLISECONDS);
- futureRef.set(fillRequest);
-
- synchronized (mLock) {
- mPendingFillRequest = fillRequest;
- mPendingFillRequestId = requestId;
- }
-
- fillRequest.whenComplete((res, err) -> mHandler.post(() -> {
- synchronized (mLock) {
- mPendingFillRequest = null;
- mPendingFillRequestId = INVALID_REQUEST_ID;
- }
- if (err == null) {
- processAutofillId(res);
- mCallbacks.onFillRequestSuccess(requestId, res,
- mComponentName.getPackageName(), flags);
- } else {
- Slog.e(TAG, "Error calling on client fill request", err);
- if (err instanceof TimeoutException) {
- dispatchCancellationSignal(cancellationSink.get());
- mCallbacks.onFillRequestTimeout(requestId);
- } else if (err instanceof CancellationException) {
- dispatchCancellationSignal(cancellationSink.get());
- } else {
- mCallbacks.onFillRequestFailure(requestId, err.getMessage());
- }
- }
- }));
- }
-
- /**
- * Gets the application info for the component.
- */
- @Nullable
- static ApplicationInfo getAppInfo(ComponentName comp, @UserIdInt int userId) {
- try {
- ApplicationInfo si = AppGlobals.getPackageManager().getApplicationInfo(
- comp.getPackageName(),
- PackageManager.GET_META_DATA,
- userId);
- if (si != null) {
- return si;
- }
- } catch (RemoteException e) {
- }
- return null;
- }
-
- /**
- * Gets the user-visible name of the application.
- */
- @Nullable
- @GuardedBy("mLock")
- static CharSequence getAppLabelLocked(Context context, ApplicationInfo appInfo) {
- return appInfo == null ? null : appInfo.loadSafeLabel(
- context.getPackageManager(), 0 /* do not ellipsize */,
- TextUtils.SAFE_STRING_FLAG_FIRST_LINE | TextUtils.SAFE_STRING_FLAG_TRIM);
- }
-
- /**
- * Gets the user-visible icon of the application.
- */
- @Nullable
- @GuardedBy("mLock")
- static Drawable getAppIconLocked(Context context, ApplicationInfo appInfo) {
- return appInfo == null ? null : appInfo.loadIcon(context.getPackageManager());
- }
-
- int cancelCurrentRequest() {
- synchronized (mLock) {
- return mPendingFillRequest != null && mPendingFillRequest.cancel(false)
- ? mPendingFillRequestId
- : INVALID_REQUEST_ID;
- }
- }
-
- /**
- * The {@link AutofillId} which the client gets from its view is not contain the session id,
- * but Autofill framework is using the {@link AutofillId} with a session id. So before using
- * those ids in the Autofill framework, applies the current session id.
- *
- * @param res which response need to apply for a session id
- */
- private void processAutofillId(FillResponse res) {
- if (res == null) {
- return;
- }
-
- final List<Dataset> datasets = res.getDatasets();
- if (datasets != null && !datasets.isEmpty()) {
- for (int i = 0; i < datasets.size(); i++) {
- final Dataset dataset = datasets.get(i);
- if (dataset != null) {
- applySessionId(dataset.getFieldIds());
- }
- }
- }
-
- final SaveInfo saveInfo = res.getSaveInfo();
- if (saveInfo != null) {
- applySessionId(saveInfo.getOptionalIds());
- applySessionId(saveInfo.getRequiredIds());
- applySessionId(saveInfo.getSanitizerValues());
- applySessionId(saveInfo.getTriggerId());
- }
- }
-
- private void applySessionId(List<AutofillId> ids) {
- if (ids == null || ids.isEmpty()) {
- return;
- }
-
- for (int i = 0; i < ids.size(); i++) {
- applySessionId(ids.get(i));
- }
- }
-
- private void applySessionId(AutofillId[][] ids) {
- if (ids == null) {
- return;
- }
- for (int i = 0; i < ids.length; i++) {
- applySessionId(ids[i]);
- }
- }
-
- private void applySessionId(AutofillId[] ids) {
- if (ids == null) {
- return;
- }
- for (int i = 0; i < ids.length; i++) {
- applySessionId(ids[i]);
- }
- }
-
- private void applySessionId(AutofillId id) {
- if (id == null) {
- return;
- }
- id.setSessionId(mSessionId);
- }
-
- private void dispatchCancellationSignal(@Nullable ICancellationSignal signal) {
- if (signal == null) {
- return;
- }
- try {
- signal.cancel();
- } catch (RemoteException e) {
- Slog.e(TAG, "Error requesting a cancellation", e);
- }
- }
-
- private class FillCallbackImpl extends IFillCallback.Stub {
- final AndroidFuture<FillResponse> mFillRequest;
- final AtomicReference<AndroidFuture<FillResponse>> mFutureRef;
- final AtomicReference<ICancellationSignal> mCancellationSink;
-
- FillCallbackImpl(AndroidFuture<FillResponse> fillRequest,
- AtomicReference<AndroidFuture<FillResponse>> futureRef,
- AtomicReference<ICancellationSignal> cancellationSink) {
- mFillRequest = fillRequest;
- mFutureRef = futureRef;
- mCancellationSink = cancellationSink;
- }
-
- @Override
- public void onCancellable(ICancellationSignal cancellation) {
- AndroidFuture<FillResponse> future = mFutureRef.get();
- if (future != null && future.isCancelled()) {
- dispatchCancellationSignal(cancellation);
- } else {
- mCancellationSink.set(cancellation);
- }
- }
-
- @Override
- public void onSuccess(FillResponse response) {
- mFillRequest.complete(response);
- }
-
- @Override
- public void onFailure(int requestId, CharSequence message) {
- String errorMessage = message == null ? "" : String.valueOf(message);
- mFillRequest.completeExceptionally(
- new RuntimeException(errorMessage));
- }
- }
-}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index f83d734..3736262 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -36,7 +36,6 @@
import static android.view.autofill.AutofillManager.ACTION_VIEW_ENTERED;
import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED;
import static android.view.autofill.AutofillManager.COMMIT_REASON_UNKNOWN;
-import static android.view.autofill.AutofillManager.FLAG_ENABLED_CLIENT_SUGGESTIONS;
import static android.view.autofill.AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM;
import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString;
@@ -446,9 +445,6 @@
*/
private final PccAssistDataReceiverImpl mPccAssistReceiver = new PccAssistDataReceiverImpl();
- @Nullable
- private ClientSuggestionsSession mClientSuggestionsSession;
-
private final ClassificationState mClassificationState = new ClassificationState();
// TODO(b/216576510): Share one BroadcastReceiver between all Sessions instead of creating a
@@ -590,9 +586,6 @@
/** Whether the current {@link FillResponse} is expired. */
private boolean mExpiredResponse;
- /** Whether the client is using {@link android.view.autofill.AutofillRequestCallback}. */
- private boolean mClientSuggestionsEnabled;
-
/** Whether the fill dialog UI is disabled. */
private boolean mFillDialogDisabled;
}
@@ -623,21 +616,14 @@
}
mWaitForInlineRequest = inlineSuggestionsRequest != null;
mPendingInlineSuggestionsRequest = inlineSuggestionsRequest;
- mWaitForInlineRequest = inlineSuggestionsRequest != null;
- maybeRequestFillFromServiceLocked();
+ maybeRequestFillLocked();
viewState.resetState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
}
} : null;
}
- void newAutofillRequestLocked(@Nullable InlineSuggestionsRequest inlineRequest) {
- mPendingFillRequest = null;
- mWaitForInlineRequest = inlineRequest != null;
- mPendingInlineSuggestionsRequest = inlineRequest;
- }
-
@GuardedBy("mLock")
- void maybeRequestFillFromServiceLocked() {
+ void maybeRequestFillLocked() {
if (mPendingFillRequest == null) {
return;
}
@@ -647,15 +633,13 @@
return;
}
- if (mPendingInlineSuggestionsRequest.isServiceSupported()) {
- mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
- mPendingFillRequest.getFillContexts(),
- mPendingFillRequest.getHints(),
- mPendingFillRequest.getClientState(),
- mPendingFillRequest.getFlags(),
- mPendingInlineSuggestionsRequest,
- mPendingFillRequest.getDelayedFillIntentSender());
- }
+ mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
+ mPendingFillRequest.getFillContexts(),
+ mPendingFillRequest.getHints(),
+ mPendingFillRequest.getClientState(),
+ mPendingFillRequest.getFlags(),
+ mPendingInlineSuggestionsRequest,
+ mPendingFillRequest.getDelayedFillIntentSender());
}
mLastFillRequest = mPendingFillRequest;
@@ -777,7 +761,7 @@
: mDelayedFillPendingIntent.getIntentSender());
mPendingFillRequest = request;
- maybeRequestFillFromServiceLocked();
+ maybeRequestFillLocked();
}
if (mActivityToken != null) {
@@ -1099,39 +1083,30 @@
}
/**
- * Cancels the last request sent to the {@link #mRemoteFillService} or the
- * {@link #mClientSuggestionsSession}.
+ * Cancels the last request sent to the {@link #mRemoteFillService}.
*/
@GuardedBy("mLock")
private void cancelCurrentRequestLocked() {
- if (mRemoteFillService == null && mClientSuggestionsSession == null) {
- wtf(null, "cancelCurrentRequestLocked() called without a remote service or a "
- + "client suggestions session. mForAugmentedAutofillOnly: %s",
- mSessionFlags.mAugmentedAutofillOnly);
+ if (mRemoteFillService == null) {
+ wtf(null, "cancelCurrentRequestLocked() called without a remote service. "
+ + "mForAugmentedAutofillOnly: %s", mSessionFlags.mAugmentedAutofillOnly);
return;
}
+ final int canceledRequest = mRemoteFillService.cancelCurrentRequest();
- if (mRemoteFillService != null) {
- final int canceledRequest = mRemoteFillService.cancelCurrentRequest();
+ // Remove the FillContext as there will never be a response for the service
+ if (canceledRequest != INVALID_REQUEST_ID && mContexts != null) {
+ final int numContexts = mContexts.size();
- // Remove the FillContext as there will never be a response for the service
- if (canceledRequest != INVALID_REQUEST_ID && mContexts != null) {
- final int numContexts = mContexts.size();
-
- // It is most likely the last context, hence search backwards
- for (int i = numContexts - 1; i >= 0; i--) {
- if (mContexts.get(i).getRequestId() == canceledRequest) {
- if (sDebug) Slog.d(TAG, "cancelCurrentRequest(): id = " + canceledRequest);
- mContexts.remove(i);
- break;
- }
+ // It is most likely the last context, hence search backwards
+ for (int i = numContexts - 1; i >= 0; i--) {
+ if (mContexts.get(i).getRequestId() == canceledRequest) {
+ if (sDebug) Slog.d(TAG, "cancelCurrentRequest(): id = " + canceledRequest);
+ mContexts.remove(i);
+ break;
}
}
}
-
- if (mClientSuggestionsSession != null) {
- mClientSuggestionsSession.cancelCurrentRequest();
- }
}
private boolean isViewFocusedLocked(int flags) {
@@ -1225,30 +1200,17 @@
requestAssistStructureForPccLocked(flags | FLAG_PCC_DETECTION);
}
- // Only ask IME to create inline suggestions request when
- // 1. Autofill provider supports it or client enabled client suggestions.
- // 2. The render service is available.
- // 3. The view is focused. (The view may not be focused if the autofill is triggered
- // manually.)
+ // Only ask IME to create inline suggestions request if Autofill provider supports it and
+ // the render service is available except the autofill is triggered manually and the view
+ // is also not focused.
final RemoteInlineSuggestionRenderService remoteRenderService =
mService.getRemoteInlineSuggestionRenderServiceLocked();
- if ((mSessionFlags.mInlineSupportedByService || mSessionFlags.mClientSuggestionsEnabled)
- && remoteRenderService != null
- && (isViewFocusedLocked(flags) || (isRequestSupportFillDialog(flags)))) {
- final Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer;
- if (mSessionFlags.mClientSuggestionsEnabled) {
- final int finalRequestId = requestId;
- inlineSuggestionsRequestConsumer = (inlineSuggestionsRequest) -> {
- // Using client suggestions
- synchronized (mLock) {
- onClientFillRequestLocked(finalRequestId, inlineSuggestionsRequest);
- }
- viewState.resetState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
- };
- } else {
- inlineSuggestionsRequestConsumer = mAssistReceiver.newAutofillRequestLocked(
- viewState, /* isInlineRequest= */ true);
- }
+ if (mSessionFlags.mInlineSupportedByService
+ && remoteRenderService != null
+ && (isViewFocusedLocked(flags) || isRequestSupportFillDialog(flags))) {
+ Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer =
+ mAssistReceiver.newAutofillRequestLocked(viewState,
+ /* isInlineRequest= */ true);
if (inlineSuggestionsRequestConsumer != null) {
final AutofillId focusedId = mCurrentViewId;
final int requestIdCopy = requestId;
@@ -1264,18 +1226,10 @@
);
viewState.setState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
}
- } else if (mSessionFlags.mClientSuggestionsEnabled) {
- // Request client suggestions for the dropdown mode
- onClientFillRequestLocked(requestId, null);
} else {
mAssistReceiver.newAutofillRequestLocked(viewState, /* isInlineRequest= */ false);
}
- if (mSessionFlags.mClientSuggestionsEnabled) {
- // Using client suggestions, unnecessary request AssistStructure
- return;
- }
-
// Now request the assist structure data.
requestAssistStructureLocked(requestId, flags);
}
@@ -1380,11 +1334,6 @@
mSessionFlags = new SessionFlags();
mSessionFlags.mAugmentedAutofillOnly = forAugmentedAutofillOnly;
mSessionFlags.mInlineSupportedByService = mService.isInlineSuggestionsEnabledLocked();
- if (mContext.checkCallingPermission(PROVIDE_OWN_AUTOFILL_SUGGESTIONS)
- == PackageManager.PERMISSION_GRANTED) {
- mSessionFlags.mClientSuggestionsEnabled =
- (mFlags & FLAG_ENABLED_CLIENT_SUGGESTIONS) != 0;
- }
setClientLocked(client);
}
@@ -1522,15 +1471,14 @@
if (requestLog != null) {
requestLog.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, -1);
}
- processNullResponseOrFallbackLocked(requestId, requestFlags);
+ processNullResponseLocked(requestId, requestFlags);
return;
}
// TODO: Check if this is required. We can still present datasets to the user even if
// traditional field classification is disabled.
fieldClassificationIds = response.getFieldClassificationIds();
- if (!mSessionFlags.mClientSuggestionsEnabled && fieldClassificationIds != null
- && !mService.isFieldClassificationEnabledLocked()) {
+ if (fieldClassificationIds != null && !mService.isFieldClassificationEnabledLocked()) {
Slog.w(TAG, "Ignoring " + response + " because field detection is disabled");
processNullResponseLocked(requestId, requestFlags);
return;
@@ -1643,9 +1591,7 @@
|| (ArrayUtils.isEmpty(saveInfo.getOptionalIds())
&& ArrayUtils.isEmpty(saveInfo.getRequiredIds())
&& ((saveInfo.getFlags() & SaveInfo.FLAG_DELAY_SAVE) == 0)))
- && (ArrayUtils.isEmpty(response.getFieldClassificationIds())
- || (!mSessionFlags.mClientSuggestionsEnabled
- && !mService.isFieldClassificationEnabledLocked())));
+ && (ArrayUtils.isEmpty(response.getFieldClassificationIds())));
}
}
@@ -1975,40 +1921,6 @@
}
}
- @GuardedBy("mLock")
- private void processNullResponseOrFallbackLocked(int requestId, int flags) {
- if (!mSessionFlags.mClientSuggestionsEnabled) {
- processNullResponseLocked(requestId, flags);
- return;
- }
-
- // fallback to the default platform password manager
- mSessionFlags.mClientSuggestionsEnabled = false;
- mLastFillDialogTriggerIds = null;
- // Log the existing FillResponse event.
- mFillResponseEventLogger.logAndEndEvent();
-
- final InlineSuggestionsRequest inlineRequest =
- (mLastInlineSuggestionsRequest != null
- && mLastInlineSuggestionsRequest.first == requestId)
- ? mLastInlineSuggestionsRequest.second : null;
-
- // Start a new FillRequest logger for client suggestion fallback.
- mFillRequestEventLogger.startLogForNewRequest();
- mRequestCount++;
- mFillRequestEventLogger.maybeSetAppPackageUid(uid);
- mFillRequestEventLogger.maybeSetFlags(
- flags & ~FLAG_ENABLED_CLIENT_SUGGESTIONS);
- mFillRequestEventLogger.maybeSetRequestTriggerReason(
- TRIGGER_REASON_NORMAL_TRIGGER);
- mFillRequestEventLogger.maybeSetIsClientSuggestionFallback(true);
-
- mAssistReceiver.newAutofillRequestLocked(inlineRequest);
- requestAssistStructureLocked(requestId,
- flags & ~FLAG_ENABLED_CLIENT_SUGGESTIONS);
- return;
- }
-
// FillServiceCallbacks
@Override
@SuppressWarnings("GuardedBy")
@@ -4205,22 +4117,13 @@
filterText = value.getTextValue().toString();
}
- final CharSequence targetLabel;
- final Drawable targetIcon;
- synchronized (mLock) {
- if (mSessionFlags.mClientSuggestionsEnabled) {
- final ApplicationInfo appInfo = ClientSuggestionsSession.getAppInfo(mComponentName,
- mService.getUserId());
- targetLabel = ClientSuggestionsSession.getAppLabelLocked(
- mService.getMaster().getContext(), appInfo);
- targetIcon = ClientSuggestionsSession.getAppIconLocked(
- mService.getMaster().getContext(), appInfo);
- } else {
- targetLabel = mService.getServiceLabelLocked();
- targetIcon = mService.getServiceIconLocked();
- }
+ final CharSequence serviceLabel;
+ final Drawable serviceIcon;
+ synchronized (this.mService.mLock) {
+ serviceLabel = mService.getServiceLabelLocked();
+ serviceIcon = mService.getServiceIconLocked();
}
- if (targetLabel == null || targetIcon == null) {
+ if (serviceLabel == null || serviceIcon == null) {
wtf(null, "onFillReady(): no service label or icon");
return;
}
@@ -4281,7 +4184,7 @@
getUiForShowing().showFillUi(filledId, response, filterText,
mService.getServicePackageName(), mComponentName,
- targetLabel, targetIcon, this, mContext, id, mCompatMode);
+ serviceLabel, serviceIcon, this, mContext, id, mCompatMode);
synchronized (mLock) {
mPresentationStatsEventLogger.maybeSetCountShown(
@@ -4477,17 +4380,6 @@
return false;
}
- final InlineSuggestionsRequest request = inlineSuggestionsRequest.get();
- if (mSessionFlags.mClientSuggestionsEnabled && !request.isClientSupported()
- || !mSessionFlags.mClientSuggestionsEnabled && !request.isServiceSupported()) {
- if (sDebug) {
- Slog.d(TAG, "Inline suggestions not supported for "
- + (mSessionFlags.mClientSuggestionsEnabled ? "client" : "service")
- + ". Falling back to dropdown.");
- }
- return false;
- }
-
final RemoteInlineSuggestionRenderService remoteRenderService =
mService.getRemoteInlineSuggestionRenderServiceLocked();
if (remoteRenderService == null) {
@@ -4502,8 +4394,8 @@
}
final InlineFillUi.InlineFillUiInfo inlineFillUiInfo =
- new InlineFillUi.InlineFillUiInfo(request, focusedId,
- filterText, remoteRenderService, userId, id);
+ new InlineFillUi.InlineFillUiInfo(inlineSuggestionsRequest.get(), focusedId,
+ filterText, remoteRenderService, userId, id);
InlineFillUi inlineFillUi = InlineFillUi.forAutofill(inlineFillUiInfo, response,
new InlineFillUi.InlineSuggestionUiCallback() {
@Override
@@ -5154,26 +5046,6 @@
}
}
- @GuardedBy("mLock")
- private void onClientFillRequestLocked(int requestId,
- InlineSuggestionsRequest inlineSuggestionsRequest) {
- if (mClientSuggestionsSession == null) {
- mClientSuggestionsSession = new ClientSuggestionsSession(id, mClient, mHandler,
- mComponentName, this);
- }
-
- if (mContexts == null) {
- mContexts = new ArrayList<>(1);
- }
- mContexts.add(new FillContext(requestId, new AssistStructure(), mCurrentViewId));
-
- if (inlineSuggestionsRequest != null && !inlineSuggestionsRequest.isClientSupported()) {
- inlineSuggestionsRequest = null;
- }
-
- mClientSuggestionsSession.onFillRequest(requestId, inlineSuggestionsRequest, mFlags);
- }
-
/**
* The result of checking whether to show the save dialog, when session can be saved.
*
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index a3a0674..0172eaf 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -54,7 +54,6 @@
import android.app.AppOpsManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.bluetooth.BluetoothDevice;
import android.companion.AssociationInfo;
import android.companion.AssociationRequest;
import android.companion.DeviceNotAssociatedException;
@@ -108,6 +107,9 @@
import com.android.server.SystemService;
import com.android.server.companion.datatransfer.SystemDataTransferProcessor;
import com.android.server.companion.datatransfer.SystemDataTransferRequestStore;
+import com.android.server.companion.datatransfer.contextsync.CrossDeviceCall;
+import com.android.server.companion.datatransfer.contextsync.CrossDeviceSyncController;
+import com.android.server.companion.datatransfer.contextsync.CrossDeviceSyncControllerCallback;
import com.android.server.companion.presence.CompanionDevicePresenceMonitor;
import com.android.server.companion.transport.CompanionTransportManager;
import com.android.server.pm.UserManagerInternal;
@@ -117,6 +119,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -200,6 +203,8 @@
private final RemoteCallbackList<IOnAssociationsChangedListener> mListeners =
new RemoteCallbackList<>();
+ private CrossDeviceSyncController mCrossDeviceSyncController;
+
public CompanionDeviceManagerService(Context context) {
super(context);
@@ -229,7 +234,7 @@
loadAssociationsFromDisk();
mAssociationStore.registerListener(mAssociationStoreChangeListener);
- mDevicePresenceMonitor = new CompanionDevicePresenceMonitor(mUserManager,
+ mDevicePresenceMonitor = new CompanionDevicePresenceMonitor(
mAssociationStore, mDevicePresenceCallback);
mAssociationRequestsProcessor = new AssociationRequestsProcessor(
@@ -239,6 +244,8 @@
mTransportManager = new CompanionTransportManager(context, mAssociationStore);
mSystemDataTransferProcessor = new SystemDataTransferProcessor(this, mAssociationStore,
mSystemDataTransferRequestStore, mTransportManager);
+ // TODO(b/279663946): move context sync to a dedicated system service
+ mCrossDeviceSyncController = new CrossDeviceSyncController(getContext(), mTransportManager);
// Publish "binder" service.
final CompanionDeviceManagerImpl impl = new CompanionDeviceManagerImpl();
@@ -315,21 +322,6 @@
MINUTES.toMillis(10));
}
- @Override
- public void onUserUnlocked(@NonNull TargetUser user) {
- // Notify and bind the app after the phone is unlocked.
- final int userId = user.getUserIdentifier();
- final Set<BluetoothDevice> blueToothDevices =
- mDevicePresenceMonitor.getPendingReportConnectedDevices().get(userId);
- for (BluetoothDevice bluetoothDevice : blueToothDevices) {
- for (AssociationInfo ai:
- mAssociationStore.getAssociationsByAddress(bluetoothDevice.getAddress())) {
- Slog.i(TAG, "onUserUnlocked, device id( " + ai.getId() + " ) is connected");
- mDevicePresenceMonitor.onBluetoothCompanionDeviceConnected(ai.getId());
- }
- }
- }
-
@NonNull
AssociationInfo getAssociationWithCallerChecks(
@UserIdInt int userId, @NonNull String packageName, @NonNull String macAddress) {
@@ -1369,6 +1361,39 @@
public void removeInactiveSelfManagedAssociations() {
CompanionDeviceManagerService.this.removeInactiveSelfManagedAssociations();
}
+
+ @Override
+ public void registerCallMetadataSyncCallback(CrossDeviceSyncControllerCallback callback) {
+ if (CompanionDeviceConfig.isEnabled(
+ CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)) {
+ mCrossDeviceSyncController.registerCallMetadataSyncCallback(callback);
+ }
+ }
+
+ @Override
+ public void crossDeviceSync(int userId, Collection<CrossDeviceCall> calls) {
+ if (CompanionDeviceConfig.isEnabled(
+ CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)) {
+ mCrossDeviceSyncController.syncToAllDevicesForUserId(userId, calls);
+ }
+ }
+
+ @Override
+ public void crossDeviceSync(AssociationInfo associationInfo,
+ Collection<CrossDeviceCall> calls) {
+ if (CompanionDeviceConfig.isEnabled(
+ CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)) {
+ mCrossDeviceSyncController.syncToSingleDevice(associationInfo, calls);
+ }
+ }
+
+ @Override
+ public void sendCrossDeviceSyncMessage(int associationId, byte[] message) {
+ if (CompanionDeviceConfig.isEnabled(
+ CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)) {
+ mCrossDeviceSyncController.syncMessageToDevice(associationId, message);
+ }
+ }
}
/**
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerServiceInternal.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerServiceInternal.java
index 3649240..3b108e6 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerServiceInternal.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerServiceInternal.java
@@ -16,12 +16,41 @@
package com.android.server.companion;
+import android.companion.AssociationInfo;
+
+import com.android.server.companion.datatransfer.contextsync.CrossDeviceCall;
+import com.android.server.companion.datatransfer.contextsync.CrossDeviceSyncControllerCallback;
+
+import java.util.Collection;
+
/**
* Companion Device Manager Local System Service Interface.
*/
-interface CompanionDeviceManagerServiceInternal {
+public interface CompanionDeviceManagerServiceInternal {
/**
* @see CompanionDeviceManagerService#removeInactiveSelfManagedAssociations
*/
void removeInactiveSelfManagedAssociations();
+
+ /**
+ * Registers a callback from an InCallService / ConnectionService to CDM to process sync
+ * requests and perform call control actions.
+ */
+ void registerCallMetadataSyncCallback(CrossDeviceSyncControllerCallback callback);
+
+ /**
+ * Requests a sync from an InCallService / ConnectionService to CDM, for the given association
+ * and message.
+ */
+ void sendCrossDeviceSyncMessage(int associationId, byte[] message);
+
+ /**
+ * Requests a sync from an InCallService to CDM, for the given user and call metadata.
+ */
+ void crossDeviceSync(int userId, Collection<CrossDeviceCall> calls);
+
+ /**
+ * Requests a sync from an InCallService to CDM, for the given association and call metadata.
+ */
+ void crossDeviceSync(AssociationInfo associationInfo, Collection<CrossDeviceCall> calls);
}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallService.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallService.java
index ae4766a..443a732 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallService.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallService.java
@@ -17,15 +17,20 @@
package com.android.server.companion.datatransfer.contextsync;
import android.annotation.Nullable;
+import android.companion.AssociationInfo;
import android.telecom.Call;
import android.telecom.InCallService;
import android.telecom.TelecomManager;
+import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
import com.android.server.companion.CompanionDeviceConfig;
+import com.android.server.companion.CompanionDeviceManagerServiceInternal;
import java.util.Collection;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.Map;
import java.util.stream.Collectors;
@@ -35,90 +40,132 @@
*/
public class CallMetadataSyncInCallService extends InCallService {
+ private static final String TAG = "CallMetadataIcs";
private static final long NOT_VALID = -1L;
+ private CompanionDeviceManagerServiceInternal mCdmsi;
+
@VisibleForTesting
final Map<Call, CrossDeviceCall> mCurrentCalls = new HashMap<>();
- @VisibleForTesting
- boolean mShouldSync;
+ @VisibleForTesting int mNumberOfActiveSyncAssociations;
final Call.Callback mTelecomCallback = new Call.Callback() {
@Override
public void onDetailsChanged(Call call, Call.Details details) {
- mCurrentCalls.get(call).updateCallDetails(details);
- }
- };
- final CallMetadataSyncCallback mCallMetadataSyncCallback = new CallMetadataSyncCallback() {
- @Override
- void processCallControlAction(int crossDeviceCallId, int callControlAction) {
- final CrossDeviceCall crossDeviceCall = getCallForId(crossDeviceCallId,
- mCurrentCalls.values());
- switch (callControlAction) {
- case android.companion.Telecom.Call.ACCEPT:
- if (crossDeviceCall != null) {
- crossDeviceCall.doAccept();
- }
- break;
- case android.companion.Telecom.Call.REJECT:
- if (crossDeviceCall != null) {
- crossDeviceCall.doReject();
- }
- break;
- case android.companion.Telecom.Call.SILENCE:
- doSilence();
- break;
- case android.companion.Telecom.Call.MUTE:
- doMute();
- break;
- case android.companion.Telecom.Call.UNMUTE:
- doUnmute();
- break;
- case android.companion.Telecom.Call.END:
- if (crossDeviceCall != null) {
- crossDeviceCall.doEnd();
- }
- break;
- case android.companion.Telecom.Call.PUT_ON_HOLD:
- if (crossDeviceCall != null) {
- crossDeviceCall.doPutOnHold();
- }
- break;
- case android.companion.Telecom.Call.TAKE_OFF_HOLD:
- if (crossDeviceCall != null) {
- crossDeviceCall.doTakeOffHold();
- }
- break;
- default:
- }
- }
-
- @Override
- void requestCrossDeviceSync(int userId) {
- }
-
- @Override
- void updateStatus(int userId, boolean shouldSyncCallMetadata) {
- if (userId == getUserId()) {
- mShouldSync = shouldSyncCallMetadata;
- if (shouldSyncCallMetadata) {
- initializeCalls();
+ if (mNumberOfActiveSyncAssociations > 0) {
+ final CrossDeviceCall crossDeviceCall = mCurrentCalls.get(call);
+ if (crossDeviceCall != null) {
+ crossDeviceCall.updateCallDetails(details);
+ sync(getUserId());
} else {
- mCurrentCalls.clear();
+ Slog.w(TAG, "Could not update details for nonexistent call");
}
}
}
};
+ final CrossDeviceSyncControllerCallback
+ mCrossDeviceSyncControllerCallback = new CrossDeviceSyncControllerCallback() {
+ @Override
+ void processContextSyncMessage(int associationId,
+ CallMetadataSyncData callMetadataSyncData) {
+ final Iterator<CallMetadataSyncData.Call> iterator =
+ callMetadataSyncData.getRequests().iterator();
+ while (iterator.hasNext()) {
+ final CallMetadataSyncData.Call call = iterator.next();
+ if (call.getId() != 0) {
+ // The call is already assigned an id; treat as control invocations.
+ for (int control : call.getControls()) {
+ processCallControlAction(call.getId(), control);
+ }
+ }
+ iterator.remove();
+ }
+ }
+
+ private void processCallControlAction(long crossDeviceCallId,
+ int callControlAction) {
+ final CrossDeviceCall crossDeviceCall = getCallForId(crossDeviceCallId,
+ mCurrentCalls.values());
+ switch (callControlAction) {
+ case android.companion.Telecom.Call.ACCEPT:
+ if (crossDeviceCall != null) {
+ crossDeviceCall.doAccept();
+ }
+ break;
+ case android.companion.Telecom.Call.REJECT:
+ if (crossDeviceCall != null) {
+ crossDeviceCall.doReject();
+ }
+ break;
+ case android.companion.Telecom.Call.SILENCE:
+ doSilence();
+ break;
+ case android.companion.Telecom.Call.MUTE:
+ doMute();
+ break;
+ case android.companion.Telecom.Call.UNMUTE:
+ doUnmute();
+ break;
+ case android.companion.Telecom.Call.END:
+ if (crossDeviceCall != null) {
+ crossDeviceCall.doEnd();
+ }
+ break;
+ case android.companion.Telecom.Call.PUT_ON_HOLD:
+ if (crossDeviceCall != null) {
+ crossDeviceCall.doPutOnHold();
+ }
+ break;
+ case android.companion.Telecom.Call.TAKE_OFF_HOLD:
+ if (crossDeviceCall != null) {
+ crossDeviceCall.doTakeOffHold();
+ }
+ break;
+ default:
+ }
+ }
+
+ @Override
+ void requestCrossDeviceSync(AssociationInfo associationInfo) {
+ if (associationInfo.getUserId() == getUserId()) {
+ sync(associationInfo);
+ }
+ }
+
+ @Override
+ void updateNumberOfActiveSyncAssociations(int userId, boolean added) {
+ if (userId == getUserId()) {
+ final boolean wasActivelySyncing = mNumberOfActiveSyncAssociations > 0;
+ if (added) {
+ mNumberOfActiveSyncAssociations++;
+ } else {
+ mNumberOfActiveSyncAssociations--;
+ }
+ if (!wasActivelySyncing && mNumberOfActiveSyncAssociations > 0) {
+ initializeCalls();
+ } else if (wasActivelySyncing && mNumberOfActiveSyncAssociations <= 0) {
+ mCurrentCalls.clear();
+ }
+ }
+ }
+ };
@Override
public void onCreate() {
super.onCreate();
- initializeCalls();
+ if (CompanionDeviceConfig.isEnabled(CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)) {
+ mCdmsi = LocalServices.getService(CompanionDeviceManagerServiceInternal.class);
+ mCdmsi.registerCallMetadataSyncCallback(mCrossDeviceSyncControllerCallback);
+ }
}
private void initializeCalls() {
if (CompanionDeviceConfig.isEnabled(CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)
- && mShouldSync) {
+ && mNumberOfActiveSyncAssociations > 0) {
mCurrentCalls.putAll(getCalls().stream().collect(Collectors.toMap(call -> call,
call -> new CrossDeviceCall(getPackageManager(), call, getCallAudioState()))));
+ mCurrentCalls.keySet().forEach(call -> call.registerCallback(mTelecomCallback,
+ getMainThreadHandler()));
+ sync(getUserId());
}
}
@@ -139,33 +186,39 @@
@Override
public void onCallAdded(Call call) {
if (CompanionDeviceConfig.isEnabled(CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)
- && mShouldSync) {
+ && mNumberOfActiveSyncAssociations > 0) {
mCurrentCalls.put(call,
new CrossDeviceCall(getPackageManager(), call, getCallAudioState()));
+ call.registerCallback(mTelecomCallback);
+ sync(getUserId());
}
}
@Override
public void onCallRemoved(Call call) {
if (CompanionDeviceConfig.isEnabled(CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)
- && mShouldSync) {
+ && mNumberOfActiveSyncAssociations > 0) {
mCurrentCalls.remove(call);
+ call.unregisterCallback(mTelecomCallback);
+ sync(getUserId());
}
}
@Override
public void onMuteStateChanged(boolean isMuted) {
if (CompanionDeviceConfig.isEnabled(CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)
- && mShouldSync) {
+ && mNumberOfActiveSyncAssociations > 0) {
mCurrentCalls.values().forEach(call -> call.updateMuted(isMuted));
+ sync(getUserId());
}
}
@Override
public void onSilenceRinger() {
if (CompanionDeviceConfig.isEnabled(CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)
- && mShouldSync) {
+ && mNumberOfActiveSyncAssociations > 0) {
mCurrentCalls.values().forEach(call -> call.updateSilencedIfRinging());
+ sync(getUserId());
}
}
@@ -183,4 +236,12 @@
telecomManager.silenceRinger();
}
}
+
+ private void sync(int userId) {
+ mCdmsi.crossDeviceSync(userId, mCurrentCalls.values());
+ }
+
+ private void sync(AssociationInfo associationInfo) {
+ mCdmsi.crossDeviceSync(associationInfo, mCurrentCalls.values());
+ }
}
\ No newline at end of file
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java
index 3d8fb7a..adc5faf 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java
@@ -16,27 +16,32 @@
package com.android.server.companion.datatransfer.contextsync;
+import static com.android.server.companion.transport.Transport.MESSAGE_REQUEST_CONTEXT_SYNC;
+
import android.app.admin.DevicePolicyManager;
import android.companion.AssociationInfo;
import android.companion.ContextSyncMessage;
+import android.companion.IOnMessageReceivedListener;
+import android.companion.IOnTransportsChangedListener;
import android.companion.Telecom;
-import android.companion.Telecom.Call;
import android.content.Context;
+import android.os.Binder;
import android.os.UserHandle;
-import android.util.Pair;
import android.util.Slog;
+import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoOutputStream;
+import android.util.proto.ProtoParseException;
+import android.util.proto.ProtoUtils;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.companion.CompanionDeviceConfig;
+import com.android.server.companion.transport.CompanionTransportManager;
+
import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
+import java.util.ArrayList;
import java.util.Collection;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
import java.util.Set;
/**
@@ -45,149 +50,308 @@
public class CrossDeviceSyncController {
private static final String TAG = "CrossDeviceSyncController";
- private static final int BYTE_ARRAY_SIZE = 64;
+
+ private static final int VERSION_1 = 1;
+ private static final int CURRENT_VERSION = VERSION_1;
private final Context mContext;
- private final Callback mCdmCallback;
- private final Map<Integer, List<AssociationInfo>> mUserIdToAssociationInfo = new HashMap<>();
- private final Map<Integer, Pair<InputStream, OutputStream>> mAssociationIdToStreams =
- new HashMap<>();
+ private final CompanionTransportManager mCompanionTransportManager;
+ private final List<AssociationInfo> mConnectedAssociations = new ArrayList<>();
private final Set<Integer> mBlocklist = new HashSet<>();
- private CallMetadataSyncCallback mInCallServiceCallMetadataSyncCallback;
+ private CrossDeviceSyncControllerCallback mCrossDeviceSyncControllerCallback;
- public CrossDeviceSyncController(Context context, Callback callback) {
+ public CrossDeviceSyncController(Context context,
+ CompanionTransportManager companionTransportManager) {
mContext = context;
- mCdmCallback = callback;
+ mCompanionTransportManager = companionTransportManager;
+ mCompanionTransportManager.addListener(new IOnTransportsChangedListener.Stub() {
+ @Override
+ public void onTransportsChanged(List<AssociationInfo> newAssociations) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (!CompanionDeviceConfig.isEnabled(
+ CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)) {
+ return;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ final List<AssociationInfo> existingAssociations = new ArrayList<>(
+ mConnectedAssociations);
+ mConnectedAssociations.clear();
+ mConnectedAssociations.addAll(newAssociations);
+
+ if (mCrossDeviceSyncControllerCallback == null) {
+ Slog.w(TAG, "No callback to report transports changed");
+ return;
+ }
+ for (AssociationInfo associationInfo : newAssociations) {
+ if (!existingAssociations.contains(associationInfo)
+ && !isAssociationBlocked(associationInfo.getId())) {
+ mCrossDeviceSyncControllerCallback.updateNumberOfActiveSyncAssociations(
+ associationInfo.getUserId(), /* added= */ true);
+ mCrossDeviceSyncControllerCallback.requestCrossDeviceSync(associationInfo);
+ }
+ }
+ for (AssociationInfo associationInfo : existingAssociations) {
+ if (!newAssociations.contains(associationInfo)) {
+ if (isAssociationBlocked(associationInfo.getId())) {
+ mBlocklist.remove(associationInfo.getId());
+ } else {
+ mCrossDeviceSyncControllerCallback.updateNumberOfActiveSyncAssociations(
+ associationInfo.getUserId(), /* added= */ false);
+ }
+ }
+ }
+ }
+ });
+ mCompanionTransportManager.addListener(MESSAGE_REQUEST_CONTEXT_SYNC,
+ new IOnMessageReceivedListener.Stub() {
+ @Override
+ public void onMessageReceived(int associationId, byte[] data) {
+ if (mCrossDeviceSyncControllerCallback == null) {
+ Slog.w(TAG, "No callback to process context sync message");
+ return;
+ }
+ mCrossDeviceSyncControllerCallback.processContextSyncMessage(associationId,
+ processTelecomDataFromSync(data));
+ }
+ });
+ }
+
+ private boolean isAssociationBlocked(int associationId) {
+ return mBlocklist.contains(associationId);
}
/** Registers the call metadata callback. */
- public void registerCallMetadataSyncCallback(CallMetadataSyncCallback callback) {
- mInCallServiceCallMetadataSyncCallback = callback;
+ public void registerCallMetadataSyncCallback(CrossDeviceSyncControllerCallback callback) {
+ mCrossDeviceSyncControllerCallback = callback;
+ for (AssociationInfo associationInfo : mConnectedAssociations) {
+ if (!isAssociationBlocked(associationInfo.getId())) {
+ mCrossDeviceSyncControllerCallback.updateNumberOfActiveSyncAssociations(
+ associationInfo.getUserId(), /* added= */ true);
+ mCrossDeviceSyncControllerCallback.requestCrossDeviceSync(associationInfo);
+ }
+ }
}
/** Allow specific associated devices to enable / disable syncing. */
public void setSyncEnabled(AssociationInfo associationInfo, boolean enabled) {
if (enabled) {
- if (mBlocklist.contains(associationInfo.getId())) {
+ if (isAssociationBlocked(associationInfo.getId())) {
mBlocklist.remove(associationInfo.getId());
- openChannel(associationInfo);
+ mCrossDeviceSyncControllerCallback.updateNumberOfActiveSyncAssociations(
+ associationInfo.getUserId(), /* added= */ true);
+ mCrossDeviceSyncControllerCallback.requestCrossDeviceSync(associationInfo);
}
} else {
- if (!mBlocklist.contains(associationInfo.getId())) {
+ if (!isAssociationBlocked(associationInfo.getId())) {
mBlocklist.add(associationInfo.getId());
- closeChannel(associationInfo);
+ mCrossDeviceSyncControllerCallback.updateNumberOfActiveSyncAssociations(
+ associationInfo.getUserId(), /* added= */ false);
+ // Send empty message to device to clear its data (otherwise it will get stale)
+ syncMessageToDevice(associationInfo.getId(), createEmptyMessage());
}
}
}
- /**
- * Opens channels to newly associated devices, and closes channels to newly disassociated
- * devices.
- *
- * TODO(b/265466098): this needs to be limited to just connected devices
- */
- public void onAssociationsChanged(int userId, List<AssociationInfo> newAssociationInfoList) {
- final List<AssociationInfo> existingAssociationInfoList = mUserIdToAssociationInfo.get(
- userId);
- // Close channels to newly-disconnected devices.
- for (AssociationInfo existingAssociationInfo : existingAssociationInfoList) {
- if (!newAssociationInfoList.contains(existingAssociationInfo) && !mBlocklist.contains(
- existingAssociationInfo.getId())) {
- closeChannel(existingAssociationInfo);
- }
- }
- // Open channels to newly-connected devices.
- for (AssociationInfo newAssociationInfo : newAssociationInfoList) {
- if (!existingAssociationInfoList.contains(newAssociationInfo) && !mBlocklist.contains(
- newAssociationInfo.getId())) {
- openChannel(newAssociationInfo);
- }
- }
- mUserIdToAssociationInfo.put(userId, newAssociationInfoList);
- }
-
private boolean isAdminBlocked(int userId) {
return mContext.getSystemService(DevicePolicyManager.class)
.getBluetoothContactSharingDisabled(UserHandle.of(userId));
}
- /** Stop reading, close streams, and close secure channel. */
- private void closeChannel(AssociationInfo associationInfo) {
- // TODO(b/265466098): stop reading from secure channel
- final Pair<InputStream, OutputStream> streams = mAssociationIdToStreams.get(
- associationInfo.getId());
- if (streams != null) {
- try {
- if (streams.first != null) {
- streams.first.close();
- }
- if (streams.second != null) {
- streams.second.close();
- }
- } catch (IOException e) {
- Slog.e(TAG, "Could not close streams for association " + associationInfo.getId(),
- e);
- }
- }
- mCdmCallback.closeSecureChannel(associationInfo.getId());
- }
-
- /** Sync initial snapshot and start reading. */
- private void openChannel(AssociationInfo associationInfo) {
- final InputStream is = new ByteArrayInputStream(new byte[BYTE_ARRAY_SIZE]);
- final OutputStream os = new ByteArrayOutputStream(BYTE_ARRAY_SIZE);
- mAssociationIdToStreams.put(associationInfo.getId(), new Pair<>(is, os));
- mCdmCallback.createSecureChannel(associationInfo.getId(), is, os);
- // TODO(b/265466098): only requestSync for this specific association / connection?
- mInCallServiceCallMetadataSyncCallback.requestCrossDeviceSync(associationInfo.getUserId());
- // TODO(b/265466098): start reading from secure channel
- }
-
/**
* Sync data to associated devices.
*
* @param userId The user whose data should be synced.
* @param calls The full list of current calls for all users.
*/
- public void crossDeviceSync(int userId, Collection<CrossDeviceCall> calls) {
- final boolean isAdminBlocked = isAdminBlocked(userId);
- for (AssociationInfo associationInfo : mUserIdToAssociationInfo.get(userId)) {
- final Pair<InputStream, OutputStream> streams = mAssociationIdToStreams.get(
- associationInfo.getId());
- final ProtoOutputStream pos = new ProtoOutputStream(streams.second);
- final long telecomToken = pos.start(ContextSyncMessage.TELECOM);
- for (CrossDeviceCall call : calls) {
- final long callsToken = pos.start(Telecom.CALLS);
- pos.write(Call.ID, call.getId());
- final long originToken = pos.start(Call.ORIGIN);
- pos.write(Call.Origin.CALLER_ID, call.getReadableCallerId(isAdminBlocked));
- pos.write(Call.Origin.APP_ICON, call.getCallingAppIcon());
- pos.write(Call.Origin.APP_NAME, call.getCallingAppName());
- pos.end(originToken);
- pos.write(Call.STATUS, call.getStatus());
- for (int control : call.getControls()) {
- pos.write(Call.CONTROLS_AVAILABLE, control);
- }
- pos.end(callsToken);
+ public void syncToAllDevicesForUserId(int userId, Collection<CrossDeviceCall> calls) {
+ final Set<Integer> associationIds = new HashSet<>();
+ for (AssociationInfo associationInfo : mConnectedAssociations) {
+ if (associationInfo.getUserId() == userId && !isAssociationBlocked(
+ associationInfo.getId())) {
+ associationIds.add(associationInfo.getId());
}
- pos.end(telecomToken);
- pos.flush();
}
+ if (associationIds.isEmpty()) {
+ Slog.w(TAG, "No eligible devices to sync to");
+ return;
+ }
+
+ mCompanionTransportManager.sendMessage(MESSAGE_REQUEST_CONTEXT_SYNC,
+ createCallUpdateMessage(calls, userId),
+ associationIds.stream().mapToInt(Integer::intValue).toArray());
}
/**
- * Callback to be implemented by CompanionDeviceManagerService.
+ * Sync data to associated devices.
+ *
+ * @param associationInfo The association whose data should be synced.
+ * @param calls The full list of current calls for all users.
*/
- public interface Callback {
- /**
- * Create a secure channel to send messages.
- */
- void createSecureChannel(int associationId, InputStream input, OutputStream output);
+ public void syncToSingleDevice(AssociationInfo associationInfo,
+ Collection<CrossDeviceCall> calls) {
+ if (isAssociationBlocked(associationInfo.getId())) {
+ Slog.e(TAG, "Cannot sync to requested device; connection is blocked");
+ return;
+ }
- /**
- * Close the secure channel created previously.
- */
- void closeSecureChannel(int associationId);
+ mCompanionTransportManager.sendMessage(MESSAGE_REQUEST_CONTEXT_SYNC,
+ createCallUpdateMessage(calls, associationInfo.getUserId()),
+ new int[]{associationInfo.getId()});
+ }
+
+ /**
+ * Sync data to associated devices.
+ *
+ * @param associationId The association whose data should be synced.
+ * @param message The message to sync.
+ */
+ public void syncMessageToDevice(int associationId, byte[] message) {
+ if (isAssociationBlocked(associationId)) {
+ Slog.e(TAG, "Cannot sync to requested device; connection is blocked");
+ return;
+ }
+
+ mCompanionTransportManager.sendMessage(MESSAGE_REQUEST_CONTEXT_SYNC, message,
+ new int[]{associationId});
+ }
+
+ @VisibleForTesting
+ CallMetadataSyncData processTelecomDataFromSync(byte[] data) {
+ final CallMetadataSyncData callMetadataSyncData = new CallMetadataSyncData();
+ final ProtoInputStream pis = new ProtoInputStream(data);
+ try {
+ int version = -1;
+ while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ switch (pis.getFieldNumber()) {
+ case (int) ContextSyncMessage.VERSION:
+ version = pis.readInt(ContextSyncMessage.VERSION);
+ Slog.e(TAG, "Processing context sync message version " + version);
+ break;
+ case (int) ContextSyncMessage.TELECOM:
+ if (version == VERSION_1) {
+ final long telecomToken = pis.start(ContextSyncMessage.TELECOM);
+ while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ if (pis.getFieldNumber() == (int) Telecom.CALLS) {
+ final long callsToken = pis.start(Telecom.CALLS);
+ callMetadataSyncData.addCall(processCallDataFromSync(pis));
+ pis.end(callsToken);
+ } else if (pis.getFieldNumber() == (int) Telecom.REQUESTS) {
+ final long requestsToken = pis.start(Telecom.REQUESTS);
+ callMetadataSyncData.addRequest(processCallDataFromSync(pis));
+ pis.end(requestsToken);
+ } else {
+ Slog.e(TAG, "Unhandled field in Telecom:"
+ + ProtoUtils.currentFieldToString(pis));
+ }
+ }
+ pis.end(telecomToken);
+ } else {
+ Slog.e(TAG, "Cannot process unsupported version " + version);
+ }
+ break;
+ default:
+ Slog.e(TAG, "Unhandled field in ContextSyncMessage:"
+ + ProtoUtils.currentFieldToString(pis));
+ }
+ }
+ } catch (IOException | ProtoParseException e) {
+ throw new RuntimeException(e);
+ }
+ return callMetadataSyncData;
+ }
+
+ @VisibleForTesting
+ CallMetadataSyncData.Call processCallDataFromSync(ProtoInputStream pis) throws IOException {
+ final CallMetadataSyncData.Call call = new CallMetadataSyncData.Call();
+ while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ switch (pis.getFieldNumber()) {
+ case (int) Telecom.Call.ID:
+ call.setId(pis.readLong(Telecom.Call.ID));
+ break;
+ case (int) Telecom.Call.ORIGIN:
+ final long originToken = pis.start(Telecom.Call.ORIGIN);
+ while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ switch (pis.getFieldNumber()) {
+ case (int) Telecom.Call.Origin.APP_ICON:
+ call.setAppIcon(pis.readBytes(Telecom.Call.Origin.APP_ICON));
+ break;
+ case (int) Telecom.Call.Origin.APP_NAME:
+ call.setAppName(pis.readString(Telecom.Call.Origin.APP_NAME));
+ break;
+ case (int) Telecom.Call.Origin.CALLER_ID:
+ call.setCallerId(pis.readString(Telecom.Call.Origin.CALLER_ID));
+ break;
+ case (int) Telecom.Call.Origin.APP_IDENTIFIER:
+ call.setAppIdentifier(
+ pis.readString(Telecom.Call.Origin.APP_IDENTIFIER));
+ break;
+ default:
+ Slog.e(TAG, "Unhandled field in Origin:"
+ + ProtoUtils.currentFieldToString(pis));
+ }
+ }
+ pis.end(originToken);
+ break;
+ case (int) Telecom.Call.STATUS:
+ call.setStatus(pis.readInt(Telecom.Call.STATUS));
+ break;
+ case (int) Telecom.Call.CONTROLS:
+ call.addControl(pis.readInt(Telecom.Call.CONTROLS));
+ break;
+ default:
+ Slog.e(TAG,
+ "Unhandled field in Telecom:" + ProtoUtils.currentFieldToString(pis));
+ }
+ }
+ return call;
+ }
+
+ @VisibleForTesting
+ byte[] createCallUpdateMessage(Collection<CrossDeviceCall> calls, int userId) {
+ final ProtoOutputStream pos = new ProtoOutputStream();
+ pos.write(ContextSyncMessage.VERSION, CURRENT_VERSION);
+ final long telecomToken = pos.start(ContextSyncMessage.TELECOM);
+ for (CrossDeviceCall call : calls) {
+ final long callsToken = pos.start(Telecom.CALLS);
+ pos.write(Telecom.Call.ID, call.getId());
+ final long originToken = pos.start(Telecom.Call.ORIGIN);
+ pos.write(Telecom.Call.Origin.CALLER_ID,
+ call.getReadableCallerId(isAdminBlocked(userId)));
+ pos.write(Telecom.Call.Origin.APP_ICON, call.getCallingAppIcon());
+ pos.write(Telecom.Call.Origin.APP_NAME, call.getCallingAppName());
+ pos.write(Telecom.Call.Origin.APP_IDENTIFIER, call.getCallingAppPackageName());
+ pos.end(originToken);
+ pos.write(Telecom.Call.STATUS, call.getStatus());
+ for (int control : call.getControls()) {
+ pos.write(Telecom.Call.CONTROLS, control);
+ }
+ pos.end(callsToken);
+ }
+ pos.end(telecomToken);
+ return pos.getBytes();
+ }
+
+ /** Create a call control message. */
+ public static byte[] createCallControlMessage(long callId, int control) {
+ final ProtoOutputStream pos = new ProtoOutputStream();
+ pos.write(ContextSyncMessage.VERSION, CURRENT_VERSION);
+ final long telecomToken = pos.start(ContextSyncMessage.TELECOM);
+ final long requestsToken = pos.start(Telecom.REQUESTS);
+ pos.write(Telecom.Call.ID, callId);
+ pos.write(Telecom.Call.CONTROLS, control);
+ pos.end(requestsToken);
+ pos.end(telecomToken);
+ return pos.getBytes();
+ }
+
+ /** Create an empty context sync message, used to clear state. */
+ public static byte[] createEmptyMessage() {
+ final ProtoOutputStream pos = new ProtoOutputStream();
+ pos.write(ContextSyncMessage.VERSION, CURRENT_VERSION);
+ return pos.getBytes();
}
}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncCallback.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncControllerCallback.java
similarity index 67%
rename from services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncCallback.java
rename to services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncControllerCallback.java
index 7c339d2..31e10a8 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncCallback.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncControllerCallback.java
@@ -16,12 +16,14 @@
package com.android.server.companion.datatransfer.contextsync;
+import android.companion.AssociationInfo;
+
/** Callback for call metadata syncing. */
-public abstract class CallMetadataSyncCallback {
+public abstract class CrossDeviceSyncControllerCallback {
- abstract void processCallControlAction(int crossDeviceCallId, int callControlAction);
+ void processContextSyncMessage(int associationId, CallMetadataSyncData callMetadataSyncData) {}
- abstract void requestCrossDeviceSync(int userId);
+ void requestCrossDeviceSync(AssociationInfo associationInfo) {}
- abstract void updateStatus(int userId, boolean shouldSyncCallMetadata);
+ void updateNumberOfActiveSyncAssociations(int userId, boolean added) {}
}
diff --git a/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java b/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
index 82d0325..f6b99b5 100644
--- a/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
+++ b/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
@@ -27,23 +27,17 @@
import android.net.MacAddress;
import android.os.Handler;
import android.os.HandlerExecutor;
-import android.os.UserHandle;
-import android.os.UserManager;
import android.util.Log;
-import android.util.SparseArray;
-import com.android.internal.annotations.GuardedBy;
import com.android.server.companion.AssociationStore;
import java.util.Arrays;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Set;
@SuppressLint("LongLogTag")
-public class BluetoothCompanionDeviceConnectionListener
+class BluetoothCompanionDeviceConnectionListener
extends BluetoothAdapter.BluetoothConnectionCallback
implements AssociationStore.OnChangeListener {
private static final String TAG = "CDM_BluetoothCompanionDeviceConnectionListener";
@@ -54,23 +48,15 @@
void onBluetoothCompanionDeviceDisconnected(int associationId);
}
- private final UserManager mUserManager;
private final @NonNull AssociationStore mAssociationStore;
private final @NonNull Callback mCallback;
/** A set of ALL connected BT device (not only companion.) */
private final @NonNull Map<MacAddress, BluetoothDevice> mAllConnectedDevices = new HashMap<>();
-
- @GuardedBy("mPendingReportConnectedDevices")
- @NonNull
- final SparseArray<Set<BluetoothDevice>> mPendingReportConnectedDevices =
- new SparseArray<>();
-
- BluetoothCompanionDeviceConnectionListener(UserManager userManager,
- @NonNull AssociationStore associationStore, @NonNull Callback callback) {
+ BluetoothCompanionDeviceConnectionListener(@NonNull AssociationStore associationStore,
+ @NonNull Callback callback) {
mAssociationStore = associationStore;
mCallback = callback;
- mUserManager = userManager;
}
public void init(@NonNull BluetoothAdapter btAdapter) {
@@ -90,32 +76,12 @@
if (DEBUG) Log.i(TAG, "onDevice_Connected() " + btDeviceToString(device));
final MacAddress macAddress = MacAddress.fromString(device.getAddress());
- final int userId = UserHandle.myUserId();
-
if (mAllConnectedDevices.put(macAddress, device) != null) {
if (DEBUG) Log.w(TAG, "Device " + btDeviceToString(device) + " is already connected.");
return;
}
- // Try to bind and notify the app after the phone is unlocked.
- if (!mUserManager.isUserUnlockingOrUnlocked(UserHandle.myUserId())) {
- if (DEBUG) {
- Log.i(TAG, "Current user is not in unlocking or unlocked stage yet. Notify "
- + "the application when the phone is unlocked");
- }
- synchronized (mPendingReportConnectedDevices) {
- Set<BluetoothDevice> bluetoothDevices = mPendingReportConnectedDevices.get(userId);
- if (bluetoothDevices == null) {
- bluetoothDevices = new HashSet<>();
- mPendingReportConnectedDevices.put(userId, bluetoothDevices);
- }
-
- bluetoothDevices.add(device);
- }
-
- } else {
- onDeviceConnectivityChanged(device, true);
- }
+ onDeviceConnectivityChanged(device, true);
}
/**
@@ -132,8 +98,6 @@
}
final MacAddress macAddress = MacAddress.fromString(device.getAddress());
- final int userId = UserHandle.myUserId();
-
if (mAllConnectedDevices.remove(macAddress) == null) {
if (DEBUG) {
Log.w(TAG, "The device wasn't tracked as connected " + btDeviceToString(device));
@@ -141,19 +105,6 @@
return;
}
- // Do not need to report the connectivity since the user is not unlock the phone so
- // that cdm is not bind with the app yet.
- if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
- synchronized (mPendingReportConnectedDevices) {
- Set<BluetoothDevice> bluetoothDevices = mPendingReportConnectedDevices.get(userId);
- if (bluetoothDevices != null) {
- bluetoothDevices.remove(device);
- }
- }
-
- return;
- }
-
onDeviceConnectivityChanged(device, false);
}
diff --git a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
index 6c56500..4010be9 100644
--- a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
+++ b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
@@ -23,16 +23,13 @@
import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
import android.companion.AssociationInfo;
import android.content.Context;
import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.os.UserManager;
import android.util.Log;
-import android.util.SparseArray;
import com.android.server.companion.AssociationStore;
@@ -89,12 +86,13 @@
private final SimulatedDevicePresenceSchedulerHelper mSchedulerHelper =
new SimulatedDevicePresenceSchedulerHelper();
- public CompanionDevicePresenceMonitor(UserManager userManager,
- @NonNull AssociationStore associationStore, @NonNull Callback callback) {
+ public CompanionDevicePresenceMonitor(@NonNull AssociationStore associationStore,
+ @NonNull Callback callback) {
mAssociationStore = associationStore;
mCallback = callback;
- mBtConnectionListener = new BluetoothCompanionDeviceConnectionListener(userManager,
- associationStore, /* BluetoothCompanionDeviceConnectionListener.Callback */ this);
+
+ mBtConnectionListener = new BluetoothCompanionDeviceConnectionListener(associationStore,
+ /* BluetoothCompanionDeviceConnectionListener.Callback */ this);
mBleScanner = new BleCompanionDeviceScanner(associationStore,
/* BleCompanionDeviceScanner.Callback */ this);
}
@@ -300,15 +298,6 @@
// what's needed.
}
- /**
- * Return a set of devices that pending to report connectivity
- */
- public SparseArray<Set<BluetoothDevice>> getPendingReportConnectedDevices() {
- synchronized (mBtConnectionListener.mPendingReportConnectedDevices) {
- return mBtConnectionListener.mPendingReportConnectedDevices;
- }
- }
-
private static void enforceCallerShellOrRoot() {
final int callingUid = Binder.getCallingUid();
if (callingUid == SHELL_UID || callingUid == ROOT_UID) return;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 678d582..cf09fde 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -762,6 +762,15 @@
}
}
+ private static void traceInstant(@NonNull String message, @NonNull ServiceRecord service) {
+ if (!Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+ return;
+ }
+ final String serviceName = (service.getComponentName() != null)
+ ? service.getComponentName().toShortString() : "(?)";
+ Trace.instant(Trace.TRACE_TAG_ACTIVITY_MANAGER, message + serviceName);
+ }
+
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage,
@Nullable String callingFeatureId, final int userId, boolean isSdkSandboxService,
@@ -818,6 +827,9 @@
}
ServiceRecord r = res.record;
+
+ traceInstant("startService(): ", r);
+
// Note, when startService() or startForegroundService() is called on an already
// running SHORT_SERVICE FGS, the call will succeed (i.e. we won't throw
// ForegroundServiceStartNotAllowedException), even when the service is already timed
@@ -1407,6 +1419,7 @@
}
private void stopServiceLocked(ServiceRecord service, boolean enqueueOomAdj) {
+ traceInstant("stopService(): ", service);
try {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "stopServiceLocked()");
if (service.delayed) {
@@ -1946,6 +1959,7 @@
if (notification == null) {
throw new IllegalArgumentException("null notification");
}
+ traceInstant("startForeground(): ", r);
final int foregroundServiceStartType = foregroundServiceType;
// Instant apps need permission to create foreground services.
if (r.appInfo.isInstantApp()) {
@@ -2484,6 +2498,7 @@
}
} else {
if (r.isForeground) {
+ traceInstant("stopForeground(): ", r);
final ServiceMap smap = getServiceMapLocked(r.userId);
if (smap != null) {
decActiveForegroundAppLocked(smap, r);
@@ -3311,6 +3326,7 @@
Slog.i(TAG_SERVICE, "Short FGS started: " + sr);
}
}
+ traceInstant("short FGS start/extend: ", sr);
sr.setShortFgsInfo(SystemClock.uptimeMillis());
// We'll restart the timeout.
@@ -3356,10 +3372,11 @@
return;
}
Slog.e(TAG_SERVICE, "Short FGS timed out: " + sr);
- final long now = SystemClock.uptimeMillis();
+ traceInstant("short FGS timeout: ", sr);
+
logFGSStateChangeLocked(sr,
FOREGROUND_SERVICE_STATE_CHANGED__STATE__TIMED_OUT,
- now > sr.mFgsEnterTime ? (int) (now - sr.mFgsEnterTime) : 0,
+ nowUptime > sr.mFgsEnterTime ? (int) (nowUptime - sr.mFgsEnterTime) : 0,
FGS_STOP_REASON_UNKNOWN,
FGS_TYPE_POLICY_CHECK_UNKNOWN);
try {
@@ -3410,6 +3427,7 @@
}
Slog.e(TAG_SERVICE, "Short FGS procstate demoted: " + sr);
+ traceInstant("short FGS demote: ", sr);
mAm.updateOomAdjLocked(sr.app, OOM_ADJ_REASON_SHORT_FGS_TIMEOUT);
}
@@ -3440,6 +3458,9 @@
} else {
Slog.e(TAG_SERVICE, message);
}
+
+ traceInstant("short FGS ANR: ", sr);
+
mAm.appNotResponding(sr.app, tr);
// TODO: Can we close the ANR dialog here, if it's still shown? Currently, the ANR
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a54e8e9..1a5d425 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5190,7 +5190,10 @@
throw new IllegalArgumentException(
"Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
}
- if (PendingIntent.isNewMutableDisallowedImplicitPendingIntent(flags, intent)) {
+ boolean isActivityResultType =
+ type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT;
+ if (PendingIntent.isNewMutableDisallowedImplicitPendingIntent(flags, intent,
+ isActivityResultType)) {
boolean isChangeEnabled = CompatChanges.isChangeEnabled(
PendingIntent.BLOCK_MUTABLE_IMPLICIT_PENDING_INTENT,
owningUid);
@@ -6915,7 +6918,7 @@
mActivityTaskManager.unhandledBack();
}
- // TODO: Move to ContentProviderHelper?
+ // TODO: Replace this method with one that returns a bound IContentProvider.
public ParcelFileDescriptor openContentUri(String uriString) throws RemoteException {
enforceNotIsolatedCaller("openContentUri");
final int userId = UserHandle.getCallingUserId();
@@ -6944,6 +6947,16 @@
Log.e(TAG, "Cannot find package for uid: " + uid);
return null;
}
+
+ final ApplicationInfo appInfo = mPackageManagerInt.getApplicationInfo(
+ androidPackage.getPackageName(), /*flags*/0, Process.SYSTEM_UID,
+ UserHandle.USER_SYSTEM);
+ if (!appInfo.isVendor() && !appInfo.isSystemApp() && !appInfo.isSystemExt()
+ && !appInfo.isProduct()) {
+ Log.e(TAG, "openContentUri may only be used by vendor/system/product.");
+ return null;
+ }
+
final AttributionSource attributionSource = new AttributionSource(
Binder.getCallingUid(), androidPackage.getPackageName(), null);
pfd = cph.provider.openFile(attributionSource, uri, "r", null);
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index f29a2e1..c687184a 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -1199,6 +1199,9 @@
.sendToTarget();
}
+ mCachedAppsWatermarkData.updateCachedAppsHighWatermarkIfNecessaryLocked(
+ numCached + numEmpty, now);
+
if (mService.mConstants.USE_MODERN_TRIM) {
// Modern trim is not sent based on lowmem state
// Dispatch UI_HIDDEN to processes that need it
@@ -1316,8 +1319,6 @@
profile.setTrimMemoryLevel(0);
});
}
- mCachedAppsWatermarkData.updateCachedAppsHighWatermarkIfNecessaryLocked(
- numCached + numEmpty, now);
return allChanged;
}
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 1426cfd..3bc5de9 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -2100,9 +2100,12 @@
final boolean frozen;
final ProcessCachedOptimizerRecord opt = proc.mOptRecord;
- opt.setPendingFreeze(false);
-
synchronized (mProcLock) {
+ // someone has canceled this freeze
+ if (!opt.isPendingFreeze()) {
+ return;
+ }
+ opt.setPendingFreeze(false);
pid = proc.getPid();
if (mFreezerOverride) {
@@ -2148,7 +2151,6 @@
try {
traceAppFreeze(proc.processName, pid, -1);
Process.setProcessFrozen(pid, proc.uid, true);
-
opt.setFreezeUnfreezeTime(SystemClock.uptimeMillis());
opt.setFrozen(true);
opt.setHasCollectedFrozenPSS(false);
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 78aafeb..6551db9 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -643,6 +643,7 @@
pw.print(prefix); pw.print("lastUntrustedSetFgsRestrictionAllowedTime=");
TimeUtils.formatDuration(mLastUntrustedSetFgsRestrictionAllowedTime, now, pw);
+ pw.println();
if (delayed) {
pw.print(prefix); pw.print("delayed="); pw.println(delayed);
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index a181402..b2fdee7 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -3747,7 +3747,8 @@
synchronized (mUserSwitchingDialogLock) {
dismissUserSwitchingDialog(null);
mUserSwitchingDialog = new UserSwitchingDialog(mService.mContext, fromUser, toUser,
- switchingFromSystemUserMessage, switchingToSystemUserMessage);
+ switchingFromSystemUserMessage, switchingToSystemUserMessage,
+ getWindowManager());
mUserSwitchingDialog.show(onShown);
}
}
diff --git a/services/core/java/com/android/server/am/UserSwitchingDialog.java b/services/core/java/com/android/server/am/UserSwitchingDialog.java
index 649305f..412fbe79 100644
--- a/services/core/java/com/android/server/am/UserSwitchingDialog.java
+++ b/services/core/java/com/android/server/am/UserSwitchingDialog.java
@@ -19,7 +19,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.app.ActivityManager;
import android.app.Dialog;
import android.content.Context;
import android.content.pm.UserInfo;
@@ -38,6 +37,7 @@
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.util.Slog;
import android.util.TypedValue;
import android.view.View;
@@ -51,6 +51,7 @@
import com.android.internal.R;
import com.android.internal.util.ObjectUtils;
import com.android.internal.util.UserIcons;
+import com.android.server.wm.WindowManagerService;
/**
* Dialog to show during the user switch. This dialog shows target user's name and their profile
@@ -70,11 +71,14 @@
protected final UserInfo mNewUser;
private final String mSwitchingFromSystemUserMessage;
private final String mSwitchingToSystemUserMessage;
+ private final WindowManagerService mWindowManager;
protected final Context mContext;
private final int mTraceCookie;
+ private final boolean mNeedToFreezeScreen;
UserSwitchingDialog(Context context, UserInfo oldUser, UserInfo newUser,
- String switchingFromSystemUserMessage, String switchingToSystemUserMessage) {
+ String switchingFromSystemUserMessage, String switchingToSystemUserMessage,
+ WindowManagerService windowManager) {
// TODO(b/278857848): Make full screen user switcher cover top part of the screen as well.
// This problem is seen only on phones, it works fine on tablets.
super(context, R.style.Theme_Material_NoActionBar_Fullscreen);
@@ -84,8 +88,10 @@
mNewUser = newUser;
mSwitchingFromSystemUserMessage = switchingFromSystemUserMessage;
mSwitchingToSystemUserMessage = switchingToSystemUserMessage;
- mDisableAnimations = ActivityManager.isLowRamDeviceStatic() || SystemProperties.getBoolean(
+ mDisableAnimations = SystemProperties.getBoolean(
"debug.usercontroller.disable_user_switching_dialog_animations", false);
+ mWindowManager = windowManager;
+ mNeedToFreezeScreen = !mDisableAnimations && !isUserSetupComplete(newUser);
mTraceCookie = UserHandle.MAX_SECONDARY_USER_ID * oldUser.id + newUser.id;
inflateContent();
@@ -167,6 +173,11 @@
: res.getString(R.string.user_switching_message, mNewUser.name);
}
+ private boolean isUserSetupComplete(UserInfo user) {
+ return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, /* default= */ 0, user.id) == 1;
+ }
+
@Override
public void show() {
asyncTraceBegin("", 0);
@@ -176,29 +187,24 @@
@Override
public void dismiss() {
super.dismiss();
+ stopFreezingScreen();
asyncTraceEnd("", 0);
}
public void show(@NonNull Runnable onShown) {
if (DEBUG) Slog.d(TAG, "show called");
show();
-
- if (mDisableAnimations) {
+ startShowAnimation(() -> {
+ startFreezingScreen();
onShown.run();
- } else {
- startShowAnimation(onShown);
- }
+ });
}
public void dismiss(@Nullable Runnable onDismissed) {
if (DEBUG) Slog.d(TAG, "dismiss called");
-
if (onDismissed == null) {
// no animation needed
dismiss();
- } else if (mDisableAnimations) {
- dismiss();
- onDismissed.run();
} else {
startDismissAnimation(() -> {
dismiss();
@@ -207,7 +213,31 @@
}
}
+ private void startFreezingScreen() {
+ if (!mNeedToFreezeScreen) {
+ return;
+ }
+ if (DEBUG) Slog.d(TAG, "startFreezingScreen");
+ Trace.traceBegin(TRACE_TAG, "startFreezingScreen");
+ mWindowManager.startFreezingScreen(0, 0);
+ Trace.traceEnd(TRACE_TAG);
+ }
+
+ private void stopFreezingScreen() {
+ if (!mNeedToFreezeScreen) {
+ return;
+ }
+ if (DEBUG) Slog.d(TAG, "stopFreezingScreen");
+ Trace.traceBegin(TRACE_TAG, "stopFreezingScreen");
+ mWindowManager.stopFreezingScreen();
+ Trace.traceEnd(TRACE_TAG);
+ }
+
private void startShowAnimation(Runnable onAnimationEnd) {
+ if (mDisableAnimations) {
+ onAnimationEnd.run();
+ return;
+ }
asyncTraceBegin("-showAnimation", 1);
startDialogAnimation(new AlphaAnimation(0, 1), () -> {
asyncTraceEnd("-showAnimation", 1);
@@ -222,6 +252,11 @@
}
private void startDismissAnimation(Runnable onAnimationEnd) {
+ if (mDisableAnimations || mNeedToFreezeScreen) {
+ // animations are disabled or screen is frozen, no need to play an animation
+ onAnimationEnd.run();
+ return;
+ }
asyncTraceBegin("-dismissAnimation", 3);
startDialogAnimation(new AlphaAnimation(1, 0), () -> {
asyncTraceEnd("-dismissAnimation", 3);
@@ -231,8 +266,11 @@
}
private void startProgressAnimation(Runnable onAnimationEnd) {
- final ImageView progressCircular = findViewById(R.id.progress_circular);
- final AnimatedVectorDrawable avd = (AnimatedVectorDrawable) progressCircular.getDrawable();
+ final AnimatedVectorDrawable avd = getSpinnerAVD();
+ if (mDisableAnimations || avd == null) {
+ onAnimationEnd.run();
+ return;
+ }
avd.registerAnimationCallback(new Animatable2.AnimationCallback() {
@Override
public void onAnimationEnd(Drawable drawable) {
@@ -242,7 +280,23 @@
avd.start();
}
+ private AnimatedVectorDrawable getSpinnerAVD() {
+ final ImageView view = findViewById(R.id.progress_circular);
+ if (view != null) {
+ final Drawable drawable = view.getDrawable();
+ if (drawable instanceof AnimatedVectorDrawable) {
+ return (AnimatedVectorDrawable) drawable;
+ }
+ }
+ return null;
+ }
+
private void startDialogAnimation(Animation animation, Runnable onAnimationEnd) {
+ final View view = findViewById(R.id.content);
+ if (mDisableAnimations || view == null) {
+ onAnimationEnd.run();
+ return;
+ }
animation.setDuration(DIALOG_SHOW_HIDE_ANIMATION_DURATION_MS);
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
@@ -260,7 +314,7 @@
}
});
- findViewById(R.id.content).startAnimation(animation);
+ view.startAnimation(animation);
}
private void asyncTraceBegin(String subTag, int subCookie) {
diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java
index 7cdea8d..9429b4c 100644
--- a/services/core/java/com/android/server/audio/SoundDoseHelper.java
+++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java
@@ -57,6 +57,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
@@ -168,7 +169,7 @@
@NonNull private final AudioHandler mAudioHandler;
@NonNull private final ISafeHearingVolumeController mVolumeController;
- private final boolean mEnableCsd;
+ private final AtomicBoolean mEnableCsd = new AtomicBoolean(false);
private final Object mCsdStateLock = new Object();
@@ -195,7 +196,7 @@
private final ISoundDoseCallback.Stub mSoundDoseCallback = new ISoundDoseCallback.Stub() {
public void onMomentaryExposure(float currentMel, int deviceId) {
- if (!mEnableCsd) {
+ if (!mEnableCsd.get()) {
Log.w(TAG, "onMomentaryExposure: csd not supported, ignoring callback");
return;
}
@@ -222,7 +223,7 @@
}
public void onNewCsdValue(float currentCsd, SoundDoseRecord[] records) {
- if (!mEnableCsd) {
+ if (!mEnableCsd.get()) {
Log.w(TAG, "onNewCsdValue: csd not supported, ignoring value");
return;
}
@@ -272,8 +273,6 @@
mContext = context;
- mEnableCsd = mContext.getResources().getBoolean(R.bool.config_audio_csd_enabled_default);
- initCsd();
initSafeVolumes();
mSafeMediaVolumeState = mSettings.getGlobalInt(audioService.getContentResolver(),
@@ -285,6 +284,10 @@
mSafeMediaVolumeIndex = mContext.getResources().getInteger(
R.integer.config_safe_media_volume_index) * 10;
+ mSoundDose.set(AudioSystem.getSoundDoseInterface(mSoundDoseCallback));
+ // Csd will be initially disabled until the mcc is read in onConfigureSafeMedia()
+ initCsd();
+
mAlarmManager = (AlarmManager) mContext.getSystemService(
Context.ALARM_SERVICE);
}
@@ -310,7 +313,7 @@
}
float getOutputRs2UpperBound() {
- if (!mEnableCsd) {
+ if (!mEnableCsd.get()) {
return 0.f;
}
@@ -329,7 +332,7 @@
}
void setOutputRs2UpperBound(float rs2Value) {
- if (!mEnableCsd) {
+ if (!mEnableCsd.get()) {
return;
}
@@ -347,7 +350,7 @@
}
float getCsd() {
- if (!mEnableCsd) {
+ if (!mEnableCsd.get()) {
return -1.f;
}
@@ -366,7 +369,7 @@
}
void setCsd(float csd) {
- if (!mEnableCsd) {
+ if (!mEnableCsd.get()) {
return;
}
@@ -400,7 +403,7 @@
}
void resetCsdTimeouts() {
- if (!mEnableCsd) {
+ if (!mEnableCsd.get()) {
return;
}
@@ -416,7 +419,7 @@
}
void forceUseFrameworkMel(boolean useFrameworkMel) {
- if (!mEnableCsd) {
+ if (!mEnableCsd.get()) {
return;
}
@@ -434,7 +437,7 @@
}
void forceComputeCsdOnAllDevices(boolean computeCsdOnAllDevices) {
- if (!mEnableCsd) {
+ if (!mEnableCsd.get()) {
return;
}
@@ -454,7 +457,7 @@
}
boolean isCsdEnabled() {
- if (!mEnableCsd) {
+ if (!mEnableCsd.get()) {
return false;
}
@@ -697,8 +700,8 @@
}
/*package*/ void dump(PrintWriter pw) {
- pw.print(" mEnableCsd="); pw.println(mEnableCsd);
- if (mEnableCsd) {
+ pw.print(" mEnableCsd="); pw.println(mEnableCsd.get());
+ if (mEnableCsd.get()) {
synchronized (mCsdStateLock) {
pw.print(" mCurrentCsd="); pw.println(mCurrentCsd);
}
@@ -719,9 +722,11 @@
pw.println();
}
- /*package*/void reset() {
+ /*package*/void reset() {
Log.d(TAG, "Reset the sound dose helper");
- mSoundDose.set(AudioSystem.getSoundDoseInterface(mSoundDoseCallback));
+
+ mSoundDose.compareAndExchange(/*expectedValue=*/null,
+ AudioSystem.getSoundDoseInterface(mSoundDoseCallback));
synchronized (mCsdStateLock) {
try {
@@ -743,7 +748,7 @@
private void updateDoseAttenuation(int newIndex, int device, int streamType,
boolean isAbsoluteVolume) {
- if (!mEnableCsd) {
+ if (!mEnableCsd.get()) {
return;
}
@@ -775,17 +780,19 @@
}
private void initCsd() {
- if (!mEnableCsd) {
- final ISoundDose soundDose = AudioSystem.getSoundDoseInterface(mSoundDoseCallback);
- if (soundDose == null) {
- Log.w(TAG, "ISoundDose instance is null.");
- return;
- }
- try {
- soundDose.disableCsd();
- } catch (RemoteException e) {
- Log.e(TAG, "Cannot disable CSD", e);
- }
+ ISoundDose soundDose = mSoundDose.get();
+ if (soundDose == null) {
+ Log.w(TAG, "ISoundDose instance is null.");
+ return;
+ }
+
+ try {
+ soundDose.setCsdEnabled(mEnableCsd.get());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Cannot disable CSD", e);
+ }
+
+ if (!mEnableCsd.get()) {
return;
}
@@ -829,7 +836,6 @@
SystemProperties.getBoolean("audio.safemedia.force", false)
|| mContext.getResources().getBoolean(
com.android.internal.R.bool.config_safe_media_volume_enabled);
-
boolean safeMediaVolumeBypass =
SystemProperties.getBoolean("audio.safemedia.bypass", false);
@@ -860,6 +866,13 @@
mAudioHandler.obtainMessage(MSG_PERSIST_SAFE_VOLUME_STATE,
persistedState, /*arg2=*/0,
/*obj=*/null), /*delay=*/0);
+
+ boolean newEnableCsd = SystemProperties.getBoolean("audio.safemedia.force", false)
+ || mContext.getResources().getBoolean(
+ R.bool.config_safe_sound_dosage_enabled);
+ if (mEnableCsd.compareAndSet(!newEnableCsd, newEnableCsd)) {
+ initCsd();
+ }
}
}
}
@@ -913,7 +926,7 @@
// legacy implementation uses mSafeMediaVolumeIndex for wired HS/HP
// instead of computing it from the volume curves
if ((deviceType == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE
- || deviceType == AudioSystem.DEVICE_OUT_WIRED_HEADSET) && !mEnableCsd) {
+ || deviceType == AudioSystem.DEVICE_OUT_WIRED_HEADSET) && !mEnableCsd.get()) {
return mSafeMediaVolumeIndex;
}
diff --git a/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java b/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java
index aab815c..adea13f 100644
--- a/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java
+++ b/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java
@@ -102,6 +102,8 @@
return new UnsupportedOperationException(action + ": NOT_SUPPORTED");
case Result.TIMEOUT:
return new ParcelableException(new RuntimeException(action + ": TIMEOUT"));
+ case Result.CANCELED:
+ return new IllegalStateException(action + ": CANCELED");
default:
return new ParcelableException(new RuntimeException(
action + ": unknown error (" + result + ")"));
@@ -123,6 +125,8 @@
return RadioTuner.TUNER_RESULT_NOT_SUPPORTED;
case Result.TIMEOUT:
return RadioTuner.TUNER_RESULT_TIMEOUT;
+ case Result.CANCELED:
+ return RadioTuner.TUNER_RESULT_CANCELED;
case Result.UNKNOWN_ERROR:
default:
return RadioTuner.TUNER_RESULT_UNKNOWN_ERROR;
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index 1f82961..6d43061 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -41,6 +41,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.BitUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.RingBuffer;
@@ -278,6 +279,11 @@
}
}
+ private boolean hasWifiTransport(Network network) {
+ final NetworkCapabilities nc = mCm.getNetworkCapabilities(network);
+ return nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
+ }
+
@Override
public synchronized void onWakeupEvent(String prefix, int uid, int ethertype, int ipNextHeader,
byte[] dstHw, String srcIp, String dstIp, int srcPort, int dstPort, long timestampNs) {
@@ -286,12 +292,21 @@
throw new IllegalArgumentException("Prefix " + prefix
+ " required in format <nethandle>:<interface>");
}
+ final long netHandle = Long.parseLong(prefixParts[0]);
+ final Network network = Network.fromNetworkHandle(netHandle);
final WakeupEvent event = new WakeupEvent();
event.iface = prefixParts[1];
event.uid = uid;
event.ethertype = ethertype;
- event.dstHwAddr = MacAddress.fromBytes(dstHw);
+ if (ArrayUtils.isEmpty(dstHw)) {
+ if (hasWifiTransport(network)) {
+ Log.e(TAG, "Empty mac address on WiFi transport, network: " + network);
+ }
+ event.dstHwAddr = null;
+ } else {
+ event.dstHwAddr = MacAddress.fromBytes(dstHw);
+ }
event.srcIp = srcIp;
event.dstIp = dstIp;
event.ipNextHeader = ipNextHeader;
@@ -306,14 +321,12 @@
final BatteryStatsInternal bsi = LocalServices.getService(BatteryStatsInternal.class);
if (bsi != null) {
- final long netHandle = Long.parseLong(prefixParts[0]);
final long elapsedMs = SystemClock.elapsedRealtime() + event.timestampMs
- System.currentTimeMillis();
- bsi.noteCpuWakingNetworkPacket(Network.fromNetworkHandle(netHandle), elapsedMs,
- event.uid);
+ bsi.noteCpuWakingNetworkPacket(network, elapsedMs, event.uid);
}
- final String dstMac = event.dstHwAddr.toString();
+ final String dstMac = String.valueOf(event.dstHwAddr);
FrameworkStatsLog.write(FrameworkStatsLog.PACKET_WAKEUP_OCCURRED,
uid, event.iface, ethertype, dstMac, srcIp, dstIp, ipNextHeader, srcPort, dstPort);
}
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 378363c..774087c 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -366,7 +366,12 @@
return getAutomaticScreenBrightness(null);
}
- float getAutomaticScreenBrightness(BrightnessEvent brightnessEvent) {
+ /**
+ * @return The current brightness recommendation calculated from the current conditions.
+ * @param brightnessEvent Event object to populate with details about why the specific
+ * brightness was chosen.
+ */
+ public float getAutomaticScreenBrightness(BrightnessEvent brightnessEvent) {
if (brightnessEvent != null) {
brightnessEvent.setLux(
mAmbientLuxValid ? mAmbientLux : PowerManager.BRIGHTNESS_INVALID_FLOAT);
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index a4bd6a6..46cd496 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -191,7 +191,7 @@
}
if (!(createEglContext(isProtected) && createEglSurface(isProtected, isWideColor)
- && setScreenshotTextureAndSetViewport(hardwareBuffer))) {
+ && setScreenshotTextureAndSetViewport(hardwareBuffer, displayInfo.rotation))) {
dismiss();
return false;
}
@@ -500,7 +500,8 @@
}
private boolean setScreenshotTextureAndSetViewport(
- ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer) {
+ ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer,
+ @Surface.Rotation int rotation) {
if (!attachEglContext()) {
return false;
}
@@ -525,14 +526,22 @@
s.release();
st.release();
}
+ // if screen is rotated, map texture starting different corner
+ int indexDelta = (rotation == Surface.ROTATION_90) ? 2
+ : (rotation == Surface.ROTATION_180) ? 4
+ : (rotation == Surface.ROTATION_270) ? 6 : 0;
// Set up texture coordinates for a quad.
// We might need to change this if the texture ends up being
// a different size from the display for some reason.
- mTexCoordBuffer.put(0, 0f); mTexCoordBuffer.put(1, 0f);
- mTexCoordBuffer.put(2, 0f); mTexCoordBuffer.put(3, 1f);
- mTexCoordBuffer.put(4, 1f); mTexCoordBuffer.put(5, 1f);
- mTexCoordBuffer.put(6, 1f); mTexCoordBuffer.put(7, 0f);
+ mTexCoordBuffer.put(indexDelta, 0f);
+ mTexCoordBuffer.put(indexDelta + 1, 0f);
+ mTexCoordBuffer.put((indexDelta + 2) % 8, 0f);
+ mTexCoordBuffer.put((indexDelta + 3) % 8, 1f);
+ mTexCoordBuffer.put((indexDelta + 4) % 8, 1f);
+ mTexCoordBuffer.put((indexDelta + 5) % 8, 1f);
+ mTexCoordBuffer.put((indexDelta + 6) % 8, 1f);
+ mTexCoordBuffer.put((indexDelta + 7) % 8, 0f);
// Set up our viewport.
GLES20.glViewport(0, 0, mDisplayWidth, mDisplayHeight);
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 26b6cb0..5771a04 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -2548,7 +2548,6 @@
final DisplayInfo displayInfo = logicalDisplay.getDisplayInfoLocked();
captureArgs = new ScreenCapture.DisplayCaptureArgs.Builder(token)
.setSize(displayInfo.getNaturalWidth(), displayInfo.getNaturalHeight())
- .setUseIdentityTransform(true)
.setCaptureSecureLayers(true)
.setAllowProtected(true)
.build();
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 0d89ba8..0861cb5 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -83,6 +83,7 @@
import com.android.server.policy.WindowManagerPolicy;
import java.io.PrintWriter;
+import java.util.Objects;
/**
* Controls the power state of the display.
@@ -605,7 +606,7 @@
mLastBrightnessEvent = new BrightnessEvent(mDisplayId);
mTempBrightnessEvent = new BrightnessEvent(mDisplayId);
mThermalBrightnessThrottlingDataId =
- logicalDisplay.getThermalBrightnessThrottlingDataIdLocked();
+ logicalDisplay.getDisplayInfoLocked().thermalBrightnessThrottlingDataId;
if (mDisplayId == Display.DEFAULT_DISPLAY) {
mBatteryStats = BatteryStatsService.getService();
@@ -955,7 +956,7 @@
&& mLogicalDisplay.getPrimaryDisplayDeviceLocked()
.getDisplayDeviceInfoLocked().type == Display.TYPE_INTERNAL;
final String thermalBrightnessThrottlingDataId =
- mLogicalDisplay.getThermalBrightnessThrottlingDataIdLocked();
+ mLogicalDisplay.getDisplayInfoLocked().thermalBrightnessThrottlingDataId;
mHandler.postAtTime(() -> {
boolean changed = false;
if (mDisplayDevice != device) {
@@ -972,8 +973,8 @@
// last command that was sent to change it's state. Let's assume it is unknown so
// that we trigger a change immediately.
mPowerState.resetScreenState();
- } else if (
- !mThermalBrightnessThrottlingDataId.equals(thermalBrightnessThrottlingDataId)) {
+ } else if (!Objects.equals(mThermalBrightnessThrottlingDataId,
+ thermalBrightnessThrottlingDataId)) {
changed = true;
mThermalBrightnessThrottlingDataId = thermalBrightnessThrottlingDataId;
mBrightnessThrottler.loadThermalBrightnessThrottlingDataFromDisplayDeviceConfig(
@@ -2189,7 +2190,8 @@
() -> {
sendUpdatePowerState();
postBrightnessChangeRunnable();
- }, mUniqueDisplayId, mLogicalDisplay.getThermalBrightnessThrottlingDataIdLocked(),
+ }, mUniqueDisplayId,
+ mLogicalDisplay.getDisplayInfoLocked().thermalBrightnessThrottlingDataId,
ddConfig.getThermalBrightnessThrottlingDataMapByThrottlingId());
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index 9e8c47f..3b3d5da 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -85,6 +85,7 @@
import com.android.server.policy.WindowManagerPolicy;
import java.io.PrintWriter;
+import java.util.Objects;
/**
* Controls the power state of the display.
@@ -488,7 +489,7 @@
mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(context, mDisplayId);
mTag = "DisplayPowerController2[" + mDisplayId + "]";
mThermalBrightnessThrottlingDataId =
- logicalDisplay.getThermalBrightnessThrottlingDataIdLocked();
+ logicalDisplay.getDisplayInfoLocked().thermalBrightnessThrottlingDataId;
mDisplayDevice = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
mUniqueDisplayId = logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId();
@@ -760,7 +761,7 @@
&& mLogicalDisplay.getPrimaryDisplayDeviceLocked()
.getDisplayDeviceInfoLocked().type == Display.TYPE_INTERNAL;
final String thermalBrightnessThrottlingDataId =
- mLogicalDisplay.getThermalBrightnessThrottlingDataIdLocked();
+ mLogicalDisplay.getDisplayInfoLocked().thermalBrightnessThrottlingDataId;
mHandler.postAtTime(() -> {
boolean changed = false;
@@ -778,8 +779,8 @@
// last command that was sent to change it's state. Let's assume it is unknown so
// that we trigger a change immediately.
mPowerState.resetScreenState();
- } else if (
- !mThermalBrightnessThrottlingDataId.equals(thermalBrightnessThrottlingDataId)) {
+ } else if (!Objects.equals(mThermalBrightnessThrottlingDataId,
+ thermalBrightnessThrottlingDataId)) {
changed = true;
mThermalBrightnessThrottlingDataId = thermalBrightnessThrottlingDataId;
mBrightnessThrottler.loadThermalBrightnessThrottlingDataFromDisplayDeviceConfig(
@@ -1301,7 +1302,8 @@
int brightnessAdjustmentFlags = 0;
if (Float.isNaN(brightnessState)) {
if (mAutomaticBrightnessStrategy.isAutoBrightnessEnabled()) {
- brightnessState = mAutomaticBrightnessStrategy.getAutomaticScreenBrightness();
+ brightnessState = mAutomaticBrightnessStrategy.getAutomaticScreenBrightness(
+ mTempBrightnessEvent);
if (BrightnessUtils.isValidBrightnessValue(brightnessState)
|| brightnessState == PowerManager.BRIGHTNESS_OFF_FLOAT) {
rawBrightnessState = mAutomaticBrightnessController
@@ -1820,7 +1822,8 @@
() -> {
sendUpdatePowerState();
postBrightnessChangeRunnable();
- }, mUniqueDisplayId, mLogicalDisplay.getThermalBrightnessThrottlingDataIdLocked(),
+ }, mUniqueDisplayId,
+ mLogicalDisplay.getDisplayInfoLocked().thermalBrightnessThrottlingDataId,
ddConfig.getThermalBrightnessThrottlingDataMapByThrottlingId());
}
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 0b6d1c8..e5c50e6 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -203,6 +203,7 @@
mIsEnabled = true;
mIsInTransition = false;
mThermalBrightnessThrottlingDataId = DisplayDeviceConfig.DEFAULT_ID;
+ mBaseDisplayInfo.thermalBrightnessThrottlingDataId = mThermalBrightnessThrottlingDataId;
}
public void setDevicePositionLocked(int position) {
@@ -514,6 +515,7 @@
mBaseDisplayInfo.layoutLimitedRefreshRate = mLayoutLimitedRefreshRate;
mBaseDisplayInfo.thermalRefreshRateThrottling = mThermalRefreshRateThrottling;
+ mBaseDisplayInfo.thermalBrightnessThrottlingDataId = mThermalBrightnessThrottlingDataId;
mPrimaryDisplayDeviceInfo = deviceInfo;
mInfo.set(null);
@@ -886,19 +888,14 @@
}
/**
- * @return The ID of the brightness throttling data that this display should use.
- */
- public String getThermalBrightnessThrottlingDataIdLocked() {
- return mThermalBrightnessThrottlingDataId;
- }
-
- /**
* @param brightnessThrottlingDataId The ID of the brightness throttling data that this
* display should use.
*/
public void setThermalBrightnessThrottlingDataIdLocked(String brightnessThrottlingDataId) {
- mThermalBrightnessThrottlingDataId =
- brightnessThrottlingDataId;
+ if (!Objects.equals(brightnessThrottlingDataId, mThermalBrightnessThrottlingDataId)) {
+ mThermalBrightnessThrottlingDataId = brightnessThrottlingDataId;
+ mDirty = true;
+ }
}
/**
diff --git a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
index f6cf866..95cbf98 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
@@ -25,6 +25,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.display.AutomaticBrightnessController;
+import com.android.server.display.brightness.BrightnessEvent;
import com.android.server.display.brightness.BrightnessReason;
import com.android.server.display.brightness.BrightnessUtils;
@@ -252,10 +253,12 @@
/**
* Evaluates the target automatic brightness of the associated display.
+ * @param brightnessEvent Event object to populate with details about why the specific
+ * brightness was chosen.
*/
- public float getAutomaticScreenBrightness() {
+ public float getAutomaticScreenBrightness(BrightnessEvent brightnessEvent) {
float brightness = (mAutomaticBrightnessController != null)
- ? mAutomaticBrightnessController.getAutomaticScreenBrightness()
+ ? mAutomaticBrightnessController.getAutomaticScreenBrightness(brightnessEvent)
: PowerManager.BRIGHTNESS_INVALID_FLOAT;
adjustAutomaticBrightnessStateIfValid(brightness);
return brightness;
diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
index fd94be9..17f928a 100644
--- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
@@ -65,7 +65,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.display.BrightnessSynchronizer;
-import com.android.internal.display.RefreshRateSettingsUtils;
import com.android.internal.os.BackgroundThread;
import com.android.server.LocalServices;
import com.android.server.display.DisplayDeviceConfig;
@@ -1067,10 +1066,10 @@
@VisibleForTesting
final class SettingsObserver extends ContentObserver {
- private final Uri mSmoothDisplaySetting =
- Settings.System.getUriFor(Settings.System.SMOOTH_DISPLAY);
- private final Uri mForcePeakRefreshRateSetting =
- Settings.System.getUriFor(Settings.System.FORCE_PEAK_REFRESH_RATE);
+ private final Uri mPeakRefreshRateSetting =
+ Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE);
+ private final Uri mMinRefreshRateSetting =
+ Settings.System.getUriFor(Settings.System.MIN_REFRESH_RATE);
private final Uri mLowPowerModeSetting =
Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE);
private final Uri mMatchContentFrameRateSetting =
@@ -1106,8 +1105,9 @@
public void observe() {
final ContentResolver cr = mContext.getContentResolver();
- mInjector.registerSmoothDisplayObserver(cr, this);
- mInjector.registerForcePeakRefreshRateObserver(cr, this);
+ mInjector.registerPeakRefreshRateObserver(cr, this);
+ cr.registerContentObserver(mMinRefreshRateSetting, false /*notifyDescendants*/, this,
+ UserHandle.USER_SYSTEM);
cr.registerContentObserver(mLowPowerModeSetting, false /*notifyDescendants*/, this,
UserHandle.USER_SYSTEM);
cr.registerContentObserver(mMatchContentFrameRateSetting, false /*notifyDescendants*/,
@@ -1149,8 +1149,8 @@
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
synchronized (mLock) {
- if (mSmoothDisplaySetting.equals(uri)
- || mForcePeakRefreshRateSetting.equals(uri)) {
+ if (mPeakRefreshRateSetting.equals(uri)
+ || mMinRefreshRateSetting.equals(uri)) {
updateRefreshRateSettingLocked();
} else if (mLowPowerModeSetting.equals(uri)) {
updateLowPowerModeSettingLocked();
@@ -1205,9 +1205,12 @@
}
private void updateRefreshRateSettingLocked() {
- updateRefreshRateSettingLocked(RefreshRateSettingsUtils.getMinRefreshRate(mContext),
- RefreshRateSettingsUtils.getPeakRefreshRate(mContext, mDefaultPeakRefreshRate),
- mDefaultRefreshRate);
+ final ContentResolver cr = mContext.getContentResolver();
+ float minRefreshRate = Settings.System.getFloatForUser(cr,
+ Settings.System.MIN_REFRESH_RATE, 0f, cr.getUserId());
+ float peakRefreshRate = Settings.System.getFloatForUser(cr,
+ Settings.System.PEAK_REFRESH_RATE, mDefaultPeakRefreshRate, cr.getUserId());
+ updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, mDefaultRefreshRate);
}
private void updateRefreshRateSettingLocked(
@@ -2840,17 +2843,12 @@
}
interface Injector {
- Uri SMOOTH_DISPLAY_URI = Settings.System.getUriFor(Settings.System.SMOOTH_DISPLAY);
- Uri FORCE_PEAK_REFRESH_RATE_URI =
- Settings.System.getUriFor(Settings.System.FORCE_PEAK_REFRESH_RATE);
+ Uri PEAK_REFRESH_RATE_URI = Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE);
@NonNull
DeviceConfigInterface getDeviceConfig();
- void registerSmoothDisplayObserver(@NonNull ContentResolver cr,
- @NonNull ContentObserver observer);
-
- void registerForcePeakRefreshRateObserver(@NonNull ContentResolver cr,
+ void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
@NonNull ContentObserver observer);
void registerDisplayListener(@NonNull DisplayManager.DisplayListener listener,
@@ -2890,16 +2888,9 @@
}
@Override
- public void registerSmoothDisplayObserver(@NonNull ContentResolver cr,
+ public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
@NonNull ContentObserver observer) {
- cr.registerContentObserver(SMOOTH_DISPLAY_URI, false /*notifyDescendants*/,
- observer, UserHandle.USER_SYSTEM);
- }
-
- @Override
- public void registerForcePeakRefreshRateObserver(@NonNull ContentResolver cr,
- @NonNull ContentObserver observer) {
- cr.registerContentObserver(FORCE_PEAK_REFRESH_RATE_URI, false /*notifyDescendants*/,
+ cr.registerContentObserver(PEAK_REFRESH_RATE_URI, false /*notifyDescendants*/,
observer, UserHandle.USER_SYSTEM);
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
index 220a438..b82129b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
@@ -35,6 +35,7 @@
ERROR_DESTINATION,
ERROR_PARAMETER,
ERROR_PARAMETER_SHORT,
+ ERROR_PARAMETER_LONG,
})
public @interface ValidationResult {};
@@ -43,6 +44,7 @@
static final int ERROR_DESTINATION = 2;
static final int ERROR_PARAMETER = 3;
static final int ERROR_PARAMETER_SHORT = 4;
+ static final int ERROR_PARAMETER_LONG = 5;
interface ParameterValidator {
/**
@@ -159,11 +161,13 @@
addValidationInfo(Constants.MESSAGE_SET_MENU_LANGUAGE,
new AsciiValidator(3), DEST_BROADCAST);
- ParameterValidator statusRequestValidator = new OneByteRangeValidator(0x01, 0x03);
+ ParameterValidator statusRequestValidator = new MinimumOneByteRangeValidator(0x01, 0x03);
addValidationInfo(
- Constants.MESSAGE_DECK_CONTROL, new OneByteRangeValidator(0x01, 0x04), DEST_DIRECT);
+ Constants.MESSAGE_DECK_CONTROL,
+ new MinimumOneByteRangeValidator(0x01, 0x04), DEST_DIRECT);
addValidationInfo(
- Constants.MESSAGE_DECK_STATUS, new OneByteRangeValidator(0x11, 0x1F), DEST_DIRECT);
+ Constants.MESSAGE_DECK_STATUS,
+ new MinimumOneByteRangeValidator(0x11, 0x1F), DEST_DIRECT);
addValidationInfo(Constants.MESSAGE_GIVE_DECK_STATUS, statusRequestValidator, DEST_DIRECT);
addValidationInfo(Constants.MESSAGE_PLAY, new PlayModeValidator(), DEST_DIRECT);
@@ -201,9 +205,11 @@
// Messages for the Device Menu Control.
addValidationInfo(
- Constants.MESSAGE_MENU_REQUEST, new OneByteRangeValidator(0x00, 0x02), DEST_DIRECT);
+ Constants.MESSAGE_MENU_REQUEST,
+ new MinimumOneByteRangeValidator(0x00, 0x02), DEST_DIRECT);
addValidationInfo(
- Constants.MESSAGE_MENU_STATUS, new OneByteRangeValidator(0x00, 0x01), DEST_DIRECT);
+ Constants.MESSAGE_MENU_STATUS,
+ new MinimumOneByteRangeValidator(0x00, 0x01), DEST_DIRECT);
// Messages for the Remote Control Passthrough.
addValidationInfo(
@@ -214,7 +220,7 @@
// Messages for the Power Status.
addValidationInfo(
Constants.MESSAGE_REPORT_POWER_STATUS,
- new OneByteRangeValidator(0x00, 0x03),
+ new MinimumOneByteRangeValidator(0x00, 0x03),
DEST_DIRECT | DEST_BROADCAST);
// Messages for the General Protocol.
@@ -229,17 +235,17 @@
oneByteValidator, DEST_DIRECT);
addValidationInfo(
Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE,
- new OneByteRangeValidator(0x00, 0x01),
+ new MinimumOneByteRangeValidator(0x00, 0x01),
DEST_ALL);
addValidationInfo(
Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS,
- new OneByteRangeValidator(0x00, 0x01),
+ new SingleByteRangeValidator(0x00, 0x01),
DEST_DIRECT);
// Messages for the Audio Rate Control.
addValidationInfo(
Constants.MESSAGE_SET_AUDIO_RATE,
- new OneByteRangeValidator(0x00, 0x06),
+ new MinimumOneByteRangeValidator(0x00, 0x06),
DEST_DIRECT);
// Messages for Feature Discovery.
@@ -900,11 +906,14 @@
}
}
- /** Check if the given parameters are one byte parameters and within range. */
- private static class OneByteRangeValidator implements ParameterValidator {
+ /**
+ * Check if the given parameters are at least one byte parameters
+ * and the first byte is within range.
+ */
+ private static class MinimumOneByteRangeValidator implements ParameterValidator {
private final int mMinValue, mMaxValue;
- OneByteRangeValidator(int minValue, int maxValue) {
+ MinimumOneByteRangeValidator(int minValue, int maxValue) {
mMinValue = minValue;
mMaxValue = maxValue;
}
@@ -918,6 +927,26 @@
}
}
+ /** Check if the given parameters are exactly one byte parameters and within range. */
+ private static class SingleByteRangeValidator implements ParameterValidator {
+ private final int mMinValue, mMaxValue;
+
+ SingleByteRangeValidator(int minValue, int maxValue) {
+ mMinValue = minValue;
+ mMaxValue = maxValue;
+ }
+
+ @Override
+ public int isValid(byte[] params) {
+ if (params.length < 1) {
+ return ERROR_PARAMETER_SHORT;
+ } else if (params.length > 1) {
+ return ERROR_PARAMETER_LONG;
+ }
+ return toErrorCode(isWithinRange(params[0], mMinValue, mMaxValue));
+ }
+ }
+
/**
* Check if the given Analogue Timer message parameters are valid. Valid parameters should
* adhere to message description of Analogue Timer defined in CEC 1.4 Specification : Message
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 75fe63a..9cd5272 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1611,6 +1611,7 @@
@HdmiCecMessageValidator.ValidationResult
int validationResult = message.getValidationResult();
if (validationResult == HdmiCecMessageValidator.ERROR_PARAMETER
+ || validationResult == HdmiCecMessageValidator.ERROR_PARAMETER_LONG
|| !verifyPhysicalAddresses(message)) {
return Constants.ABORT_INVALID_OPERAND;
} else if (validationResult != HdmiCecMessageValidator.OK
diff --git a/services/core/java/com/android/server/infra/ServiceNameBaseResolver.java b/services/core/java/com/android/server/infra/ServiceNameBaseResolver.java
index 76ea05e..66ce5c7 100644
--- a/services/core/java/com/android/server/infra/ServiceNameBaseResolver.java
+++ b/services/core/java/com/android/server/infra/ServiceNameBaseResolver.java
@@ -268,7 +268,7 @@
}
if (enabled) {
Slog.i(TAG, "disabling default service for user " + userId);
- mDefaultServicesDisabled.removeAt(userId);
+ mDefaultServicesDisabled.delete(userId);
} else {
Slog.i(TAG, "enabling default service for user " + userId);
mDefaultServicesDisabled.put(userId, true);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index c70d555..57f8d14 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -856,13 +856,15 @@
@GuardedBy("ImfLock.class")
private final WeakHashMap<IBinder, IBinder> mImeTargetWindowMap = new WeakHashMap<>();
- private static final class SoftInputShowHideHistory {
+ @VisibleForTesting
+ static final class SoftInputShowHideHistory {
private final Entry[] mEntries = new Entry[16];
private int mNextIndex = 0;
private static final AtomicInteger sSequenceNumber = new AtomicInteger(0);
- private static final class Entry {
+ static final class Entry {
final int mSequenceNumber = sSequenceNumber.getAndIncrement();
+ @Nullable
final ClientState mClientState;
@SoftInputModeFlags
final int mFocusedWindowSoftInputMode;
@@ -874,7 +876,7 @@
final boolean mInFullscreenMode;
@NonNull
final String mFocusedWindowName;
- @NonNull
+ @Nullable
final EditorInfo mEditorInfo;
@NonNull
final String mRequestWindowName;
@@ -953,9 +955,13 @@
pw.print(prefix);
pw.print(" editorInfo: ");
- pw.print(" inputType=" + entry.mEditorInfo.inputType);
- pw.print(" privateImeOptions=" + entry.mEditorInfo.privateImeOptions);
- pw.println(" fieldId (viewId)=" + entry.mEditorInfo.fieldId);
+ if (entry.mEditorInfo != null) {
+ pw.print(" inputType=" + entry.mEditorInfo.inputType);
+ pw.print(" privateImeOptions=" + entry.mEditorInfo.privateImeOptions);
+ pw.println(" fieldId (viewId)=" + entry.mEditorInfo.fieldId);
+ } else {
+ pw.println("null");
+ }
pw.print(prefix);
pw.println(" focusedWindowSoftInputMode=" + InputMethodDebug.softInputModeToString(
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 33e6a8f1..f0ab815 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -316,7 +316,6 @@
import com.android.server.notification.toast.ToastRecord;
import com.android.server.pm.PackageManagerService;
import com.android.server.pm.UserManagerInternal;
-import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.powerstats.StatsPullAtomCallbackImpl;
import com.android.server.statusbar.StatusBarManagerInternal;
@@ -2559,8 +2558,8 @@
Context.STATS_MANAGER),
getContext().getSystemService(TelephonyManager.class),
LocalServices.getService(ActivityManagerInternal.class),
- createToastRateLimiter(), new PermissionHelper(LocalServices.getService(
- PermissionManagerServiceInternal.class), AppGlobals.getPackageManager(),
+ createToastRateLimiter(), new PermissionHelper(getContext(),
+ AppGlobals.getPackageManager(),
AppGlobals.getPermissionManager()),
LocalServices.getService(UsageStatsManagerInternal.class),
getContext().getSystemService(TelecomManager.class),
@@ -11599,6 +11598,8 @@
StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
try {
listener.onNotificationPosted(sbnHolder, rankingUpdate);
+ } catch (android.os.DeadObjectException ex) {
+ Slog.wtf(TAG, "unable to notify listener (posted): " + info, ex);
} catch (RemoteException ex) {
Slog.e(TAG, "unable to notify listener (posted): " + info, ex);
}
@@ -11620,6 +11621,8 @@
reason = REASON_LISTENER_CANCEL;
}
listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
+ } catch (android.os.DeadObjectException ex) {
+ Slog.wtf(TAG, "unable to notify listener (removed): " + info, ex);
} catch (RemoteException ex) {
Slog.e(TAG, "unable to notify listener (removed): " + info, ex);
}
@@ -11630,6 +11633,8 @@
final INotificationListener listener = (INotificationListener) info.service;
try {
listener.onNotificationRankingUpdate(rankingUpdate);
+ } catch (android.os.DeadObjectException ex) {
+ Slog.wtf(TAG, "unable to notify listener (ranking update): " + info, ex);
} catch (RemoteException ex) {
Slog.e(TAG, "unable to notify listener (ranking update): " + info, ex);
}
diff --git a/services/core/java/com/android/server/notification/PermissionHelper.java b/services/core/java/com/android/server/notification/PermissionHelper.java
index b6fd822..93c83e1 100644
--- a/services/core/java/com/android/server/notification/PermissionHelper.java
+++ b/services/core/java/com/android/server/notification/PermissionHelper.java
@@ -25,6 +25,7 @@
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
+import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -37,7 +38,6 @@
import android.util.Slog;
import com.android.internal.util.ArrayUtils;
-import com.android.server.pm.permission.PermissionManagerServiceInternal;
import java.util.Collections;
import java.util.HashSet;
@@ -53,13 +53,13 @@
private static final String NOTIFICATION_PERMISSION = Manifest.permission.POST_NOTIFICATIONS;
- private final PermissionManagerServiceInternal mPmi;
+ private final Context mContext;
private final IPackageManager mPackageManager;
private final IPermissionManager mPermManager;
- public PermissionHelper(PermissionManagerServiceInternal pmi, IPackageManager packageManager,
+ public PermissionHelper(Context context, IPackageManager packageManager,
IPermissionManager permManager) {
- mPmi = pmi;
+ mContext = context;
mPackageManager = packageManager;
mPermManager = permManager;
}
@@ -71,7 +71,7 @@
public boolean hasPermission(int uid) {
final long callingId = Binder.clearCallingIdentity();
try {
- return mPmi.checkUidPermission(uid, NOTIFICATION_PERMISSION) == PERMISSION_GRANTED;
+ return mContext.checkPermission(NOTIFICATION_PERMISSION, -1, uid) == PERMISSION_GRANTED;
} finally {
Binder.restoreCallingIdentity(callingId);
}
@@ -193,8 +193,8 @@
return;
}
- boolean currentlyGranted = mPmi.checkPermission(packageName, NOTIFICATION_PERMISSION,
- userId) != PackageManager.PERMISSION_DENIED;
+ int uid = mPackageManager.getPackageUid(packageName, 0, userId);
+ boolean currentlyGranted = hasPermission(uid);
if (grant && !currentlyGranted) {
mPermManager.grantRuntimePermission(packageName, NOTIFICATION_PERMISSION, userId);
} else if (!grant && currentlyGranted) {
diff --git a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
index 48ee64f..8a28888 100644
--- a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
+++ b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
@@ -437,6 +437,16 @@
.addCategory(Intent.CATEGORY_DEFAULT)
.build();
+ private static final DefaultCrossProfileIntentFilter CLONE_TO_PARENT_PHOTOPICKER_SELECTION =
+ new DefaultCrossProfileIntentFilter.Builder(
+ DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
+ /* flags= */ 0x00000018, // 0x00000018 means FLAG_IS_PACKAGE_FOR_FILTER
+ // and FLAG_ALLOW_CHAINED_RESOLUTION set
+ /* letsPersonalDataIntoProfile= */ false)
+ .addAction(MediaStore.ACTION_USER_SELECT_IMAGES_FOR_APP)
+ .addCategory(Intent.CATEGORY_DEFAULT)
+ .build();
+
/*
Allowing send action from clone to parent profile to share content from clone apps to parent
apps
@@ -611,7 +621,8 @@
CLONE_TO_PARENT_VIEW_ACTION,
CLONE_TO_PARENT_PICK_INSERT_ACTION,
CLONE_TO_PARENT_DIAL_DATA,
- CLONE_TO_PARENT_SMS_MMS
+ CLONE_TO_PARENT_SMS_MMS,
+ CLONE_TO_PARENT_PHOTOPICKER_SELECTION
);
}
}
diff --git a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
index 92f00113..9c3b38a 100644
--- a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
+++ b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
@@ -395,7 +395,7 @@
private class KeyHandler extends Handler {
KeyHandler() {
- super(Looper.getMainLooper());
+ super(Looper.myLooper());
}
@Override
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 580b4d6..077f8d5 100755
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -1124,18 +1124,6 @@
}
}
- private boolean setTvMessageEnabled(int deviceId, TvStreamConfig streamConfig, int type,
- boolean enabled) {
- synchronized (mImplLock) {
- if (mReleased) {
- return false;
- }
-
- return mHal.setTvMessageEnabled(deviceId, streamConfig, type, enabled)
- == TvInputHal.SUCCESS;
- }
- }
-
private boolean startCapture(Surface surface, TvStreamConfig config) {
synchronized (mImplLock) {
if (mReleased) {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 98d2d3d..9020cb3 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1353,9 +1353,6 @@
void complete() {
// Only changes from home+lock to just home or lock need attention
- // If setting the wallpaper fails, this callback will be called
- // when the wallpaper is detached, in which case wallpapers may have
- // already changed. Make sure we're not overwriting a more recent wallpaper.
if (mNewWallpaper.mSystemWasBoth) {
if (DEBUG) {
Slog.v(TAG, "Handling change from system+lock wallpaper");
@@ -1378,7 +1375,8 @@
mOriginalSystem.wallpaperComponent;
lockWp.connection = mOriginalSystem.connection;
lockWp.connection.mWallpaper = lockWp;
- updateEngineFlags(mOriginalSystem, FLAG_LOCK);
+ mOriginalSystem.mWhich = FLAG_LOCK;
+ updateEngineFlags(mOriginalSystem);
notifyWallpaperColorsChanged(lockWp, FLAG_LOCK);
} else {
// Failed rename, use current system wp for both
@@ -1387,7 +1385,7 @@
}
WallpaperData currentSystem = mWallpaperMap.get(mNewWallpaper.userId);
currentSystem.mWhich = FLAG_SYSTEM | FLAG_LOCK;
- updateEngineFlags(currentSystem, FLAG_SYSTEM | FLAG_LOCK);
+ updateEngineFlags(currentSystem);
mLockWallpaperMap.remove(mNewWallpaper.userId);
}
} else {
@@ -1396,7 +1394,7 @@
Slog.v(TAG, "live system+lock to system success");
}
mOriginalSystem.mWhich = FLAG_LOCK;
- updateEngineFlags(mOriginalSystem, FLAG_LOCK);
+ updateEngineFlags(mOriginalSystem);
mLockWallpaperMap.put(mNewWallpaper.userId, mOriginalSystem);
mLastLockWallpaper = mOriginalSystem;
notifyWallpaperColorsChanged(mOriginalSystem, FLAG_LOCK);
@@ -1409,7 +1407,7 @@
WallpaperData currentSystem = mWallpaperMap.get(mNewWallpaper.userId);
if (currentSystem.wallpaperId == mOriginalSystem.wallpaperId) {
currentSystem.mWhich = FLAG_SYSTEM;
- updateEngineFlags(currentSystem, FLAG_SYSTEM);
+ updateEngineFlags(currentSystem);
}
}
}
@@ -1422,24 +1420,6 @@
Slog.v(TAG, "new lastLockWp: " + mLastLockWallpaper);
}
}
-
- private void updateEngineFlags(WallpaperData wallpaper, @SetWallpaperFlags int which) {
- if (wallpaper.connection == null) {
- return;
- }
- wallpaper.connection.forEachDisplayConnector(
- connector -> {
- try {
- if (connector.mEngine != null) {
- connector.mEngine.setWallpaperFlags(which);
- mWindowManagerInternal.setWallpaperShowWhenLocked(
- connector.mToken, (which & FLAG_LOCK) != 0);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to update wallpaper engine flags", e);
- }
- });
- }
}
class MyPackageMonitor extends PackageMonitor {
@@ -3095,6 +3075,9 @@
newWallpaper.userId);
if (lockedWallpaper != null) {
detachWallpaperLocked(lockedWallpaper);
+ if (same) {
+ updateEngineFlags(newWallpaper);
+ }
}
mLockWallpaperMap.remove(newWallpaper.userId);
}
@@ -3430,6 +3413,27 @@
}
}
+ // Updates the given wallpaper's Engine so that its destination flags are the same as those of
+ // the wallpaper, e.g., after a wallpaper has been changed from displaying on home+lock to home
+ // or lock only.
+ private void updateEngineFlags(WallpaperData wallpaper) {
+ if (wallpaper.connection == null) {
+ return;
+ }
+ wallpaper.connection.forEachDisplayConnector(
+ connector -> {
+ try {
+ if (connector.mEngine != null) {
+ connector.mEngine.setWallpaperFlags(wallpaper.mWhich);
+ mWindowManagerInternal.setWallpaperShowWhenLocked(
+ connector.mToken, (wallpaper.mWhich & FLAG_LOCK) != 0);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to update wallpaper engine flags", e);
+ }
+ });
+ }
+
private void clearWallpaperComponentLocked(WallpaperData wallpaper) {
wallpaper.wallpaperComponent = null;
detachWallpaperLocked(wallpaper);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 78c066b..c3cd3ec 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -5400,7 +5400,9 @@
return;
}
if (inFinishingTransition) {
- // Let the finishing transition commit the visibility.
+ // Let the finishing transition commit the visibility, but let the controller know
+ // about it so that we can recover from degenerate cases.
+ mTransitionController.mValidateCommitVis.add(this);
return;
}
// If we are preparing an app transition, then delay changing
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index f5079d3..e47787e 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -33,6 +33,7 @@
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.os.Process.SYSTEM_UID;
+import static android.view.MotionEvent.CLASSIFICATION_MULTI_FINGER_SWIPE;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
@@ -209,7 +210,8 @@
private final PointerEventListener mListener = new PointerEventListener() {
@Override
public void onPointerEvent(MotionEvent ev) {
- if (!mFreezeTaskListReordering || ev.getAction() != MotionEvent.ACTION_DOWN) {
+ if (!mFreezeTaskListReordering || ev.getAction() != MotionEvent.ACTION_DOWN
+ || ev.getClassification() == CLASSIFICATION_MULTI_FINGER_SWIPE) {
// Skip if we aren't freezing or starting a gesture
return;
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 3f4296a..d3edeae 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -3239,7 +3239,7 @@
if (task.getActivity(activity -> !activity.finishing && activity.mUserId == userId)
!= null) {
mService.getTaskChangeNotificationController().notifyTaskProfileLocked(
- task.getTaskInfo());
+ task.getTaskInfo(), userId);
}
}, true /* traverseTopToBottom */);
}
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index b5df3e0..bbb8563 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -193,6 +193,7 @@
.setSourceCrop(new Rect(0, 0, width, height))
.setAllowProtected(true)
.setCaptureSecureLayers(true)
+ .setHintForSeamlessTransition(true)
.build();
screenshotBuffer = ScreenCapture.captureDisplay(captureArgs);
} else {
@@ -202,6 +203,7 @@
.setCaptureSecureLayers(true)
.setAllowProtected(true)
.setSourceCrop(new Rect(0, 0, width, height))
+ .setHintForSeamlessTransition(true)
.build();
screenshotBuffer = ScreenCapture.captureLayers(captureArgs);
}
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index 49d064f..9324e29 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -144,7 +144,7 @@
};
private final TaskStackConsumer mNotifyTaskProfileLocked = (l, m) -> {
- l.onTaskProfileLocked((RunningTaskInfo) m.obj);
+ l.onTaskProfileLocked((RunningTaskInfo) m.obj, m.arg1);
};
private final TaskStackConsumer mNotifyTaskSnapshotChanged = (l, m) -> {
@@ -467,9 +467,9 @@
* Notify listeners that the task has been put in a locked state because one or more of the
* activities inside it belong to a managed profile user that has been locked.
*/
- void notifyTaskProfileLocked(ActivityManager.RunningTaskInfo taskInfo) {
+ void notifyTaskProfileLocked(RunningTaskInfo taskInfo, int userId) {
final Message msg = mHandler.obtainMessage(NOTIFY_TASK_PROFILE_LOCKED_LISTENERS_MSG,
- taskInfo);
+ userId, 0, taskInfo);
forAllLocalListeners(mNotifyTaskProfileLocked, msg);
msg.sendToTarget();
}
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index d531ad1..7bd3b32 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -55,6 +55,7 @@
import static android.window.TransitionInfo.FLAG_TASK_LAUNCHING_BEHIND;
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
import static android.window.TransitionInfo.FLAG_WILL_IME_SHOWN;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_PENDING_INTENT;
import static com.android.server.wm.ActivityRecord.State.RESUMED;
import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM;
@@ -65,12 +66,14 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.ActivityOptions;
import android.app.IApplicationThread;
import android.content.pm.ActivityInfo;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.os.Binder;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.RemoteException;
@@ -85,6 +88,7 @@
import android.view.WindowManager;
import android.window.ScreenCapture;
import android.window.TransitionInfo;
+import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
@@ -185,7 +189,7 @@
final ArraySet<WindowContainer> mParticipants = new ArraySet<>();
/** The final animation targets derived from participants after promotion. */
- private ArrayList<ChangeInfo> mTargets;
+ ArrayList<ChangeInfo> mTargets;
/** The displays that this transition is running on. */
private final ArrayList<DisplayContent> mTargetDisplays = new ArrayList<>();
@@ -271,9 +275,14 @@
/** Any 2 transitions of this type can run in parallel with each other. Used for testing. */
static final int PARALLEL_TYPE_MUTUAL = 1;
+ /** This is a recents transition. */
+ static final int PARALLEL_TYPE_RECENTS = 2;
+
+
@IntDef(prefix = { "PARALLEL_TYPE_" }, value = {
PARALLEL_TYPE_NONE,
- PARALLEL_TYPE_MUTUAL
+ PARALLEL_TYPE_MUTUAL,
+ PARALLEL_TYPE_RECENTS
})
@Retention(RetentionPolicy.SOURCE)
@interface ParallelType {}
@@ -328,6 +337,21 @@
mFlags |= flag;
}
+ void calcParallelCollectType(WindowContainerTransaction wct) {
+ for (int i = 0; i < wct.getHierarchyOps().size(); ++i) {
+ final WindowContainerTransaction.HierarchyOp hop = wct.getHierarchyOps().get(i);
+ if (hop.getType() != HIERARCHY_OP_TYPE_PENDING_INTENT) continue;
+ final Bundle b = hop.getLaunchOptions();
+ if (b == null || b.isEmpty()) continue;
+ final boolean transientLaunch = b.getBoolean(ActivityOptions.KEY_TRANSIENT_LAUNCH);
+ if (transientLaunch) {
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ "Starting a Recents transition which can be parallel.");
+ mParallelCollectType = PARALLEL_TYPE_RECENTS;
+ }
+ }
+ }
+
/** Records an activity as transient-launch. This activity must be already collected. */
void setTransientLaunch(@NonNull ActivityRecord activity, @Nullable Task restoreBelow) {
if (mTransientLaunches == null) {
@@ -380,6 +404,10 @@
return false;
}
+ boolean hasTransientLaunch() {
+ return mTransientLaunches != null && !mTransientLaunches.isEmpty();
+ }
+
boolean isTransientLaunch(@NonNull ActivityRecord activity) {
return mTransientLaunches != null && mTransientLaunches.containsKey(activity);
}
@@ -984,13 +1012,20 @@
// Record all the now-hiding activities so that they are committed. Just use
// mParticipants because we can avoid a new list this way.
for (int i = 0; i < mTransientHideTasks.size(); ++i) {
- // Only worry about tasks that were actually hidden. Otherwise, we could end-up
- // committing visibility for activity-level changes that aren't part of this
- // transition.
- if (mTransientHideTasks.get(i).isVisibleRequested()) continue;
- mTransientHideTasks.get(i).forAllActivities(r -> {
+ final Task rootTask = mTransientHideTasks.get(i);
+ rootTask.forAllActivities(r -> {
// Only check leaf-tasks that were collected
if (!mParticipants.contains(r.getTask())) return;
+ if (rootTask.isVisibleRequested()) {
+ // This transient-hide didn't hide, so don't commit anything (otherwise we
+ // could prematurely commit invisible on unrelated activities). To be safe,
+ // though, notify the controller to prevent degenerate cases.
+ if (!r.isVisibleRequested()) {
+ mController.mValidateCommitVis.add(r);
+ }
+ return;
+ }
+ // This did hide: commit immediately so that other transitions know about it.
mParticipants.add(r);
});
}
@@ -2964,11 +2999,14 @@
Rect cropBounds = new Rect(bounds);
cropBounds.offsetTo(0, 0);
+ final boolean isDisplayRotation = wc.asDisplayContent() != null
+ && wc.asDisplayContent().isRotationChanging();
ScreenCapture.LayerCaptureArgs captureArgs =
new ScreenCapture.LayerCaptureArgs.Builder(wc.getSurfaceControl())
.setSourceCrop(cropBounds)
.setCaptureSecureLayers(true)
.setAllowProtected(true)
+ .setHintForSeamlessTransition(isDisplayRotation)
.build();
ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
ScreenCapture.captureLayers(captureArgs);
@@ -2979,8 +3017,6 @@
Slog.w(TAG, "Failed to capture screenshot for " + wc);
return false;
}
- final boolean isDisplayRotation = wc.asDisplayContent() != null
- && wc.asDisplayContent().isRotationChanging();
// Some tests may check the name "RotationLayer" to detect display rotation.
final String name = isDisplayRotation ? "RotationLayer" : "transition snapshot: " + wc;
SurfaceControl snapshotSurface = wc.makeAnimationLeash()
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 7950eda..e1da91a 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -133,6 +133,13 @@
final ArrayList<Runnable> mStateValidators = new ArrayList<>();
/**
+ * List of activity-records whose visibility changed outside the main/tracked part of a
+ * transition (eg. in the finish-transaction). These will be checked when idle to recover from
+ * degenerate states.
+ */
+ final ArrayList<ActivityRecord> mValidateCommitVis = new ArrayList<>();
+
+ /**
* Currently playing transitions (in the order they were started). When finished, records are
* removed from this list.
*/
@@ -848,6 +855,15 @@
}
}
mStateValidators.clear();
+ for (int i = 0; i < mValidateCommitVis.size(); ++i) {
+ final ActivityRecord ar = mValidateCommitVis.get(i);
+ if (!ar.isVisibleRequested() && ar.isVisible()) {
+ Slog.e(TAG, "Uncommitted visibility change: " + ar);
+ ar.commitVisibility(ar.isVisibleRequested(), false /* layout */,
+ false /* fromTransition */);
+ }
+ }
+ mValidateCommitVis.clear();
}
/**
@@ -879,6 +895,8 @@
// If it's a legacy sync, then it needs to wait until there is no collecting transition.
if (queued.mTransition == null) return;
if (!canStartCollectingNow(queued.mTransition)) return;
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Moving #%d from collecting"
+ + " to waiting.", mCollectingTransition.getSyncId());
mWaitingTransitions.add(mCollectingTransition);
mCollectingTransition = null;
} else if (mSyncEngine.hasActiveSync()) {
@@ -930,10 +948,37 @@
* in {@link #getIsIndependent} later.
*/
boolean getCanBeIndependent(Transition collecting, Transition queued) {
+ // For tests
if (queued.mParallelCollectType == Transition.PARALLEL_TYPE_MUTUAL
&& collecting.mParallelCollectType == Transition.PARALLEL_TYPE_MUTUAL) {
return true;
}
+ // For recents
+ if (queued.mParallelCollectType == Transition.PARALLEL_TYPE_RECENTS) {
+ if (collecting.mParallelCollectType == Transition.PARALLEL_TYPE_RECENTS) {
+ // Must serialize with itself.
+ return false;
+ }
+ // allow this if `collecting` only has activities
+ for (int i = 0; i < collecting.mParticipants.size(); ++i) {
+ final WindowContainer wc = collecting.mParticipants.valueAt(i);
+ final ActivityRecord ar = wc.asActivityRecord();
+ if (ar == null && wc.asWindowState() == null && wc.asWindowToken() == null) {
+ // Is task or above, so can't be independent
+ return false;
+ }
+ if (ar != null && ar.isActivityTypeHomeOrRecents()) {
+ // It's a recents or home type, so it conflicts.
+ return false;
+ }
+ }
+ return true;
+ } else if (collecting.mParallelCollectType == Transition.PARALLEL_TYPE_RECENTS) {
+ // We can collect simultaneously with recents if it is populated. This is because
+ // we know that recents will not collect/trampoline any more stuff. If anything in the
+ // queued transition overlaps, it will end up just waiting in sync-queue anyways.
+ return true;
+ }
return false;
}
@@ -942,11 +987,47 @@
* `running` is playing based on its current state.
*/
static boolean getIsIndependent(Transition running, Transition incoming) {
+ // For tests
if (running.mParallelCollectType == Transition.PARALLEL_TYPE_MUTUAL
&& incoming.mParallelCollectType == Transition.PARALLEL_TYPE_MUTUAL) {
return true;
}
- return false;
+ // For now there's only one mutually-independent pair: an all activity-level transition and
+ // a transient-launch where none of the activities are part of the transient-launch task,
+ // so the following logic is hard-coded specifically for this.
+ // Also, we currently restrict valid transient-launches to just recents.
+ final Transition recents;
+ final Transition other;
+ if (running.mParallelCollectType == Transition.PARALLEL_TYPE_RECENTS
+ && running.hasTransientLaunch()) {
+ if (incoming.mParallelCollectType == Transition.PARALLEL_TYPE_RECENTS) {
+ // Recents can't be independent from itself.
+ return false;
+ }
+ recents = running;
+ other = incoming;
+ } else if (incoming.mParallelCollectType == Transition.PARALLEL_TYPE_RECENTS
+ && incoming.hasTransientLaunch()) {
+ recents = incoming;
+ other = running;
+ } else {
+ return false;
+ }
+ // Check against *targets* because that is the post-promotion set of containers that are
+ // actually animating.
+ for (int i = 0; i < other.mTargets.size(); ++i) {
+ final WindowContainer wc = other.mTargets.get(i).mContainer;
+ final ActivityRecord ar = wc.asActivityRecord();
+ if (ar == null && wc.asWindowState() == null && wc.asWindowToken() == null) {
+ // Is task or above, so for now don't let them be independent.
+ return false;
+ }
+ if (ar != null && recents.isTransientLaunch(ar)) {
+ // Change overlaps with recents, so serialize.
+ return false;
+ }
+ }
+ return true;
}
void assignTrack(Transition transition, TransitionInfo info) {
@@ -970,9 +1051,15 @@
if (track < 0) {
// Didn't overlap with anything, so give it its own track
track = mTrackCount;
+ if (track > 0) {
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Playing #%d in parallel on "
+ + "track #%d", transition.getSyncId(), track);
+ }
}
if (sync) {
info.setFlags(info.getFlags() | TransitionInfo.FLAG_SYNC);
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Marking #%d animation as SYNC.",
+ transition.getSyncId());
}
transition.mAnimationTrack = track;
info.setTrack(track);
@@ -1145,6 +1232,8 @@
// Check if we can run in parallel here.
if (canStartCollectingNow(transit)) {
// start running in parallel.
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Moving #%d from"
+ + " collecting to waiting.", mCollectingTransition.getSyncId());
mWaitingTransitions.add(mCollectingTransition);
mCollectingTransition = null;
moveToCollecting(transit);
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 510e675..a5cdd0b 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -3594,8 +3594,11 @@
&& !mTransitionController.useShellTransitionsRotation()) {
if (deltaRotation != Surface.ROTATION_0) {
updateSurfaceRotation(t, deltaRotation, null /* positionLeash */);
+ t.setFixedTransformHint(mSurfaceControl,
+ getWindowConfiguration().getDisplayRotation());
} else if (deltaRotation != mLastDeltaRotation) {
t.setMatrix(mSurfaceControl, 1, 0, 0, 1);
+ t.unsetFixedTransformHint(mSurfaceControl);
}
}
mLastDeltaRotation = deltaRotation;
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index cd42528..d5aa520 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -299,6 +299,7 @@
final boolean needsSetReady = t != null;
final Transition nextTransition = new Transition(type, 0 /* flags */,
mTransitionController, mService.mWindowManager.mSyncEngine);
+ nextTransition.calcParallelCollectType(wct);
mTransitionController.startCollectOrQueue(nextTransition,
(deferred) -> {
nextTransition.start();
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 6f07b77..032f08a 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1980,19 +1980,16 @@
/**
* Like isOnScreen(), but we don't return true if the window is part
- * of a transition but has not yet started animating.
+ * of a transition that has not yet been started.
*/
boolean isReadyForDisplay() {
- if (!mHasSurface || mDestroying || !isVisibleByPolicy()) {
- return false;
- }
- if (mToken.waitingToShow && getDisplayContent().mAppTransition.isTransitionSet()
- && !isAnimating(TRANSITION | PARENTS, ANIMATION_TYPE_APP_TRANSITION)) {
+ if (mToken.waitingToShow && getDisplayContent().mAppTransition.isTransitionSet()) {
return false;
}
final boolean parentAndClientVisible = !isParentWindowHidden()
&& mViewVisibility == View.VISIBLE && mToken.isVisible();
- return parentAndClientVisible || isAnimating(TRANSITION | PARENTS, ANIMATION_TYPE_ALL);
+ return mHasSurface && isVisibleByPolicy() && !mDestroying
+ && (parentAndClientVisible || isAnimating(TRANSITION | PARENTS));
}
boolean isFullyTransparent() {
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index da54b15..4c5efef 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -596,6 +596,7 @@
.build();
t.setPosition(leash, mLastSurfacePosition.x, mLastSurfacePosition.y);
t.reparent(getSurfaceControl(), leash);
+ t.setFixedTransformHint(leash, getWindowConfiguration().getDisplayRotation());
mFixedRotationTransformLeash = leash;
updateSurfaceRotation(t, rotation, mFixedRotationTransformLeash);
return mFixedRotationTransformLeash;
diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
index fc7fd1a..b073ff4 100644
--- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
@@ -98,7 +98,9 @@
mRequestId, mClientRequest,
mClientAppInfo.getPackageName(),
PermissionUtils.hasPermission(mContext, mClientAppInfo.getPackageName(),
- Manifest.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS)),
+ Manifest.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS),
+ // TODO(b/279480457): populate
+ /*defaultProviderId=*/new ArrayList<>()),
providerDataList);
mClientCallback.onPendingIntent(mPendingIntent);
} catch (RemoteException e) {
diff --git a/services/credentials/java/com/android/server/credentials/MetricUtilities.java b/services/credentials/java/com/android/server/credentials/MetricUtilities.java
index 50e5163..4e82ee7 100644
--- a/services/credentials/java/com/android/server/credentials/MetricUtilities.java
+++ b/services/credentials/java/com/android/server/credentials/MetricUtilities.java
@@ -35,6 +35,7 @@
/**
* For all future metric additions, this will contain their names for local usage after importing
* from {@link com.android.internal.util.FrameworkStatsLog}.
+ * TODO(b/271135048) - Emit all atoms, including all V4 atoms (specifically the rest of track 1).
*/
public class MetricUtilities {
private static final boolean LOG_FLAG = true;
diff --git a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
index 520b937..40514b2 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
@@ -75,7 +75,8 @@
CreateCredentialRequest providerCreateRequest =
createProviderRequest(providerInfo.getCapabilities(),
createRequestSession.mClientRequest,
- createRequestSession.mClientAppInfo);
+ createRequestSession.mClientAppInfo,
+ providerInfo.isSystemProvider());
if (providerCreateRequest != null) {
return new ProviderCreateSession(
context,
@@ -114,9 +115,16 @@
}
@Nullable
- private static CreateCredentialRequest createProviderRequest(List<String> providerCapabilities,
+ private static CreateCredentialRequest createProviderRequest(
+ List<String> providerCapabilities,
android.credentials.CreateCredentialRequest clientRequest,
- CallingAppInfo callingAppInfo) {
+ CallingAppInfo callingAppInfo,
+ boolean isSystemProvider) {
+ if (clientRequest.isSystemProviderRequired() && !isSystemProvider) {
+ // Request requires system provider but this session does not correspond to a
+ // system service
+ return null;
+ }
String capability = clientRequest.getType();
if (providerCapabilities.contains(capability)) {
return new CreateCredentialRequest(callingAppInfo, capability,
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index a62d9e8..0c3d2a4 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -40,7 +40,6 @@
import android.service.credentials.CredentialProviderService;
import android.service.credentials.GetCredentialRequest;
import android.service.credentials.RemoteEntry;
-import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -413,11 +412,9 @@
*/
private boolean onAuthenticationEntrySelected(
@Nullable ProviderPendingIntentResponse providerPendingIntentResponse) {
- Log.i(TAG, "onAuthenticationEntrySelected");
// Authentication entry is expected to have a BeginGetCredentialResponse instance. If it
// does not have it, we remove the authentication entry and do not add any more content.
if (providerPendingIntentResponse == null) {
- Log.i(TAG, "providerPendingIntentResponse is null");
// Nothing received. This is equivalent to no content received.
return false;
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
index c10f564..ead86ce 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
@@ -266,7 +266,7 @@
.collect(Collectors.toList());
updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED,
/*source=*/ CredentialsSource.REGISTRY);
- // TODO(use metric later)
+ // TODO(b/273353677) : metric should be emitted similarly to sibling classes
}
@Nullable
diff --git a/services/credentials/java/com/android/server/credentials/ProviderSession.java b/services/credentials/java/com/android/server/credentials/ProviderSession.java
index d02a8c1..73fdc1c 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderSession.java
@@ -268,12 +268,9 @@
/*pId=*/-1, appInfo.uid) == PackageManager.PERMISSION_GRANTED) {
return true;
}
- } catch (SecurityException e) {
+ } catch (SecurityException | PackageManager.NameNotFoundException e) {
Slog.e(TAG, "Error getting info for " + mComponentName.flattenToString(), e);
return false;
- } catch (PackageManager.NameNotFoundException e) {
- Slog.i(TAG, "Error getting info for " + mComponentName.flattenToString(), e);
- return false;
}
return false;
}
diff --git a/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java b/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java
index 721d3d7..b212606 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java
@@ -30,7 +30,6 @@
* Some types are redundant across these metric collectors, but that has debug use-cases as
* these data-types are available at different moments of the flow (and typically, one can feed
* into the next).
- * TODO(b/270403549) - iterate on this in V3+
*/
public class CandidatePhaseMetric {
@@ -56,10 +55,7 @@
private int mProviderQueryStatus = -1;
// Indicates if an exception was thrown by this provider, false by default
private boolean mHasException = false;
- // Indicates the number of total entries available. We can also locally store the entries, but
- // cannot emit them in the current split form. TODO(b/271135048) - possibly readjust candidate
- // entries. Also, it may be okay to remove this and instead aggregate from inner counts.
- // Defaults to -1
+ // Indicates the number of total entries available, defaults to -1
private int mNumEntriesTotal = -1;
// The count of action entries from this provider, defaults to -1
private int mActionEntryCount = -1;
diff --git a/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderFinalPhaseMetric.java b/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderFinalPhaseMetric.java
index c80cc24..8f08bb0 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderFinalPhaseMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderFinalPhaseMetric.java
@@ -29,11 +29,8 @@
* Some types are redundant across these metric collectors, but that has debug use-cases as
* these data-types are available at different moments of the flow (and typically, one can feed
* into the next).
- * TODO(b/270403549) - iterate on this in V3+
*/
public class ChosenProviderFinalPhaseMetric {
-
- // TODO(b/270403549) - applies elsewhere, likely removed or replaced w/ some hashed/count index
private static final String TAG = "ChosenFinalPhaseMetric";
// The session id associated with this API call, used to unite split emits
private int mSessionId = -1;
diff --git a/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java b/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java
index 0ecd9cc..5cfb0e7 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java
@@ -26,7 +26,6 @@
* Some types are redundant across these metric collectors, but that has debug use-cases as
* these data-types are available at different moments of the flow (and typically, one can feed
* into the next).
- * TODO(b/270403549) - iterate on this in V3+
*/
public class InitialPhaseMetric {
private static final String TAG = "InitialPhaseMetric";
@@ -47,7 +46,6 @@
private long mCredentialServiceBeginQueryTimeNanoseconds = -1;
// Indicates if the origin was specified when making this API request
- // TODO(b/271135048) - Emit once metrics approved
private boolean mOriginSpecified = false;
// Stores the deduped request information, particularly {"req":5}.
diff --git a/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java b/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java
index 547c09a..4ecdfef 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java
@@ -337,10 +337,6 @@
*/
public void logApiCalledAtFinish(int apiStatus) {
try {
- // TODO (b/270403549) - this browsing phase object is fine but also have a new emit
- // For the returned types by authentication entries - i.e. a CandidatePhase During
- // Browse
- // Possibly think of adding in more atoms for other APIs as well.
logApiCalledFinalPhase(mChosenProviderFinalPhaseMetric, mCandidateBrowsingPhaseMetric,
apiStatus,
++mSequenceCounter);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index a35f34d..675ebd3 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -521,6 +521,7 @@
import java.security.cert.X509Certificate;
import java.text.DateFormat;
import java.time.LocalDate;
+import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -533,6 +534,7 @@
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
+import java.util.Queue;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
@@ -568,7 +570,15 @@
private static final int REQUEST_PROFILE_OFF_DEADLINE = 5572;
+ // Binary XML serializer doesn't support longer strings
+ private static final int MAX_POLICY_STRING_LENGTH = 65535;
+ // FrameworkParsingPackageUtils#MAX_FILE_NAME_SIZE, Android packages are used in dir names.
+ private static final int MAX_PACKAGE_NAME_LENGTH = 223;
+
private static final int MAX_PROFILE_NAME_LENGTH = 200;
+ private static final int MAX_LONG_SUPPORT_MESSAGE_LENGTH = 20000;
+ private static final int MAX_SHORT_SUPPORT_MESSAGE_LENGTH = 200;
+ private static final int MAX_ORG_NAME_LENGTH = 200;
private static final long MS_PER_DAY = TimeUnit.DAYS.toMillis(1);
@@ -864,7 +874,7 @@
// TODO(b/265683382) remove the flag after rollout.
private static final String KEEP_PROFILES_RUNNING_FLAG = "enable_keep_profiles_running";
- private static final boolean DEFAULT_KEEP_PROFILES_RUNNING_FLAG = false;
+ private static final boolean DEFAULT_KEEP_PROFILES_RUNNING_FLAG = true;
private static final String ENABLE_WORK_PROFILE_TELEPHONY_FLAG =
"enable_work_profile_telephony";
@@ -6041,7 +6051,7 @@
@Override
public void lockNow(int flags, String callerPackageName, boolean parent) {
CallerIdentity caller;
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
caller = getCallerIdentity(callerPackageName);
} else {
caller = getCallerIdentity();
@@ -6053,7 +6063,7 @@
ActiveAdmin admin;
// Make sure the caller has any active admin with the right policy or
// the required permission.
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
admin = enforcePermissionAndGetEnforcingAdmin(
/* admin= */ null,
/* permission= */ MANAGE_DEVICE_POLICY_LOCK,
@@ -8907,13 +8917,13 @@
}
CallerIdentity caller;
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
}
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
// The effect of this policy is device-wide.
enforcePermission(SET_TIME, caller.getPackageName(), UserHandle.USER_ALL);
} else {
@@ -8941,13 +8951,13 @@
return false;
}
CallerIdentity caller;
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
}
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
enforceCanQuery(SET_TIME, caller.getPackageName(), UserHandle.USER_ALL);
} else {
Objects.requireNonNull(who, "ComponentName is null");
@@ -8976,7 +8986,7 @@
caller = getCallerIdentity(who);
}
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
// The effect of this policy is device-wide.
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
who,
@@ -9016,13 +9026,13 @@
}
CallerIdentity caller;
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
}
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
// The effect of this policy is device-wide.
enforceCanQuery(SET_TIME_ZONE, caller.getPackageName(), UserHandle.USER_ALL);
} else {
@@ -9325,7 +9335,7 @@
}
CallerIdentity caller;
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
@@ -9335,7 +9345,7 @@
final int userHandle = caller.getUserId();
int affectedUserId = parent ? getProfileParentId(userHandle) : userHandle;
synchronized (getLockObject()) {
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
// SUPPORT USES_POLICY_DISABLE_KEYGUARD_FEATURES
EnforcingAdmin admin = enforcePermissionAndGetEnforcingAdmin(
who, MANAGE_DEVICE_POLICY_KEYGUARD, caller.getPackageName(),
@@ -9414,7 +9424,7 @@
synchronized (getLockObject()) {
if (who != null) {
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
EnforcingAdmin admin = getEnforcingAdminForCaller(
who, who.getPackageName());
Integer features = mDevicePolicyEngine.getLocalPolicySetByAdmin(
@@ -9428,7 +9438,7 @@
}
}
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
Integer features = mDevicePolicyEngine.getResolvedPolicy(
PolicyDefinition.KEYGUARD_DISABLED_FEATURES,
affectedUserId);
@@ -11625,7 +11635,7 @@
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_APPLICATION_RESTRICTIONS);
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
who,
MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
@@ -11730,7 +11740,15 @@
}
Objects.requireNonNull(agent, "agent is null");
- int userHandle = UserHandle.getCallingUserId();
+
+ enforceMaxPackageNameLength(agent.getPackageName());
+ final String agentAsString = agent.flattenToString();
+ enforceMaxStringLength(agentAsString, "agent name");
+ if (args != null) {
+ enforceMaxStringLength(args, "args");
+ }
+
+ int userHandle = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
ActiveAdmin ap;
if (isPermissionCheckFlagEnabled()) {
@@ -11747,7 +11765,7 @@
checkCanExecuteOrThrowUnsafe(
DevicePolicyManager.OPERATION_SET_TRUST_AGENT_CONFIGURATION);
- ap.trustAgentInfos.put(agent.flattenToString(), new TrustAgentInfo(args));
+ ap.trustAgentInfos.put(agentAsString, new TrustAgentInfo(args));
saveSettingsLocked(userHandle);
}
}
@@ -12017,6 +12035,10 @@
isDeviceOwner(caller) || isProfileOwner(caller));
if (packageList != null) {
+ for (String pkg : packageList) {
+ enforceMaxPackageNameLength(pkg);
+ }
+
int userId = caller.getUserId();
final List<AccessibilityServiceInfo> enabledServices;
long id = mInjector.binderClearCallingIdentity();
@@ -12174,7 +12196,7 @@
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
@@ -12184,7 +12206,7 @@
int userId = getProfileParentUserIfRequested(
caller.getUserId(), calledOnParentInstance);
if (calledOnParentInstance) {
- if (!isPermissionCheckFlagEnabled()) {
+ if (!isPolicyEngineForFinanceFlagEnabled()) {
Preconditions.checkCallAuthorization(
isProfileOwnerOfOrganizationOwnedDevice(caller));
}
@@ -12192,12 +12214,16 @@
"Permitted input methods must allow all input methods or only "
+ "system input methods when called on the parent instance of an "
+ "organization-owned device");
- } else if (!isPermissionCheckFlagEnabled()) {
+ } else if (!isPolicyEngineForFinanceFlagEnabled()) {
Preconditions.checkCallAuthorization(
isDefaultDeviceOwner(caller) || isProfileOwner(caller));
}
if (packageList != null) {
+ for (String pkg : packageList) {
+ enforceMaxPackageNameLength(pkg);
+ }
+
List<InputMethodInfo> enabledImes = mInjector.binderWithCleanCallingIdentity(() ->
InputMethodManagerInternal.get().getEnabledInputMethodListAsUser(userId));
if (enabledImes != null) {
@@ -12216,7 +12242,9 @@
synchronized (getLockObject()) {
if (isPolicyEngineForFinanceFlagEnabled()) {
- EnforcingAdmin admin = getEnforcingAdminForCaller(who, callerPackageName);
+ EnforcingAdmin admin = enforcePermissionAndGetEnforcingAdmin(
+ who, MANAGE_DEVICE_POLICY_INPUT_METHODS,
+ caller.getPackageName(), userId);
mDevicePolicyEngine.setLocalPolicy(
PolicyDefinition.PERMITTED_INPUT_METHODS,
admin,
@@ -13034,7 +13062,7 @@
String packageName) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforceCanQueryAndGetEnforcingAdmin(
who,
MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
@@ -13104,7 +13132,7 @@
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
ActiveAdmin admin;
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
who,
MANAGE_DEVICE_POLICY_PACKAGE_STATE,
@@ -13201,7 +13229,7 @@
public boolean isPackageSuspended(ComponentName who, String callerPackage, String packageName) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
enforcePermission(
MANAGE_DEVICE_POLICY_PACKAGE_STATE,
caller.getPackageName(),
@@ -13411,6 +13439,13 @@
public void setUserRestrictionGlobally(String callerPackage, String key) {
final CallerIdentity caller = getCallerIdentity(callerPackage);
+ EnforcingAdmin admin = enforcePermissionForUserRestriction(
+ /* who= */ null,
+ key,
+ caller.getPackageName(),
+ UserHandle.USER_ALL
+ );
+
checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_USER_RESTRICTION);
if (!isPolicyEngineForFinanceFlagEnabled()) {
@@ -13427,13 +13462,6 @@
throw new IllegalArgumentException("Invalid restriction key: " + key);
}
- EnforcingAdmin admin = enforcePermissionForUserRestriction(
- /* who= */ null,
- key,
- caller.getPackageName(),
- UserHandle.USER_ALL
- );
-
setGlobalUserRestrictionInternal(admin, key, /* enabled= */ true);
logUserRestrictionCall(key, /* enabled= */ true, /* parent= */ false, caller);
@@ -13807,7 +13835,7 @@
boolean hidden, boolean parent) {
CallerIdentity caller = getCallerIdentity(who, callerPackage);
final int userId = parent ? getProfileParentId(caller.getUserId()) : caller.getUserId();
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
// TODO: We need to ensure the delegate with DELEGATION_PACKAGE_ACCESS can do this
enforcePermission(MANAGE_DEVICE_POLICY_PACKAGE_STATE, caller.getPackageName(), userId);
} else {
@@ -13826,7 +13854,7 @@
boolean result;
synchronized (getLockObject()) {
if (parent) {
- if (!isPolicyEngineForFinanceFlagEnabled()) {
+ if (!isPermissionCheckFlagEnabled()) {
Preconditions.checkCallAuthorization(
isProfileOwnerOfOrganizationOwnedDevice(
caller.getUserId()) && isManagedProfile(caller.getUserId()));
@@ -13843,7 +13871,7 @@
Slogf.v(LOG_TAG, "calling pm.setApplicationHiddenSettingAsUser(%s, %b, %d)",
packageName, hidden, userId);
}
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
EnforcingAdmin admin = getEnforcingAdminForCaller(who, callerPackage);
mDevicePolicyEngine.setLocalPolicy(
PolicyDefinition.APPLICATION_HIDDEN(packageName),
@@ -13882,7 +13910,7 @@
String packageName, boolean parent) {
CallerIdentity caller = getCallerIdentity(who, callerPackage);
int userId = parent ? getProfileParentId(caller.getUserId()) : caller.getUserId();
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
// TODO: Also support DELEGATION_PACKAGE_ACCESS
enforcePermission(MANAGE_DEVICE_POLICY_PACKAGE_STATE, caller.getPackageName(), userId);
} else {
@@ -13894,7 +13922,7 @@
synchronized (getLockObject()) {
if (parent) {
- if (!isPolicyEngineForFinanceFlagEnabled()) {
+ if (!isPermissionCheckFlagEnabled()) {
Preconditions.checkCallAuthorization(
isProfileOwnerOfOrganizationOwnedDevice(caller.getUserId())
&& isManagedProfile(caller.getUserId()));
@@ -14082,14 +14110,17 @@
if (!mHasFeature) {
return;
}
+
+ enforceMaxStringLength(accountType, "account type");
+
CallerIdentity caller;
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
}
synchronized (getLockObject()) {
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
int affectedUser = getAffectedUser(parent);
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
who,
@@ -14152,7 +14183,7 @@
CallerIdentity caller;
Preconditions.checkArgumentNonnegative(userId, "Invalid userId");
final ArraySet<String> resultSet = new ArraySet<>();
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
int affectedUser = parent ? getProfileParentId(userId) : userId;
caller = getCallerIdentity(callerPackageName);
if (!hasPermission(MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
@@ -14772,6 +14803,10 @@
public void setLockTaskPackages(ComponentName who, String callerPackageName, String[] packages)
throws SecurityException {
Objects.requireNonNull(packages, "packages is null");
+ for (String pkg : packages) {
+ enforceMaxPackageNameLength(pkg);
+ }
+
CallerIdentity caller;
if (isPolicyEngineForFinanceFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
@@ -15519,12 +15554,12 @@
public boolean setStatusBarDisabled(ComponentName who, String callerPackageName,
boolean disabled) {
CallerIdentity caller;
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
}
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
enforcePermission(MANAGE_DEVICE_POLICY_STATUS_BAR, caller.getPackageName(),
UserHandle.USER_ALL);
} else {
@@ -15535,7 +15570,7 @@
int userId = caller.getUserId();
synchronized (getLockObject()) {
- if (!isPolicyEngineForFinanceFlagEnabled()) {
+ if (!isPermissionCheckFlagEnabled()) {
Preconditions.checkCallAuthorization(isUserAffiliatedWithDeviceLocked(userId),
"Admin " + who + " is neither the device owner or affiliated "
+ "user's profile owner.");
@@ -15594,7 +15629,7 @@
@Override
public boolean isStatusBarDisabled(String callerPackage) {
final CallerIdentity caller = getCallerIdentity(callerPackage);
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
enforceCanQuery(
MANAGE_DEVICE_POLICY_STATUS_BAR, caller.getPackageName(), caller.getUserId());
} else {
@@ -15604,7 +15639,7 @@
int userId = caller.getUserId();
synchronized (getLockObject()) {
- if (!isPolicyEngineForFinanceFlagEnabled()) {
+ if (!isPermissionCheckFlagEnabled()) {
Preconditions.checkCallAuthorization(isUserAffiliatedWithDeviceLocked(userId),
"Admin " + callerPackage
+ " is neither the device owner or affiliated user's profile owner.");
@@ -16339,7 +16374,8 @@
// TODO(b/128928355): if this restriction is enforced by multiple DPCs, return
// the admin for the calling user.
Slogf.w(LOG_TAG, "getEnforcingAdminAndUserDetailsInternal(%d, %s): multiple "
- + "sources for restriction %s on user %d", restriction, userId);
+ + "sources for restriction %s on user %d",
+ userId, restriction, restriction, userId);
result = new Bundle();
result.putInt(Intent.EXTRA_USER_ID, userId);
return result;
@@ -16764,7 +16800,7 @@
}
}
EnforcingAdmin enforcingAdmin;
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
admin,
MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
@@ -16935,7 +16971,7 @@
public int getPermissionGrantState(ComponentName admin, String callerPackage,
String packageName, String permission) throws RemoteException {
final CallerIdentity caller = getCallerIdentity(admin, callerPackage);
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
enforceCanQuery(MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS, caller.getPackageName(),
caller.getUserId());
} else {
@@ -17374,6 +17410,8 @@
CallerIdentity caller;
ActiveAdmin admin;
+ message = truncateIfLonger(message, MAX_SHORT_SUPPORT_MESSAGE_LENGTH);
+
if (isPermissionCheckFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
@@ -17434,6 +17472,9 @@
if (!mHasFeature) {
return;
}
+
+ message = truncateIfLonger(message, MAX_LONG_SUPPORT_MESSAGE_LENGTH);
+
Objects.requireNonNull(who, "ComponentName is null");
final CallerIdentity caller = getCallerIdentity(who);
synchronized (getLockObject()) {
@@ -17598,6 +17639,8 @@
Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
}
+ text = truncateIfLonger(text, MAX_ORG_NAME_LENGTH);
+
synchronized (getLockObject()) {
if (!isPermissionCheckFlagEnabled()) {
admin = getProfileOwnerOrDeviceOwnerLocked(caller.getUserId());
@@ -17878,9 +17921,8 @@
throw new IllegalArgumentException("ids must not be null");
}
for (String id : ids) {
- if (TextUtils.isEmpty(id)) {
- throw new IllegalArgumentException("ids must not contain empty string");
- }
+ Preconditions.checkArgument(!TextUtils.isEmpty(id), "ids must not have empty string");
+ enforceMaxStringLength(id, "affiliation id");
}
final Set<String> affiliationIds = new ArraySet<>(ids);
@@ -19067,14 +19109,14 @@
throw new IllegalArgumentException("token must be at least 32-byte long");
}
CallerIdentity caller;
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
caller = getCallerIdentity(admin, callerPackageName);
} else {
caller = getCallerIdentity(admin);
}
final int userId = caller.getUserId();
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
admin,
MANAGE_DEVICE_POLICY_RESET_PASSWORD,
@@ -19130,7 +19172,7 @@
return false;
}
CallerIdentity caller;
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
caller = getCallerIdentity(admin, callerPackageName);
} else {
caller = getCallerIdentity(admin);
@@ -19138,7 +19180,7 @@
final int userId = caller.getUserId();
boolean result = false;
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
admin,
MANAGE_DEVICE_POLICY_RESET_PASSWORD,
@@ -19177,14 +19219,14 @@
return false;
}
CallerIdentity caller;
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
caller = getCallerIdentity(admin, callerPackageName);
} else {
caller = getCallerIdentity(admin);
}
int userId = caller.getUserId();
- if (isPolicyEngineForFinanceFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
admin,
MANAGE_DEVICE_POLICY_RESET_PASSWORD,
@@ -19393,6 +19435,9 @@
"Provided administrator and target are the same object.");
Preconditions.checkArgument(!admin.getPackageName().equals(target.getPackageName()),
"Provided administrator and target have the same package name.");
+ if (bundle != null) {
+ enforceMaxStringLength(bundle, "bundle");
+ }
final CallerIdentity caller = getCallerIdentity(admin);
Preconditions.checkCallAuthorization(
@@ -22798,6 +22843,7 @@
MANAGE_DEVICE_POLICY_DISPLAY,
MANAGE_DEVICE_POLICY_FACTORY_RESET,
MANAGE_DEVICE_POLICY_FUN,
+ MANAGE_DEVICE_POLICY_INPUT_METHODS,
MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES,
MANAGE_DEVICE_POLICY_KEYGUARD,
MANAGE_DEVICE_POLICY_LOCALE,
@@ -22873,9 +22919,11 @@
MANAGE_DEVICE_POLICY_BLUETOOTH,
MANAGE_DEVICE_POLICY_CALLS,
MANAGE_DEVICE_POLICY_CAMERA,
+ MANAGE_DEVICE_POLICY_CERTIFICATES,
MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES,
MANAGE_DEVICE_POLICY_DISPLAY,
MANAGE_DEVICE_POLICY_FACTORY_RESET,
+ MANAGE_DEVICE_POLICY_INPUT_METHODS,
MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES,
MANAGE_DEVICE_POLICY_KEYGUARD,
MANAGE_DEVICE_POLICY_LOCALE,
@@ -22908,7 +22956,6 @@
MANAGE_DEVICE_POLICY_ACROSS_USERS,
MANAGE_DEVICE_POLICY_AIRPLANE_MODE,
MANAGE_DEVICE_POLICY_APPS_CONTROL,
- MANAGE_DEVICE_POLICY_CERTIFICATES,
MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE,
MANAGE_DEVICE_POLICY_DEFAULT_SMS,
MANAGE_DEVICE_POLICY_LOCALE,
@@ -23033,11 +23080,12 @@
//Map of Permission to Delegate Scope.
private static final HashMap<String, String> DELEGATE_SCOPES = new HashMap<>();
{
- DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS, DELEGATION_PERMISSION_GRANT);
DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_APP_RESTRICTIONS, DELEGATION_APP_RESTRICTIONS);
DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_BLOCK_UNINSTALL, DELEGATION_BLOCK_UNINSTALL);
- DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, DELEGATION_SECURITY_LOGGING);
+ DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_CERTIFICATES, DELEGATION_CERT_INSTALL);
DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_PACKAGE_STATE, DELEGATION_PACKAGE_ACCESS);
+ DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS, DELEGATION_PERMISSION_GRANT);
+ DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, DELEGATION_SECURITY_LOGGING);
}
private static final HashMap<String, String> CROSS_USER_PERMISSIONS =
@@ -24137,6 +24185,53 @@
});
}
+ /**
+ * Truncates char sequence to maximum length, nulls are ignored.
+ */
+ private static CharSequence truncateIfLonger(CharSequence input, int maxLength) {
+ return input == null || input.length() <= maxLength
+ ? input
+ : input.subSequence(0, maxLength);
+ }
+
+ /**
+ * Throw if string argument is too long to be serialized.
+ */
+ private static void enforceMaxStringLength(String str, String argName) {
+ Preconditions.checkArgument(
+ str.length() <= MAX_POLICY_STRING_LENGTH, argName + " loo long");
+ }
+
+ private static void enforceMaxPackageNameLength(String pkg) {
+ Preconditions.checkArgument(
+ pkg.length() <= MAX_PACKAGE_NAME_LENGTH, "Package name too long");
+ }
+
+ /**
+ * Throw if persistable bundle contains any string that we can't serialize.
+ */
+ private static void enforceMaxStringLength(PersistableBundle bundle, String argName) {
+ // Persistable bundles can have other persistable bundles as values, traverse with a queue.
+ Queue<PersistableBundle> queue = new ArrayDeque<>();
+ queue.add(bundle);
+ while (!queue.isEmpty()) {
+ PersistableBundle current = queue.remove();
+ for (String key : current.keySet()) {
+ enforceMaxStringLength(key, "key in " + argName);
+ Object value = current.get(key);
+ if (value instanceof String) {
+ enforceMaxStringLength((String) value, "string value in " + argName);
+ } else if (value instanceof String[]) {
+ for (String str : (String[]) value) {
+ enforceMaxStringLength(str, "string value in " + argName);
+ }
+ } else if (value instanceof PersistableBundle) {
+ queue.add((PersistableBundle) value);
+ }
+ }
+ }
+ }
+
private ActiveAdmin getActiveAdminForCaller(@Nullable ComponentName who,
CallerIdentity caller) {
synchronized (getLockObject()) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index 3a47b47..2b57c59 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -154,6 +154,7 @@
// Freeze time for testing.
long nowElapsed;
boolean useMotionSensor = true;
+ boolean isLocationPrefetchEnabled = true;
InjectorForTest(Context ctx) {
super(ctx);
@@ -223,6 +224,11 @@
}
@Override
+ boolean isLocationPrefetchEnabled() {
+ return isLocationPrefetchEnabled;
+ }
+
+ @Override
PowerManager getPowerManager() {
return mPowerManager;
}
@@ -991,6 +997,43 @@
}
@Test
+ public void testStepIdleStateLocked_ValidStates_LocationPrefetchDisabled() {
+ mInjector.locationManager = mLocationManager;
+ mInjector.isLocationPrefetchEnabled = false;
+ cleanupDeviceIdleController();
+ setupDeviceIdleController();
+ doReturn(mock(LocationProvider.class)).when(mLocationManager).getProvider(anyString());
+ // Make sure the controller doesn't think there's a wake-from-idle alarm coming soon.
+ setAlarmSoon(false);
+ // Set state to INACTIVE.
+ mDeviceIdleController.becomeActiveLocked("testing", 0);
+ setChargingOn(false);
+ setScreenOn(false);
+ verifyStateConditions(STATE_INACTIVE);
+
+ mDeviceIdleController.stepIdleStateLocked("testing");
+ verifyStateConditions(STATE_IDLE_PENDING);
+
+ mDeviceIdleController.stepIdleStateLocked("testing");
+ verifyStateConditions(STATE_SENSING);
+
+ mDeviceIdleController.stepIdleStateLocked("testing");
+ // Prefetch location is off, so SENSING should go straight through to IDLE.
+ verifyStateConditions(STATE_IDLE);
+
+ // Should just alternate between IDLE and IDLE_MAINTENANCE now.
+
+ mDeviceIdleController.stepIdleStateLocked("testing");
+ verifyStateConditions(STATE_IDLE_MAINTENANCE);
+
+ mDeviceIdleController.stepIdleStateLocked("testing");
+ verifyStateConditions(STATE_IDLE);
+
+ mDeviceIdleController.stepIdleStateLocked("testing");
+ verifyStateConditions(STATE_IDLE_MAINTENANCE);
+ }
+
+ @Test
public void testStepIdleStateLocked_ValidStates_WithLocationManager_NoProviders() {
// Make sure the controller doesn't think there's a wake-from-idle alarm coming soon.
setAlarmSoon(false);
@@ -1024,6 +1067,46 @@
}
@Test
+ public void testStepIdleStateLocked_ValidStates_WithLocationManager_MissingProviders() {
+ mInjector.locationManager = mLocationManager;
+ doReturn(null).when(mLocationManager)
+ .getProvider(eq(LocationManager.FUSED_PROVIDER));
+ doReturn(null).when(mLocationManager)
+ .getProvider(eq(LocationManager.GPS_PROVIDER));
+ doReturn(mock(LocationProvider.class)).when(mLocationManager)
+ .getProvider(eq(LocationManager.NETWORK_PROVIDER));
+ // Make sure the controller doesn't think there's a wake-from-idle alarm coming soon.
+ setAlarmSoon(false);
+ // Set state to INACTIVE.
+ mDeviceIdleController.becomeActiveLocked("testing", 0);
+ setChargingOn(false);
+ setScreenOn(false);
+ verifyStateConditions(STATE_INACTIVE);
+
+ mDeviceIdleController.stepIdleStateLocked("testing");
+ verifyStateConditions(STATE_IDLE_PENDING);
+
+ mDeviceIdleController.stepIdleStateLocked("testing");
+ verifyStateConditions(STATE_SENSING);
+
+ mDeviceIdleController.stepIdleStateLocked("testing");
+ // Location manager exists, but the required providers don't exist,
+ // so SENSING should go straight through to IDLE.
+ verifyStateConditions(STATE_IDLE);
+
+ // Should just alternate between IDLE and IDLE_MAINTENANCE now.
+
+ mDeviceIdleController.stepIdleStateLocked("testing");
+ verifyStateConditions(STATE_IDLE_MAINTENANCE);
+
+ mDeviceIdleController.stepIdleStateLocked("testing");
+ verifyStateConditions(STATE_IDLE);
+
+ mDeviceIdleController.stepIdleStateLocked("testing");
+ verifyStateConditions(STATE_IDLE_MAINTENANCE);
+ }
+
+ @Test
public void testStepIdleStateLocked_ValidStates_WithLocationManager_WithProviders() {
mInjector.locationManager = mLocationManager;
doReturn(mock(LocationProvider.class)).when(mLocationManager).getProvider(anyString());
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
index c4aa0bb..8dc0ac6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
@@ -64,6 +64,7 @@
import com.android.server.LocalServices;
import com.android.server.am.BatteryStatsService;
import com.android.server.display.RampAnimator.DualRampAnimator;
+import com.android.server.display.brightness.BrightnessEvent;
import com.android.server.display.color.ColorDisplayService;
import com.android.server.display.layout.Layout;
import com.android.server.display.whitebalance.DisplayWhiteBalanceController;
@@ -596,17 +597,17 @@
// We should still set screen state for the default display
DisplayPowerRequest dpr = new DisplayPowerRequest();
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
- advanceTime(1);
+ advanceTime(1); // Run updatePowerState
verify(mHolder.displayPowerState, times(2)).setScreenState(anyInt());
mHolder = createDisplayPowerController(42, UNIQUE_ID);
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
- advanceTime(1);
+ advanceTime(1); // Run updatePowerState
verify(mHolder.displayPowerState, never()).setScreenState(anyInt());
mHolder.dpc.onBootCompleted();
- advanceTime(1);
+ advanceTime(1); // Run updatePowerState
verify(mHolder.displayPowerState).setScreenState(anyInt());
}
@@ -632,8 +633,8 @@
.thenReturn(brightness);
dpr.policy = DisplayPowerRequest.POLICY_BRIGHT;
when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
- when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness())
- .thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+ when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
+ any(BrightnessEvent.class))).thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT);
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
advanceTime(1); // Run updatePowerState
@@ -667,8 +668,8 @@
.thenReturn(brightness);
dpr.policy = DisplayPowerRequest.POLICY_BRIGHT;
when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
- when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness())
- .thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+ when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
+ any(BrightnessEvent.class))).thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT);
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
advanceTime(1); // Run updatePowerState
@@ -822,6 +823,21 @@
);
}
+ @Test
+ public void testUpdateBrightnessThrottlingDataId() {
+ mHolder.display.getDisplayInfoLocked().thermalBrightnessThrottlingDataId =
+ "throttling-data-id";
+ clearInvocations(mHolder.display.getPrimaryDisplayDeviceLocked().getDisplayDeviceConfig());
+
+ mHolder.dpc.onDisplayChanged(mHolder.hbmMetadata, Layout.NO_LEAD_DISPLAY);
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.display.getPrimaryDisplayDeviceLocked().getDisplayDeviceConfig())
+ .getThermalBrightnessThrottlingDataMapByThrottlingId();
+ }
+
/**
* Creates a mock and registers it to {@link LocalServices}.
*/
@@ -862,8 +878,6 @@
when(logicalDisplayMock.getDisplayInfoLocked()).thenReturn(info);
when(logicalDisplayMock.isEnabledLocked()).thenReturn(isEnabled);
when(logicalDisplayMock.isInTransitionLocked()).thenReturn(false);
- when(logicalDisplayMock.getThermalBrightnessThrottlingDataIdLocked()).thenReturn(
- DisplayDeviceConfig.DEFAULT_ID);
when(displayDeviceMock.getDisplayDeviceInfoLocked()).thenReturn(deviceInfo);
when(displayDeviceMock.getUniqueId()).thenReturn(uniqueId);
when(displayDeviceMock.getDisplayDeviceConfig()).thenReturn(displayDeviceConfigMock);
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
index 415adbb..5c0810f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -829,6 +829,21 @@
);
}
+ @Test
+ public void testUpdateBrightnessThrottlingDataId() {
+ mHolder.display.getDisplayInfoLocked().thermalBrightnessThrottlingDataId =
+ "throttling-data-id";
+ clearInvocations(mHolder.display.getPrimaryDisplayDeviceLocked().getDisplayDeviceConfig());
+
+ mHolder.dpc.onDisplayChanged(mHolder.hbmMetadata, Layout.NO_LEAD_DISPLAY);
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.display.getPrimaryDisplayDeviceLocked().getDisplayDeviceConfig())
+ .getThermalBrightnessThrottlingDataMapByThrottlingId();
+ }
+
/**
* Creates a mock and registers it to {@link LocalServices}.
*/
@@ -869,8 +884,6 @@
when(logicalDisplayMock.getDisplayInfoLocked()).thenReturn(info);
when(logicalDisplayMock.isEnabledLocked()).thenReturn(isEnabled);
when(logicalDisplayMock.isInTransitionLocked()).thenReturn(false);
- when(logicalDisplayMock.getThermalBrightnessThrottlingDataIdLocked()).thenReturn(
- DisplayDeviceConfig.DEFAULT_ID);
when(displayDeviceMock.getDisplayDeviceInfoLocked()).thenReturn(deviceInfo);
when(displayDeviceMock.getUniqueId()).thenReturn(uniqueId);
when(displayDeviceMock.getDisplayDeviceConfig()).thenReturn(displayDeviceConfigMock);
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java b/services/tests/mockingservicestests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java
deleted file mode 100644
index 17fba9f..0000000
--- a/services/tests/mockingservicestests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2023 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.display;
-
-import static com.android.internal.display.RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.when;
-
-import android.hardware.display.DisplayManager;
-import android.provider.Settings;
-import android.testing.TestableContext;
-import android.view.Display;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.display.RefreshRateSettingsUtils;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class RefreshRateSettingsUtilsTest {
-
- @Rule
- public final TestableContext mContext = new TestableContext(
- InstrumentationRegistry.getInstrumentation().getContext());
-
- @Mock
- private DisplayManager mDisplayManagerMock;
- @Mock
- private Display mDisplayMock;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- mContext.addMockSystemService(DisplayManager.class, mDisplayManagerMock);
-
- Display.Mode[] modes = new Display.Mode[] {
- new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
- /* refreshRate= */ 60),
- new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
- /* refreshRate= */ 120),
- new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
- /* refreshRate= */ 90)
- };
-
- when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock);
- when(mDisplayMock.getSupportedModes()).thenReturn(modes);
- }
-
- @Test
- public void testFindHighestRefreshRateForDefaultDisplay() {
- when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(null);
- assertEquals(DEFAULT_REFRESH_RATE,
- RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext),
- /* delta= */ 0);
-
- when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock);
- assertEquals(120,
- RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext),
- /* delta= */ 0);
- }
-
- @Test
- public void testGetMinRefreshRate() {
- Settings.System.putInt(mContext.getContentResolver(),
- Settings.System.FORCE_PEAK_REFRESH_RATE, -1);
- assertEquals(0, RefreshRateSettingsUtils.getMinRefreshRate(mContext), /* delta= */ 0);
-
- Settings.System.putInt(mContext.getContentResolver(),
- Settings.System.FORCE_PEAK_REFRESH_RATE, 0);
- assertEquals(0, RefreshRateSettingsUtils.getMinRefreshRate(mContext), /* delta= */ 0);
-
- Settings.System.putInt(mContext.getContentResolver(),
- Settings.System.FORCE_PEAK_REFRESH_RATE, 1);
- assertEquals(120, RefreshRateSettingsUtils.getMinRefreshRate(mContext), /* delta= */ 0);
- }
-
- @Test
- public void testGetPeakRefreshRate() {
- float defaultPeakRefreshRate = 100;
-
- Settings.System.putInt(mContext.getContentResolver(), Settings.System.SMOOTH_DISPLAY, -1);
- assertEquals(defaultPeakRefreshRate,
- RefreshRateSettingsUtils.getPeakRefreshRate(mContext, defaultPeakRefreshRate),
- /* delta= */ 0);
-
- Settings.System.putInt(mContext.getContentResolver(), Settings.System.SMOOTH_DISPLAY, 0);
- assertEquals(DEFAULT_REFRESH_RATE,
- RefreshRateSettingsUtils.getPeakRefreshRate(mContext, defaultPeakRefreshRate),
- /* delta= */ 0);
-
- Settings.System.putInt(mContext.getContentResolver(), Settings.System.SMOOTH_DISPLAY, 1);
- assertEquals(120,
- RefreshRateSettingsUtils.getPeakRefreshRate(mContext, defaultPeakRefreshRate),
- /* delta= */ 0);
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncControllerTest.java
new file mode 100644
index 0000000..eec026cc
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncControllerTest.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.companion.datatransfer.contextsync;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.when;
+
+import android.platform.test.annotations.Presubmit;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.server.companion.transport.CompanionTransportManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@Presubmit
+@RunWith(AndroidTestingRunner.class)
+public class CrossDeviceSyncControllerTest {
+
+ private CrossDeviceSyncController mCrossDeviceSyncController;
+ @Mock
+ private CompanionTransportManager mMockCompanionTransportManager;
+ @Mock
+ private CrossDeviceCall mMockCrossDeviceCall;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mCrossDeviceSyncController = new CrossDeviceSyncController(
+ InstrumentationRegistry.getInstrumentation().getContext(),
+ mMockCompanionTransportManager);
+ }
+
+ @Test
+ public void processTelecomDataFromSync_createCallUpdateMessage_emptyCallsAndRequests() {
+ final byte[] data = mCrossDeviceSyncController.createCallUpdateMessage(new HashSet<>(),
+ InstrumentationRegistry.getInstrumentation().getContext().getUserId());
+ final CallMetadataSyncData callMetadataSyncData =
+ mCrossDeviceSyncController.processTelecomDataFromSync(data);
+ assertWithMessage("Unexpectedly found a call").that(
+ callMetadataSyncData.getCalls()).isEmpty();
+ assertWithMessage("Unexpectedly found a request").that(
+ callMetadataSyncData.getRequests()).isEmpty();
+ }
+
+ @Test
+ public void processTelecomDataFromSync_createEmptyMessage_emptyCallsAndRequests() {
+ final byte[] data = CrossDeviceSyncController.createEmptyMessage();
+ final CallMetadataSyncData callMetadataSyncData =
+ mCrossDeviceSyncController.processTelecomDataFromSync(data);
+ assertWithMessage("Unexpectedly found a call").that(
+ callMetadataSyncData.getCalls()).isEmpty();
+ assertWithMessage("Unexpectedly found a request").that(
+ callMetadataSyncData.getRequests()).isEmpty();
+ }
+
+ @Test
+ public void processTelecomDataFromSync_createCallUpdateMessage_hasCalls() {
+ when(mMockCrossDeviceCall.getId()).thenReturn(5L);
+ final String callerId = "Firstname Lastname";
+ when(mMockCrossDeviceCall.getReadableCallerId(anyBoolean())).thenReturn(callerId);
+ final String appName = "AppName";
+ when(mMockCrossDeviceCall.getCallingAppName()).thenReturn(appName);
+ final String appIcon = "ABCD";
+ when(mMockCrossDeviceCall.getCallingAppIcon()).thenReturn(appIcon.getBytes());
+ when(mMockCrossDeviceCall.getStatus()).thenReturn(android.companion.Telecom.Call.RINGING);
+ final Set<Integer> controls = Set.of(
+ android.companion.Telecom.Call.ACCEPT,
+ android.companion.Telecom.Call.REJECT,
+ android.companion.Telecom.Call.SILENCE);
+ when(mMockCrossDeviceCall.getControls()).thenReturn(controls);
+ final byte[] data = mCrossDeviceSyncController.createCallUpdateMessage(
+ new HashSet<>(List.of(mMockCrossDeviceCall)),
+ InstrumentationRegistry.getInstrumentation().getContext().getUserId());
+ final CallMetadataSyncData callMetadataSyncData =
+ mCrossDeviceSyncController.processTelecomDataFromSync(data);
+ assertWithMessage("Wrong number of active calls").that(
+ callMetadataSyncData.getCalls()).hasSize(1);
+ final CallMetadataSyncData.Call call =
+ callMetadataSyncData.getCalls().stream().findAny().orElseThrow();
+ assertWithMessage("Wrong id").that(call.getId()).isEqualTo(5L);
+ assertWithMessage("Wrong app icon").that(new String(call.getAppIcon())).isEqualTo(appIcon);
+ assertWithMessage("Wrong app name").that(call.getAppName()).isEqualTo(appName);
+ assertWithMessage("Wrong caller id").that(call.getCallerId()).isEqualTo(callerId);
+ assertWithMessage("Wrong status").that(call.getStatus())
+ .isEqualTo(android.companion.Telecom.Call.RINGING);
+ assertWithMessage("Wrong controls").that(call.getControls()).isEqualTo(controls);
+ assertWithMessage("Unexpectedly has requests").that(
+ callMetadataSyncData.getRequests()).isEmpty();
+ }
+
+ @Test
+ public void processTelecomDataFromMessage_createCallControlMessage_hasCallControlRequest() {
+ final byte[] data = CrossDeviceSyncController.createCallControlMessage(
+ /* callId= */ 5L, /* status= */ android.companion.Telecom.Call.ACCEPT);
+ final CallMetadataSyncData callMetadataSyncData =
+ mCrossDeviceSyncController.processTelecomDataFromSync(data);
+ assertWithMessage("Wrong number of requests").that(
+ callMetadataSyncData.getRequests()).hasSize(1);
+ final CallMetadataSyncData.Call call =
+ callMetadataSyncData.getRequests().stream().findAny().orElseThrow();
+ assertWithMessage("Wrong id").that(call.getId()).isEqualTo(5L);
+ assertWithMessage("Wrong app icon").that(call.getAppIcon()).isNull();
+ assertWithMessage("Wrong app name").that(call.getAppName()).isNull();
+ assertWithMessage("Wrong caller id").that(call.getCallerId()).isNull();
+ assertWithMessage("Wrong status").that(call.getStatus())
+ .isEqualTo(android.companion.Telecom.Call.UNKNOWN_STATUS);
+ assertWithMessage("Wrong controls").that(call.getControls())
+ .isEqualTo(Set.of(android.companion.Telecom.Call.ACCEPT));
+ assertWithMessage("Unexpectedly has active calls").that(
+ callMetadataSyncData.getCalls()).isEmpty();
+ }
+}
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 34b88b0..1e342f5 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -130,6 +130,7 @@
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.IpcDataCache;
+import android.os.PersistableBundle;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
@@ -1511,7 +1512,6 @@
* Validates that when the device owner is removed, the reset password token is cleared
*/
@Test
- @Ignore("b/277916462")
public void testClearDeviceOwner_clearResetPasswordToken() throws Exception {
mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
@@ -2602,7 +2602,6 @@
}
@Test
- @Ignore("b/277916462")
public void testSetApplicationHiddenWithDO() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -2628,7 +2627,6 @@
}
@Test
- @Ignore("b/277916462")
public void testSetApplicationHiddenWithPOOfOrganizationOwnedDevice() throws Exception {
final int MANAGED_PROFILE_USER_ID = CALLER_USER_HANDLE;
final int MANAGED_PROFILE_ADMIN_UID =
@@ -4375,7 +4373,6 @@
}
@Test
- @Ignore("b/277916462")
public void testSetAutoTimeZoneEnabledModifiesSetting() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -4387,7 +4384,6 @@
}
@Test
- @Ignore("b/277916462")
public void testSetAutoTimeZoneEnabledWithPOOnUser0() throws Exception {
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
setupProfileOwnerOnUser0();
@@ -4399,7 +4395,6 @@
}
@Test
- @Ignore("b/277916462")
public void testSetAutoTimeZoneEnabledFailWithPONotOnUser0() throws Exception {
setupProfileOwner();
assertExpectException(SecurityException.class, null,
@@ -4409,7 +4404,6 @@
}
@Test
- @Ignore("b/277916462")
public void testSetAutoTimeZoneEnabledWithPOOfOrganizationOwnedDevice() throws Exception {
setupProfileOwner();
configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
@@ -5383,7 +5377,6 @@
}
@Test
- @Ignore("b/277916462")
public void testResetPasswordWithToken() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -5418,7 +5411,6 @@
}
@Test
- @Ignore("b/277916462")
public void resetPasswordWithToken_NumericPin() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -5439,7 +5431,6 @@
}
@Test
- @Ignore("b/277916462")
public void resetPasswordWithToken_EmptyPassword() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -7260,7 +7251,6 @@
}
@Test
- @Ignore("b/277916462")
public void testCanProfileOwnerResetPasswordWhenLocked() throws Exception {
setDeviceEncryptionPerUser();
setupProfileOwner();
@@ -7324,7 +7314,6 @@
}
@Test
- @Ignore("b/277916462")
public void testSetAccountTypesWithManagementDisabledOnManagedProfile() throws Exception {
setupProfileOwner();
@@ -7344,7 +7333,6 @@
}
@Test
- @Ignore("b/277916462")
public void testSetAccountTypesWithManagementDisabledOnOrgOwnedManagedProfile()
throws Exception {
mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS);
@@ -8539,6 +8527,46 @@
eq(FUSED_PROVIDER), any(), eq(getServices().executor), any());
}
+ /**
+ * Verifies that bundles with tons of moderately long strings are persisted correctly.
+ *
+ * Policy is serialized into binary XML and there is a limit on the max string length: 65535.
+ * This test ensures that as long as each string in the trust agent configuration is below this
+ * limit, the policy can be serialized and deserialized correctly, even when the total length
+ * of the configuration is above that limit. This should be the case because PersistableBundle
+ * contents are stored as XML subtrees rather than as strings.
+ */
+ @Test
+ public void testSetTrustAgentConfiguration_largeBundlePersisted() {
+ setAsProfileOwner(admin1);
+
+ ComponentName agent = new ComponentName("some.trust.agent", "some.trust.agent.Agent");
+ PersistableBundle configIn = new PersistableBundle();
+ String kilobyteString = new String(new char[1024]).replace('\0', 'A');
+ for (int i = 0; i < 1024; i++) {
+ configIn.putString("key-" + i, kilobyteString);
+ }
+
+ runAsCaller(mAdmin1Context, dpms, dpm -> {
+ dpm.setTrustAgentConfiguration(admin1, agent, configIn);
+ });
+
+ // Re-read policies to see if they were serialized/deserialized correctly.
+ initializeDpms();
+
+ List<PersistableBundle> configsOut = new ArrayList<>();
+ runAsCaller(mAdmin1Context, dpms, dpm -> {
+ configsOut.addAll(dpm.getTrustAgentConfiguration(admin1, agent));
+ });
+
+ assertThat(configsOut.size()).isEqualTo(1);
+ PersistableBundle configOut = configsOut.get(0);
+ assertThat(configOut.size()).isEqualTo(1024);
+ for (int i = 0; i < 1024; i++) {
+ assertThat(configOut.getString("key-" + i, null)).isEqualTo(kilobyteString);
+ }
+ }
+
private void setupVpnAuthorization(String userVpnPackage, int userVpnUid) {
final AppOpsManager.PackageOps vpnOp = new AppOpsManager.PackageOps(userVpnPackage,
userVpnUid, List.of(new AppOpsManager.OpEntry(
diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
index 7536c79..1eec70d 100644
--- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -649,9 +649,9 @@
assertEquals(0, mLogicalDisplayMapper.getDisplayLocked(device2)
.getLeadDisplayIdLocked());
assertEquals("concurrent", mLogicalDisplayMapper.getDisplayLocked(device1)
- .getThermalBrightnessThrottlingDataIdLocked());
+ .getDisplayInfoLocked().thermalBrightnessThrottlingDataId);
assertEquals("concurrent", mLogicalDisplayMapper.getDisplayLocked(device2)
- .getThermalBrightnessThrottlingDataIdLocked());
+ .getDisplayInfoLocked().thermalBrightnessThrottlingDataId);
mLogicalDisplayMapper.setDeviceStateLocked(1, false);
advanceTime(1000);
@@ -661,10 +661,10 @@
assertFalse(mLogicalDisplayMapper.getDisplayLocked(device2).isInTransitionLocked());
assertEquals(DisplayDeviceConfig.DEFAULT_ID,
mLogicalDisplayMapper.getDisplayLocked(device1)
- .getThermalBrightnessThrottlingDataIdLocked());
+ .getDisplayInfoLocked().thermalBrightnessThrottlingDataId);
assertEquals(DisplayDeviceConfig.DEFAULT_ID,
mLogicalDisplayMapper.getDisplayLocked(device2)
- .getThermalBrightnessThrottlingDataIdLocked());
+ .getDisplayInfoLocked().thermalBrightnessThrottlingDataId);
mLogicalDisplayMapper.setDeviceStateLocked(2, false);
advanceTime(1000);
@@ -674,10 +674,10 @@
assertFalse(mLogicalDisplayMapper.getDisplayLocked(device2).isInTransitionLocked());
assertEquals(DisplayDeviceConfig.DEFAULT_ID,
mLogicalDisplayMapper.getDisplayLocked(device1)
- .getThermalBrightnessThrottlingDataIdLocked());
+ .getDisplayInfoLocked().thermalBrightnessThrottlingDataId);
assertEquals(DisplayDeviceConfig.DEFAULT_ID,
mLogicalDisplayMapper.getDisplayLocked(device2)
- .getThermalBrightnessThrottlingDataIdLocked());
+ .getDisplayInfoLocked().thermalBrightnessThrottlingDataId);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java
index 5ea3029..f6cf571 100644
--- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java
@@ -205,4 +205,19 @@
assertNotEquals(info3, info2);
assertTrue(refreshRanges.contentEquals(info3.thermalRefreshRateThrottling));
}
+
+ @Test
+ public void testSetThermalBrightnessThrottlingDataId() {
+ String brightnessThrottlingDataId = "throttling_data_id";
+ DisplayInfo info1 = mLogicalDisplay.getDisplayInfoLocked();
+ mLogicalDisplay.setThermalBrightnessThrottlingDataIdLocked(brightnessThrottlingDataId);
+ DisplayInfo info2 = mLogicalDisplay.getDisplayInfoLocked();
+ // Display info should only be updated when updateLocked is called
+ assertEquals(info2, info1);
+
+ mLogicalDisplay.updateLocked(mDeviceRepo);
+ DisplayInfo info3 = mLogicalDisplay.getDisplayInfoLocked();
+ assertNotEquals(info3, info2);
+ assertEquals(brightnessThrottlingDataId, info3.thermalBrightnessThrottlingDataId);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
index eb208d2..d9cf15b 100644
--- a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -40,6 +41,7 @@
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.internal.util.test.FakeSettingsProviderRule;
import com.android.server.display.AutomaticBrightnessController;
+import com.android.server.display.brightness.BrightnessEvent;
import com.android.server.display.brightness.BrightnessReason;
import org.junit.After;
@@ -262,12 +264,13 @@
float automaticScreenBrightness = 0.3f;
AutomaticBrightnessController automaticBrightnessController = mock(
AutomaticBrightnessController.class);
- when(automaticBrightnessController.getAutomaticScreenBrightness()).thenReturn(
- automaticScreenBrightness);
+ when(automaticBrightnessController.getAutomaticScreenBrightness(any(BrightnessEvent.class)))
+ .thenReturn(automaticScreenBrightness);
mAutomaticBrightnessStrategy.setAutomaticBrightnessController(
automaticBrightnessController);
assertEquals(automaticScreenBrightness,
- mAutomaticBrightnessStrategy.getAutomaticScreenBrightness(), 0.0f);
+ mAutomaticBrightnessStrategy.getAutomaticScreenBrightness(
+ new BrightnessEvent(DISPLAY_ID)), 0.0f);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
index e492252..b2a3a57 100644
--- a/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
@@ -84,7 +84,6 @@
import com.android.internal.R;
import com.android.internal.display.BrightnessSynchronizer;
-import com.android.internal.display.RefreshRateSettingsUtils;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.Preconditions;
import com.android.internal.util.test.FakeSettingsProvider;
@@ -159,9 +158,6 @@
LocalServices.addService(SensorManagerInternal.class, mSensorManagerInternalMock);
LocalServices.removeServiceForTest(DisplayManagerInternal.class);
LocalServices.addService(DisplayManagerInternal.class, mDisplayManagerInternalMock);
-
- clearSmoothDisplaySetting();
- clearForcePeakRefreshRateSetting();
}
private DisplayModeDirector createDirectorFromRefreshRateArray(
@@ -922,6 +918,7 @@
public void testLockFpsForLowZone() throws Exception {
DisplayModeDirector director =
createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
+ setPeakRefreshRate(90);
director.getSettingsObserver().setDefaultRefreshRate(90);
director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
@@ -929,7 +926,6 @@
config.setRefreshRateInLowZone(90);
config.setLowDisplayBrightnessThresholds(new int[] { 10 });
config.setLowAmbientBrightnessThresholds(new int[] { 20 });
- config.setDefaultPeakRefreshRate(90);
Sensor lightSensor = createLightSensor();
SensorManager sensorManager = createMockSensorManager(lightSensor);
@@ -980,6 +976,7 @@
public void testLockFpsForHighZone() throws Exception {
DisplayModeDirector director =
createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
+ setPeakRefreshRate(90 /*fps*/);
director.getSettingsObserver().setDefaultRefreshRate(90);
director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
@@ -987,7 +984,6 @@
config.setRefreshRateInHighZone(60);
config.setHighDisplayBrightnessThresholds(new int[] { 255 });
config.setHighAmbientBrightnessThresholds(new int[] { 8000 });
- config.setDefaultPeakRefreshRate(90);
Sensor lightSensor = createLightSensor();
SensorManager sensorManager = createMockSensorManager(lightSensor);
@@ -1035,123 +1031,16 @@
}
@Test
- public void testSmoothDisplay() {
- float defaultRefreshRate = 60;
- int defaultPeakRefreshRate = 100;
- DisplayModeDirector director =
- createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
- director.getSettingsObserver().setDefaultRefreshRate(defaultRefreshRate);
- director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
-
- final FakeDeviceConfig config = mInjector.getDeviceConfig();
- config.setDefaultPeakRefreshRate(defaultPeakRefreshRate);
-
- Sensor lightSensor = createLightSensor();
- SensorManager sensorManager = createMockSensorManager(lightSensor);
- director.start(sensorManager);
-
- // Default value of the setting
-
- Vote vote = director.getVote(Display.DEFAULT_DISPLAY,
- Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
- assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
- defaultPeakRefreshRate);
- vote = director.getVote(Display.DEFAULT_DISPLAY,
- Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
- assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
- Float.POSITIVE_INFINITY);
- vote = director.getVote(Display.DEFAULT_DISPLAY,
- Vote.PRIORITY_DEFAULT_RENDER_FRAME_RATE);
- assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
- defaultRefreshRate);
-
- setSmoothDisplayEnabled(false);
-
- vote = director.getVote(Display.DEFAULT_DISPLAY,
- Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
- assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
- RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE);
- vote = director.getVote(Display.DEFAULT_DISPLAY,
- Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
- assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
- Float.POSITIVE_INFINITY);
- vote = director.getVote(Display.DEFAULT_DISPLAY,
- Vote.PRIORITY_DEFAULT_RENDER_FRAME_RATE);
- assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
- defaultRefreshRate);
-
- setSmoothDisplayEnabled(true);
-
- vote = director.getVote(Display.DEFAULT_DISPLAY,
- Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
- assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
- RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext));
- vote = director.getVote(Display.DEFAULT_DISPLAY,
- Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
- assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
- Float.POSITIVE_INFINITY);
- vote = director.getVote(Display.DEFAULT_DISPLAY,
- Vote.PRIORITY_DEFAULT_RENDER_FRAME_RATE);
- assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
- defaultRefreshRate);
- }
-
- @Test
- public void testForcePeakRefreshRate() {
- float defaultRefreshRate = 60;
- DisplayModeDirector director =
- createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
- director.getSettingsObserver().setDefaultRefreshRate(defaultRefreshRate);
- director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
-
- Sensor lightSensor = createLightSensor();
- SensorManager sensorManager = createMockSensorManager(lightSensor);
- director.start(sensorManager);
-
- setForcePeakRefreshRateEnabled(false);
- setSmoothDisplayEnabled(false);
-
- Vote vote = director.getVote(Display.DEFAULT_DISPLAY,
- Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
- assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
- RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE);
- vote = director.getVote(Display.DEFAULT_DISPLAY,
- Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
- assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0,
- /* frameRateHigh= */ Float.POSITIVE_INFINITY);
- vote = director.getVote(Display.DEFAULT_DISPLAY,
- Vote.PRIORITY_DEFAULT_RENDER_FRAME_RATE);
- assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
- defaultRefreshRate);
-
- setForcePeakRefreshRateEnabled(true);
-
- vote = director.getVote(Display.DEFAULT_DISPLAY,
- Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
- assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
- RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext));
- vote = director.getVote(Display.DEFAULT_DISPLAY,
- Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
- assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */
- RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext),
- /* frameRateHigh= */ Float.POSITIVE_INFINITY);
- vote = director.getVote(Display.DEFAULT_DISPLAY,
- Vote.PRIORITY_DEFAULT_RENDER_FRAME_RATE);
- assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
- defaultRefreshRate);
- }
-
- @Test
public void testSensorRegistration() {
// First, configure brightness zones or DMD won't register for sensor data.
final FakeDeviceConfig config = mInjector.getDeviceConfig();
config.setRefreshRateInHighZone(60);
config.setHighDisplayBrightnessThresholds(new int[] { 255 });
config.setHighAmbientBrightnessThresholds(new int[] { 8000 });
- config.setDefaultPeakRefreshRate(90);
DisplayModeDirector director =
createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
+ setPeakRefreshRate(90 /*fps*/);
director.getSettingsObserver().setDefaultRefreshRate(90);
director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
@@ -2527,10 +2416,10 @@
config.setRefreshRateInHighZone(60);
config.setHighDisplayBrightnessThresholds(new int[] { 255 });
config.setHighAmbientBrightnessThresholds(new int[] { 8000 });
- config.setDefaultPeakRefreshRate(90);
DisplayModeDirector director =
createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
+ setPeakRefreshRate(90 /*fps*/);
director.getSettingsObserver().setDefaultRefreshRate(90);
director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
@@ -2828,30 +2717,10 @@
listener.onDisplayChanged(DISPLAY_ID);
}
- private void setSmoothDisplayEnabled(boolean enabled) {
- Settings.System.putInt(mContext.getContentResolver(), Settings.System.SMOOTH_DISPLAY,
- enabled ? 1 : 0);
- mInjector.notifySmoothDisplaySettingChanged();
- waitForIdleSync();
- }
-
- private void clearSmoothDisplaySetting() {
- Settings.System.putInt(mContext.getContentResolver(), Settings.System.SMOOTH_DISPLAY, -1);
- mInjector.notifySmoothDisplaySettingChanged();
- waitForIdleSync();
- }
-
- private void setForcePeakRefreshRateEnabled(boolean enabled) {
- Settings.System.putInt(mContext.getContentResolver(),
- Settings.System.FORCE_PEAK_REFRESH_RATE, enabled ? 1 : 0);
- mInjector.notifyForcePeakRefreshRateSettingChanged();
- waitForIdleSync();
- }
-
- private void clearForcePeakRefreshRateSetting() {
- Settings.System.putInt(mContext.getContentResolver(),
- Settings.System.FORCE_PEAK_REFRESH_RATE, -1);
- mInjector.notifySmoothDisplaySettingChanged();
+ private void setPeakRefreshRate(float fps) {
+ Settings.System.putFloat(mContext.getContentResolver(), Settings.System.PEAK_REFRESH_RATE,
+ fps);
+ mInjector.notifyPeakRefreshRateChanged();
waitForIdleSync();
}
@@ -2900,8 +2769,7 @@
private final Display mDisplay;
private boolean mDisplayInfoValid = true;
private ContentObserver mBrightnessObserver;
- private ContentObserver mSmoothDisplaySettingObserver;
- private ContentObserver mForcePeakRefreshRateSettingObserver;
+ private ContentObserver mPeakRefreshRateObserver;
FakesInjector() {
mDeviceConfig = new FakeDeviceConfig();
@@ -2918,15 +2786,9 @@
}
@Override
- public void registerSmoothDisplayObserver(@NonNull ContentResolver cr,
+ public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
@NonNull ContentObserver observer) {
- mSmoothDisplaySettingObserver = observer;
- }
-
- @Override
- public void registerForcePeakRefreshRateObserver(@NonNull ContentResolver cr,
- @NonNull ContentObserver observer) {
- mForcePeakRefreshRateSettingObserver = observer;
+ mPeakRefreshRateObserver = observer;
}
@Override
@@ -2976,17 +2838,10 @@
ApplicationProvider.getApplicationContext().getResources());
}
- void notifySmoothDisplaySettingChanged() {
- if (mSmoothDisplaySettingObserver != null) {
- mSmoothDisplaySettingObserver.dispatchChange(false /*selfChange*/,
- SMOOTH_DISPLAY_URI);
- }
- }
-
- void notifyForcePeakRefreshRateSettingChanged() {
- if (mForcePeakRefreshRateSettingObserver != null) {
- mForcePeakRefreshRateSettingObserver.dispatchChange(false /*selfChange*/,
- FORCE_PEAK_REFRESH_RATE_URI);
+ void notifyPeakRefreshRateChanged() {
+ if (mPeakRefreshRateObserver != null) {
+ mPeakRefreshRateObserver.dispatchChange(false /*selfChange*/,
+ PEAK_REFRESH_RATE_URI);
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
index a446e10..c53a7a7 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
@@ -18,6 +18,7 @@
import static com.android.server.hdmi.HdmiCecMessageValidator.ERROR_DESTINATION;
import static com.android.server.hdmi.HdmiCecMessageValidator.ERROR_PARAMETER;
+import static com.android.server.hdmi.HdmiCecMessageValidator.ERROR_PARAMETER_LONG;
import static com.android.server.hdmi.HdmiCecMessageValidator.ERROR_PARAMETER_SHORT;
import static com.android.server.hdmi.HdmiCecMessageValidator.ERROR_SOURCE;
import static com.android.server.hdmi.HdmiCecMessageValidator.OK;
@@ -145,11 +146,12 @@
@Test
public void isValid_systemAudioModeStatus() {
assertMessageValidity("40:7E:00").isEqualTo(OK);
- assertMessageValidity("40:7E:01:01").isEqualTo(OK);
+ assertMessageValidity("40:7E:01").isEqualTo(OK);
assertMessageValidity("0F:7E:00").isEqualTo(ERROR_DESTINATION);
assertMessageValidity("F0:7E").isEqualTo(ERROR_SOURCE);
assertMessageValidity("40:7E").isEqualTo(ERROR_PARAMETER_SHORT);
+ assertMessageValidity("40:7E:01:1F:28").isEqualTo(ERROR_PARAMETER_LONG);
assertMessageValidity("40:7E:02").isEqualTo(ERROR_PARAMETER);
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 4dd5e94..fd6eb92 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -761,6 +761,13 @@
assertThat(mHdmiControlServiceSpy.handleCecCommand(message))
.isEqualTo(Constants.ABORT_INVALID_OPERAND);
+
+ // Validating ERROR_PARAMETER_LONG will generate ABORT_INVALID_OPERAND.
+ // Taken from HdmiCecMessageValidatorTest#isValid_systemAudioModeStatus
+ HdmiCecMessage systemAudioModeStatus = HdmiUtils.buildMessage("40:7E:01:1F:28");
+
+ assertThat(mHdmiControlServiceSpy.handleCecCommand(systemAudioModeStatus))
+ .isEqualTo(Constants.ABORT_INVALID_OPERAND);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodManagerServiceTests.java b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodManagerServiceTests.java
index d07831d..fd65807 100644
--- a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodManagerServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodManagerServiceTests.java
@@ -20,16 +20,25 @@
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
+import android.platform.test.annotations.Presubmit;
+
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.inputmethod.SoftInputShowHideReason;
+
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class InputMethodManagerServiceTests {
@@ -87,4 +96,25 @@
InputMethodManagerService.computeImeDisplayIdForTarget(
SYSTEM_DECORATION_SUPPORT_DISPLAY_ID, sChecker));
}
+
+ @Test
+ public void testSoftInputShowHideHistoryDump_withNulls_doesntThrow() {
+ var writer = new StringWriter();
+ var history = new InputMethodManagerService.SoftInputShowHideHistory();
+ history.addEntry(new InputMethodManagerService.SoftInputShowHideHistory.Entry(
+ null,
+ null,
+ null,
+ SOFT_INPUT_STATE_UNSPECIFIED,
+ SoftInputShowHideReason.SHOW_SOFT_INPUT,
+ false,
+ null,
+ null,
+ null,
+ null));
+
+ history.dump(new PrintWriter(writer), "" /* prefix */);
+
+ // Asserts that dump doesn't throw an NPE.
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java
index d9cd77d..af144cf 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java
@@ -37,7 +37,6 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import android.annotation.NonNull;
-import android.content.AttributionSource;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.INetd;
@@ -50,7 +49,7 @@
import android.os.PermissionEnforcer;
import android.os.Process;
import android.os.RemoteException;
-import android.permission.PermissionCheckerManager;
+import android.os.test.FakePermissionEnforcer;
import android.platform.test.annotations.Presubmit;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArrayMap;
@@ -90,7 +89,6 @@
private ArgumentCaptor<INetdUnsolicitedEventListener> mUnsolListenerCaptor;
private final MockDependencies mDeps = new MockDependencies();
- private final MockPermissionEnforcer mPermissionEnforcer = new MockPermissionEnforcer();
private final class MockDependencies extends NetworkManagementService.Dependencies {
@Override
@@ -118,24 +116,6 @@
}
}
- private static final class MockPermissionEnforcer extends PermissionEnforcer {
- @Override
- protected int checkPermission(@NonNull String permission,
- @NonNull AttributionSource source) {
- String[] granted = new String [] {
- android.Manifest.permission.NETWORK_SETTINGS,
- android.Manifest.permission.OBSERVE_NETWORK_POLICY,
- android.Manifest.permission.SHUTDOWN
- };
- for (String p : granted) {
- if (p.equals(permission)) {
- return PermissionCheckerManager.PERMISSION_GRANTED;
- }
- }
- return PermissionCheckerManager.PERMISSION_HARD_DENIED;
- }
- }
-
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -145,12 +125,15 @@
eq(ConnectivityManager.class));
doReturn(mCm).when(mContext).getSystemService(eq(Context.CONNECTIVITY_SERVICE));
// The AIDL stub will use PermissionEnforcer to check permission from the caller.
- // Mock the service. See MockPermissionEnforcer above.
+ // Mock the service and grant the expected permissions.
+ FakePermissionEnforcer permissionEnforcer = new FakePermissionEnforcer();
+ permissionEnforcer.grant(android.Manifest.permission.NETWORK_SETTINGS);
+ permissionEnforcer.grant(android.Manifest.permission.OBSERVE_NETWORK_POLICY);
+ permissionEnforcer.grant(android.Manifest.permission.SHUTDOWN);
doReturn(Context.PERMISSION_ENFORCER_SERVICE).when(mContext).getSystemServiceName(
eq(PermissionEnforcer.class));
- doReturn(mPermissionEnforcer).when(mContext).getSystemService(
+ doReturn(permissionEnforcer).when(mContext).getSystemService(
eq(Context.PERMISSION_ENFORCER_SERVICE));
-
// Start the service and wait until it connects to our socket.
mNMService = NetworkManagementService.create(mContext, mDeps);
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
index 397e3c1..539f329 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
@@ -36,6 +36,7 @@
import static org.mockito.Mockito.when;
import android.Manifest;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
@@ -47,7 +48,6 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.server.UiServiceTestCase;
-import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -67,7 +67,7 @@
public class PermissionHelperTest extends UiServiceTestCase {
@Mock
- private PermissionManagerServiceInternal mPmi;
+ private Context mContext;
@Mock
private IPackageManager mPackageManager;
@Mock
@@ -80,7 +80,7 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mPermissionHelper = new PermissionHelper(mPmi, mPackageManager, mPermManager);
+ mPermissionHelper = new PermissionHelper(mContext, mPackageManager, mPermManager);
PackageInfo testPkgInfo = new PackageInfo();
testPkgInfo.requestedPermissions = new String[]{ Manifest.permission.POST_NOTIFICATIONS };
when(mPackageManager.getPackageInfo(anyString(), anyLong(), anyInt()))
@@ -89,12 +89,12 @@
@Test
public void testHasPermission() throws Exception {
- when(mPmi.checkUidPermission(anyInt(), anyString()))
+ when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
.thenReturn(PERMISSION_GRANTED);
assertThat(mPermissionHelper.hasPermission(1)).isTrue();
- when(mPmi.checkUidPermission(anyInt(), anyString()))
+ when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
.thenReturn(PERMISSION_DENIED);
assertThat(mPermissionHelper.hasPermission(1)).isFalse();
@@ -241,7 +241,7 @@
@Test
public void testSetNotificationPermission_grantUserSet() throws Exception {
- when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+ when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
.thenReturn(PERMISSION_DENIED);
mPermissionHelper.setNotificationPermission("pkg", 10, true, true);
@@ -255,7 +255,7 @@
@Test
public void testSetNotificationPermission_pkgPerm_grantedByDefaultPermSet_allUserSet()
throws Exception {
- when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+ when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
.thenReturn(PERMISSION_DENIED);
when(mPermManager.getPermissionFlags(anyString(),
eq(Manifest.permission.POST_NOTIFICATIONS),
@@ -273,7 +273,7 @@
@Test
public void testSetNotificationPermission_revokeUserSet() throws Exception {
- when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+ when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
.thenReturn(PERMISSION_GRANTED);
mPermissionHelper.setNotificationPermission("pkg", 10, false, true);
@@ -287,7 +287,7 @@
@Test
public void testSetNotificationPermission_grantNotUserSet() throws Exception {
- when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+ when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
.thenReturn(PERMISSION_DENIED);
mPermissionHelper.setNotificationPermission("pkg", 10, true, false);
@@ -300,7 +300,7 @@
@Test
public void testSetNotificationPermission_revokeNotUserSet() throws Exception {
- when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+ when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
.thenReturn(PERMISSION_GRANTED);
mPermissionHelper.setNotificationPermission("pkg", 10, false, false);
@@ -340,7 +340,7 @@
@Test
public void testSetNotificationPermission_alreadyGrantedNotRegranted() throws Exception {
- when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+ when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
.thenReturn(PERMISSION_GRANTED);
mPermissionHelper.setNotificationPermission("pkg", 10, true, false);
@@ -350,7 +350,7 @@
@Test
public void testSetNotificationPermission_alreadyRevokedNotRerevoked() throws Exception {
- when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+ when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
.thenReturn(PERMISSION_DENIED);
mPermissionHelper.setNotificationPermission("pkg", 10, false, false);
@@ -360,16 +360,19 @@
@Test
public void testSetNotificationPermission_doesntRequestNotChanged() throws Exception {
- when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+ int testUid = -1;
+ when(mContext.checkPermission(anyString(), anyInt(), anyInt()))
.thenReturn(PERMISSION_GRANTED);
+ when(mPackageManager.getPackageUid(anyString(), anyInt(), anyInt()))
+ .thenReturn(testUid);
PackageInfo testPkgInfo = new PackageInfo();
testPkgInfo.requestedPermissions = new String[]{ Manifest.permission.RECORD_AUDIO };
when(mPackageManager.getPackageInfo(anyString(), anyLong(), anyInt()))
.thenReturn(testPkgInfo);
mPermissionHelper.setNotificationPermission("pkg", 10, false, false);
- verify(mPmi, never()).checkPermission(
- eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(10));
+ verify(mContext, never()).checkPermission(
+ eq(Manifest.permission.POST_NOTIFICATIONS), eq(-1), eq(testUid));
verify(mPermManager, never()).revokeRuntimePermission(
eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(10), anyString());
}
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index 5636795..3513557 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -202,9 +202,11 @@
.canonicalToCurrentPackageNames(any());
} catch (PackageManager.NameNotFoundException ignored) { }
- doReturn(mTelecomManager).when(mContext).getSystemService(eq(Context.TELECOM_SERVICE));
- doReturn(mNotificationManager).when(mContext)
- .getSystemService(eq(NotificationManager.class));
+ doReturn(false).when(mTelecomManager).isInCall();
+ doReturn(false).when(mTelecomManager).isRinging();
+ doReturn(mTelecomManager).when(mPhoneWindowManager).getTelecommService();
+ doNothing().when(mNotificationManager).silenceNotificationSound();
+ doReturn(mNotificationManager).when(mPhoneWindowManager).getNotificationService();
doReturn(mVibrator).when(mContext).getSystemService(eq(Context.VIBRATOR_SERVICE));
final PowerManager.WakeLock wakeLock = mock(PowerManager.WakeLock.class);
@@ -235,6 +237,7 @@
doNothing().when(mPhoneWindowManager).screenTurnedOn(anyInt());
doNothing().when(mPhoneWindowManager).startedWakingUp(anyInt(), anyInt());
doNothing().when(mPhoneWindowManager).finishedWakingUp(anyInt(), anyInt());
+ doNothing().when(mPhoneWindowManager).lockNow(any());
mPhoneWindowManager.init(new TestInjector(mContext, mWindowManagerFuncsImpl));
mPhoneWindowManager.systemReady();
@@ -249,6 +252,7 @@
void tearDown() {
mHandlerThread.quitSafely();
LocalServices.removeServiceForTest(InputMethodManagerInternal.class);
+ Mockito.reset(mPhoneWindowManager);
mMockitoSession.finishMocking();
}
@@ -322,6 +326,7 @@
void overrideDisplayState(int state) {
doReturn(state).when(mDisplay).getState();
+ doReturn(state == STATE_ON).when(mDisplayPolicy).isAwake();
Mockito.reset(mPowerManager);
}
@@ -388,6 +393,7 @@
}
void assertDreamRequest() {
+ waitForIdle();
verify(mDreamManagerInternal).requestDream();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index dfc453f..d173ce9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -1134,7 +1134,7 @@
TaskChangeNotificationController controller = mAtm.getTaskChangeNotificationController();
spyOn(controller);
mWm.mRoot.lockAllProfileTasks(profileUserId);
- verify(controller).notifyTaskProfileLocked(any());
+ verify(controller).notifyTaskProfileLocked(any(), eq(profileUserId));
// Create the work lock activity on top of the task
final ActivityRecord workLockActivity = new ActivityBuilder(mAtm).setTask(task).build();
@@ -1144,7 +1144,7 @@
// Make sure the listener won't be notified again.
clearInvocations(controller);
mWm.mRoot.lockAllProfileTasks(profileUserId);
- verify(controller, never()).notifyTaskProfileLocked(any());
+ verify(controller, never()).notifyTaskProfileLocked(any(), anyInt());
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceControlTests.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceControlTests.java
index 342ab83..4f45d5c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceControlTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceControlTests.java
@@ -125,9 +125,10 @@
public void testSurfaceChangedOnRotation() {
final Instrumentation instrumentation = getInstrumentation();
final Context context = instrumentation.getContext();
- final Activity activity = instrumentation.startActivitySync(new Intent().setComponent(
+ final Intent intent = new Intent().setComponent(
new ComponentName(context, ActivityOptionsTest.MainActivity.class))
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ final Activity activity = instrumentation.startActivitySync(intent);
final SurfaceView sv = new SurfaceView(activity);
final AtomicInteger surfaceChangedCount = new AtomicInteger();
instrumentation.runOnMainSync(() -> activity.setContentView(sv));
@@ -157,12 +158,27 @@
instrumentation.waitForIdleSync();
final int newRotation = activity.getResources().getConfiguration()
.windowConfiguration.getRotation();
+ if (rotation == newRotation) {
+ // The device might not support requested orientation.
+ activity.finishAndRemoveTask();
+ return;
+ }
final int count = surfaceChangedCount.get();
+ activity.moveTaskToBack(true /* nonRoot */);
+ instrumentation.getUiAutomation().syncInputTransactions();
+ context.startActivity(intent);
+ instrumentation.getUiAutomation().syncInputTransactions();
+ final int countAfterToFront = count - surfaceChangedCount.get();
activity.finishAndRemoveTask();
+
// The first count is triggered from creation, so the target number is 2.
- if (rotation != newRotation && count > 2) {
+ if (count > 2) {
fail("More than once surfaceChanged for rotation change: " + count);
}
+ if (countAfterToFront > 1) {
+ fail("More than once surfaceChanged for app transition with rotation change: "
+ + countAfterToFront);
+ }
}
private SurfaceControl buildTestSurface() {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index a98429a..ef13594 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -2539,10 +2539,20 @@
}
@Override
- public void reportChooserSelection(String packageName, int userId, String contentType,
- String[] annotations, String action) {
+ public void reportChooserSelection(@NonNull String packageName, int userId,
+ @NonNull String contentType, String[] annotations, @NonNull String action) {
if (packageName == null) {
- Slog.w(TAG, "Event report user selecting a null package");
+ throw new IllegalArgumentException("Package selection must not be null.");
+ }
+ if (contentType == null) {
+ throw new IllegalArgumentException("Content type for selection must not be null.");
+ }
+ if (action == null) {
+ throw new IllegalArgumentException("Selection action must not be null.");
+ }
+ // Verify if this package exists before reporting an event for it.
+ if (mPackageManagerInternal.getPackageUid(packageName, 0, userId) < 0) {
+ Slog.w(TAG, "Event report user selecting an invalid package");
return;
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index b062e6b..913535e 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -296,7 +296,10 @@
// Helper to add session logger to the capacity limited detached list.
// If we are at capacity, remove the oldest, and retry
- private void addDetachedSessionLogger(EventLogger logger) {
+ private void detachSessionLogger(EventLogger logger) {
+ if (!mSessionEventLoggers.remove(logger)) {
+ return;
+ }
// Attempt to push to the top of the queue
while (!mDetachedSessionEventLoggers.offerFirst(logger)) {
// Remove the oldest element, if one still exists
@@ -872,8 +875,7 @@
private void detach() {
mSoundTriggerHelper.detach();
- mSessionEventLoggers.remove(mEventLogger);
- addDetachedSessionLogger(mEventLogger);
+ detachSessionLogger(mEventLogger);
}
private void enforceCallingPermission(String permission) {
@@ -1659,8 +1661,7 @@
private void detachInternal() {
mEventLogger.enqueue(new SessionEvent(Type.DETACH, null));
- mSessionEventLoggers.remove(mEventLogger);
- addDetachedSessionLogger(mEventLogger);
+ detachSessionLogger(mEventLogger);
mSoundTriggerHelper.detach();
}
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
index 13fe14c..00cedd7 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
@@ -78,7 +78,7 @@
public @NonNull
SoundTriggerModuleDescriptor[] listModules() {
Identity identity = getIdentity();
- enforcePermissionsForPreflight(identity);
+ enforcePermissionForPreflight(mContext, identity, CAPTURE_AUDIO_HOTWORD);
return mDelegate.listModules();
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 486945d..edaaf3f 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -913,8 +913,10 @@
}
// Handle case where all hotword detector sessions are destroyed with only the visual
// detector session left
- if (mDetectorSessions.size() == 1
- && mDetectorSessions.get(0) instanceof VisualQueryDetectorSession) {
+ boolean allHotwordDetectionServiceSessionsRemoved = mDetectorSessions.size() == 0
+ || (mDetectorSessions.size() == 1 && mDetectorSessions.get(0)
+ instanceof VisualQueryDetectorSession);
+ if (allHotwordDetectionServiceSessionsRemoved) {
unbindHotwordDetectionService();
}
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index f27c23b..1888943 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -5773,14 +5773,15 @@
* </ul>
* @hide
*/
- public static final String KEY_SA_DISABLE_POLICY_INT = KEY_PREFIX + "sa_disable_policy_int";
+ public static final String KEY_NR_SA_DISABLE_POLICY_INT =
+ KEY_PREFIX + "sa_disable_policy_int";
/** @hide */
@IntDef({
- SA_DISABLE_POLICY_NONE,
- SA_DISABLE_POLICY_WFC_ESTABLISHED,
- SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED,
- SA_DISABLE_POLICY_VOWIFI_REGISTERED
+ NR_SA_DISABLE_POLICY_NONE,
+ NR_SA_DISABLE_POLICY_WFC_ESTABLISHED,
+ NR_SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED,
+ NR_SA_DISABLE_POLICY_VOWIFI_REGISTERED
})
public @interface NrSaDisablePolicy {}
@@ -5788,14 +5789,14 @@
* Do not disables NR SA mode.
* @hide
*/
- public static final int SA_DISABLE_POLICY_NONE = 0;
+ public static final int NR_SA_DISABLE_POLICY_NONE = 0;
/**
* Disables NR SA mode when VoWiFi call is established in order to improve the delay or
* voice mute when the handover from ePDG to NR is not supported in UE or network.
* @hide
*/
- public static final int SA_DISABLE_POLICY_WFC_ESTABLISHED = 1;
+ public static final int NR_SA_DISABLE_POLICY_WFC_ESTABLISHED = 1;
/**
* Disables NR SA mode when VoWiFi call is established when VoNR is disabled in order to
@@ -5803,14 +5804,14 @@
* in UE or network.
* @hide
*/
- public static final int SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED = 2;
+ public static final int NR_SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED = 2;
/**
* Disables NR SA mode when IMS is registered over WiFi in order to improve the delay or
* voice mute when the handover from ePDG to NR is not supported in UE or network.
* @hide
*/
- public static final int SA_DISABLE_POLICY_VOWIFI_REGISTERED = 3;
+ public static final int NR_SA_DISABLE_POLICY_VOWIFI_REGISTERED = 3;
private Ims() {}
@@ -5883,7 +5884,7 @@
defaults.putInt(KEY_REGISTRATION_RETRY_BASE_TIMER_MILLIS_INT, 30000);
defaults.putInt(KEY_REGISTRATION_RETRY_MAX_TIMER_MILLIS_INT, 1800000);
defaults.putInt(KEY_REGISTRATION_SUBSCRIBE_EXPIRY_TIMER_SEC_INT, 600000);
- defaults.putInt(KEY_SA_DISABLE_POLICY_INT, SA_DISABLE_POLICY_NONE);
+ defaults.putInt(KEY_NR_SA_DISABLE_POLICY_INT, NR_SA_DISABLE_POLICY_NONE);
defaults.putIntArray(
KEY_IPSEC_AUTHENTICATION_ALGORITHMS_INT_ARRAY,