Merge "Block relayout during transition to desktop" 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/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/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/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/provider/Settings.java b/core/java/android/provider/Settings.java
index 79e7574..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
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 6061a0f..7822dde 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -1063,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/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/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/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/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/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/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/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
index a2b35d3..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
@@ -21,7 +21,6 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_OPEN;
@@ -494,18 +493,17 @@
mController = null;
}
- // TODO(b/278084491): pass in display id
- public void showDesktopApps() {
+ @Override
+ public void showDesktopApps(int displayId) {
executeRemoteCallWithTaskPermission(mController, "showDesktopApps",
- controller -> controller.showDesktopApps(DEFAULT_DISPLAY));
+ controller -> controller.showDesktopApps(displayId));
}
- // TODO(b/278084491): pass in display id
@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(DEFAULT_DISPLAY),
+ controller -> result[0] = controller.getVisibleTaskCount(displayId),
true /* blocking */
);
return result[0];
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 5e4844a..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
@@ -30,7 +30,6 @@
import android.graphics.Region
import android.os.IBinder
import android.os.SystemProperties
-import android.view.Display.DEFAULT_DISPLAY
import android.view.SurfaceControl
import android.view.WindowManager.TRANSIT_CHANGE
import android.view.WindowManager.TRANSIT_NONE
@@ -561,21 +560,19 @@
controller = null
}
- // TODO(b/278084491): pass in display id
- override fun showDesktopApps() {
+ override fun showDesktopApps(displayId: Int) {
ExecutorUtils.executeRemoteCallWithTaskPermission(
controller,
"showDesktopApps"
- ) { c -> c.showDesktopApps(DEFAULT_DISPLAY) }
+ ) { c -> c.showDesktopApps(displayId) }
}
- // TODO(b/278084491): pass in display id
- override fun getVisibleTaskCount(): Int {
+ override fun getVisibleTaskCount(displayId: Int): Int {
val result = IntArray(1)
ExecutorUtils.executeRemoteCallWithTaskPermission(
controller,
"getVisibleTaskCount",
- { controller -> result[0] = controller.getVisibleTaskCount(DEFAULT_DISPLAY) },
+ { 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/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/transition/Tracer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java
index 9d7c39f..ba364f8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java
@@ -73,7 +73,8 @@
if (mHandlerIds.containsKey(handler)) {
handlerId = mHandlerIds.get(handler);
} else {
- handlerId = mHandlerIds.size();
+ // + 1 to avoid 0 ids which can be confused with missing value when dumped to proto
+ handlerId = mHandlerIds.size() + 1;
mHandlerIds.put(handler, handlerId);
}
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/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/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/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/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/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/Android.bp b/packages/SystemUI/Android.bp
index 6a7b8cd..e6bbf97 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -158,7 +158,6 @@
"SystemUIAnimationLib",
"SystemUICommon",
"SystemUICustomizationLib",
- "SystemUILogLib",
"SystemUIPluginLib",
"SystemUISharedLib",
"SystemUI-statsd",
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 6e55000..c8eb4b4 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -992,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/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
index 941a925..3a19990 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
@@ -33,8 +33,8 @@
import com.android.systemui.animation.Interpolators
import com.android.systemui.animation.TextAnimator
import com.android.systemui.customization.R
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.DEBUG
import java.io.PrintWriter
import java.util.Calendar
import java.util.Locale
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
index aa1bb3f..b0c0240 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
@@ -23,12 +23,6 @@
import android.provider.Settings
import android.util.Log
import androidx.annotation.OpenForTesting
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.LogMessage
-import com.android.systemui.log.LogMessageImpl
-import com.android.systemui.log.MessageInitializer
-import com.android.systemui.log.MessagePrinter
import com.android.systemui.plugins.ClockController
import com.android.systemui.plugins.ClockId
import com.android.systemui.plugins.ClockMetadata
@@ -38,6 +32,12 @@
import com.android.systemui.plugins.PluginLifecycleManager
import com.android.systemui.plugins.PluginListener
import com.android.systemui.plugins.PluginManager
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.plugins.log.LogMessage
+import com.android.systemui.plugins.log.LogMessageImpl
+import com.android.systemui.plugins.log.MessageInitializer
+import com.android.systemui.plugins.log.MessagePrinter
import com.android.systemui.util.Assert
import java.io.PrintWriter
import java.util.concurrent.ConcurrentHashMap
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
index 6aa74fb..2cc3600 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
@@ -24,7 +24,6 @@
import android.widget.FrameLayout
import androidx.annotation.VisibleForTesting
import com.android.systemui.customization.R
-import com.android.systemui.log.LogBuffer
import com.android.systemui.plugins.ClockAnimations
import com.android.systemui.plugins.ClockConfig
import com.android.systemui.plugins.ClockController
@@ -33,6 +32,7 @@
import com.android.systemui.plugins.ClockFaceController
import com.android.systemui.plugins.ClockFaceEvents
import com.android.systemui.plugins.ClockSettings
+import com.android.systemui.plugins.log.LogBuffer
import java.io.PrintWriter
import java.util.Locale
import java.util.TimeZone
diff --git a/packages/SystemUI/log/.gitignore b/packages/SystemUI/log/.gitignore
deleted file mode 100644
index f9a33db..0000000
--- a/packages/SystemUI/log/.gitignore
+++ /dev/null
@@ -1,9 +0,0 @@
-.idea/
-.gradle/
-gradle/
-build/
-gradlew*
-local.properties
-*.iml
-android.properties
-buildSrc
\ No newline at end of file
diff --git a/packages/SystemUI/log/Android.bp b/packages/SystemUI/log/Android.bp
deleted file mode 100644
index 627ac4b..0000000
--- a/packages/SystemUI/log/Android.bp
+++ /dev/null
@@ -1,38 +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 {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
-}
-
-android_library {
- name: "SystemUILogLib",
- srcs: [
- "src/**/*.java",
- "src/**/*.kt",
- ],
- static_libs: [
- "androidx.core_core-ktx",
- "androidx.annotation_annotation",
- "error_prone_annotations",
- "SystemUICommon",
- ],
- manifest: "AndroidManifest.xml",
- kotlincflags: ["-Xjvm-default=all"],
-}
diff --git a/packages/SystemUI/log/AndroidManifest.xml b/packages/SystemUI/log/AndroidManifest.xml
deleted file mode 100644
index 4021e1a..0000000
--- a/packages/SystemUI/log/AndroidManifest.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.systemui.log">
-
-
-</manifest>
diff --git a/packages/SystemUI/plugin/Android.bp b/packages/SystemUI/plugin/Android.bp
index 1008d37..e306d4a 100644
--- a/packages/SystemUI/plugin/Android.bp
+++ b/packages/SystemUI/plugin/Android.bp
@@ -34,10 +34,10 @@
static_libs: [
"androidx.annotation_annotation",
+ "error_prone_annotations",
"PluginCoreLib",
"SystemUIAnimationLib",
"SystemUICommon",
- "SystemUILogLib",
],
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
index 7bf139e..ca3e710 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
@@ -18,8 +18,8 @@
import android.graphics.drawable.Drawable
import android.view.View
import com.android.internal.annotations.Keep
-import com.android.systemui.log.LogBuffer
import com.android.systemui.plugins.annotations.ProvidesInterface
+import com.android.systemui.plugins.log.LogBuffer
import java.io.PrintWriter
import java.util.Locale
import java.util.TimeZone
diff --git a/packages/SystemUI/log/src/com/android/systemui/log/ConstantStringsLogger.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/ConstantStringsLogger.kt
similarity index 95%
rename from packages/SystemUI/log/src/com/android/systemui/log/ConstantStringsLogger.kt
rename to packages/SystemUI/plugin/src/com/android/systemui/plugins/log/ConstantStringsLogger.kt
index bc35095..f95b187 100644
--- a/packages/SystemUI/log/src/com/android/systemui/log/ConstantStringsLogger.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/ConstantStringsLogger.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.log
+package com.android.systemui.plugins.log
import com.google.errorprone.annotations.CompileTimeConstant
diff --git a/packages/SystemUI/log/src/com/android/systemui/log/ConstantStringsLoggerImpl.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/ConstantStringsLoggerImpl.kt
similarity index 96%
rename from packages/SystemUI/log/src/com/android/systemui/log/ConstantStringsLoggerImpl.kt
rename to packages/SystemUI/plugin/src/com/android/systemui/plugins/log/ConstantStringsLoggerImpl.kt
index 6fc52536..91b39e6 100644
--- a/packages/SystemUI/log/src/com/android/systemui/log/ConstantStringsLoggerImpl.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/ConstantStringsLoggerImpl.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.log
+package com.android.systemui.plugins.log
import com.google.errorprone.annotations.CompileTimeConstant
diff --git a/packages/SystemUI/log/src/com/android/systemui/log/LogBuffer.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt
similarity index 99%
rename from packages/SystemUI/log/src/com/android/systemui/log/LogBuffer.kt
rename to packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt
index af1a11f..0a7ccc5 100644
--- a/packages/SystemUI/log/src/com/android/systemui/log/LogBuffer.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.log
+package com.android.systemui.plugins.log
import android.os.Trace
import android.util.Log
diff --git a/packages/SystemUI/log/src/com/android/systemui/log/LogLevel.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogLevel.kt
similarity index 95%
rename from packages/SystemUI/log/src/com/android/systemui/log/LogLevel.kt
rename to packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogLevel.kt
index 7d9647a..b036cf0 100644
--- a/packages/SystemUI/log/src/com/android/systemui/log/LogLevel.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogLevel.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.log
+package com.android.systemui.plugins.log
import android.util.Log
diff --git a/packages/SystemUI/log/src/com/android/systemui/log/LogMessage.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogMessage.kt
similarity index 98%
rename from packages/SystemUI/log/src/com/android/systemui/log/LogMessage.kt
rename to packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogMessage.kt
index 88c34f8..9468681 100644
--- a/packages/SystemUI/log/src/com/android/systemui/log/LogMessage.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogMessage.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.log
+package com.android.systemui.plugins.log
import java.io.PrintWriter
import java.text.SimpleDateFormat
diff --git a/packages/SystemUI/log/src/com/android/systemui/log/LogMessageImpl.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogMessageImpl.kt
similarity index 97%
rename from packages/SystemUI/log/src/com/android/systemui/log/LogMessageImpl.kt
rename to packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogMessageImpl.kt
index 5e10f78..f2a6a91 100644
--- a/packages/SystemUI/log/src/com/android/systemui/log/LogMessageImpl.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogMessageImpl.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.log
+package com.android.systemui.plugins.log
/** Recyclable implementation of [LogMessage]. */
data class LogMessageImpl(
diff --git a/packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTracker.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTracker.kt
similarity index 96%
rename from packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTracker.kt
rename to packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTracker.kt
index 55f3a73..cfe894f 100644
--- a/packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTracker.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTracker.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.log
+package com.android.systemui.plugins.log
/** Keeps track of which [LogBuffer] messages should also appear in logcat. */
interface LogcatEchoTracker {
diff --git a/packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTrackerDebug.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerDebug.kt
similarity index 98%
rename from packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTrackerDebug.kt
rename to packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerDebug.kt
index d0ad28f..7a125ac 100644
--- a/packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTrackerDebug.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerDebug.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.log
+package com.android.systemui.plugins.log
import android.content.ContentResolver
import android.database.ContentObserver
diff --git a/packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTrackerProd.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerProd.kt
similarity index 95%
rename from packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTrackerProd.kt
rename to packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerProd.kt
index 56966773..3c8bda4 100644
--- a/packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTrackerProd.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerProd.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.log
+package com.android.systemui.plugins.log
/** Production version of [LogcatEchoTracker] that isn't configurable. */
class LogcatEchoTrackerProd : LogcatEchoTracker {
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/tests/src/com/android/systemui/log/LogBufferTest.kt b/packages/SystemUI/plugin/tests/log/LogBufferTest.kt
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/log/LogBufferTest.kt
rename to packages/SystemUI/plugin/tests/log/LogBufferTest.kt
index 0cf6d3d..a39b856 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/LogBufferTest.kt
+++ b/packages/SystemUI/plugin/tests/log/LogBufferTest.kt
@@ -2,6 +2,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.log.LogBuffer
import com.google.common.truth.Truth.assertThat
import java.io.PrintWriter
import java.io.StringWriter
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/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/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 6b461ee..c57fef1 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3038,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/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/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 4bf7be6..8b87e2a 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -42,14 +42,14 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
import com.android.systemui.log.dagger.KeyguardLargeClockLog
import com.android.systemui.log.dagger.KeyguardSmallClockLog
import com.android.systemui.plugins.ClockController
import com.android.systemui.plugins.ClockFaceController
import com.android.systemui.plugins.ClockTickRate
import com.android.systemui.plugins.WeatherData
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.DEBUG
import com.android.systemui.shared.regionsampling.RegionSampler
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 4629e8b..beb0949 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -15,12 +15,13 @@
import androidx.annotation.IntDef;
import androidx.annotation.VisibleForTesting;
+import com.android.keyguard.clock.DefaultClockController;
import com.android.keyguard.dagger.KeyguardStatusViewScope;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
-import com.android.systemui.log.LogBuffer;
-import com.android.systemui.log.LogLevel;
import com.android.systemui.plugins.ClockController;
+import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.plugins.log.LogLevel;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -46,6 +47,9 @@
public static final int LARGE = 0;
public static final int SMALL = 1;
+ // compensate for translation of parents subject to device screen
+ // In this case, the translation comes from KeyguardStatusView
+ public int screenOffsetYPadding = 0;
/** Returns a region for the large clock to position itself, based on the given parent. */
public static Rect getLargeClockRegion(ViewGroup parent) {
@@ -161,8 +165,18 @@
}
if (mLargeClockFrame.isLaidOut()) {
- mClock.getLargeClock().getEvents().onTargetRegionChanged(
- getLargeClockRegion(mLargeClockFrame));
+ Rect targetRegion = getLargeClockRegion(mLargeClockFrame);
+ if (mClock instanceof DefaultClockController) {
+ mClock.getLargeClock().getEvents().onTargetRegionChanged(
+ targetRegion);
+ } else {
+ mClock.getLargeClock().getEvents().onTargetRegionChanged(
+ new Rect(
+ targetRegion.left,
+ targetRegion.top - screenOffsetYPadding,
+ targetRegion.right,
+ targetRegion.bottom - screenOffsetYPadding));
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 50dac32..aee9abc 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -39,10 +39,10 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
-import com.android.systemui.log.LogBuffer;
-import com.android.systemui.log.LogLevel;
import com.android.systemui.log.dagger.KeyguardClockLog;
import com.android.systemui.plugins.ClockController;
+import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.plugins.log.LogLevel;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.clocks.ClockRegistry;
import com.android.systemui.shared.regionsampling.RegionSampler;
@@ -169,6 +169,14 @@
}
/**
+ * Used for status view to pass the screen offset from parent view
+ */
+ public void setLockscreenClockY(int clockY) {
+ mView.screenOffsetYPadding = clockY;
+ mView.updateClockTargetRegions();
+ }
+
+ /**
* Attach the controller to the view it relates to.
*/
@Override
@@ -394,13 +402,6 @@
PropertyAnimator.setProperty(mStatusArea, AnimatableProperty.TRANSLATION_X,
x, props, animate);
}
-
- }
-
- void updateKeyguardStatusViewOffset() {
- // updateClockTargetRegions will call onTargetRegionChanged
- // which will require the correct translationY property of keyguardStatusView after updating
- mView.updateClockTargetRegions();
}
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 0826f8a..68d8143 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -215,6 +215,15 @@
}
/**
+ * Pass top margin from ClockPositionAlgorithm in NotificationPanelViewController
+ * Use for clock view in LS to compensate for top margin to align to the screen
+ * Regardless of translation from AOD and unlock gestures
+ */
+ public void setLockscreenClockY(int clockY) {
+ mKeyguardClockSwitchController.setLockscreenClockY(clockY);
+ }
+
+ /**
* Set whether the view accessibility importance mode.
*/
public void setStatusAccessibilityImportance(int mode) {
@@ -230,7 +239,6 @@
* Update position of the view with an optional animation
*/
public void updatePosition(int x, int y, float scale, boolean animate) {
- float oldY = mView.getY();
setProperty(AnimatableProperty.Y, y, animate);
ClockController clock = mKeyguardClockSwitchController.getClock();
@@ -246,10 +254,6 @@
setProperty(AnimatableProperty.SCALE_X, 1f, animate);
setProperty(AnimatableProperty.SCALE_Y, 1f, animate);
}
-
- if (oldY != y) {
- mKeyguardClockSwitchController.updateKeyguardStatusViewOffset();
- }
}
/**
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/keyguard/KeyguardVisibilityHelper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
index d8568ba..651c979 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
@@ -22,8 +22,8 @@
import android.view.View;
import com.android.systemui.animation.Interpolators;
-import com.android.systemui.log.LogBuffer;
-import com.android.systemui.log.LogLevel;
+import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.plugins.log.LogLevel;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
index 2d0bf9c..6740375 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
@@ -27,9 +27,9 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
-import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.dagger.KeyguardClockLog;
import com.android.systemui.plugins.PluginManager;
+import com.android.systemui.plugins.log.LogBuffer;
import com.android.systemui.shared.clocks.ClockRegistry;
import com.android.systemui.shared.clocks.DefaultClockProvider;
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/BiometricMessageDeferralLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/BiometricMessageDeferralLogger.kt
index e7295ef..2bb75aa 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/BiometricMessageDeferralLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/BiometricMessageDeferralLogger.kt
@@ -17,9 +17,9 @@
package com.android.keyguard.logging
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
import com.android.systemui.log.dagger.BiometricLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.DEBUG
import javax.inject.Inject
/** Helper class for logging for [com.android.systemui.biometrics.FaceHelpMessageDeferral] */
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt
index c00b2c6..20f9007 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt
@@ -18,11 +18,11 @@
import android.hardware.biometrics.BiometricSourceType
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.INFO
import com.android.systemui.log.dagger.BiometricLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.plugins.log.LogLevel.DEBUG
+import com.android.systemui.plugins.log.LogLevel.INFO
import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_DISMISS_BOUNCER
import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_NONE
import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_ONLY_WAKE
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
index 8b925b1..4d71a89 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
@@ -18,9 +18,9 @@
import com.android.systemui.biometrics.AuthRippleController
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.KeyguardLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.statusbar.KeyguardIndicationController
import com.google.errorprone.annotations.CompileTimeConstant
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
index 9058754..1661806 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
@@ -27,13 +27,13 @@
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.keyguard.TrustGrantFlags
import com.android.systemui.log.dagger.KeyguardUpdateMonitorLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.ERROR
-import com.android.systemui.log.LogLevel.INFO
-import com.android.systemui.log.LogLevel.VERBOSE
-import com.android.systemui.log.LogLevel.WARNING
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.plugins.log.LogLevel.DEBUG
+import com.android.systemui.plugins.log.LogLevel.ERROR
+import com.android.systemui.plugins.log.LogLevel.INFO
+import com.android.systemui.plugins.log.LogLevel.VERBOSE
+import com.android.systemui.plugins.log.LogLevel.WARNING
import com.google.errorprone.annotations.CompileTimeConstant
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/TrustRepositoryLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/TrustRepositoryLogger.kt
index daafea8..249b3fe 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/TrustRepositoryLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/TrustRepositoryLogger.kt
@@ -18,9 +18,9 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.TrustModel
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.KeyguardUpdateMonitorLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
/** Logging helper for trust repository. */
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/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index 55f6d07..d0ac296 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -37,7 +37,7 @@
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.WakefulnessLifecycle
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.CircleReveal
import com.android.systemui.statusbar.LiftReveal
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/UdfpsLogger.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsLogger.kt
index 39199d1..0d08b43 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsLogger.kt
@@ -16,12 +16,12 @@
package com.android.systemui.biometrics
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.LogLevel.ERROR
-import com.android.systemui.log.LogLevel.VERBOSE
-import com.android.systemui.log.LogLevel.WARNING
import com.android.systemui.log.dagger.UdfpsLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.plugins.log.LogLevel.ERROR
+import com.android.systemui.plugins.log.LogLevel.VERBOSE
+import com.android.systemui.plugins.log.LogLevel.WARNING
import com.google.errorprone.annotations.CompileTimeConstant
import javax.inject.Inject
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/bluetooth/BluetoothLogger.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/BluetoothLogger.kt
index 96af42b..d99625a 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/BluetoothLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/BluetoothLogger.kt
@@ -17,9 +17,9 @@
package com.android.systemui.bluetooth
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.BluetoothLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
/** Helper class for logging bluetooth events. */
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt b/packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt
index 5b3a982..d27708f 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt
@@ -20,11 +20,11 @@
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.INFO
-import com.android.systemui.log.LogMessage
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.plugins.log.LogLevel.DEBUG
+import com.android.systemui.plugins.log.LogLevel.INFO
+import com.android.systemui.plugins.log.LogMessage
import com.android.systemui.log.dagger.BroadcastDispatcherLog
import javax.inject.Inject
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/doze/DozeLogger.kt b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
index 5369780..d19c6ec 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
@@ -19,10 +19,10 @@
import android.view.Display
import com.android.systemui.doze.DozeLog.Reason
import com.android.systemui.doze.DozeLog.reasonToString
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.ERROR
-import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.DEBUG
+import com.android.systemui.plugins.log.LogLevel.ERROR
+import com.android.systemui.plugins.log.LogLevel.INFO
import com.android.systemui.log.dagger.DozeLog
import com.android.systemui.statusbar.policy.DevicePostureController
import com.google.errorprone.annotations.CompileTimeConstant
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamLogger.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamLogger.kt
index fdb7651..eb79290 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamLogger.kt
@@ -16,9 +16,9 @@
package com.android.systemui.dreams
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.DreamLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
/** Logs dream-related stuff to a {@link LogBuffer}. */
diff --git a/packages/SystemUI/src/com/android/systemui/dump/DumpHandler.kt b/packages/SystemUI/src/com/android/systemui/dump/DumpHandler.kt
index 4b03fd3..a2f65ba 100644
--- a/packages/SystemUI/src/com/android/systemui/dump/DumpHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/dump/DumpHandler.kt
@@ -24,7 +24,7 @@
import com.android.systemui.dump.DumpHandler.Companion.PRIORITY_ARG_CRITICAL
import com.android.systemui.dump.DumpHandler.Companion.PRIORITY_ARG_NORMAL
import com.android.systemui.dump.nano.SystemUIProtoDump
-import com.android.systemui.log.LogBuffer
+import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.shared.system.UncaughtExceptionPreHandlerManager
import com.google.protobuf.nano.MessageNano
import java.io.BufferedOutputStream
diff --git a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
index 1e01c9c..7d1ffca 100644
--- a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
@@ -20,7 +20,7 @@
import com.android.systemui.Dumpable
import com.android.systemui.ProtoDumpable
import com.android.systemui.dump.nano.SystemUIProtoDump
-import com.android.systemui.log.LogBuffer
+import com.android.systemui.plugins.log.LogBuffer
import java.io.PrintWriter
import javax.inject.Inject
import javax.inject.Singleton
diff --git a/packages/SystemUI/src/com/android/systemui/dump/LogBufferEulogizer.kt b/packages/SystemUI/src/com/android/systemui/dump/LogBufferEulogizer.kt
index 0eab1af..8299b13 100644
--- a/packages/SystemUI/src/com/android/systemui/dump/LogBufferEulogizer.kt
+++ b/packages/SystemUI/src/com/android/systemui/dump/LogBufferEulogizer.kt
@@ -19,7 +19,7 @@
import android.content.Context
import android.util.Log
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogBuffer
+import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.util.io.Files
import com.android.systemui.util.time.SystemClock
import java.io.IOException
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 3c635310..6ca409f 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -206,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")
@@ -236,6 +231,11 @@
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")
@@ -391,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
@@ -401,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")
@@ -600,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
@@ -623,7 +625,7 @@
// 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 - biometrics (udfps, sfps, BiometricPrompt, etc.)
// TODO(b/259264861): Tracking Bug
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
index 7c5641f..e650b9f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
@@ -19,7 +19,7 @@
import com.android.keyguard.logging.KeyguardLogger
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.log.LogLevel.VERBOSE
+import com.android.systemui.plugins.log.LogLevel.VERBOSE
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
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/log/FaceAuthenticationLogger.kt b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt
index 62e4207..efd3ad6 100644
--- a/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt
@@ -6,8 +6,9 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus
import com.android.systemui.keyguard.shared.model.TransitionStep
-import com.android.systemui.log.LogLevel.DEBUG
import com.android.systemui.log.dagger.FaceAuthLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.DEBUG
import javax.inject.Inject
private const val TAG = "DeviceEntryFaceAuthRepositoryLog"
diff --git a/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt b/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
index e4465ac..d6e29e0 100644
--- a/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
@@ -19,6 +19,9 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.log.LogBufferHelper.Companion.adjustMaxSize
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogcatEchoTracker
+
import javax.inject.Inject
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt b/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt
index af24826..edc278d 100644
--- a/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt
@@ -21,9 +21,10 @@
import android.graphics.RectF
import androidx.core.graphics.toRectF
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.ERROR
import com.android.systemui.log.dagger.ScreenDecorationsLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.DEBUG
+import com.android.systemui.plugins.log.LogLevel.ERROR
import javax.inject.Inject
private const val TAG = "ScreenDecorationsLog"
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/BiometricLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/BiometricLog.java
index 233f7a12..4b774d3 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/BiometricLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/BiometricLog.java
@@ -23,7 +23,7 @@
import javax.inject.Qualifier;
/**
- * A {@link com.android.systemui.log.LogBuffer} for BiometricMessages processing such as
+ * A {@link com.android.systemui.plugins.log.LogBuffer} for BiometricMessages processing such as
* {@link com.android.systemui.biometrics.FaceHelpMessageDeferral}
*/
@Qualifier
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/BroadcastDispatcherLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/BroadcastDispatcherLog.java
index 7d1f1c2..5cca1ab 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/BroadcastDispatcherLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/BroadcastDispatcherLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/CollapsedSbFragmentLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/CollapsedSbFragmentLog.java
index 9ca0293..1d016d8 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/CollapsedSbFragmentLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/CollapsedSbFragmentLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/DozeLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/DozeLog.java
index 7c5f402..c9f78bc 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/DozeLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardClockLog.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardClockLog.kt
index 8732ef5..9f563fe4 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardClockLog.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardClockLog.kt
@@ -18,19 +18,19 @@
import javax.inject.Qualifier
-/** A [com.android.systemui.log.LogBuffer] for keyguard clock logs. */
+/** A [com.android.systemui.plugins.log.LogBuffer] for keyguard clock logs. */
@Qualifier
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class KeyguardClockLog
-/** A [com.android.systemui.log.LogBuffer] for small keyguard clock logs. */
+/** A [com.android.systemui.plugins.log.LogBuffer] for small keyguard clock logs. */
@Qualifier
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class KeyguardSmallClockLog
-/** A [com.android.systemui.log.LogBuffer] for large keyguard clock logs. */
+/** A [com.android.systemui.plugins.log.LogBuffer] for large keyguard clock logs. */
@Qualifier
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LSShadeTransitionLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LSShadeTransitionLog.java
index 08d969b..76d20be 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LSShadeTransitionLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LSShadeTransitionLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 90ef8a7..658f6a0 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -22,13 +22,13 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.LogBufferFactory;
-import com.android.systemui.log.LogcatEchoTracker;
-import com.android.systemui.log.LogcatEchoTrackerDebug;
-import com.android.systemui.log.LogcatEchoTrackerProd;
import com.android.systemui.log.table.TableLogBuffer;
import com.android.systemui.log.table.TableLogBufferFactory;
+import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.plugins.log.LogcatEchoTracker;
+import com.android.systemui.plugins.log.LogcatEchoTrackerDebug;
+import com.android.systemui.plugins.log.LogcatEchoTrackerProd;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.util.Compile;
import com.android.systemui.util.wakelock.WakeLockLog;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaBrowserLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaBrowserLog.java
index 1c00c93..af43347 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaBrowserLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaBrowserLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaCarouselControllerLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaCarouselControllerLog.java
index 86a916e..f4dac6e 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaCarouselControllerLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaCarouselControllerLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaMuteAwaitLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaMuteAwaitLog.java
index c67d8be..73690ab 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaMuteAwaitLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaMuteAwaitLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTimeoutListenerLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTimeoutListenerLog.java
index 98e6556..0c2cd92 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTimeoutListenerLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaTimeoutListenerLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaViewLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaViewLog.java
index dde0ee0..5b7f4bb 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaViewLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaViewLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NearbyMediaDevicesLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NearbyMediaDevicesLog.java
index b1c6dcf..6d91f0c 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/NearbyMediaDevicesLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NearbyMediaDevicesLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotifInteractionLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotifInteractionLog.java
index 20fc6ff..26af496 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/NotifInteractionLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotifInteractionLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationHeadsUpLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationHeadsUpLog.java
index fcc184a..61daf9c 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationHeadsUpLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationHeadsUpLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationInterruptLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationInterruptLog.java
index 760fbf3..a59afa0 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationInterruptLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationInterruptLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLockscreenLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLockscreenLog.java
index f1646a8..a2d381e 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLockscreenLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLockscreenLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLog.java
index a0b6864..6f8ea7f 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationRenderLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationRenderLog.java
index 8c8753a..835d349 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationRenderLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationRenderLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationSectionLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationSectionLog.java
index 7259eeb..6e2bd7b 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationSectionLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationSectionLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/PrivacyLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/PrivacyLog.java
index e96e532..77b1bf5 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/PrivacyLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/PrivacyLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/QSConfigLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/QSConfigLog.java
index 973f650..295bf88 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/QSConfigLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/QSConfigLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/QSFragmentDisableLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/QSFragmentDisableLog.java
index 557a254..9fd166b 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/QSFragmentDisableLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/QSFragmentDisableLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/QSLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/QSLog.java
index dd5010c..dd168ba 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/QSLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/QSLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeLog.java
index bd0d298..d24bfcb 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeWindowLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeWindowLog.java
index 4aa2b1d..1d2b68c 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeWindowLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeWindowLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/StatusBarNetworkControllerLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/StatusBarNetworkControllerLog.java
index f26b316..af0f7c5 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/StatusBarNetworkControllerLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/StatusBarNetworkControllerLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/SwipeUpLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/SwipeUpLog.java
index 4d797c1..d58b538 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/SwipeUpLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/SwipeUpLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/ToastLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/ToastLog.java
index 8671dbf..ba8b27c 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/ToastLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/ToastLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/UnseenNotificationLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/UnseenNotificationLog.java
index dbb6e8c..5c2321b 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/UnseenNotificationLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/UnseenNotificationLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
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 b936e83..9d883cc 100644
--- a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
@@ -20,8 +20,8 @@
import com.android.systemui.Dumpable
import com.android.systemui.common.buffer.RingBuffer
import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.LogcatEchoTracker
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.plugins.log.LogcatEchoTracker
import com.android.systemui.util.time.SystemClock
import java.io.PrintWriter
import java.text.SimpleDateFormat
@@ -35,7 +35,7 @@
* A logger that logs changes in table format.
*
* Some parts of System UI maintain a lot of pieces of state at once.
- * [com.android.systemui.log.LogBuffer] allows us to easily log change events:
+ * [com.android.systemui.plugins.log.LogBuffer] allows us to easily log change events:
* - 10-10 10:10:10.456: state2 updated to newVal2
* - 10-10 10:11:00.000: stateN updated to StateN(val1=true, val2=1)
* - 10-10 10:11:02.123: stateN updated to StateN(val1=true, val2=2)
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt
index 19e1124..42e742d 100644
--- a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt
@@ -21,7 +21,7 @@
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dump.DumpManager
import com.android.systemui.log.LogBufferHelper.Companion.adjustMaxSize
-import com.android.systemui.log.LogcatEchoTracker
+import com.android.systemui.plugins.log.LogcatEchoTracker
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
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/media/controls/pipeline/MediaTimeoutLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutLogger.kt
index e2e269d..f731dc0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutLogger.kt
@@ -18,9 +18,9 @@
import android.media.session.PlaybackState
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.MediaTimeoutListenerLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
private const val TAG = "MediaTimeout"
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt
index 9e53d77..095cf09 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt
@@ -18,9 +18,9 @@
import android.content.ComponentName
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.MediaBrowserLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
/** A logger for events in [ResumeMediaBrowser]. */
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselControllerLogger.kt
index 0ed2434..9af11b9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselControllerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselControllerLogger.kt
@@ -17,9 +17,9 @@
package com.android.systemui.media.controls.ui
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.MediaCarouselControllerLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
/** A debug logger for [MediaCarouselController]. */
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewLogger.kt
index c781b76..fdac33a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewLogger.kt
@@ -17,9 +17,9 @@
package com.android.systemui.media.controls.ui
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.MediaViewLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
private const val TAG = "MediaView"
diff --git a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
index 46efac5..9ae4577 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
@@ -17,7 +17,6 @@
package com.android.systemui.media.dagger;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.LogBufferFactory;
import com.android.systemui.media.controls.pipeline.MediaDataManager;
import com.android.systemui.media.controls.ui.MediaHierarchyManager;
@@ -31,15 +30,16 @@
import com.android.systemui.media.taptotransfer.MediaTttFlags;
import com.android.systemui.media.taptotransfer.receiver.MediaTttReceiverLogBuffer;
import com.android.systemui.media.taptotransfer.sender.MediaTttSenderLogBuffer;
-
-import dagger.Lazy;
-import dagger.Module;
-import dagger.Provides;
+import com.android.systemui.plugins.log.LogBuffer;
import java.util.Optional;
import javax.inject.Named;
+import dagger.Lazy;
+import dagger.Module;
+import dagger.Provides;
+
/** Dagger module for the media package. */
@Module(subcomponents = {
MediaComplicationComponent.class,
diff --git a/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitLogger.kt b/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitLogger.kt
index bbcf259..5ace3ea 100644
--- a/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitLogger.kt
@@ -2,8 +2,8 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.dagger.MediaMuteAwaitLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
/** Log messages for [MediaMuteAwaitConnectionManager]. */
diff --git a/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesLogger.kt b/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesLogger.kt
index 66399d5..78408fc 100644
--- a/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesLogger.kt
@@ -2,8 +2,8 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.dagger.NearbyMediaDevicesLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
/** Log messages for [NearbyMediaDevicesManager]. */
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtils.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtils.kt
index eeda1027..0e839c6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtils.kt
@@ -16,8 +16,8 @@
package com.android.systemui.media.taptotransfer.common
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
/** A helper for logging media tap-to-transfer events. */
object MediaTttLoggerUtils {
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogBuffer.java b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogBuffer.java
index 31ccb9a..67e464c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogBuffer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogBuffer.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogger.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogger.kt
index 1502df7..b0c6257 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogger.kt
@@ -18,8 +18,8 @@
import android.app.StatusBarManager
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogBuffer
import com.android.systemui.media.taptotransfer.common.MediaTttLoggerUtils
+import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.temporarydisplay.TemporaryViewLogger
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogBuffer.java b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogBuffer.java
index edee4a8..a262e97 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogBuffer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogBuffer.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogger.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogger.kt
index 03bcfc8..964a95b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogger.kt
@@ -18,9 +18,9 @@
import android.app.StatusBarManager
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
import com.android.systemui.media.taptotransfer.common.MediaTttLoggerUtils
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
/** A logger for all events related to the media tap-to-transfer sender experience. */
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/privacy/logging/PrivacyLogger.kt b/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt
index f9e1adf..03503fd 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt
@@ -18,9 +18,9 @@
import android.permission.PermissionGroupUsage
import com.android.systemui.log.dagger.PrivacyLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.LogMessage
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.plugins.log.LogMessage
import com.android.systemui.privacy.PrivacyDialog
import com.android.systemui.privacy.PrivacyItem
import java.text.SimpleDateFormat
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/QSFragmentDisableFlagsLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt
index cd52ec2..025fb22 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt
@@ -1,8 +1,8 @@
package com.android.systemui.qs
import com.android.systemui.log.dagger.QSFragmentDisableLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
index c00a81c..5b461a6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
@@ -21,14 +21,14 @@
import android.content.res.Configuration.Orientation
import android.service.quicksettings.Tile
import android.view.View
-import com.android.systemui.log.ConstantStringsLogger
-import com.android.systemui.log.ConstantStringsLoggerImpl
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.ERROR
-import com.android.systemui.log.LogLevel.VERBOSE
import com.android.systemui.log.dagger.QSConfigLog
import com.android.systemui.log.dagger.QSLog
+import com.android.systemui.plugins.log.ConstantStringsLogger
+import com.android.systemui.plugins.log.ConstantStringsLoggerImpl
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.DEBUG
+import com.android.systemui.plugins.log.LogLevel.ERROR
+import com.android.systemui.plugins.log.LogLevel.VERBOSE
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.statusbar.StatusBarState
import com.google.errorprone.annotations.CompileTimeConstant
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt
index a066242..e85440c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt
@@ -18,8 +18,8 @@
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
+import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository
import com.android.systemui.qs.pipeline.data.repository.TileSpecSettingsRepository
import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
index b564334..767ce91 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.qs.pipeline.shared.logging
import android.annotation.UserIdInt
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.qs.pipeline.dagger.QSTileListLog
import com.android.systemui.qs.pipeline.shared.TileSpec
import javax.inject.Inject
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..4b44ac0 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -1513,6 +1513,8 @@
mKeyguardStatusViewController.getClockBottom(mStatusBarHeaderHeightKeyguard),
mKeyguardStatusViewController.isClockTopAligned());
mClockPositionAlgorithm.run(mClockPositionResult);
+ mKeyguardStatusViewController.setLockscreenClockY(
+ mClockPositionAlgorithm.getExpandedPreferredClockY());
mKeyguardBottomAreaInteractor.setClockPosition(
mClockPositionResult.clockX, mClockPositionResult.clockY);
boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
@@ -4474,7 +4476,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 92c9a80..a1fa8fb 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
@@ -887,7 +887,9 @@
}
void setOverScrollAmount(int overExpansion) {
- mQs.setOverScrollAmount(overExpansion);
+ if (mQs != null) {
+ mQs.setOverScrollAmount(overExpansion);
+ }
}
private void setOverScrolling(boolean overscrolling) {
@@ -1230,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/shade/ShadeLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
index 25073c1b..1839e13 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
@@ -18,8 +18,8 @@
import android.view.MotionEvent
import com.android.systemui.log.dagger.ShadeLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.shade.ShadeViewController.Companion.FLING_COLLAPSE
import com.android.systemui.shade.ShadeViewController.Companion.FLING_EXPAND
import com.android.systemui.shade.ShadeViewController.Companion.FLING_HIDE
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt
index d8d4279..9851625 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt
@@ -18,12 +18,12 @@
import android.view.WindowManager
import com.android.systemui.log.dagger.ShadeWindowLog
-import com.android.systemui.log.ConstantStringsLogger
-import com.android.systemui.log.ConstantStringsLoggerImpl
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogMessage
+import com.android.systemui.plugins.log.ConstantStringsLogger
+import com.android.systemui.plugins.log.ConstantStringsLoggerImpl
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.plugins.log.LogLevel.DEBUG
+import com.android.systemui.plugins.log.LogMessage
import javax.inject.Inject
private const val TAG = "systemui.shadewindow"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt
index e008ec0..90c52bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt
@@ -18,8 +18,8 @@
import android.app.PendingIntent
import com.android.systemui.log.dagger.NotifInteractionLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 0ea2570..ea5a1c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -41,8 +41,8 @@
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRUST;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_USER_LOCKED;
import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_ON;
-import static com.android.systemui.log.LogLevel.ERROR;
import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
+import static com.android.systemui.plugins.log.LogLevel.ERROR;
import android.app.AlarmManager;
import android.app.admin.DevicePolicyManager;
@@ -95,8 +95,8 @@
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
-import com.android.systemui.log.LogLevel;
import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.log.LogLevel;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
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/connectivity/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
index 2465c21..6e74542 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
@@ -73,9 +73,9 @@
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.log.LogBuffer;
-import com.android.systemui.log.LogLevel;
import com.android.systemui.log.dagger.StatusBarNetworkControllerLog;
+import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.plugins.log.LogLevel;
import com.android.systemui.qs.tiles.dialog.InternetDialogFactory;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
@@ -87,8 +87,6 @@
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.util.CarrierConfigTracker;
-import kotlin.Unit;
-
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -103,6 +101,8 @@
import javax.inject.Inject;
+import kotlin.Unit;
+
/** Platform implementation of the network controller. **/
@SysUISingleton
public class NetworkControllerImpl extends BroadcastReceiver
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureLogger.kt
index a67c26c..9ce6b02 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureLogger.kt
@@ -18,8 +18,8 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.dagger.SwipeUpLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
/** Log messages for [SwipeUpGestureHandler]. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt
index a3a72d9..3058fbb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.notification
import com.android.systemui.log.dagger.NotifInteractionLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
index f7679ed..dd3c2a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
@@ -13,9 +13,9 @@
package com.android.systemui.statusbar.notification
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
import com.android.systemui.log.dagger.NotificationLockscreenLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.DEBUG
import com.android.systemui.statusbar.StatusBarState
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/RemoteInputControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/RemoteInputControllerLogger.kt
index 487a5f8..9582dfad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/RemoteInputControllerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/RemoteInputControllerLogger.kt
@@ -17,9 +17,9 @@
package com.android.systemui.statusbar.notification
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
import com.android.systemui.log.dagger.NotificationRemoteInputLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.DEBUG
import javax.inject.Inject
/** Logger class for [RemoteInputController]. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerLogger.kt
index 39d0833..68d1319 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.notification.collection.coalescer
import com.android.systemui.log.dagger.NotificationLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
class GroupCoalescerLogger @Inject constructor(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt
index 79c63e6..2919def 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt
@@ -1,8 +1,8 @@
package com.android.systemui.statusbar.notification.collection.coordinator
import com.android.systemui.log.dagger.NotificationLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.statusbar.notification.row.NotificationGuts
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorLogger.kt
index e17ce5c..32c3c66 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorLogger.kt
@@ -3,8 +3,8 @@
import android.util.Log
import com.android.systemui.log.dagger.NotificationHeadsUpLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
private const val TAG = "HeadsUpCoordinator"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt
index 1f8ec34..6503a64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt
@@ -16,9 +16,9 @@
package com.android.systemui.statusbar.notification.collection.coordinator
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.UnseenNotificationLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
private const val TAG = "KeyguardCoordinator"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt
index 6271d38..9558f47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.notification.collection.coordinator
import com.android.systemui.log.dagger.NotificationLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt
index 1f4861a..d804454 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.notification.collection.coordinator
import com.android.systemui.log.dagger.NotificationLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
private const val TAG = "ShadeEventCoordinator"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
index f13ff68..4adc90a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
@@ -17,10 +17,10 @@
package com.android.systemui.statusbar.notification.collection.listbuilder
import com.android.systemui.log.dagger.NotificationLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.INFO
-import com.android.systemui.log.LogLevel.WARNING
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.DEBUG
+import com.android.systemui.plugins.log.LogLevel.INFO
+import com.android.systemui.plugins.log.LogLevel.WARNING
import com.android.systemui.statusbar.notification.NotifPipelineFlags
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.ListEntry
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
index 20de785..911a2d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
@@ -21,12 +21,12 @@
import android.service.notification.NotificationListenerService.RankingMap
import android.service.notification.StatusBarNotification
import com.android.systemui.log.dagger.NotificationLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.ERROR
-import com.android.systemui.log.LogLevel.INFO
-import com.android.systemui.log.LogLevel.WARNING
-import com.android.systemui.log.LogLevel.WTF
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.DEBUG
+import com.android.systemui.plugins.log.LogLevel.ERROR
+import com.android.systemui.plugins.log.LogLevel.INFO
+import com.android.systemui.plugins.log.LogLevel.WARNING
+import com.android.systemui.plugins.log.LogLevel.WTF
import com.android.systemui.statusbar.notification.collection.NotifCollection
import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason
import com.android.systemui.statusbar.notification.collection.NotifCollection.FutureDismissal
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderLogger.kt
index 07fd349..9c71e5c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.notification.collection.render
import com.android.systemui.log.dagger.NotificationLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.statusbar.notification.NotifPipelineFlags
import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
import com.android.systemui.util.Compile
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt
index a880b71..1e22c2c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.notification.collection.render
import com.android.systemui.log.dagger.NotificationLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import java.lang.RuntimeException
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt
index 0b31265..d4f11fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt
@@ -1,8 +1,8 @@
package com.android.systemui.statusbar.notification.interruption
import com.android.systemui.log.dagger.NotificationHeadsUpLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.INFO
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
index 5bac2a9..115e0502 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
@@ -19,10 +19,10 @@
import android.util.Log
import com.android.systemui.log.dagger.NotificationInterruptLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.INFO
-import com.android.systemui.log.LogLevel.WARNING
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.DEBUG
+import com.android.systemui.plugins.log.LogLevel.INFO
+import com.android.systemui.plugins.log.LogLevel.WARNING
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import com.android.systemui.util.Compile
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationRoundnessLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationRoundnessLogger.kt
index fe03b2a..10197a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationRoundnessLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationRoundnessLogger.kt
@@ -16,9 +16,9 @@
package com.android.systemui.statusbar.notification.logging
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.INFO
import com.android.systemui.log.dagger.NotificationRenderLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.INFO
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView
import com.android.systemui.statusbar.notification.stack.NotificationSection
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt
index 45be0b1..46fef3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.notification.row
import com.android.systemui.log.dagger.NotificationLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.INFO
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt
index c3dd92a..ce11be3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt
@@ -17,9 +17,9 @@
package com.android.systemui.statusbar.notification.row
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.NotificationLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt
index 684a276..8a5d29a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.notification.row
import com.android.systemui.log.dagger.NotificationLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.INFO
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsLogger.kt
index f953187..b61c55e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsLogger.kt
@@ -18,8 +18,8 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.dagger.NotificationSectionLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
private const val TAG = "NotifSections"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt
index 5b0ec1d..64dd6dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt
@@ -1,9 +1,9 @@
package com.android.systemui.statusbar.notification.stack
import com.android.systemui.log.dagger.NotificationHeadsUpLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.DEBUG
+import com.android.systemui.plugins.log.LogLevel.INFO
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt
index cca84b3..f5de678 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt
@@ -1,8 +1,8 @@
package com.android.systemui.statusbar.notification.stack
import com.android.systemui.log.dagger.NotificationHeadsUpLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.statusbar.notification.logKey
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 90a6d0f..eba04f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -239,7 +239,11 @@
}
}
- private int getExpandedPreferredClockY() {
+ /**
+ * give the static topMargin, used for lockscreen clocks to get the initial translationY
+ * to do counter translation
+ */
+ public int getExpandedPreferredClockY() {
if (mIsSplitShade) {
return mSplitShadeTargetTopMargin;
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 12ed71b..e835c5ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -45,7 +45,7 @@
import com.android.systemui.animation.InterpolatorsAndroidX;
import com.android.systemui.battery.BatteryMeterViewController;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.log.LogLevel;
+import com.android.systemui.plugins.log.LogLevel;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shade.ShadeViewStateProvider;
import com.android.systemui.statusbar.CommandQueue;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt
index 5c357d7..4839fe6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt
@@ -20,8 +20,8 @@
import android.view.View
import com.android.internal.logging.nano.MetricsProto.MetricsEvent
import com.android.systemui.log.dagger.LSShadeTransitionLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView
import javax.inject.Inject
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/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/StatusBarNotificationActivityStarterLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt
index 12f023b..1f0b96a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt
@@ -18,11 +18,11 @@
import android.app.PendingIntent
import com.android.systemui.log.dagger.NotifInteractionLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.ERROR
-import com.android.systemui.log.LogLevel.INFO
-import com.android.systemui.log.LogLevel.WARNING
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.DEBUG
+import com.android.systemui.plugins.log.LogLevel.ERROR
+import com.android.systemui.plugins.log.LogLevel.INFO
+import com.android.systemui.plugins.log.LogLevel.WARNING
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import javax.inject.Inject
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/phone/fragment/CollapsedStatusBarFragmentLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt
index 0c86b51..d64bc58 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.phone.fragment
import com.android.systemui.log.dagger.CollapsedSbFragmentLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
index 19c77e0..b3d2461 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
@@ -22,7 +22,7 @@
import com.android.systemui.log.LogBufferFactory
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableLogBufferFactory
-import com.android.systemui.log.LogBuffer
+import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.statusbar.pipeline.airplane.data.repository.AirplaneModeRepository
import com.android.systemui.statusbar.pipeline.airplane.data.repository.AirplaneModeRepositoryImpl
import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt
index b3a1c40..68cbbce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt
@@ -22,8 +22,8 @@
import com.android.settingslib.SignalIcon
import com.android.settingslib.mobile.MobileMappings
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.statusbar.pipeline.dagger.MobileInputLog
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
index 7e0c145..f2f9143 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
@@ -20,8 +20,8 @@
import com.android.systemui.Dumpable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.statusbar.pipeline.dagger.MobileViewLog
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.LocationBasedMobileViewModel
import java.io.PrintWriter
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt
index 507549b..f67bc8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt
@@ -19,8 +19,8 @@
import android.view.View
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.statusbar.pipeline.dagger.VerboseMobileViewLog
import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger.Companion.getIdForLogging
import com.android.systemui.statusbar.pipeline.mobile.ui.model.SignalIconModel
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityInputLogger.kt
index 051f43f..82492ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityInputLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityInputLogger.kt
@@ -19,8 +19,8 @@
import android.net.Network
import android.net.NetworkCapabilities
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.statusbar.pipeline.dagger.SharedConnectivityInputLog
import com.android.systemui.statusbar.pipeline.shared.data.model.DefaultConnectionModel
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt
index 328d901..a96e8ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt
@@ -18,8 +18,8 @@
import android.net.Network
import android.net.NetworkCapabilities
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
/** Helper object for logs that are shared between wifi and mobile. */
object LoggerHelper {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModel.kt
index 058eda4..2a02687 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModel.kt
@@ -17,7 +17,7 @@
package com.android.systemui.statusbar.pipeline.shared.data.model
import android.net.NetworkCapabilities
-import com.android.systemui.log.LogMessage
+import com.android.systemui.plugins.log.LogMessage
/**
* A model for all of the current default connections(s).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt
index 4a9ceac..bb0b166 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt
@@ -19,8 +19,8 @@
import android.net.Network
import android.net.NetworkCapabilities
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.statusbar.pipeline.dagger.WifiInputLog
import com.android.systemui.statusbar.pipeline.shared.LoggerHelper
import javax.inject.Inject
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 6ba2a81..f61f3b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt
@@ -21,9 +21,9 @@
import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_LOCKED
import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_UNLOCKED
import com.android.internal.R
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.VERBOSE
import com.android.systemui.log.dagger.DeviceStateAutoRotationLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.VERBOSE
import javax.inject.Inject
class DeviceStateRotationLockSettingControllerLogger
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
index 06ed1fd..df1e80b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
@@ -17,9 +17,9 @@
package com.android.systemui.statusbar.policy
import com.android.systemui.log.dagger.NotificationHeadsUpLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.INFO
-import com.android.systemui.log.LogLevel.VERBOSE
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.INFO
+import com.android.systemui.plugins.log.LogLevel.VERBOSE
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import javax.inject.Inject
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/temporarydisplay/TemporaryViewLogger.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt
index 066ac04..667e22a 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.temporarydisplay
import android.view.View
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
/** A logger for temporary view changes -- see [TemporaryViewDisplayController]. */
open class TemporaryViewLogger<T : TemporaryViewInfo>(
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt
index d55751b..f239428 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.temporarydisplay.chipbar
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.temporarydisplay.TemporaryViewLogger
import com.android.systemui.temporarydisplay.dagger.ChipbarLog
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/TemporaryDisplayModule.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/TemporaryDisplayModule.kt
index cae1308..b1be404 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/TemporaryDisplayModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/TemporaryDisplayModule.kt
@@ -18,9 +18,9 @@
import android.content.Context
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
import com.android.systemui.media.taptotransfer.MediaTttFlags
+import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.settings.DisplayTracker
import com.android.systemui.statusbar.gesture.SwipeUpGestureLogger
import com.android.systemui.temporarydisplay.chipbar.SwipeChipbarAwayGestureHandler
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt b/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt
index dfe748a..fda5114 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt
@@ -17,10 +17,10 @@
package com.android.systemui.toast
import com.android.systemui.log.dagger.ToastLog
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogMessage
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.plugins.log.LogLevel.DEBUG
+import com.android.systemui.plugins.log.LogMessage
import javax.inject.Inject
private const val TAG = "ToastLog"
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLog.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLog.java
index 9cebc33..59cb052 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLog.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLog.java
@@ -18,7 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLogger.kt b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLogger.kt
index 0926800..951903d 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLogger.kt
@@ -17,8 +17,8 @@
package com.android.systemui.util.wakelock
import android.os.PowerManager
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
class WakeLockLogger @Inject constructor(@WakeLockLog private val buffer: LogBuffer) {
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/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index 19d5278..8f4b320 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -35,7 +35,7 @@
import com.android.systemui.plugins.ClockFaceConfig
import com.android.systemui.plugins.ClockFaceEvents
import com.android.systemui.plugins.ClockTickRate
-import com.android.systemui.log.LogBuffer
+import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.ConfigurationController
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index fb73845..95db0c0 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -45,7 +45,6 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
-import com.android.systemui.log.LogBuffer;
import com.android.systemui.plugins.ClockAnimations;
import com.android.systemui.plugins.ClockController;
import com.android.systemui.plugins.ClockEvents;
@@ -53,6 +52,7 @@
import com.android.systemui.plugins.ClockFaceController;
import com.android.systemui.plugins.ClockFaceEvents;
import com.android.systemui.plugins.ClockTickRate;
+import com.android.systemui.plugins.log.LogBuffer;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.clocks.AnimatableClockView;
import com.android.systemui.shared.clocks.ClockRegistry;
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/dump/DumpHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt
index e8cbdf3..19135d0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt
@@ -21,7 +21,7 @@
import com.android.systemui.Dumpable
import com.android.systemui.ProtoDumpable
import com.android.systemui.SysuiTestCase
-import com.android.systemui.log.LogBuffer
+import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.shared.system.UncaughtExceptionPreHandlerManager
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dump/DumpManagerTest.kt
index d22c409..0c5a74c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dump/DumpManagerTest.kt
@@ -19,7 +19,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.Dumpable
import com.android.systemui.SysuiTestCase
-import com.android.systemui.log.LogBuffer
+import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.util.mockito.any
import java.io.PrintWriter
import org.junit.Before
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt b/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt
index bd029a7..64547f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt
@@ -16,9 +16,9 @@
package com.android.systemui.dump
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.LogcatEchoTracker
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.plugins.log.LogcatEchoTracker
/**
* Creates a LogBuffer that will echo everything to logcat, which is useful for debugging tests.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt
index c2195c7..bf3c73a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt
@@ -24,8 +24,8 @@
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogcatEchoTracker
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogcatEchoTracker
import com.android.systemui.user.data.repository.FakeUserRepository
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
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 df8a718..a2b2322 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
@@ -18,9 +18,9 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.LogcatEchoTracker
import com.android.systemui.log.table.TableChange.Companion.IS_INITIAL_PREFIX
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.plugins.log.LogcatEchoTracker
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
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/media/taptotransfer/common/MediaTttLoggerUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtilsTest.kt
index b322bb7..8da1c64 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtilsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtilsTest.kt
@@ -19,9 +19,9 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
-import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
-import com.android.systemui.log.LogcatEchoTracker
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogcatEchoTracker
import com.google.common.truth.Truth.assertThat
import java.io.PrintWriter
import java.io.StringWriter
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLoggerTest.kt
index 64f3fd3..95df484 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLoggerTest.kt
@@ -19,9 +19,9 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
-import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
-import com.android.systemui.log.LogcatEchoTracker
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogcatEchoTracker
import com.google.common.truth.Truth.assertThat
import java.io.PrintWriter
import java.io.StringWriter
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt
index 2287da5..0033757 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt
@@ -19,9 +19,9 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
-import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
-import com.android.systemui.log.LogcatEchoTracker
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogcatEchoTracker
import com.google.common.truth.Truth.assertThat
import java.io.PrintWriter
import java.io.StringWriter
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/QSFragmentDisableFlagsLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt
index aacc695..68c10f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt
@@ -20,7 +20,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.log.LogBufferFactory
-import com.android.systemui.log.LogcatEchoTracker
+import com.android.systemui.plugins.log.LogcatEchoTracker
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
import com.google.common.truth.Truth.assertThat
import java.io.PrintWriter
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/statusbar/LSShadeTransitionLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
index 8cb530c..5fc0ffe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
@@ -4,7 +4,7 @@
import android.util.DisplayMetrics
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.log.LogBuffer
+import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.statusbar.notification.row.ExpandableView
import com.android.systemui.statusbar.phone.LSShadeTransitionLogger
import com.android.systemui.statusbar.phone.LockscreenGestureLogger
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java
index c7ea09c..5431eba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java
@@ -70,7 +70,7 @@
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java
index d5689dc..9441d49 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java
@@ -48,7 +48,7 @@
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.settingslib.net.DataUsageController;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.util.CarrierConfigTracker;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java
index 35b9814..4c1f0a8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java
@@ -43,7 +43,7 @@
import com.android.settingslib.net.DataUsageController;
import com.android.systemui.R;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.log.LogBuffer;
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.util.CarrierConfigTracker;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
index a37c386..bef9fcb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
@@ -19,9 +19,9 @@
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.LogcatEchoTracker
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.plugins.log.LogcatEchoTracker
import com.android.systemui.statusbar.StatusBarState
import com.google.common.truth.Truth.assertThat
import org.junit.Before
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/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
index 65e2964..3a0a94d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
@@ -20,7 +20,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.log.LogBufferFactory
-import com.android.systemui.log.LogcatEchoTracker
+import com.android.systemui.plugins.log.LogcatEchoTracker
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
import com.google.common.truth.Truth.assertThat
import java.io.PrintWriter
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index 4b1caca..2a3c775 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -52,9 +52,9 @@
import com.android.systemui.SysuiBaseFragmentTest;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.log.LogBuffer;
-import com.android.systemui.log.LogcatEchoTracker;
import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.plugins.log.LogcatEchoTracker;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shade.ShadeExpansionStateManager;
import com.android.systemui.shade.ShadeViewController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModelTest.kt
index c43778a..03cd94f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModelTest.kt
@@ -18,7 +18,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.log.LogMessageImpl
+import com.android.systemui.plugins.log.LogMessageImpl
import com.google.common.truth.Truth.assertThat
import org.junit.Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt
index 4514249..2e66b20 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt
@@ -19,9 +19,9 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
-import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
-import com.android.systemui.log.LogcatEchoTracker
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogcatEchoTracker
import com.google.common.truth.Truth.assertThat
import java.io.PrintWriter
import java.io.StringWriter
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/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index d8fbd08..0172eaf 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -107,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;
@@ -116,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;
@@ -199,6 +203,8 @@
private final RemoteCallbackList<IOnAssociationsChangedListener> mListeners =
new RemoteCallbackList<>();
+ private CrossDeviceSyncController mCrossDeviceSyncController;
+
public CompanionDeviceManagerService(Context context) {
super(context);
@@ -238,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();
@@ -1353,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/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/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/UserSwitchingDialog.java b/services/core/java/com/android/server/am/UserSwitchingDialog.java
index 6da6a6e..412fbe79 100644
--- a/services/core/java/com/android/server/am/UserSwitchingDialog.java
+++ b/services/core/java/com/android/server/am/UserSwitchingDialog.java
@@ -266,12 +266,11 @@
}
private void startProgressAnimation(Runnable onAnimationEnd) {
- if (mDisableAnimations) {
+ final AnimatedVectorDrawable avd = getSpinnerAVD();
+ if (mDisableAnimations || avd == null) {
onAnimationEnd.run();
return;
}
- final ImageView progressCircular = findViewById(R.id.progress_circular);
- final AnimatedVectorDrawable avd = (AnimatedVectorDrawable) progressCircular.getDrawable();
avd.registerAnimationCallback(new Animatable2.AnimationCallback() {
@Override
public void onAnimationEnd(Drawable drawable) {
@@ -281,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
@@ -299,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/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/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/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/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index d531ad1..0f74aeb 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);
});
}
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/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/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/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/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/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/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/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();
}
}