Merge "Explicitly re-show the keyguard if we were hiding." into tm-qpr-dev
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 449729e..48df9e6 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -3933,6 +3933,9 @@
* processes to reclaim memory; the system will take care of restarting
* these processes in the future as needed.
*
+ * <p class="note">Third party applications can only use this API to kill their own processes.
+ * </p>
+ *
* @param packageName The name of the package whose processes are to
* be killed.
*/
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index d53ad17..e27af17 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -61,7 +61,6 @@
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
@@ -181,9 +180,6 @@
private final ArrayList<Engine> mActiveEngines
= new ArrayList<Engine>();
- private Handler mBackgroundHandler;
- private HandlerThread mBackgroundThread;
-
static final class WallpaperCommand {
String action;
int x;
@@ -202,6 +198,14 @@
*/
public class Engine {
IWallpaperEngineWrapper mIWallpaperEngine;
+ final ArraySet<RectF> mLocalColorAreas = new ArraySet<>(4);
+ final ArraySet<RectF> mLocalColorsToAdd = new ArraySet<>(4);
+
+ // 2D matrix [x][y] to represent a page of a portion of a window
+ EngineWindowPage[] mWindowPages = new EngineWindowPage[0];
+ Bitmap mLastScreenshot;
+ int mLastWindowPage = -1;
+ private boolean mResetWindowPages;
// Copies from mIWallpaperEngine.
HandlerCaller mCaller;
@@ -263,27 +267,11 @@
final Object mLock = new Object();
boolean mOffsetMessageEnqueued;
-
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
float mPendingXOffset;
float mPendingYOffset;
float mPendingXOffsetStep;
float mPendingYOffsetStep;
-
- /**
- * local color extraction related fields
- * to be used by the background thread only (except the atomic boolean)
- */
- final ArraySet<RectF> mLocalColorAreas = new ArraySet<>(4);
- final ArraySet<RectF> mLocalColorsToAdd = new ArraySet<>(4);
- private long mLastProcessLocalColorsTimestamp;
- private AtomicBoolean mProcessLocalColorsPending = new AtomicBoolean(false);
- private int mPixelCopyCount = 0;
- // 2D matrix [x][y] to represent a page of a portion of a window
- EngineWindowPage[] mWindowPages = new EngineWindowPage[0];
- Bitmap mLastScreenshot;
- private boolean mResetWindowPages;
-
boolean mPendingSync;
MotionEvent mPendingMove;
boolean mIsInAmbientMode;
@@ -292,8 +280,12 @@
private long mLastColorInvalidation;
private final Runnable mNotifyColorsChanged = this::notifyColorsChanged;
+ // used to throttle processLocalColors
+ private long mLastProcessLocalColorsTimestamp;
+ private AtomicBoolean mProcessLocalColorsPending = new AtomicBoolean(false);
private final Supplier<Long> mClockFunction;
private final Handler mHandler;
+
private Display mDisplay;
private Context mDisplayContext;
private int mDisplayState;
@@ -833,7 +825,7 @@
+ "was not established.");
}
mResetWindowPages = true;
- processLocalColors();
+ processLocalColors(mPendingXOffset, mPendingXOffsetStep);
} catch (RemoteException e) {
Log.w(TAG, "Can't notify system because wallpaper connection was lost.", e);
}
@@ -1372,7 +1364,7 @@
resetWindowPages();
mSession.finishDrawing(mWindow, null /* postDrawTransaction */,
Integer.MAX_VALUE);
- processLocalColors();
+ processLocalColors(mPendingXOffset, mPendingXOffsetStep);
}
reposition();
reportEngineShown(shouldWaitForEngineShown());
@@ -1517,7 +1509,7 @@
if (!mDestroyed) {
mVisible = visible;
reportVisibility();
- if (mReportedVisible) processLocalColors();
+ if (mReportedVisible) processLocalColors(mPendingXOffset, mPendingXOffsetStep);
} else {
AnimationHandler.requestAnimatorsEnabled(visible, this);
}
@@ -1601,41 +1593,31 @@
}
// setup local color extraction data
- processLocalColors();
+ processLocalColors(xOffset, xOffsetStep);
}
/**
* Thread-safe util to call {@link #processLocalColorsInternal} with a minimum interval of
* {@link #PROCESS_LOCAL_COLORS_INTERVAL_MS} between two calls.
*/
- private void processLocalColors() {
+ private void processLocalColors(float xOffset, float xOffsetStep) {
if (mProcessLocalColorsPending.compareAndSet(false, true)) {
final long now = mClockFunction.get();
final long timeSinceLastColorProcess = now - mLastProcessLocalColorsTimestamp;
final long timeToWait = Math.max(0,
PROCESS_LOCAL_COLORS_INTERVAL_MS - timeSinceLastColorProcess);
- mBackgroundHandler.postDelayed(() -> {
+ mHandler.postDelayed(() -> {
mLastProcessLocalColorsTimestamp = now + timeToWait;
mProcessLocalColorsPending.set(false);
- processLocalColorsInternal();
+ processLocalColorsInternal(xOffset, xOffsetStep);
}, timeToWait);
}
}
- private void processLocalColorsInternal() {
+ private void processLocalColorsInternal(float xOffset, float xOffsetStep) {
// implemented by the wallpaper
if (supportsLocalColorExtraction()) return;
- assertBackgroundThread();
- float xOffset;
- float xOffsetStep;
- float wallpaperDimAmount;
- synchronized (mLock) {
- xOffset = mPendingXOffset;
- xOffsetStep = mPendingXOffsetStep;
- wallpaperDimAmount = mWallpaperDimAmount;
- }
-
if (DEBUG) {
Log.d(TAG, "processLocalColors " + xOffset + " of step "
+ xOffsetStep);
@@ -1698,7 +1680,7 @@
xPage = mWindowPages.length - 1;
}
current = mWindowPages[xPage];
- updatePage(current, xPage, xPages, wallpaperDimAmount);
+ updatePage(current, xPage, xPages, finalXOffsetStep);
Trace.endSection();
}
@@ -1718,23 +1700,16 @@
}
}
- /**
- * Must be called with the surface lock held.
- * Must not be called if the surface is not valid.
- * Will unlock the surface when done using it.
- */
void updatePage(EngineWindowPage currentPage, int pageIndx, int numPages,
- float wallpaperDimAmount) {
-
- assertBackgroundThread();
-
+ float xOffsetStep) {
// in case the clock is zero, we start with negative time
long current = SystemClock.elapsedRealtime() - DEFAULT_UPDATE_SCREENSHOT_DURATION;
long lapsed = current - currentPage.getLastUpdateTime();
// Always update the page when the last update time is <= 0
// This is important especially when the device first boots
- if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION) return;
-
+ if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION) {
+ return;
+ }
Surface surface = mSurfaceHolder.getSurface();
if (!surface.isValid()) return;
boolean widthIsLarger = mSurfaceSize.x > mSurfaceSize.y;
@@ -1750,42 +1725,33 @@
Bitmap screenShot = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
final Bitmap finalScreenShot = screenShot;
- final String pixelCopySectionName = "WallpaperService#pixelCopy";
- final int pixelCopyCount = mPixelCopyCount++;
- Trace.beginAsyncSection(pixelCopySectionName, pixelCopyCount);
- try {
- PixelCopy.request(surface, screenShot, (res) -> {
- Trace.endAsyncSection(pixelCopySectionName, pixelCopyCount);
- if (DEBUG) Log.d(TAG, "result of pixel copy is " + res);
- if (res != PixelCopy.SUCCESS) {
- Bitmap lastBitmap = currentPage.getBitmap();
- // assign the last bitmap taken for now
- currentPage.setBitmap(mLastScreenshot);
- Bitmap lastScreenshot = mLastScreenshot;
- if (lastScreenshot != null && !lastScreenshot.isRecycled()
- && !Objects.equals(lastBitmap, lastScreenshot)) {
- updatePageColors(currentPage, pageIndx, numPages, wallpaperDimAmount);
- }
- } else {
- mLastScreenshot = finalScreenShot;
- // going to hold this lock for a while
- currentPage.setBitmap(finalScreenShot);
- currentPage.setLastUpdateTime(current);
- updatePageColors(currentPage, pageIndx, numPages, wallpaperDimAmount);
+ Trace.beginSection("WallpaperService#pixelCopy");
+ PixelCopy.request(surface, screenShot, (res) -> {
+ Trace.endSection();
+ if (DEBUG) Log.d(TAG, "result of pixel copy is " + res);
+ if (res != PixelCopy.SUCCESS) {
+ Bitmap lastBitmap = currentPage.getBitmap();
+ // assign the last bitmap taken for now
+ currentPage.setBitmap(mLastScreenshot);
+ Bitmap lastScreenshot = mLastScreenshot;
+ if (lastScreenshot != null && !lastScreenshot.isRecycled()
+ && !Objects.equals(lastBitmap, lastScreenshot)) {
+ updatePageColors(currentPage, pageIndx, numPages, xOffsetStep);
}
- }, mBackgroundHandler);
- } catch (IllegalArgumentException e) {
- // this can potentially happen if the surface is invalidated right between the
- // surface.isValid() check and the PixelCopy operation.
- // in this case, stop: we'll compute colors on the next processLocalColors call.
- Log.i(TAG, "Cancelling processLocalColors: exception caught during PixelCopy");
- }
+ } else {
+ mLastScreenshot = finalScreenShot;
+ // going to hold this lock for a while
+ currentPage.setBitmap(finalScreenShot);
+ currentPage.setLastUpdateTime(current);
+ updatePageColors(currentPage, pageIndx, numPages, xOffsetStep);
+ }
+ }, mHandler);
+
}
// locked by the passed page
- private void updatePageColors(
- EngineWindowPage page, int pageIndx, int numPages, float wallpaperDimAmount) {
+ private void updatePageColors(EngineWindowPage page, int pageIndx, int numPages,
+ float xOffsetStep) {
if (page.getBitmap() == null) return;
- assertBackgroundThread();
Trace.beginSection("WallpaperService#updatePageColors");
if (DEBUG) {
Log.d(TAG, "updatePageColorsLocked for page " + pageIndx + " with areas "
@@ -1807,7 +1773,7 @@
Log.e(TAG, "Error creating page local color bitmap", e);
continue;
}
- WallpaperColors color = WallpaperColors.fromBitmap(target, wallpaperDimAmount);
+ WallpaperColors color = WallpaperColors.fromBitmap(target, mWallpaperDimAmount);
target.recycle();
WallpaperColors currentColor = page.getColors(area);
@@ -1824,26 +1790,17 @@
+ " local color callback for area" + area + " for page " + pageIndx
+ " of " + numPages);
}
- mHandler.post(() -> {
- try {
- mConnection.onLocalWallpaperColorsChanged(area, color,
- mDisplayContext.getDisplayId());
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling Connection.onLocalWallpaperColorsChanged", e);
- }
- });
+ try {
+ mConnection.onLocalWallpaperColorsChanged(area, color,
+ mDisplayContext.getDisplayId());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling Connection.onLocalWallpaperColorsChanged", e);
+ }
}
}
Trace.endSection();
}
- private void assertBackgroundThread() {
- if (!mBackgroundHandler.getLooper().isCurrentThread()) {
- throw new IllegalStateException(
- "ProcessLocalColors should be called from the background thread");
- }
- }
-
private RectF generateSubRect(RectF in, int pageInx, int numPages) {
float minLeft = (float) (pageInx) / (float) (numPages);
float maxRight = (float) (pageInx + 1) / (float) (numPages);
@@ -1868,6 +1825,7 @@
if (supportsLocalColorExtraction()) return;
if (!mResetWindowPages) return;
mResetWindowPages = false;
+ mLastWindowPage = -1;
for (int i = 0; i < mWindowPages.length; i++) {
mWindowPages[i].setLastUpdateTime(0L);
}
@@ -1893,10 +1851,12 @@
if (DEBUG) {
Log.d(TAG, "addLocalColorsAreas adding local color areas " + regions);
}
- mBackgroundHandler.post(() -> {
+ mHandler.post(() -> {
mLocalColorsToAdd.addAll(regions);
- processLocalColors();
+ processLocalColors(mPendingXOffset, mPendingYOffset);
});
+
+
}
/**
@@ -1906,7 +1866,7 @@
*/
public void removeLocalColorsAreas(@NonNull List<RectF> regions) {
if (supportsLocalColorExtraction()) return;
- mBackgroundHandler.post(() -> {
+ mHandler.post(() -> {
float step = mPendingXOffsetStep;
mLocalColorsToAdd.removeAll(regions);
mLocalColorAreas.removeAll(regions);
@@ -2537,9 +2497,6 @@
@Override
public void onCreate() {
Trace.beginSection("WPMS.onCreate");
- mBackgroundThread = new HandlerThread("DefaultWallpaperLocalColorExtractor");
- mBackgroundThread.start();
- mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
super.onCreate();
Trace.endSection();
}
@@ -2552,7 +2509,6 @@
mActiveEngines.get(i).detach();
}
mActiveEngines.clear();
- mBackgroundThread.quitSafely();
Trace.endSection();
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 02027e4..293f9082 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -823,6 +823,11 @@
/** @hide */
public final void destroy() {
mDestroyed = true;
+ onDestroy();
+ }
+
+ /** @hide */
+ protected void onDestroy() {
}
/** @hide */
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index d8afe50..e7217de 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -33,6 +33,7 @@
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_OPEN_ALL_APPS;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_QUICK_SWITCH;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_UNLOCK_ENTRANCE_ANIMATION;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_CLOCK_MOVE_ANIMATION;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_LAUNCH_CAMERA;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_OCCLUSION;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_PASSWORD_APPEAR;
@@ -231,6 +232,7 @@
public static final int CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS = 66;
public static final int CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE = 67;
public static final int CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME = 68;
+ public static final int CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION = 70;
private static final int NO_STATSD_LOGGING = -1;
@@ -308,6 +310,8 @@
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_SWIPE_TO_RECENTS,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_CLOSE_ALL_APPS_SWIPE,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_CLOSE_ALL_APPS_TO_HOME,
+ NO_STATSD_LOGGING,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_CLOCK_MOVE_ANIMATION,
};
private static volatile InteractionJankMonitor sInstance;
@@ -396,7 +400,8 @@
CUJ_RECENTS_SCROLLING,
CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS,
CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE,
- CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME
+ CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME,
+ CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {
@@ -917,6 +922,8 @@
return "LAUNCHER_CLOSE_ALL_APPS_SWIPE";
case CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME:
return "LAUNCHER_CLOSE_ALL_APPS_TO_HOME";
+ case CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION:
+ return "LOCKSCREEN_CLOCK_MOVE_ANIMATION";
}
return "UNKNOWN";
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 3a0e09d..6fed26c 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -81,7 +81,6 @@
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
-import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
@@ -202,7 +201,6 @@
public static final int RESET_REASON_ADB_COMMAND = 2;
public static final int RESET_REASON_FULL_CHARGE = 3;
public static final int RESET_REASON_MEASURED_ENERGY_BUCKETS_CHANGE = 4;
- public static final int RESET_REASON_PLUGGED_IN_FOR_LONG_DURATION = 5;
protected Clock mClock;
@@ -389,89 +387,6 @@
}
}
- /** Provide BatteryStatsImpl configuration choices */
- public static class BatteryStatsConfig {
- static final int RESET_ON_UNPLUG_HIGH_BATTERY_LEVEL_FLAG = 1 << 0;
- static final int RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG = 1 << 1;
-
- private final int mFlags;
-
- private BatteryStatsConfig(Builder builder) {
- int flags = 0;
- if (builder.mResetOnUnplugHighBatteryLevel) {
- flags |= RESET_ON_UNPLUG_HIGH_BATTERY_LEVEL_FLAG;
- }
- if (builder.mResetOnUnplugAfterSignificantCharge) {
- flags |= RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG;
- }
- mFlags = flags;
- }
-
- /**
- * Returns whether a BatteryStats reset should occur on unplug when the battery level is
- * high.
- */
- boolean shouldResetOnUnplugHighBatteryLevel() {
- return (mFlags & RESET_ON_UNPLUG_HIGH_BATTERY_LEVEL_FLAG)
- == RESET_ON_UNPLUG_HIGH_BATTERY_LEVEL_FLAG;
- }
-
- /**
- * Returns whether a BatteryStats reset should occur on unplug if the battery charge a
- * significant amount since it has been plugged in.
- */
- boolean shouldResetOnUnplugAfterSignificantCharge() {
- return (mFlags & RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG)
- == RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG;
- }
-
- /**
- * Builder for BatteryStatsConfig
- */
- public static class Builder {
- private boolean mResetOnUnplugHighBatteryLevel;
- private boolean mResetOnUnplugAfterSignificantCharge;
- public Builder() {
- mResetOnUnplugHighBatteryLevel = true;
- mResetOnUnplugAfterSignificantCharge = true;
- }
-
- /**
- * Build the BatteryStatsConfig.
- */
- public BatteryStatsConfig build() {
- return new BatteryStatsConfig(this);
- }
-
- /**
- * Set whether a BatteryStats reset should occur on unplug when the battery level is
- * high.
- */
- public Builder setResetOnUnplugHighBatteryLevel(boolean reset) {
- mResetOnUnplugHighBatteryLevel = reset;
- return this;
- }
-
- /**
- * Set whether a BatteryStats reset should occur on unplug if the battery charge a
- * significant amount since it has been plugged in.
- */
- public Builder setResetOnUnplugAfterSignificantCharge(boolean reset) {
- mResetOnUnplugAfterSignificantCharge = reset;
- return this;
- }
- }
-
- }
-
- /** Handles calls to AlarmManager */
- public interface AlarmInterface {
- /** Schedule an RTC alarm */
- void schedule(long rtcTimeMs, long windowLengthMs);
- /** Cancel the previously scheduled alarm */
- void cancel();
- }
-
private final PlatformIdleStateCallback mPlatformIdleStateCallback;
private final Runnable mDeferSetCharging = new Runnable() {
@@ -802,7 +717,6 @@
protected boolean mHaveBatteryLevel = false;
protected boolean mRecordingHistory = false;
int mNumHistoryItems;
- private long mBatteryPluggedInRealTimeMs = 0;
private static final int HISTORY_TAG_INDEX_LIMIT = 0x7ffe;
private static final int MAX_HISTORY_TAG_STRING_LENGTH = 1024;
@@ -1545,13 +1459,6 @@
@GuardedBy("this")
protected final Constants mConstants;
- @VisibleForTesting
- @GuardedBy("this")
- protected BatteryStatsConfig mBatteryStatsConfig = new BatteryStatsConfig.Builder().build();
-
- @VisibleForTesting
- protected AlarmInterface mLongPlugInAlarmInterface = null;
-
/*
* Holds a SamplingTimer associated with each Resource Power Manager state and voter,
* recording their times when on-battery (regardless of screen state).
@@ -1718,13 +1625,12 @@
public BatteryStatsImpl(Clock clock, File historyDirectory) {
init(clock);
mStartClockTimeMs = clock.currentTimeMillis();
+ mCheckinFile = null;
mDailyFile = null;
if (historyDirectory == null) {
- mCheckinFile = null;
mStatsFile = null;
mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer);
} else {
- mCheckinFile = new AtomicFile(new File(historyDirectory, "batterystats-checkin.bin"));
mStatsFile = new AtomicFile(new File(historyDirectory, "batterystats.bin"));
mBatteryStatsHistory = new BatteryStatsHistory(this, historyDirectory, mHistoryBuffer);
}
@@ -12642,27 +12548,6 @@
}
/**
- * Injects BatteryStatsConfig
- */
- public void setBatteryStatsConfig(BatteryStatsConfig config) {
- synchronized (this) {
- mBatteryStatsConfig = config;
- }
- }
-
- /**
- * Injects a LongPlugInAlarmHandler
- */
- public void setLongPlugInAlarmInterface(AlarmInterface longPlugInAlarmInterface) {
- synchronized (this) {
- mLongPlugInAlarmInterface = longPlugInAlarmInterface;
- if (!mOnBattery) {
- scheduleNextResetWhilePluggedInCheck();
- }
- }
- }
-
- /**
* Starts tracking CPU time-in-state for threads of the system server process,
* keeping a separate account of threads receiving incoming binder calls.
*/
@@ -13134,12 +13019,12 @@
}
@GuardedBy("this")
- public void resetAllStatsAndHistoryLocked(int reason) {
+ public void resetAllStatsCmdLocked() {
final long mSecUptime = mClock.uptimeMillis();
long uptimeUs = mSecUptime * 1000;
long mSecRealtime = mClock.elapsedRealtime();
long realtimeUs = mSecRealtime * 1000;
- resetAllStatsLocked(mSecUptime, mSecRealtime, reason);
+ resetAllStatsLocked(mSecUptime, mSecRealtime, RESET_REASON_ADB_COMMAND);
mDischargeStartLevel = mHistoryCur.batteryLevel;
pullPendingStateUpdatesLocked();
addHistoryRecordLocked(mSecRealtime, mSecUptime);
@@ -15613,73 +15498,6 @@
}
/**
- * Might reset battery stats if conditions are met. Assumed the device is currently plugged in.
- */
- @GuardedBy("this")
- public void maybeResetWhilePluggedInLocked() {
- final long elapsedRealtimeMs = mClock.elapsedRealtime();
- if (shouldResetWhilePluggedInLocked(elapsedRealtimeMs)) {
- Slog.i(TAG,
- "Resetting due to long plug in duration. elapsed time = " + elapsedRealtimeMs
- + " ms, last plug in time = " + mBatteryPluggedInRealTimeMs
- + " ms, last reset time = " + mRealtimeStartUs / 1000);
- resetAllStatsAndHistoryLocked(RESET_REASON_PLUGGED_IN_FOR_LONG_DURATION);
- }
-
- scheduleNextResetWhilePluggedInCheck();
- }
-
- @GuardedBy("this")
- private void scheduleNextResetWhilePluggedInCheck() {
- if (mLongPlugInAlarmInterface != null) {
- final long timeoutMs = mClock.currentTimeMillis()
- + mConstants.RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS
- * DateUtils.HOUR_IN_MILLIS;
- Calendar nextAlarm = Calendar.getInstance();
- nextAlarm.setTimeInMillis(timeoutMs);
-
- // Find the 2 AM the same day as the end of the minimum duration.
- // This logic does not handle a Daylight Savings transition, or a timezone change
- // while the alarm has been set. The need to reset after a long period while plugged
- // in is not strict enough to warrant a well architected out solution.
- nextAlarm.set(Calendar.MILLISECOND, 0);
- nextAlarm.set(Calendar.SECOND, 0);
- nextAlarm.set(Calendar.MINUTE, 0);
- nextAlarm.set(Calendar.HOUR_OF_DAY, 2);
- long nextTimeMs = nextAlarm.getTimeInMillis();
- if (nextTimeMs < timeoutMs) {
- // The 2AM on the day of the timeout, move on the next day.
- nextTimeMs += DateUtils.DAY_IN_MILLIS;
- }
- mLongPlugInAlarmInterface.schedule(nextTimeMs, DateUtils.HOUR_IN_MILLIS);
- }
- }
-
-
- @GuardedBy("this")
- private boolean shouldResetWhilePluggedInLocked(long elapsedRealtimeMs) {
- if (mNoAutoReset) return false;
- if (!mSystemReady) return false;
-
- final long pluggedInThresholdMs = mBatteryPluggedInRealTimeMs
- + mConstants.RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS
- * DateUtils.HOUR_IN_MILLIS;
- if (elapsedRealtimeMs >= pluggedInThresholdMs) {
- // The device has been plugged in for a long time.
- final long resetThresholdMs = mRealtimeStartUs / 1000
- + mConstants.RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS
- * DateUtils.HOUR_IN_MILLIS;
- if (elapsedRealtimeMs >= resetThresholdMs) {
- // And it has been a long time since the last reset.
- return true;
- }
- }
-
- return false;
- }
-
-
- /**
* Notifies BatteryStatsImpl that the system server is ready.
*/
public void onSystemReady() {
@@ -15687,32 +15505,6 @@
}
@GuardedBy("this")
- private boolean shouldResetOnUnplugLocked(int batteryStatus, int batteryLevel) {
- if (mNoAutoReset) return false;
- if (!mSystemReady) return false;
- if (mBatteryStatsConfig.shouldResetOnUnplugHighBatteryLevel()) {
- // Allow resetting due to currently being at high battery level
- if (batteryStatus == BatteryManager.BATTERY_STATUS_FULL) return true;
- if (batteryLevel >= 90) return true;
- }
- if (mBatteryStatsConfig.shouldResetOnUnplugAfterSignificantCharge()) {
- // Allow resetting after a significant charge (from a very low level to a now very
- // high level).
- if (mDischargePlugLevel < 20 && batteryLevel >= 80) return true;
- }
- if (getHighDischargeAmountSinceCharge() >= 200) {
- // Reset the stats if battery got partially charged and discharged repeatedly without
- // ever reaching the full charge.
- // This reset is done in order to prevent stats sessions from going on forever.
- // Exceedingly long battery sessions would lead to an overflow of
- // data structures such as mWakeupReasonStats.
- return true;
- }
-
- return false;
- }
-
- @GuardedBy("this")
protected void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime,
final boolean onBattery, final int oldStatus, final int level, final int chargeUah) {
boolean doWrite = false;
@@ -15724,10 +15516,23 @@
final long realtimeUs = mSecRealtime * 1000;
final int screenState = mScreenState;
if (onBattery) {
+ // We will reset our status if we are unplugging after the
+ // battery was last full, or the level is at 100, or
+ // we have gone through a significant charge (from a very low
+ // level to a now very high level).
+ // Also, we will reset the stats if battery got partially charged
+ // and discharged repeatedly without ever reaching the full charge.
+ // This reset is done in order to prevent stats sessions from going on forever.
+ // Exceedingly long battery sessions would lead to an overflow of
+ // data structures such as mWakeupReasonStats.
boolean reset = false;
- if (shouldResetOnUnplugLocked(oldStatus, level)) {
+ if (!mNoAutoReset && mSystemReady
+ && (oldStatus == BatteryManager.BATTERY_STATUS_FULL
+ || level >= 90
+ || (mDischargeCurrentLevel < 20 && level >= 80)
+ || getHighDischargeAmountSinceCharge() >= 200)) {
Slog.i(TAG, "Resetting battery stats: level=" + level + " status=" + oldStatus
- + " dischargeLevel=" + mDischargePlugLevel
+ + " dischargeLevel=" + mDischargeCurrentLevel
+ " lowAmount=" + getLowDischargeAmountSinceCharge()
+ " highAmount=" + getHighDischargeAmountSinceCharge());
// Before we write, collect a snapshot of the final aggregated
@@ -15784,9 +15589,6 @@
mInitStepMode = mCurStepMode;
mModStepMode = 0;
pullPendingStateUpdatesLocked();
- if (mLongPlugInAlarmInterface != null) {
- mLongPlugInAlarmInterface.cancel();
- }
mHistoryCur.batteryLevel = (byte)level;
mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: "
@@ -15818,7 +15620,6 @@
mLastChargingStateLevel = level;
mOnBattery = mOnBatteryInternal = false;
pullPendingStateUpdatesLocked();
- mBatteryPluggedInRealTimeMs = mSecRealtime;
mHistoryCur.batteryLevel = (byte)level;
mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
@@ -15836,7 +15637,6 @@
mMaxChargeStepLevel = level;
mInitStepMode = mCurStepMode;
mModStepMode = 0;
- scheduleNextResetWhilePluggedInCheck();
}
if (doWrite || (mLastWriteTimeMs + (60 * 1000)) < mSecRealtime) {
if (mStatsFile != null && mBatteryStatsHistory.getActiveFile() != null) {
@@ -16851,8 +16651,6 @@
public static final String KEY_MAX_HISTORY_BUFFER_KB = "max_history_buffer_kb";
public static final String KEY_BATTERY_CHARGED_DELAY_MS =
"battery_charged_delay_ms";
- public static final String KEY_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS =
- "reset_while_plugged_in_minimum_duration_hours";
private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true;
private static final long DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME = 1_000;
@@ -16865,8 +16663,6 @@
private static final int DEFAULT_MAX_HISTORY_FILES_LOW_RAM_DEVICE = 64;
private static final int DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB = 64; /*Kilo Bytes*/
private static final int DEFAULT_BATTERY_CHARGED_DELAY_MS = 900000; /* 15 min */
- // Little less than 2 days
- private static final int DEFAULT_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS = 47;
public boolean TRACK_CPU_ACTIVE_CLUSTER_TIME = DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME;
/* Do not set default value for KERNEL_UID_READERS_THROTTLE_TIME. Need to trigger an
@@ -16882,8 +16678,6 @@
public int MAX_HISTORY_FILES;
public int MAX_HISTORY_BUFFER; /*Bytes*/
public int BATTERY_CHARGED_DELAY_MS = DEFAULT_BATTERY_CHARGED_DELAY_MS;
- public int RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS =
- DEFAULT_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS;
private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -16960,11 +16754,6 @@
DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB
: DEFAULT_MAX_HISTORY_BUFFER_KB)
* 1024;
-
- RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS = mParser.getInt(
- KEY_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS,
- DEFAULT_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS);
-
updateBatteryChargedDelayMsLocked();
}
}
@@ -17019,8 +16808,6 @@
pw.println(MAX_HISTORY_BUFFER/1024);
pw.print(KEY_BATTERY_CHARGED_DELAY_MS); pw.print("=");
pw.println(BATTERY_CHARGED_DELAY_MS);
- pw.print(KEY_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS); pw.print("=");
- pw.println(RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS);
}
}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index bb69192f..e603e2ed 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -295,6 +295,7 @@
private boolean mClosingActionMenu;
private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
+ private int mAudioMode = AudioManager.MODE_NORMAL;
private MediaController mMediaController;
private AudioManager mAudioManager;
@@ -317,6 +318,8 @@
}
};
+ private AudioManager.OnModeChangedListener mOnModeChangedListener;
+
private Transition mEnterTransition = null;
private Transition mReturnTransition = USE_DEFAULT_TRANSITION;
private Transition mExitTransition = null;
@@ -1950,9 +1953,9 @@
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
- // If we have a session send it the volume command, otherwise
- // use the suggested stream.
- if (mMediaController != null) {
+ // If we have a session and no active phone call send it the volume command,
+ // otherwise use the suggested stream.
+ if (mMediaController != null && !isActivePhoneCallOngoing()) {
getMediaSessionManager().dispatchVolumeKeyEventToSessionAsSystemService(event,
mMediaController.getSessionToken());
} else {
@@ -2003,6 +2006,11 @@
return false;
}
+ private boolean isActivePhoneCallOngoing() {
+ return mAudioMode == AudioManager.MODE_IN_CALL
+ || mAudioMode == AudioManager.MODE_IN_COMMUNICATION;
+ }
+
private KeyguardManager getKeyguardManager() {
if (mKeyguardManager == null) {
mKeyguardManager = (KeyguardManager) getContext().getSystemService(
@@ -2326,6 +2334,14 @@
}
}
+ @Override
+ protected void onDestroy() {
+ if (mOnModeChangedListener != null) {
+ getAudioManager().removeOnModeChangedListener(mOnModeChangedListener);
+ mOnModeChangedListener = null;
+ }
+ }
+
private class PanelMenuPresenterCallback implements MenuPresenter.Callback {
@Override
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
@@ -3208,6 +3224,15 @@
@Override
public void setMediaController(MediaController controller) {
mMediaController = controller;
+ if (controller != null && mOnModeChangedListener == null) {
+ mAudioMode = getAudioManager().getMode();
+ mOnModeChangedListener = mode -> mAudioMode = mode;
+ getAudioManager().addOnModeChangedListener(getContext().getMainExecutor(),
+ mOnModeChangedListener);
+ } else if (mOnModeChangedListener != null) {
+ getAudioManager().removeOnModeChangedListener(mOnModeChangedListener);
+ mOnModeChangedListener = null;
+ }
}
@Override
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 31903e2..0e95e30 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3154,7 +3154,11 @@
android:protectionLevel="normal" />
<!-- Allows an application to call
- {@link android.app.ActivityManager#killBackgroundProcesses}.
+ {@link android.app.ActivityManager#killBackgroundProcesses}.
+
+ <p class="note">Third party applications can only use this API to kill their own
+ processes.</p>
+
<p>Protection level: normal
-->
<permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 58c8b29..dafa0ad 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -6092,9 +6092,4 @@
<!-- Whether to show weather on the lock screen by default. -->
<bool name="config_lockscreenWeatherEnabledByDefault">false</bool>
-
- <!-- Whether to reset Battery Stats on unplug when the battery level is high. -->
- <bool name="config_batteryStatsResetOnUnplugHighBatteryLevel">true</bool>
- <!-- Whether to reset Battery Stats on unplug if the battery was significantly charged -->
- <bool name="config_batteryStatsResetOnUnplugAfterSignificantCharge">true</bool>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 8addca2..591ba5f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4903,7 +4903,4 @@
<!-- Whether to show weather on the lockscreen by default. -->
<java-symbol type="bool" name="config_lockscreenWeatherEnabledByDefault" />
-
- <java-symbol type="bool" name="config_batteryStatsResetOnUnplugHighBatteryLevel" />
- <java-symbol type="bool" name="config_batteryStatsResetOnUnplugAfterSignificantCharge" />
</resources>
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsResetTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsResetTest.java
deleted file mode 100644
index 9c2d332..0000000
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsResetTest.java
+++ /dev/null
@@ -1,362 +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.os;
-
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-import android.os.BatteryManager;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class BatteryStatsResetTest {
-
- private static final int BATTERY_NOMINAL_VOLTAGE_MV = 3700;
- private static final int BATTERY_CAPACITY_UAH = 4_000_000;
- private static final int BATTERY_CHARGE_RATE_SECONDS_PER_LEVEL = 100;
-
- private MockClock mMockClock;
- private MockBatteryStatsImpl mBatteryStatsImpl;
-
-
- /**
- * Battery status. Must be one of the following:
- * {@link BatteryManager#BATTERY_STATUS_UNKNOWN}
- * {@link BatteryManager#BATTERY_STATUS_CHARGING}
- * {@link BatteryManager#BATTERY_STATUS_DISCHARGING}
- * {@link BatteryManager#BATTERY_STATUS_NOT_CHARGING}
- * {@link BatteryManager#BATTERY_STATUS_FULL}
- */
- private int mBatteryStatus;
- /**
- * Battery health. Must be one of the following:
- * {@link BatteryManager#BATTERY_HEALTH_UNKNOWN}
- * {@link BatteryManager#BATTERY_HEALTH_GOOD}
- * {@link BatteryManager#BATTERY_HEALTH_OVERHEAT}
- * {@link BatteryManager#BATTERY_HEALTH_DEAD}
- * {@link BatteryManager#BATTERY_HEALTH_OVER_VOLTAGE}
- * {@link BatteryManager#BATTERY_HEALTH_UNSPECIFIED_FAILURE}
- * {@link BatteryManager#BATTERY_HEALTH_COLD}
- */
- private int mBatteryHealth;
- /**
- * Battery plug type. Can be the union of any number of the following flags:
- * {@link BatteryManager#BATTERY_PLUGGED_AC}
- * {@link BatteryManager#BATTERY_PLUGGED_USB}
- * {@link BatteryManager#BATTERY_PLUGGED_WIRELESS}
- * {@link BatteryManager#BATTERY_PLUGGED_DOCK}
- *
- * Zero means the device is unplugged.
- */
- private int mBatteryPlugType;
- private int mBatteryLevel;
- private int mBatteryTemp;
- private int mBatteryVoltageMv;
- private int mBatteryChargeUah;
- private int mBatteryChargeFullUah;
- private long mBatteryChargeTimeToFullSeconds;
-
- @Before
- public void setUp() {
- final Context context = InstrumentationRegistry.getContext();
-
- mMockClock = new MockClock();
- mBatteryStatsImpl = new MockBatteryStatsImpl(mMockClock, context.getFilesDir());
- mBatteryStatsImpl.onSystemReady();
-
-
- // Set up the battery state. Start off with a fully charged plugged in battery.
- mBatteryStatus = BatteryManager.BATTERY_STATUS_FULL;
- mBatteryHealth = BatteryManager.BATTERY_HEALTH_GOOD;
- mBatteryPlugType = BatteryManager.BATTERY_PLUGGED_USB;
- mBatteryLevel = 100;
- mBatteryTemp = 70; // Arbitrary reasonable temperature.
- mBatteryVoltageMv = BATTERY_NOMINAL_VOLTAGE_MV;
- mBatteryChargeUah = BATTERY_CAPACITY_UAH;
- mBatteryChargeFullUah = BATTERY_CAPACITY_UAH;
- mBatteryChargeTimeToFullSeconds = 0;
- }
-
- @Test
- public void testResetOnUnplug_highBatteryLevel() {
- mBatteryStatsImpl.setBatteryStatsConfig(
- new BatteryStatsImpl.BatteryStatsConfig.Builder()
- .setResetOnUnplugHighBatteryLevel(true)
- .build());
-
- long expectedResetTimeUs = 0;
-
- unplugBattery();
- dischargeToLevel(60);
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- chargeToLevel(80);
- unplugBattery();
- // Reset should not occur until battery level above 90.
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- chargeToLevel(95);
- // Reset should not occur until unplug.
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- unplugBattery();
- // Reset should occur on unplug now that battery level is high (>=90)
- expectedResetTimeUs = mMockClock.elapsedRealtime() * 1000;
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // disable high battery level reset on unplug.
- mBatteryStatsImpl.setBatteryStatsConfig(
- new BatteryStatsImpl.BatteryStatsConfig.Builder()
- .setResetOnUnplugHighBatteryLevel(false)
- .build());
-
- dischargeToLevel(60);
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- chargeToLevel(95);
- unplugBattery();
- // Reset should not occur since the high battery level logic has been disabled.
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
- }
-
- @Test
- public void testResetOnUnplug_significantCharge() {
- mBatteryStatsImpl.setBatteryStatsConfig(
- new BatteryStatsImpl.BatteryStatsConfig.Builder()
- .setResetOnUnplugAfterSignificantCharge(true)
- .build());
- long expectedResetTimeUs = 0;
-
- unplugBattery();
- // Battery level dropped below 20%.
- dischargeToLevel(15);
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- chargeToLevel(50);
- unplugBattery();
- // Reset should not occur until battery level above 80
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- chargeToLevel(85);
- unplugBattery();
- // Reset should not occur because the charge session did not go from 20% to 80%
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // Battery level dropped below 20%.
- dischargeToLevel(15);
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- chargeToLevel(85);
- unplugBattery();
- // Reset should occur after significant charge amount.
- expectedResetTimeUs = mMockClock.elapsedRealtime() * 1000;
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // disable reset on unplug after significant charge.
- mBatteryStatsImpl.setBatteryStatsConfig(
- new BatteryStatsImpl.BatteryStatsConfig.Builder()
- .setResetOnUnplugAfterSignificantCharge(false)
- .build());
-
- // Battery level dropped below 20%.
- dischargeToLevel(15);
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- chargeToLevel(85);
- unplugBattery();
- // Reset should not occur after significant charge amount.
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
- }
-
- @Test
- public void testResetOnUnplug_manyPartialCharges() {
- long expectedResetTimeUs = 0;
-
- unplugBattery();
- // Cumulative battery discharged: 60%.
- dischargeToLevel(40);
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- chargeToLevel(80);
- unplugBattery();
- // Reset should not occur
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // Cumulative battery discharged: 100%.
- dischargeToLevel(40);
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- chargeToLevel(80);
- unplugBattery();
- // Reset should not occur
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // Cumulative battery discharged: 140%.
- dischargeToLevel(40);
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- chargeToLevel(80);
- unplugBattery();
- // Reset should not occur
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // Cumulative battery discharged: 180%.
- dischargeToLevel(40);
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- chargeToLevel(80);
- unplugBattery();
- // Reset should not occur
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // Cumulative battery discharged: 220%.
- dischargeToLevel(40);
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- chargeToLevel(80);
- unplugBattery();
- // Should reset after >200% of cumulative battery discharge
- expectedResetTimeUs = mMockClock.elapsedRealtime() * 1000;
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
- }
-
- @Test
- public void testResetWhilePluggedIn_longPlugIn() {
- // disable high battery level reset on unplug.
- mBatteryStatsImpl.setBatteryStatsConfig(
- new BatteryStatsImpl.BatteryStatsConfig.Builder()
- .setResetOnUnplugHighBatteryLevel(false)
- .setResetOnUnplugAfterSignificantCharge(false)
- .build());
- long expectedResetTimeUs = 0;
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- mBatteryStatsImpl.maybeResetWhilePluggedInLocked();
- // Reset should not occur
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // Increment time a day
- incTimeMs(24L * 60L * 60L * 1000L);
- mBatteryStatsImpl.maybeResetWhilePluggedInLocked();
- // Reset should still not occur
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // Increment time a day
- incTimeMs(24L * 60L * 60L * 1000L);
- mBatteryStatsImpl.maybeResetWhilePluggedInLocked();
- // Reset 47 hour threshold crossed, reset should occur.
- expectedResetTimeUs = mMockClock.elapsedRealtime() * 1000;
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // Increment time a day
- incTimeMs(24L * 60L * 60L * 1000L);
- mBatteryStatsImpl.maybeResetWhilePluggedInLocked();
- // Reset should not occur
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // Increment time a day
- incTimeMs(24L * 60L * 60L * 1000L);
- mBatteryStatsImpl.maybeResetWhilePluggedInLocked();
- // Reset another 47 hour threshold crossed, reset should occur.
- expectedResetTimeUs = mMockClock.elapsedRealtime() * 1000;
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // Increment time a day
- incTimeMs(24L * 60L * 60L * 1000L);
- mBatteryStatsImpl.maybeResetWhilePluggedInLocked();
- // Reset should not occur
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- unplugBattery();
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
-
- // Increment time a day
- incTimeMs(24L * 60L * 60L * 1000L);
- mBatteryStatsImpl.maybeResetWhilePluggedInLocked();
- // Reset should not occur, since unplug occurred recently.
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // Increment time a day
- incTimeMs(24L * 60L * 60L * 1000L);
- mBatteryStatsImpl.maybeResetWhilePluggedInLocked();
- // Reset another 47 hour threshold crossed, reset should occur.
- expectedResetTimeUs = mMockClock.elapsedRealtime() * 1000;
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
- }
-
- private void dischargeToLevel(int targetLevel) {
- mBatteryStatus = BatteryManager.BATTERY_STATUS_DISCHARGING;
- for (int level = mBatteryLevel - 1; level >= targetLevel; level--) {
- prepareBatteryLevel(level);
- incTimeMs(5000); // Arbitrary discharge rate.
- updateBatteryState();
- }
- }
-
- private void chargeToLevel(int targetLevel) {
- mBatteryStatus = BatteryManager.BATTERY_STATUS_CHARGING;
- for (int level = mBatteryLevel + 1; level <= targetLevel; level++) {
- if (level >= 100) mBatteryStatus = BatteryManager.BATTERY_STATUS_FULL;
- prepareBatteryLevel(level);
- incTimeMs(BATTERY_CHARGE_RATE_SECONDS_PER_LEVEL * 1000);
- updateBatteryState();
- }
- }
-
- private void unplugBattery() {
- mBatteryPlugType = 0;
- updateBatteryState();
- }
-
- private void plugBattery(int type) {
- mBatteryPlugType |= type;
- updateBatteryState();
- }
-
- private void prepareBatteryLevel(int level) {
- mBatteryLevel = level;
- mBatteryChargeUah = mBatteryLevel * mBatteryChargeFullUah / 100;
- mBatteryChargeTimeToFullSeconds =
- (100 - mBatteryLevel) * BATTERY_CHARGE_RATE_SECONDS_PER_LEVEL;
- }
-
- private void incTimeMs(long milliseconds) {
- mMockClock.realtime += milliseconds;
- mMockClock.uptime += milliseconds / 2; // Arbitrary slower uptime accumulation
- mMockClock.currentTime += milliseconds;
- }
-
- private void updateBatteryState() {
- mBatteryStatsImpl.setBatteryStateLocked(mBatteryStatus, mBatteryHealth, mBatteryPlugType,
- mBatteryLevel, mBatteryTemp, mBatteryVoltageMv, mBatteryChargeUah,
- mBatteryChargeFullUah, mBatteryChargeTimeToFullSeconds,
- mMockClock.elapsedRealtime(), mMockClock.uptimeMillis(),
- mMockClock.currentTimeMillis());
- }
-}
-
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
index ae2d1af..2742861 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
@@ -342,7 +342,7 @@
Context context = InstrumentationRegistry.getContext();
BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
mStatsRule.setCurrentTime(5 * MINUTE_IN_MS);
- batteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ batteryStats.resetAllStatsCmdLocked();
BatteryUsageStatsStore batteryUsageStatsStore = new BatteryUsageStatsStore(context,
batteryStats, new File(context.getCacheDir(), "BatteryUsageStatsProviderTest"),
@@ -357,14 +357,14 @@
batteryStats.noteFlashlightOffLocked(APP_UID,
20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS);
mStatsRule.setCurrentTime(25 * MINUTE_IN_MS);
- batteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ batteryStats.resetAllStatsCmdLocked();
batteryStats.noteFlashlightOnLocked(APP_UID,
30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
batteryStats.noteFlashlightOffLocked(APP_UID,
50 * MINUTE_IN_MS, 50 * MINUTE_IN_MS);
mStatsRule.setCurrentTime(55 * MINUTE_IN_MS);
- batteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ batteryStats.resetAllStatsCmdLocked();
// This section should be ignored because the timestamp is out or range
batteryStats.noteFlashlightOnLocked(APP_UID,
@@ -372,7 +372,7 @@
batteryStats.noteFlashlightOffLocked(APP_UID,
70 * MINUTE_IN_MS, 70 * MINUTE_IN_MS);
mStatsRule.setCurrentTime(75 * MINUTE_IN_MS);
- batteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ batteryStats.resetAllStatsCmdLocked();
// This section should be ignored because it represents the current stats session
batteryStats.noteFlashlightOnLocked(APP_UID,
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsStoreTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsStoreTest.java
index 11b9047..c9729fa 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsStoreTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsStoreTest.java
@@ -84,7 +84,7 @@
mMockClock.realtime = 1_000_000;
mMockClock.uptime = 1_000_000;
- mBatteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ mBatteryStats.resetAllStatsCmdLocked();
final long[] timestamps = mBatteryUsageStatsStore.listBatteryUsageStatsTimestamps();
assertThat(timestamps).hasLength(1);
@@ -114,7 +114,7 @@
final int numberOfSnapshots =
(int) (MAX_BATTERY_STATS_SNAPSHOT_STORAGE_BYTES / snapshotFileSize);
for (int i = 0; i < numberOfSnapshots + 2; i++) {
- mBatteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ mBatteryStats.resetAllStatsCmdLocked();
mMockClock.realtime += 10_000_000;
mMockClock.uptime += 10_000_000;
@@ -141,7 +141,7 @@
mMockClock.currentTime += 10_000_000;
prepareBatteryStats();
- mBatteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ mBatteryStats.resetAllStatsCmdLocked();
}
assertThat(getDirectorySize(mStoreDirectory)).isNotEqualTo(0);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index a673384..7d3e7ca 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -204,7 +204,7 @@
// and exit, since exit itself can trigger a number of changes that update the stages.
private boolean mShouldUpdateRecents;
private boolean mExitSplitScreenOnHide;
- private boolean mIsSplitEntering;
+ private boolean mIsDividerRemoteAnimating;
private boolean mIsDropEntering;
private boolean mIsExiting;
@@ -881,7 +881,7 @@
// Set false to avoid record new bounds with old task still on top;
mShouldUpdateRecents = false;
- mIsSplitEntering = true;
+ mIsDividerRemoteAnimating = true;
if (mSplitRequest == null) {
mSplitRequest = new SplitRequest(mainTaskId,
mainPendingIntent != null ? mainPendingIntent.getIntent() : null,
@@ -974,7 +974,7 @@
}
private void onRemoteAnimationFinishedOrCancelled(WindowContainerTransaction evictWct) {
- mIsSplitEntering = false;
+ mIsDividerRemoteAnimating = false;
mShouldUpdateRecents = true;
mSplitRequest = null;
// If any stage has no child after animation finished, it means that split will display
@@ -1240,7 +1240,7 @@
}
});
mShouldUpdateRecents = false;
- mIsSplitEntering = false;
+ mIsDividerRemoteAnimating = false;
mSplitLayout.getInvisibleBounds(mTempRect1);
if (childrenToTop == null || childrenToTop.getTopVisibleChildTaskId() == INVALID_TASK_ID) {
@@ -1573,7 +1573,7 @@
&& !ENABLE_SHELL_TRANSITIONS) {
// Clear the divider remote animating flag as the divider will be re-rendered to apply
// the new rotation config.
- mIsSplitEntering = false;
+ mIsDividerRemoteAnimating = false;
mSplitLayout.update(null /* t */);
onLayoutSizeChanged(mSplitLayout);
}
@@ -1623,9 +1623,9 @@
}
void onChildTaskAppeared(StageListenerImpl stageListener, int taskId) {
+ // Handle entering split screen while there is a split pair running in the background.
if (stageListener == mSideStageListener && !isSplitScreenVisible() && isSplitActive()
- && !mIsSplitEntering) {
- // Handle entring split case here if split already running background.
+ && mSplitRequest == null) {
if (mIsDropEntering) {
mSplitLayout.resetDividerPosition();
} else {
@@ -1717,7 +1717,7 @@
mDividerVisible = visible;
sendSplitVisibilityChanged();
- if (mIsSplitEntering) {
+ if (mIsDividerRemoteAnimating) {
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
" Skip animating divider bar due to it's remote animating.");
return;
@@ -1737,7 +1737,7 @@
" Skip animating divider bar due to divider leash not ready.");
return;
}
- if (mIsSplitEntering) {
+ if (mIsDividerRemoteAnimating) {
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
" Skip animating divider bar due to it's remote animating.");
return;
@@ -1805,7 +1805,8 @@
mSplitLayout.flingDividerToDismiss(
mSideStagePosition != SPLIT_POSITION_BOTTOM_OR_RIGHT,
EXIT_REASON_APP_FINISHED);
- } else if (!isSplitScreenVisible() && !mIsSplitEntering) {
+ } else if (!isSplitScreenVisible() && mSplitRequest == null) {
+ // Dismiss split screen in the background once any sides of the split become empty.
exitSplitScreen(null /* childrenToTop */, EXIT_REASON_APP_FINISHED);
}
} else if (isSideStage && hasChildren && !mMainStage.isActive()) {
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DemotingTestWithoutBugDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DemotingTestWithoutBugDetector.kt
new file mode 100644
index 0000000..f64ea45
--- /dev/null
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DemotingTestWithoutBugDetector.kt
@@ -0,0 +1,77 @@
+/*
+ * 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.systemui.lint
+
+import com.android.tools.lint.client.api.UElementHandler
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import org.jetbrains.uast.UAnnotation
+import org.jetbrains.uast.UElement
+
+class DemotingTestWithoutBugDetector : Detector(), SourceCodeScanner {
+ override fun getApplicableUastTypes(): List<Class<out UElement>> {
+ return listOf(UAnnotation::class.java)
+ }
+
+ override fun createUastHandler(context: JavaContext): UElementHandler {
+ return object : UElementHandler() {
+ override fun visitAnnotation(node: UAnnotation) {
+ if (node.qualifiedName !in DEMOTING_ANNOTATION) {
+ return
+ }
+ val bugId = node.findAttributeValue("bugId")!!.evaluate() as Int
+ if (bugId <= 0) {
+ val location = context.getLocation(node)
+ val message = "Please attach a bug id to track demoted test"
+ context.report(ISSUE, node, location, message)
+ }
+ }
+ }
+ }
+
+ companion object {
+ val DEMOTING_ANNOTATION =
+ listOf("androidx.test.filters.FlakyTest", "android.platform.test.annotations.FlakyTest")
+
+ @JvmField
+ val ISSUE: Issue =
+ Issue.create(
+ id = "DemotingTestWithoutBug",
+ briefDescription = "Demoting a test without attaching a bug.",
+ explanation =
+ """
+ Annotations (`@FlakyTest`) demote tests to an unmonitored \
+ test suite. Please set the `bugId` field in such annotations to track \
+ the test status.
+ """,
+ category = Category.TESTING,
+ priority = 8,
+ severity = Severity.WARNING,
+ implementation =
+ Implementation(
+ DemotingTestWithoutBugDetector::class.java,
+ Scope.JAVA_FILE_SCOPE
+ )
+ )
+ }
+}
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
index 84f7050..387b67d 100644
--- a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
@@ -39,7 +39,8 @@
RegisterReceiverViaContextDetector.ISSUE,
SoftwareBitmapDetector.ISSUE,
NonInjectedServiceDetector.ISSUE,
- StaticSettingsProviderDetector.ISSUE
+ StaticSettingsProviderDetector.ISSUE,
+ DemotingTestWithoutBugDetector.ISSUE
)
override val api: Int
diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DemotingTestWithoutBugDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DemotingTestWithoutBugDetectorTest.kt
new file mode 100644
index 0000000..557c300
--- /dev/null
+++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DemotingTestWithoutBugDetectorTest.kt
@@ -0,0 +1,151 @@
+/*
+ * 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.systemui.lint
+
+import com.android.tools.lint.checks.infrastructure.TestFile
+import com.android.tools.lint.checks.infrastructure.TestFiles
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import org.junit.Test
+
+class DemotingTestWithoutBugDetectorTest : SystemUILintDetectorTest() {
+
+ override fun getDetector(): Detector = DemotingTestWithoutBugDetector()
+ override fun getIssues(): List<Issue> = listOf(DemotingTestWithoutBugDetector.ISSUE)
+
+ @Test
+ fun testMarkFlaky_withBugId() {
+ lint()
+ .files(
+ TestFiles.java(
+ """
+ package test.pkg;
+ import androidx.test.filters.FlakyTest;
+
+ @FlakyTest(bugId = 123)
+ public class TestClass {
+ public void testCase() {}
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(DemotingTestWithoutBugDetector.ISSUE)
+ .run()
+ .expectClean()
+
+ lint()
+ .files(
+ TestFiles.java(
+ """
+ package test.pkg;
+ import android.platform.test.annotations.FlakyTest;
+
+ @FlakyTest(bugId = 123)
+ public class TestClass {
+ public void testCase() {}
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(DemotingTestWithoutBugDetector.ISSUE)
+ .run()
+ .expectClean()
+ }
+
+ @Test
+ fun testMarkFlaky_withoutBugId() {
+ lint()
+ .files(
+ TestFiles.java(
+ """
+ package test.pkg;
+ import androidx.test.filters.FlakyTest;
+
+ @FlakyTest
+ public class TestClass {
+ public void testCase() {}
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(DemotingTestWithoutBugDetector.ISSUE)
+ .run()
+ .expect(
+ """
+ src/test/pkg/TestClass.java:4: Warning: Please attach a bug id to track demoted test [DemotingTestWithoutBug]
+ @FlakyTest
+ ~~~~~~~~~~
+ 0 errors, 1 warnings
+ """
+ )
+
+ lint()
+ .files(
+ TestFiles.java(
+ """
+ package test.pkg;
+ import android.platform.test.annotations.FlakyTest;
+
+ @FlakyTest
+ public class TestClass {
+ public void testCase() {}
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(DemotingTestWithoutBugDetector.ISSUE)
+ .run()
+ .expect(
+ """
+ src/test/pkg/TestClass.java:4: Warning: Please attach a bug id to track demoted test [DemotingTestWithoutBug]
+ @FlakyTest
+ ~~~~~~~~~~
+ 0 errors, 1 warnings
+ """
+ )
+ }
+
+ private val filtersFlakyTestStub: TestFile =
+ java(
+ """
+ package androidx.test.filters;
+
+ public @interface FlakyTest {
+ int bugId() default -1;
+ }
+ """
+ )
+ private val annotationsFlakyTestStub: TestFile =
+ java(
+ """
+ package android.platform.test.annotations;
+
+ public @interface FlakyTest {
+ int bugId() default -1;
+ }
+ """
+ )
+ private val stubs = arrayOf(filtersFlakyTestStub, annotationsFlakyTestStub)
+}
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 992d143..6cc5b9d 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -78,7 +78,7 @@
<!-- The vertical margin between the date and the owner info. -->
<!-- The translation for disappearing security views after having solved them. -->
- <dimen name="disappear_y_translation">-50dp</dimen>
+ <dimen name="disappear_y_translation">-32dp</dimen>
<!-- Dimens for animation for the Bouncer PIN view -->
<dimen name="pin_view_trans_y_entry">120dp</dimen>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 6bfaf5e..b2add4f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -18,7 +18,6 @@
import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
-import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
import static android.app.ActivityTaskManager.getService;
import android.annotation.NonNull;
@@ -45,6 +44,7 @@
import android.os.SystemClock;
import android.provider.Settings;
import android.util.Log;
+import android.view.Display;
import android.view.IRecentsAnimationController;
import android.view.IRecentsAnimationRunner;
import android.view.RemoteAnimationTarget;
@@ -112,6 +112,13 @@
}
/**
+ * @see #getRunningTasks(boolean , int)
+ */
+ public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents) {
+ return getRunningTasks(filterOnlyVisibleRecents, Display.INVALID_DISPLAY);
+ }
+
+ /**
* We ask for {@link #NUM_RECENT_ACTIVITIES_REQUEST} activities because when in split screen,
* we'll get back 2 activities for each split app and one for launcher. Launcher might be more
* "recently" used than one of the split apps so if we only request 2 tasks, then we might miss
@@ -120,10 +127,12 @@
* @return an array of up to {@link #NUM_RECENT_ACTIVITIES_REQUEST} running tasks
* filtering only for tasks that can be visible in the recent tasks list.
*/
- public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents) {
+ public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents,
+ int displayId) {
// Note: The set of running tasks from the system is ordered by recency
List<ActivityManager.RunningTaskInfo> tasks =
- mAtm.getTasks(NUM_RECENT_ACTIVITIES_REQUEST, filterOnlyVisibleRecents);
+ mAtm.getTasks(NUM_RECENT_ACTIVITIES_REQUEST,
+ filterOnlyVisibleRecents, /* keepInExtras= */ false, displayId);
return tasks.toArray(new RunningTaskInfo[tasks.size()]);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index c1fae9e..33bea02 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -69,6 +69,7 @@
private Interpolator mLinearOutSlowInInterpolator;
private Interpolator mFastOutLinearInInterpolator;
+ private DisappearAnimationListener mDisappearAnimationListener;
public KeyguardPasswordView(Context context) {
this(context, null);
@@ -186,9 +187,13 @@
return;
}
Insets shownInsets = controller.getShownStateInsets();
- Insets insets = Insets.add(shownInsets, Insets.of(0, 0, 0,
- (int) (-shownInsets.bottom / 4
- * anim.getAnimatedFraction())));
+ int dist = (int) (-shownInsets.bottom / 4
+ * anim.getAnimatedFraction());
+ Insets insets = Insets.add(shownInsets, Insets.of(0, 0, 0, dist));
+ if (mDisappearAnimationListener != null) {
+ mDisappearAnimationListener.setTranslationY(-dist);
+ }
+
controller.setInsetsAndAlpha(insets,
(float) animation.getAnimatedValue(),
anim.getAnimatedFraction());
@@ -209,6 +214,7 @@
controller.finish(false);
runOnFinishImeAnimationRunnable();
finishRunnable.run();
+ mDisappearAnimationListener = null;
Trace.endSection();
});
}
@@ -286,4 +292,19 @@
}
});
}
+
+ /**
+ * Listens to the progress of the disappear animation and handles it.
+ */
+ interface DisappearAnimationListener {
+ void setTranslationY(int transY);
+ }
+
+ /**
+ * Set an instance of the disappear animation listener to this class. This will be
+ * removed when the animation completes.
+ */
+ public void setDisappearAnimationListener(DisappearAnimationListener listener) {
+ mDisappearAnimationListener = listener;
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index c6f0eee..2949616 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -39,6 +39,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
@@ -173,6 +174,17 @@
private @Mode int mCurrentMode = MODE_UNINITIALIZED;
private int mWidth = -1;
+ /**
+ * This callback is used to animate KeyguardSecurityContainer and its child views based on
+ * the interaction with the ime. After
+ * {@link WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation)},
+ * {@link #onApplyWindowInsets} is called where we
+ * set the bottom padding to be the height of the keyboard. We use this padding to determine
+ * the delta of vertical distance for y-translation animations.
+ * Note that bottom padding is not set when the disappear animation is started because
+ * we are deferring the y translation logic to the animator in
+ * {@link KeyguardPasswordView#startDisappearAnimation(Runnable)}
+ */
private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback =
new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {
@@ -213,7 +225,6 @@
continue;
}
interpolatedFraction = animation.getInterpolatedFraction();
-
final int paddingBottom = (int) MathUtils.lerp(
start, end,
interpolatedFraction);
@@ -568,13 +579,21 @@
*/
public void startDisappearAnimation(SecurityMode securitySelection) {
mDisappearAnimRunning = true;
- mViewMode.startDisappearAnimation(securitySelection);
+ if (securitySelection == SecurityMode.Password
+ && mSecurityViewFlipper.getSecurityView() instanceof KeyguardPasswordView) {
+ ((KeyguardPasswordView) mSecurityViewFlipper.getSecurityView())
+ .setDisappearAnimationListener(this::setTranslationY);
+ } else {
+ mViewMode.startDisappearAnimation(securitySelection);
+ }
}
/**
* This will run when the bouncer shows in all cases except when the user drags the bouncer up.
*/
public void startAppearAnimation(SecurityMode securityMode) {
+ setTranslationY(0f);
+ setAlpha(1f);
updateChildren(0 /* translationY */, 1f /* alpha */);
mViewMode.startAppearAnimation(securityMode);
}
@@ -623,7 +642,13 @@
int inset = max(bottomInset, imeInset);
int paddingBottom = max(inset, getContext().getResources()
.getDimensionPixelSize(R.dimen.keyguard_security_view_bottom_margin));
- setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), paddingBottom);
+ // If security mode is password, we rely on the animation value of defined in
+ // KeyguardPasswordView to determine the y translation animation.
+ // This means that we will prevent the WindowInsetsAnimationCallback from setting any y
+ // translation values by preventing the setting of the padding here.
+ if (!mDisappearAnimRunning) {
+ setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), paddingBottom);
+ }
return insets.inset(0, 0, 0, inset);
}
@@ -1043,10 +1068,13 @@
int yTranslation = mResources.getDimensionPixelSize(R.dimen.disappear_y_translation);
+ AnimatorSet anims = new AnimatorSet();
ObjectAnimator yAnim = ObjectAnimator.ofFloat(mView, View.TRANSLATION_Y, yTranslation);
- yAnim.setInterpolator(Interpolators.STANDARD_ACCELERATE);
- yAnim.setDuration(500);
- yAnim.start();
+ ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(mView, View.ALPHA, 0f);
+
+ anims.setInterpolator(Interpolators.STANDARD_ACCELERATE);
+ anims.playTogether(alphaAnim, yAnim);
+ anims.start();
}
private void setupUserSwitcher() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index c32b853..b8bb260 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -636,17 +636,12 @@
public void startAppearAnimation() {
if (mCurrentSecurityMode != SecurityMode.None) {
- setAlpha(1f);
+ mView.setAlpha(1f);
mView.startAppearAnimation(mCurrentSecurityMode);
getCurrentSecurityController().startAppearAnimation();
}
}
- /** Set the alpha of the security container view */
- public void setAlpha(float alpha) {
- mView.setAlpha(alpha);
- }
-
public boolean startDisappearAnimation(Runnable onFinishRunnable) {
boolean didRunAnimation = false;
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index c214f53..2501be9 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -263,10 +263,11 @@
@Override // ClipboardListener.ClipboardOverlay
public void setClipData(ClipData data, String source) {
ClipboardModel model = ClipboardModel.fromClipData(mContext, mClipboardUtils, data, source);
- if (mExitAnimator != null && mExitAnimator.isRunning()) {
+ boolean wasExiting = (mExitAnimator != null && mExitAnimator.isRunning());
+ if (wasExiting) {
mExitAnimator.cancel();
}
- boolean shouldAnimate = !model.dataMatches(mClipboardModel);
+ boolean shouldAnimate = !model.dataMatches(mClipboardModel) || wasExiting;
mClipboardModel = model;
mClipboardLogger.setClipSource(mClipboardModel.getSource());
if (shouldAnimate) {
@@ -313,15 +314,19 @@
mOnPreviewTapped = this::editText;
break;
case IMAGE:
- if (model.isSensitive() || model.loadThumbnail(mContext) != null) {
- mView.showImagePreview(
- model.isSensitive() ? null : model.loadThumbnail(mContext));
- mView.setEditAccessibilityAction(true);
- mOnPreviewTapped = () -> editImage(model.getUri());
- } else {
- // image loading failed
- mView.showDefaultTextPreview();
- }
+ mBgExecutor.execute(() -> {
+ if (model.isSensitive() || model.loadThumbnail(mContext) != null) {
+ mView.post(() -> {
+ mView.showImagePreview(
+ model.isSensitive() ? null : model.loadThumbnail(mContext));
+ mView.setEditAccessibilityAction(true);
+ });
+ mOnPreviewTapped = () -> editImage(model.getUri());
+ } else {
+ // image loading failed
+ mView.post(mView::showDefaultTextPreview);
+ }
+ });
break;
case URI:
case OTHER:
@@ -363,15 +368,15 @@
private void classifyText(ClipboardModel model) {
mBgExecutor.execute(() -> {
- Optional<RemoteAction> remoteAction = mClipboardUtils.getAction(
- model.getText(), model.getTextLinks(), model.getSource());
+ Optional<RemoteAction> remoteAction =
+ mClipboardUtils.getAction(model.getTextLinks(), model.getSource());
if (model.equals(mClipboardModel)) {
remoteAction.ifPresent(action -> {
mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_ACTION_SHOWN);
- mView.setActionChip(action, () -> {
+ mView.post(() -> mView.setActionChip(action, () -> {
mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_ACTION_TAPPED);
animateOut();
- });
+ }));
});
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java
index a85f8b9..25caaea 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java
@@ -39,6 +39,9 @@
class ClipboardOverlayUtils {
+ // minimum proportion of entire text an entity must take up, to be considered for smart actions
+ private static final float MINIMUM_ENTITY_PROPORTION = .8f;
+
private final TextClassifier mTextClassifier;
@Inject
@@ -65,19 +68,23 @@
return false;
}
- public Optional<RemoteAction> getAction(CharSequence text, TextLinks textLinks, String source) {
- return getActions(text, textLinks).stream().filter(remoteAction -> {
+ public Optional<RemoteAction> getAction(TextLinks textLinks, String source) {
+ return getActions(textLinks).stream().filter(remoteAction -> {
ComponentName component = remoteAction.getActionIntent().getIntent().getComponent();
return component != null && !TextUtils.equals(source, component.getPackageName());
}).findFirst();
}
- private ArrayList<RemoteAction> getActions(CharSequence text, TextLinks textLinks) {
+ private ArrayList<RemoteAction> getActions(TextLinks textLinks) {
ArrayList<RemoteAction> actions = new ArrayList<>();
for (TextLinks.TextLink link : textLinks.getLinks()) {
- TextClassification classification = mTextClassifier.classifyText(
- text, link.getStart(), link.getEnd(), null);
- actions.addAll(classification.getActions());
+ // skip classification for incidental entities
+ if (link.getEnd() - link.getStart()
+ >= textLinks.getText().length() * MINIMUM_ENTITY_PROPORTION) {
+ TextClassification classification = mTextClassifier.classifyText(
+ textLinks.getText(), link.getStart(), link.getEnd(), null);
+ actions.addAll(classification.getActions());
+ }
}
return actions;
}
@@ -92,9 +99,13 @@
private ArrayList<RemoteAction> getActions(ClipData.Item item) {
ArrayList<RemoteAction> actions = new ArrayList<>();
for (TextLinks.TextLink link : item.getTextLinks().getLinks()) {
- TextClassification classification = mTextClassifier.classifyText(
- item.getText(), link.getStart(), link.getEnd(), null);
- actions.addAll(classification.getActions());
+ // skip classification for incidental entities
+ if (link.getEnd() - link.getStart()
+ >= item.getText().length() * MINIMUM_ENTITY_PROPORTION) {
+ TextClassification classification = mTextClassifier.classifyText(
+ item.getText(), link.getStart(), link.getEnd(), null);
+ actions.addAll(classification.getActions());
+ }
}
return actions;
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
index fb01691..cb2d673 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
@@ -29,6 +29,7 @@
import com.android.systemui.settings.brightness.BrightnessDialog;
import com.android.systemui.statusbar.tv.notifications.TvNotificationPanelActivity;
import com.android.systemui.tuner.TunerActivity;
+import com.android.systemui.usb.UsbAccessoryUriActivity;
import com.android.systemui.usb.UsbConfirmActivity;
import com.android.systemui.usb.UsbDebuggingActivity;
import com.android.systemui.usb.UsbDebuggingSecondaryUserActivity;
@@ -94,6 +95,12 @@
@ClassKey(UsbConfirmActivity.class)
public abstract Activity bindUsbConfirmActivity(UsbConfirmActivity activity);
+ /** Inject into UsbAccessoryUriActivity. */
+ @Binds
+ @IntoMap
+ @ClassKey(UsbAccessoryUriActivity.class)
+ public abstract Activity bindUsbAccessoryUriActivity(UsbAccessoryUriActivity activity);
+
/** Inject into CreateUserActivity. */
@Binds
@IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index f0ee443..cedc226a 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -75,6 +75,7 @@
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.connectivity.ConnectivityModule;
+import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
@@ -256,9 +257,7 @@
abstract FingerprintInteractiveToAuthProvider optionalFingerprintInteractiveToAuthProvider();
@BindsOptionalOf
- //TODO(b/269430792 remove full qualifier. Full qualifier is used to avoid merge conflict.)
- abstract com.android.systemui.statusbar.events.SystemStatusAnimationScheduler
- optionalSystemStatusAnimationScheduler();
+ abstract SystemStatusAnimationScheduler optionalSystemStatusAnimationScheduler();
@SysUISingleton
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
index 73c2289..a7b3bbc 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
@@ -254,7 +254,10 @@
mCurrentScrimController = mScrimManager.getCurrentController();
session.registerCallback(() -> {
- mVelocityTracker.recycle();
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
mScrimManager.removeCallback(mScrimManagerCallback);
mCapture = null;
mNotificationShadeWindowController.setForcePluginOpen(false, this);
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 5ae86b1..9b36b92 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -352,7 +352,7 @@
val MEDIA_TTT_RECEIVER_SUCCESS_RIPPLE = releasedFlag(910, "media_ttt_receiver_success_ripple")
// TODO(b/263512203): Tracking Bug
- val MEDIA_EXPLICIT_INDICATOR = unreleasedFlag(911, "media_explicit_indicator", teamfood = true)
+ val MEDIA_EXPLICIT_INDICATOR = unreleasedFlag(911, "media_explicit_indicator")
// TODO(b/265813373): Tracking Bug
val MEDIA_TAP_TO_TRANSFER_DISMISS_GESTURE = releasedFlag(912, "media_ttt_dismiss_gesture")
@@ -385,6 +385,9 @@
// TODO(b/265045965): Tracking Bug
val SHOW_LOWLIGHT_ON_DIRECT_BOOT = releasedFlag(1003, "show_lowlight_on_direct_boot")
+ @JvmField
+ val ENABLE_LOW_LIGHT_CLOCK_UNDOCKED = unreleasedFlag(1004, "enable_low_light_clock_undocked")
+
// 1100 - windowing
@Keep
@JvmField
@@ -461,7 +464,7 @@
@Keep
@JvmField
val ENABLE_PIP_SIZE_LARGE_SCREEN =
- sysPropBooleanFlag(1114, "persist.wm.debug.enable_pip_size_large_screen", default = false)
+ sysPropBooleanFlag(1114, "persist.wm.debug.enable_pip_size_large_screen", default = true)
// TODO(b/265998256): Tracking bug
@Keep
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt
index b0f9c4e..d078688 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt
@@ -21,6 +21,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.keyboard.backlight.ui.KeyboardBacklightDialogCoordinator
import javax.inject.Inject
/** A [CoreStartable] that launches components interested in physical keyboard interaction. */
@@ -28,11 +29,12 @@
class PhysicalKeyboardCoreStartable
@Inject
constructor(
+ private val keyboardBacklightDialogCoordinator: KeyboardBacklightDialogCoordinator,
private val featureFlags: FeatureFlags,
) : CoreStartable {
override fun start() {
if (featureFlags.isEnabled(Flags.KEYBOARD_BACKLIGHT_INDICATOR)) {
- // TODO(b/268645743) start listening for keyboard backlight brightness
+ keyboardBacklightDialogCoordinator.startListening()
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractor.kt
new file mode 100644
index 0000000..65e70b3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractor.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.keyboard.backlight.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyboard.data.repository.KeyboardRepository
+import com.android.systemui.keyboard.shared.model.BacklightModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+
+/** Allows listening to changes to keyboard backlight level */
+@SysUISingleton
+class KeyboardBacklightInteractor
+@Inject
+constructor(
+ private val keyboardRepository: KeyboardRepository,
+) {
+
+ /** Emits current backlight level as [BacklightModel] or null if keyboard is not connected */
+ val backlight: Flow<BacklightModel?> =
+ keyboardRepository.keyboardConnected.flatMapLatest { connected ->
+ if (connected) keyboardRepository.backlight else flowOf(null)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinator.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinator.kt
new file mode 100644
index 0000000..85d0379
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinator.kt
@@ -0,0 +1,59 @@
+/*
+ * 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.keyboard.backlight.ui
+
+import android.content.Context
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyboard.backlight.ui.view.KeyboardBacklightDialog
+import com.android.systemui.keyboard.backlight.ui.viewmodel.BacklightDialogViewModel
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * Based on the state produced from [BacklightDialogViewModel] shows or hides keyboard backlight
+ * indicator
+ */
+@SysUISingleton
+class KeyboardBacklightDialogCoordinator
+@Inject
+constructor(
+ @Application private val applicationScope: CoroutineScope,
+ private val context: Context,
+ private val viewModel: BacklightDialogViewModel,
+) {
+
+ var dialog: KeyboardBacklightDialog? = null
+
+ fun startListening() {
+ applicationScope.launch {
+ viewModel.dialogContent.collect { dialogViewModel ->
+ if (dialogViewModel != null) {
+ if (dialog == null) {
+ dialog = KeyboardBacklightDialog(context, dialogViewModel)
+ // pass viewModel and show
+ }
+ } else {
+ dialog?.dismiss()
+ dialog = null
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
new file mode 100644
index 0000000..b68a2a8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
@@ -0,0 +1,32 @@
+/*
+ * 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.keyboard.backlight.ui.view
+
+import android.app.Dialog
+import android.content.Context
+import android.os.Bundle
+import com.android.systemui.keyboard.backlight.ui.viewmodel.BacklightDialogContentViewModel
+
+class KeyboardBacklightDialog(context: Context, val viewModel: BacklightDialogContentViewModel) :
+ Dialog(context) {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ // TODO(b/268650355) Implement the dialog
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogContentViewModel.kt
similarity index 68%
copy from packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt
copy to packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogContentViewModel.kt
index ea15a9f..3ef0ca3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogContentViewModel.kt
@@ -15,10 +15,6 @@
*
*/
-package com.android.systemui.keyboard.data.model
+package com.android.systemui.keyboard.backlight.ui.viewmodel
-/**
- * Model for current state of keyboard backlight brightness. [level] indicates current level of
- * backlight brightness and [maxLevel] its max possible value.
- */
-data class BacklightModel(val level: Int, val maxLevel: Int)
+data class BacklightDialogContentViewModel(val currentValue: Int, val maxValue: Int)
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModel.kt
new file mode 100644
index 0000000..86abca5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModel.kt
@@ -0,0 +1,72 @@
+/*
+ * 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.keyboard.backlight.ui.viewmodel
+
+import android.view.accessibility.AccessibilityManager
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyboard.backlight.domain.interactor.KeyboardBacklightInteractor
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper
+import javax.inject.Inject
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.map
+
+/**
+ * Responsible for dialog visibility and content - emits [BacklightDialogContentViewModel] if dialog
+ * should be shown and hidden otherwise
+ */
+@SysUISingleton
+class BacklightDialogViewModel
+@Inject
+constructor(
+ interactor: KeyboardBacklightInteractor,
+ private val accessibilityManagerWrapper: AccessibilityManagerWrapper,
+) {
+
+ private val timeoutMillis: Long
+ get() =
+ accessibilityManagerWrapper
+ .getRecommendedTimeoutMillis(
+ DEFAULT_DIALOG_TIMEOUT_MILLIS,
+ AccessibilityManager.FLAG_CONTENT_ICONS
+ )
+ .toLong()
+
+ val dialogContent: Flow<BacklightDialogContentViewModel?> =
+ interactor.backlight
+ .filterNotNull()
+ .map { BacklightDialogContentViewModel(it.level, it.maxLevel) }
+ .timeout(timeoutMillis, emitAfterTimeout = null)
+
+ private fun <T> Flow<T>.timeout(timeoutMillis: Long, emitAfterTimeout: T): Flow<T> {
+ return flatMapLatest {
+ flow {
+ emit(it)
+ delay(timeoutMillis)
+ emit(emitAfterTimeout)
+ }
+ }
+ }
+
+ private companion object {
+ const val DEFAULT_DIALOG_TIMEOUT_MILLIS = 3000
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt
index 70faf40..9449ece 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt
@@ -23,7 +23,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.keyboard.data.model.BacklightModel
+import com.android.systemui.keyboard.shared.model.BacklightModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shared/model/BacklightModel.kt
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt
rename to packages/SystemUI/src/com/android/systemui/keyboard/shared/model/BacklightModel.kt
index ea15a9f..4a32f79 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shared/model/BacklightModel.kt
@@ -15,7 +15,7 @@
*
*/
-package com.android.systemui.keyboard.data.model
+package com.android.systemui.keyboard.shared.model
/**
* Model for current state of keyboard backlight brightness. [level] indicates current level of
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index 76f20d25..a3b3d0f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -80,9 +80,6 @@
*/
val isKeyguardShowing: Flow<Boolean>
- /** Is the keyguard in a unlocked state? */
- val isKeyguardUnlocked: Flow<Boolean>
-
/** Is an activity showing over the keyguard? */
val isKeyguardOccluded: Flow<Boolean>
@@ -281,31 +278,6 @@
}
.distinctUntilChanged()
- override val isKeyguardUnlocked: Flow<Boolean> =
- conflatedCallbackFlow {
- val callback =
- object : KeyguardStateController.Callback {
- override fun onUnlockedChanged() {
- trySendWithFailureLogging(
- keyguardStateController.isUnlocked,
- TAG,
- "updated isKeyguardUnlocked"
- )
- }
- }
-
- keyguardStateController.addCallback(callback)
- // Adding the callback does not send an initial update.
- trySendWithFailureLogging(
- keyguardStateController.isUnlocked,
- TAG,
- "initial isKeyguardUnlocked"
- )
-
- awaitClose { keyguardStateController.removeCallback(callback) }
- }
- .distinctUntilChanged()
-
override val isKeyguardGoingAway: Flow<Boolean> = conflatedCallbackFlow {
val callback =
object : KeyguardStateController.Callback {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
index 100bc59..0c4bca6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
@@ -68,11 +68,8 @@
/**
* Begin a transition from one state to another. Transitions are interruptible, and will issue a
* [TransitionStep] with state = [TransitionState.CANCELED] before beginning the next one.
- *
- * When canceled, there are two options: to continue from the current position of the prior
- * transition, or to reset the position. When [resetIfCanceled] == true, it will do the latter.
*/
- fun startTransition(info: TransitionInfo, resetIfCanceled: Boolean = false): UUID?
+ fun startTransition(info: TransitionInfo): UUID?
/**
* Allows manual control of a transition. When calling [startTransition], the consumer must pass
@@ -133,10 +130,7 @@
)
}
- override fun startTransition(
- info: TransitionInfo,
- resetIfCanceled: Boolean,
- ): UUID? {
+ override fun startTransition(info: TransitionInfo): UUID? {
if (lastStep.from == info.from && lastStep.to == info.to) {
Log.i(TAG, "Duplicate call to start the transition, rejecting: $info")
return null
@@ -144,11 +138,7 @@
val startingValue =
if (lastStep.transitionState != TransitionState.FINISHED) {
Log.i(TAG, "Transition still active: $lastStep, canceling")
- if (resetIfCanceled) {
- 0f
- } else {
- lastStep.value
- }
+ lastStep.value
} else {
0f
}
@@ -237,7 +227,10 @@
}
private fun trace(step: TransitionStep, isManual: Boolean) {
- if (step.transitionState == TransitionState.RUNNING) {
+ if (
+ step.transitionState != TransitionState.STARTED &&
+ step.transitionState != TransitionState.FINISHED
+ ) {
return
}
val traceName =
@@ -250,10 +243,7 @@
val traceCookie = traceName.hashCode()
if (step.transitionState == TransitionState.STARTED) {
Trace.beginAsyncSection(traceName, traceCookie)
- } else if (
- step.transitionState == TransitionState.FINISHED ||
- step.transitionState == TransitionState.CANCELED
- ) {
+ } else if (step.transitionState == TransitionState.FINISHED) {
Trace.endAsyncSection(traceName, traceCookie)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index 3beac0b..8715d1f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -34,6 +34,7 @@
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
@@ -56,7 +57,14 @@
private fun listenForDreamingToLockscreen() {
scope.launch {
- keyguardInteractor.isAbleToDream
+ // Dependending on the dream, either dream state or occluded change will change first,
+ // so listen for both
+ combine(keyguardInteractor.isAbleToDream, keyguardInteractor.isKeyguardOccluded) {
+ isAbleToDream,
+ isKeyguardOccluded ->
+ isAbleToDream && isKeyguardOccluded
+ }
+ .distinctUntilChanged()
.sample(
combine(
keyguardInteractor.dozeTransitionModel,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 911861d..d01f489 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -130,59 +130,55 @@
shadeRepository.shadeModel
.sample(
combine(
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ keyguardTransitionInteractor.finishedKeyguardState,
keyguardInteractor.statusBarState,
- keyguardInteractor.isKeyguardUnlocked,
- ::toTriple
+ ::Pair
),
- ::toQuad
+ ::toTriple
)
- .collect { (shadeModel, keyguardState, statusBarState, isKeyguardUnlocked) ->
+ .collect { (shadeModel, keyguardState, statusBarState) ->
val id = transitionId
if (id != null) {
- if (keyguardState.to == KeyguardState.PRIMARY_BOUNCER) {
- // An existing `id` means a transition is started, and calls to
- // `updateTransition` will control it until FINISHED or CANCELED
- var nextState =
- if (shadeModel.expansionAmount == 0f) {
- TransitionState.FINISHED
- } else if (shadeModel.expansionAmount == 1f) {
- TransitionState.CANCELED
- } else {
- TransitionState.RUNNING
- }
- keyguardTransitionRepository.updateTransition(
- id,
- 1f - shadeModel.expansionAmount,
- nextState,
- )
-
- if (
- nextState == TransitionState.CANCELED ||
- nextState == TransitionState.FINISHED
- ) {
- transitionId = null
+ // An existing `id` means a transition is started, and calls to
+ // `updateTransition` will control it until FINISHED or CANCELED
+ var nextState =
+ if (shadeModel.expansionAmount == 0f) {
+ TransitionState.FINISHED
+ } else if (shadeModel.expansionAmount == 1f) {
+ TransitionState.CANCELED
+ } else {
+ TransitionState.RUNNING
}
+ keyguardTransitionRepository.updateTransition(
+ id,
+ 1f - shadeModel.expansionAmount,
+ nextState,
+ )
- // If canceled, just put the state back
- if (nextState == TransitionState.CANCELED) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.PRIMARY_BOUNCER,
- to = KeyguardState.LOCKSCREEN,
- animator = getAnimator(0.milliseconds)
- )
+ if (
+ nextState == TransitionState.CANCELED ||
+ nextState == TransitionState.FINISHED
+ ) {
+ transitionId = null
+ }
+
+ // If canceled, just put the state back
+ if (nextState == TransitionState.CANCELED) {
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ ownerName = name,
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = KeyguardState.LOCKSCREEN,
+ animator = getAnimator(0.milliseconds)
)
- }
+ )
}
} else {
// TODO (b/251849525): Remove statusbarstate check when that state is
// integrated into KeyguardTransitionRepository
if (
- keyguardState.to == KeyguardState.LOCKSCREEN &&
+ keyguardState == KeyguardState.LOCKSCREEN &&
shadeModel.isUserDragging &&
- !isKeyguardUnlocked &&
statusBarState == KEYGUARD
) {
transitionId =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
index 94961cb..b59b413 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
@@ -17,9 +17,6 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
-import com.android.keyguard.KeyguardSecurityModel
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode.Password
-import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -29,8 +26,6 @@
import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
-import kotlin.time.Duration
-import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
@@ -42,8 +37,7 @@
@Application private val scope: CoroutineScope,
private val keyguardInteractor: KeyguardInteractor,
private val keyguardTransitionRepository: KeyguardTransitionRepository,
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
- private val keyguardSecurityModel: KeyguardSecurityModel,
+ private val keyguardTransitionInteractor: KeyguardTransitionInteractor
) : TransitionInteractor(FromPrimaryBouncerTransitionInteractor::class.simpleName!!) {
override fun start() {
@@ -99,47 +93,31 @@
private fun listenForPrimaryBouncerToGone() {
scope.launch {
keyguardInteractor.isKeyguardGoingAway
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
- .collect { (isKeyguardGoingAway, lastStartedTransitionStep) ->
- if (
- isKeyguardGoingAway &&
- lastStartedTransitionStep.to == KeyguardState.PRIMARY_BOUNCER
- ) {
- val securityMode =
- keyguardSecurityModel.getSecurityMode(
- KeyguardUpdateMonitor.getCurrentUser()
- )
- // IME for password requires a slightly faster animation
- val duration =
- if (securityMode == Password) {
- TO_GONE_SHORT_DURATION
- } else {
- TO_GONE_DURATION
- }
+ .sample(keyguardTransitionInteractor.finishedKeyguardState) { a, b -> Pair(a, b) }
+ .collect { pair ->
+ val (isKeyguardGoingAway, keyguardState) = pair
+ if (isKeyguardGoingAway && keyguardState == KeyguardState.PRIMARY_BOUNCER) {
keyguardTransitionRepository.startTransition(
TransitionInfo(
ownerName = name,
from = KeyguardState.PRIMARY_BOUNCER,
to = KeyguardState.GONE,
- animator = getAnimator(duration),
- ),
- resetIfCanceled = true,
+ animator = getAnimator(),
+ )
)
}
}
}
}
- private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
+ private fun getAnimator(): ValueAnimator {
return ValueAnimator().apply {
setInterpolator(Interpolators.LINEAR)
- setDuration(duration.inWholeMilliseconds)
+ setDuration(TRANSITION_DURATION_MS)
}
}
companion object {
- private val DEFAULT_DURATION = 300.milliseconds
- val TO_GONE_DURATION = 250.milliseconds
- val TO_GONE_SHORT_DURATION = 200.milliseconds
+ private const val TRANSITION_DURATION_MS = 300L
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index ec99049..d25aff0a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -33,9 +33,7 @@
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.WakefulnessModel
-import com.android.systemui.keyguard.shared.model.WakefulnessModel.Companion.isWakingOrStartingToWake
import com.android.systemui.statusbar.CommandQueue
-import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.delay
@@ -97,9 +95,6 @@
awaitClose { commandQueue.removeCallback(callback) }
}
- /** The device wake/sleep state */
- val wakefulnessModel: Flow<WakefulnessModel> = repository.wakefulness
-
/**
* Dozing and dreaming have overlapping events. If the doze state remains in FINISH, it means
* that doze mode is not running and DREAMING is ok to commence.
@@ -114,12 +109,6 @@
isDreaming && isDozeOff(dozeTransitionModel.to)
}
)
- .sample(
- wakefulnessModel,
- { isAbleToDream, wakefulnessModel ->
- isAbleToDream && isWakingOrStartingToWake(wakefulnessModel)
- }
- )
.flatMapLatest { isAbleToDream ->
flow {
delay(50)
@@ -130,8 +119,6 @@
/** Whether the keyguard is showing or not. */
val isKeyguardShowing: Flow<Boolean> = repository.isKeyguardShowing
- /** Whether the keyguard is unlocked or not. */
- val isKeyguardUnlocked: Flow<Boolean> = repository.isKeyguardUnlocked
/** Whether the keyguard is occluded (covered by an activity). */
val isKeyguardOccluded: Flow<Boolean> = repository.isKeyguardOccluded
/** Whether the keyguard is going away. */
@@ -140,6 +127,8 @@
val primaryBouncerShowing: Flow<Boolean> = bouncerRepository.primaryBouncerVisible
/** Whether the alternate bouncer is showing or not. */
val alternateBouncerShowing: Flow<Boolean> = bouncerRepository.alternateBouncerVisible
+ /** The device wake/sleep state */
+ val wakefulnessModel: Flow<WakefulnessModel> = repository.wakefulness
/** Observable for the [StatusBarState] */
val statusBarState: Flow<StatusBarState> = repository.statusBarState
/**
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 e650b9f..51b0277 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
@@ -61,15 +61,7 @@
}
scope.launch {
- keyguardInteractor.isAbleToDream.collect {
- logger.log(TAG, VERBOSE, "isAbleToDream", it)
- }
- }
-
- scope.launch {
- keyguardInteractor.isKeyguardOccluded.collect {
- logger.log(TAG, VERBOSE, "isOccluded", it)
- }
+ keyguardInteractor.isDreaming.collect { logger.log(TAG, VERBOSE, "isDreaming", it) }
}
scope.launch {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index 3c0ec35..1b7da5b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -78,10 +78,6 @@
val occludedToLockscreenTransition: Flow<TransitionStep> =
repository.transition(OCCLUDED, LOCKSCREEN)
- /** PRIMARY_BOUNCER->GONE transition information. */
- val primaryBouncerToGoneTransition: Flow<TransitionStep> =
- repository.transition(PRIMARY_BOUNCER, GONE)
-
/**
* AOD<->LOCKSCREEN transition information, mapped to dozeAmount range of AOD (1f) <->
* Lockscreen (0f).
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 2337ffc..7db567b 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
@@ -31,7 +31,6 @@
import com.android.systemui.keyguard.data.BouncerViewDelegate
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel
-import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.ActivityStarter
import kotlinx.coroutines.awaitCancellation
@@ -45,7 +44,6 @@
fun bind(
view: ViewGroup,
viewModel: KeyguardBouncerViewModel,
- primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel,
componentFactory: KeyguardBouncerComponent.Factory
) {
// Builds the KeyguardSecurityContainerController from bouncer view group.
@@ -147,12 +145,6 @@
}
launch {
- primaryBouncerToGoneTransitionViewModel.bouncerAlpha.collect { alpha ->
- securityContainerController.setAlpha(alpha)
- }
- }
-
- launch {
viewModel.bouncerExpansionAmount
.filter { it == EXPANSION_VISIBLE }
.collect {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
deleted file mode 100644
index 0890791..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
+++ /dev/null
@@ -1,58 +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.systemui.keyguard.ui.viewmodel
-
-import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GONE_DURATION
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
-import javax.inject.Inject
-import kotlin.time.Duration.Companion.milliseconds
-import kotlinx.coroutines.flow.Flow
-
-/**
- * Breaks down PRIMARY_BOUNCER->GONE transition into discrete steps for corresponding views to
- * consume.
- */
-@SysUISingleton
-class PrimaryBouncerToGoneTransitionViewModel
-@Inject
-constructor(
- private val interactor: KeyguardTransitionInteractor,
-) {
- private val transitionAnimation =
- KeyguardTransitionAnimationFlow(
- transitionDuration = TO_GONE_DURATION,
- transitionFlow = interactor.primaryBouncerToGoneTransition,
- )
-
- /** Bouncer container alpha */
- val bouncerAlpha: Flow<Float> =
- transitionAnimation.createFlow(
- duration = 200.milliseconds,
- onStep = { 1f - it },
- )
-
- /** Scrim alpha */
- val scrimAlpha: Flow<Float> =
- transitionAnimation.createFlow(
- duration = TO_GONE_DURATION,
- interpolator = EMPHASIZED_ACCELERATE,
- onStep = { 1f - it },
- )
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 25ff308b..019ca52 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -631,7 +631,9 @@
final NavigationBarView navBarView =
mNavBarControllerLazy.get().getNavigationBarView(mContext.getDisplayId());
final NotificationPanelViewController panelController =
- mCentralSurfacesOptionalLazy.get().get().getNotificationPanelViewController();
+ mCentralSurfacesOptionalLazy.get()
+ .map(CentralSurfaces::getNotificationPanelViewController)
+ .orElse(null);
if (SysUiState.DEBUG) {
Log.d(TAG_OPS, "Updating sysui state flags: navBarFragment=" + navBarFragment
+ " navBarView=" + navBarView + " panelController=" + panelController);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index e53eea9..3be2417 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -23,6 +23,7 @@
import static androidx.constraintlayout.widget.ConstraintSet.END;
import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION;
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
import static com.android.keyguard.KeyguardClockSwitch.SMALL;
import static com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE;
@@ -71,6 +72,7 @@
import android.provider.Settings;
import android.transition.ChangeBounds;
import android.transition.Transition;
+import android.transition.TransitionListenerAdapter;
import android.transition.TransitionManager;
import android.transition.TransitionSet;
import android.transition.TransitionValues;
@@ -98,6 +100,7 @@
import androidx.constraintlayout.widget.ConstraintSet;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.policy.SystemBarUtils;
@@ -353,6 +356,7 @@
private final NotificationGutsManager mGutsManager;
private final AlternateBouncerInteractor mAlternateBouncerInteractor;
private final QuickSettingsController mQsController;
+ private final InteractionJankMonitor mInteractionJankMonitor;
private long mDownTime;
private boolean mTouchSlopExceededBeforeDown;
@@ -642,6 +646,19 @@
step.getTransitionState() == TransitionState.RUNNING;
};
+ private final TransitionListenerAdapter mKeyguardStatusAlignmentTransitionListener =
+ new TransitionListenerAdapter() {
+ @Override
+ public void onTransitionCancel(Transition transition) {
+ mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION);
+ }
+
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ mInteractionJankMonitor.end(CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION);
+ }
+ };
+
@Inject
public NotificationPanelViewController(NotificationPanelView view,
@Main Handler handler,
@@ -706,6 +723,7 @@
NotificationStackSizeCalculator notificationStackSizeCalculator,
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
ShadeTransitionController shadeTransitionController,
+ InteractionJankMonitor interactionJankMonitor,
SystemClock systemClock,
KeyguardBottomAreaViewModel keyguardBottomAreaViewModel,
KeyguardBottomAreaInteractor keyguardBottomAreaInteractor,
@@ -720,6 +738,7 @@
DumpManager dumpManager,
KeyguardLongPressViewModel keyguardLongPressViewModel,
KeyguardInteractor keyguardInteractor) {
+ mInteractionJankMonitor = interactionJankMonitor;
keyguardStateController.addCallback(new KeyguardStateController.Callback() {
@Override
public void onKeyguardFadingAwayChanged() {
@@ -1540,6 +1559,7 @@
int statusConstraint = shouldBeCentered ? PARENT_ID : R.id.qs_edge_guideline;
constraintSet.connect(R.id.keyguard_status_view, END, statusConstraint, END);
if (animate) {
+ mInteractionJankMonitor.begin(mView, CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION);
ChangeBounds transition = new ChangeBounds();
if (mSplitShadeEnabled) {
// Excluding media from the transition on split-shade, as it doesn't transition
@@ -1563,6 +1583,7 @@
// The clock container can sometimes be null. If it is, just fall back to the
// old animation rather than setting up the custom animations.
if (clockContainerView == null || clockContainerView.getChildCount() == 0) {
+ transition.addListener(mKeyguardStatusAlignmentTransitionListener);
TransitionManager.beginDelayedTransition(
mNotificationContainerParent, transition);
} else {
@@ -1581,10 +1602,11 @@
adapter.setDuration(KEYGUARD_STATUS_VIEW_CUSTOM_CLOCK_MOVE_DURATION);
adapter.addTarget(clockView);
set.addTransition(adapter);
-
+ set.addListener(mKeyguardStatusAlignmentTransitionListener);
TransitionManager.beginDelayedTransition(mNotificationContainerParent, set);
}
} else {
+ transition.addListener(mKeyguardStatusAlignmentTransitionListener);
TransitionManager.beginDelayedTransition(
mNotificationContainerParent, transition);
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index c130b39..87350b46 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -45,7 +45,6 @@
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.keyguard.ui.binder.KeyguardBouncerViewBinder;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel;
-import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationInsetsController;
@@ -134,8 +133,7 @@
KeyguardBouncerViewModel keyguardBouncerViewModel,
KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory,
AlternateBouncerInteractor alternateBouncerInteractor,
- KeyguardTransitionInteractor keyguardTransitionInteractor,
- PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel
+ KeyguardTransitionInteractor keyguardTransitionInteractor
) {
mLockscreenShadeTransitionController = transitionController;
mFalsingCollector = falsingCollector;
@@ -162,7 +160,6 @@
KeyguardBouncerViewBinder.bind(
mView.findViewById(R.id.keyguard_bouncer_container),
keyguardBouncerViewModel,
- primaryBouncerToGoneTransitionViewModel,
keyguardBouncerComponentFactory);
collectFlow(mView, keyguardTransitionInteractor.getLockscreenToDreamingTransition(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 39e4000..4522e41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -443,6 +443,7 @@
CancellationSignal cancellationSignal = new CancellationSignal();
cancellationSignal.setOnCancelListener(
() -> runningInflations.values().forEach(CancellationSignal::cancel));
+
return cancellationSignal;
}
@@ -783,6 +784,7 @@
public static class AsyncInflationTask extends AsyncTask<Void, Void, InflationProgress>
implements InflationCallback, InflationTask {
+ private static final long IMG_PRELOAD_TIMEOUT_MS = 1000L;
private final NotificationEntry mEntry;
private final Context mContext;
private final boolean mInflateSynchronously;
@@ -876,7 +878,7 @@
recoveredBuilder, mIsLowPriority, mUsesIncreasedHeight,
mUsesIncreasedHeadsUpHeight, packageContext);
InflatedSmartReplyState previousSmartReplyState = mRow.getExistingSmartReplyState();
- return inflateSmartReplyViews(
+ InflationProgress result = inflateSmartReplyViews(
inflationProgress,
mReInflateFlags,
mEntry,
@@ -884,6 +886,11 @@
packageContext,
previousSmartReplyState,
mSmartRepliesInflater);
+
+ // wait for image resolver to finish preloading
+ mRow.getImageResolver().waitForPreloadedImages(IMG_PRELOAD_TIMEOUT_MS);
+
+ return result;
} catch (Exception e) {
mError = e;
return null;
@@ -918,6 +925,9 @@
mCallback.handleInflationException(mRow.getEntry(),
new InflationException("Couldn't inflate contentViews" + e));
}
+
+ // Cancel any image loading tasks, not useful any more
+ mRow.getImageResolver().cancelRunningTasks();
}
@Override
@@ -944,6 +954,9 @@
// Notify the resolver that the inflation task has finished,
// try to purge unnecessary cached entries.
mRow.getImageResolver().purgeCache();
+
+ // Cancel any image loading tasks that have not completed at this point
+ mRow.getImageResolver().cancelRunningTasks();
}
private static class RtlEnabledContext extends ContextWrapper {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
index 41eeada0..fe0b312 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
@@ -22,8 +22,11 @@
import android.util.Log;
import java.util.Set;
+import java.util.concurrent.CancellationException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
/**
* A cache for inline images of image messages.
@@ -56,12 +59,13 @@
}
@Override
- public Drawable get(Uri uri) {
+ public Drawable get(Uri uri, long timeoutMs) {
Drawable result = null;
try {
- result = mCache.get(uri).get();
- } catch (InterruptedException | ExecutionException ex) {
- Log.d(TAG, "get: Failed get image from " + uri);
+ result = mCache.get(uri).get(timeoutMs, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException | ExecutionException
+ | TimeoutException | CancellationException ex) {
+ Log.d(TAG, "get: Failed get image from " + uri + " " + ex);
}
return result;
}
@@ -72,6 +76,15 @@
mCache.entrySet().removeIf(entry -> !wantedSet.contains(entry.getKey()));
}
+ @Override
+ public void cancelRunningTasks() {
+ mCache.forEach((key, value) -> {
+ if (value.getStatus() != AsyncTask.Status.FINISHED) {
+ value.cancel(true);
+ }
+ });
+ }
+
private static class PreloadImageTask extends AsyncTask<Uri, Void, Drawable> {
private final NotificationInlineImageResolver mResolver;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
index b05e64ab..c620f44 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
@@ -23,6 +23,7 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
+import android.os.SystemClock;
import android.util.Log;
import com.android.internal.R;
@@ -45,6 +46,9 @@
public class NotificationInlineImageResolver implements ImageResolver {
private static final String TAG = NotificationInlineImageResolver.class.getSimpleName();
+ // Timeout for loading images from ImageCache when calling from UI thread
+ private static final long MAX_UI_THREAD_TIMEOUT_MS = 100L;
+
private final Context mContext;
private final ImageCache mImageCache;
private Set<Uri> mWantedUriSet;
@@ -123,17 +127,25 @@
return null;
}
+ /**
+ * Loads an image from the Uri.
+ * This method is synchronous and is usually called from the Main thread.
+ * It will time-out after MAX_UI_THREAD_TIMEOUT_MS.
+ *
+ * @param uri Uri of the target image.
+ * @return drawable of the image, null if loading failed/timeout
+ */
@Override
public Drawable loadImage(Uri uri) {
- return hasCache() ? loadImageFromCache(uri) : resolveImage(uri);
+ return hasCache() ? loadImageFromCache(uri, MAX_UI_THREAD_TIMEOUT_MS) : resolveImage(uri);
}
- private Drawable loadImageFromCache(Uri uri) {
+ private Drawable loadImageFromCache(Uri uri, long timeoutMs) {
// if the uri isn't currently cached, try caching it first
if (!mImageCache.hasEntry(uri)) {
mImageCache.preload((uri));
}
- return mImageCache.get(uri);
+ return mImageCache.get(uri, timeoutMs);
}
/**
@@ -208,6 +220,30 @@
}
/**
+ * Wait for a maximum timeout for images to finish preloading
+ * @param timeoutMs total timeout time
+ */
+ void waitForPreloadedImages(long timeoutMs) {
+ if (!hasCache()) {
+ return;
+ }
+ Set<Uri> preloadedUris = getWantedUriSet();
+ if (preloadedUris != null) {
+ // Decrement remaining timeout after each image check
+ long endTimeMs = SystemClock.elapsedRealtime() + timeoutMs;
+ preloadedUris.forEach(
+ uri -> loadImageFromCache(uri, endTimeMs - SystemClock.elapsedRealtime()));
+ }
+ }
+
+ void cancelRunningTasks() {
+ if (!hasCache()) {
+ return;
+ }
+ mImageCache.cancelRunningTasks();
+ }
+
+ /**
* A interface for internal cache implementation of this resolver.
*/
interface ImageCache {
@@ -216,7 +252,7 @@
* @param uri The uri of the image.
* @return Drawable of the image.
*/
- Drawable get(Uri uri);
+ Drawable get(Uri uri, long timeoutMs);
/**
* Set the image resolver that actually resolves image from specified uri.
@@ -241,6 +277,11 @@
* Purge unnecessary entries in the cache.
*/
void purge();
+
+ /**
+ * Cancel all unfinished image loading tasks
+ */
+ void cancelRunningTasks();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index b5d51ce..be791f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -3695,12 +3695,6 @@
@Override
public void notifyBiometricAuthModeChanged() {
mDozeServiceHost.updateDozing();
- if (mBiometricUnlockController.getMode()
- == BiometricUnlockController.MODE_DISMISS_BOUNCER) {
- // Don't update the scrim controller at this time, in favor of the transition repository
- // updating the scrim
- return;
- }
updateScrimController();
}
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 753032c..3268032 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -59,7 +59,7 @@
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.fragment.StatusBarIconBlocklistKt;
-import com.android.systemui.statusbar.phone.fragment.StatusBarSystemEventAnimator;
+import com.android.systemui.statusbar.phone.fragment.StatusBarSystemEventDefaultAnimator;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -75,6 +75,8 @@
import javax.inject.Inject;
+import kotlin.Unit;
+
/** View Controller for {@link com.android.systemui.statusbar.phone.KeyguardStatusBarView}. */
public class KeyguardStatusBarViewController extends ViewController<KeyguardStatusBarView> {
private static final String TAG = "KeyguardStatusBarViewController";
@@ -123,7 +125,8 @@
public void onDensityOrFontScaleChanged() {
mView.loadDimens();
// The animator is dependent on resources for offsets
- mSystemEventAnimator = new StatusBarSystemEventAnimator(mView, getResources());
+ mSystemEventAnimator =
+ getSystemEventAnimator(mSystemEventAnimator.isAnimationRunning());
}
@Override
@@ -248,7 +251,8 @@
private int mStatusBarState;
private boolean mDozing;
private boolean mShowingKeyguardHeadsUp;
- private StatusBarSystemEventAnimator mSystemEventAnimator;
+ private StatusBarSystemEventDefaultAnimator mSystemEventAnimator;
+ private float mSystemEventAnimatorAlpha = 1;
/**
* The alpha value to be set on the View. If -1, this value is to be ignored.
@@ -324,7 +328,7 @@
mView.setKeyguardUserAvatarEnabled(
!mStatusBarUserChipViewModel.getChipEnabled());
- mSystemEventAnimator = new StatusBarSystemEventAnimator(mView, r);
+ mSystemEventAnimator = getSystemEventAnimator(/* isAnimationRunning */ false);
mDisableStateTracker = new DisableStateTracker(
/* mask1= */ DISABLE_SYSTEM_INFO,
@@ -480,6 +484,10 @@
* (1.0f - mKeyguardHeadsUpShowingAmount);
}
+ if (mSystemEventAnimator.isAnimationRunning()) {
+ newAlpha = Math.min(newAlpha, mSystemEventAnimatorAlpha);
+ }
+
boolean hideForBypass =
mFirstBypassAttempt && mKeyguardUpdateMonitor.shouldListenForFace()
|| mDelayShowingKeyguardStatusBar;
@@ -488,7 +496,7 @@
&& !mDozing
&& !hideForBypass
&& !mDisableStateTracker.isDisabled()
- ? View.VISIBLE : View.INVISIBLE;
+ ? View.VISIBLE : View.INVISIBLE;
updateViewState(newAlpha, newVisibility);
}
@@ -614,4 +622,15 @@
updateBlockedIcons();
}
};
+
+ private StatusBarSystemEventDefaultAnimator getSystemEventAnimator(boolean isAnimationRunning) {
+ return new StatusBarSystemEventDefaultAnimator(getResources(), (alpha) -> {
+ mSystemEventAnimatorAlpha = alpha;
+ updateViewState();
+ return Unit.INSTANCE;
+ }, (translationX) -> {
+ mView.setTranslationX(translationX);
+ return Unit.INSTANCE;
+ }, isAnimationRunning);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index c01137a..8e0ec284 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.phone;
-import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
-
import static java.lang.Float.isNaN;
import android.animation.Animator;
@@ -55,11 +53,7 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants;
-import com.android.systemui.keyguard.shared.model.TransitionState;
-import com.android.systemui.keyguard.shared.model.TransitionStep;
-import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.statusbar.notification.stack.ViewState;
@@ -77,8 +71,6 @@
import javax.inject.Inject;
-import kotlinx.coroutines.CoroutineDispatcher;
-
/**
* Controls both the scrim behind the notifications and in front of the notifications (when a
* security method gets shown).
@@ -259,28 +251,6 @@
private boolean mWakeLockHeld;
private boolean mKeyguardOccluded;
- private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
- private CoroutineDispatcher mMainDispatcher;
- private boolean mIsBouncerToGoneTransitionStarted = false;
- private boolean mIsBouncerToGoneTransitionRunning = false;
- private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
- private final Consumer<Float> mScrimAlphaConsumer =
- (Float alpha) -> {
- mScrimInFront.setViewAlpha(0f);
- mNotificationsScrim.setViewAlpha(0f);
- mScrimBehind.setViewAlpha(alpha);
- };
- final Consumer<TransitionStep> mPrimaryBouncerToGoneTransition =
- (TransitionStep step) -> {
- mIsBouncerToGoneTransitionRunning =
- step.getTransitionState() == TransitionState.RUNNING;
- mIsBouncerToGoneTransitionStarted =
- step.getTransitionState() == TransitionState.STARTED;
- if (mIsBouncerToGoneTransitionStarted) {
- transitionTo(ScrimState.UNLOCKED);
- }
- };
-
@Inject
public ScrimController(
LightBarController lightBarController,
@@ -295,10 +265,7 @@
@Main Executor mainExecutor,
ScreenOffAnimationController screenOffAnimationController,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
- StatusBarKeyguardViewManager statusBarKeyguardViewManager,
- PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel,
- KeyguardTransitionInteractor keyguardTransitionInteractor,
- @Main CoroutineDispatcher mainDispatcher) {
+ StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
mScrimStateListener = lightBarController::setScrimState;
mDefaultScrimAlpha = BUSY_SCRIM_ALPHA;
@@ -337,9 +304,6 @@
}
});
mColors = new GradientColors();
- mPrimaryBouncerToGoneTransitionViewModel = primaryBouncerToGoneTransitionViewModel;
- mKeyguardTransitionInteractor = keyguardTransitionInteractor;
- mMainDispatcher = mainDispatcher;
}
/**
@@ -379,11 +343,6 @@
for (ScrimState state : ScrimState.values()) {
state.prepare(state);
}
-
- collectFlow(behindScrim, mKeyguardTransitionInteractor.getPrimaryBouncerToGoneTransition(),
- mPrimaryBouncerToGoneTransition, mMainDispatcher);
- collectFlow(behindScrim, mPrimaryBouncerToGoneTransitionViewModel.getScrimAlpha(),
- mScrimAlphaConsumer, mMainDispatcher);
}
/**
@@ -406,11 +365,6 @@
}
public void transitionTo(ScrimState state, Callback callback) {
- if (mIsBouncerToGoneTransitionRunning) {
- Log.i(TAG, "Skipping transition to: " + state
- + " while mIsBouncerToGoneTransitionRunning");
- return;
- }
if (state == mState) {
// Call the callback anyway, unless it's already enqueued
if (callback != null && mCallback != callback) {
@@ -830,11 +784,10 @@
mBehindAlpha = 0;
mNotificationsAlpha = 0;
} else {
+ // Behind scrim will finish fading in at 30% expansion.
float behindFraction = MathUtils
.constrainedMap(0f, 1f, 0f, 0.3f, mPanelExpansionFraction);
- if (!mIsBouncerToGoneTransitionStarted) {
- mBehindAlpha = behindFraction * mDefaultScrimAlpha;
- }
+ mBehindAlpha = behindFraction * mDefaultScrimAlpha;
// Delay fade-in of notification scrim a bit further, to coincide with the
// behind scrim finishing fading in.
// Also to coincide with the view starting to fade in, otherwise the empty
@@ -1172,9 +1125,7 @@
Trace.traceCounter(Trace.TRACE_TAG_APP, getScrimName(scrimView) + "_tint",
Color.alpha(tint));
scrimView.setTint(tint);
- if (!mIsBouncerToGoneTransitionRunning) {
- scrimView.setViewAlpha(alpha);
- }
+ scrimView.setViewAlpha(alpha);
} else {
scrim.setAlpha(alpha);
}
@@ -1522,9 +1473,6 @@
}
public void setKeyguardOccluded(boolean keyguardOccluded) {
- if (mKeyguardOccluded == keyguardOccluded) {
- return;
- }
mKeyguardOccluded = keyguardOccluded;
updateScrims();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt
index c04ea36..5903fa3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt
@@ -26,19 +26,39 @@
import com.android.systemui.statusbar.events.STATUS_BAR_X_MOVE_OUT
import com.android.systemui.statusbar.events.SystemStatusAnimationCallback
import com.android.systemui.util.animation.AnimationUtil.Companion.frames
+import com.android.systemui.util.doOnCancel
+import com.android.systemui.util.doOnEnd
+
+/**
+ * An implementation of [StatusBarSystemEventDefaultAnimator], applying the onAlphaChanged and
+ * onTranslationXChanged callbacks directly to the provided animatedView.
+ */
+class StatusBarSystemEventAnimator @JvmOverloads constructor(
+ val animatedView: View,
+ resources: Resources,
+ isAnimationRunning: Boolean = false
+) : StatusBarSystemEventDefaultAnimator(
+ resources = resources,
+ onAlphaChanged = animatedView::setAlpha,
+ onTranslationXChanged = animatedView::setTranslationX,
+ isAnimationRunning = isAnimationRunning
+)
/**
* Tied directly to [SystemStatusAnimationScheduler]. Any StatusBar-like thing (keyguard, collapsed
- * status bar fragment), can just feed this an animatable view to get the default system status
- * animation.
+ * status bar fragment), can use this Animator to get the default system status animation. It simply
+ * needs to implement the onAlphaChanged and onTranslationXChanged callbacks.
*
* This animator relies on resources, and should be recreated whenever resources are updated. While
* this class could be used directly as the animation callback, it's probably best to forward calls
* to it so that it can be recreated at any moment without needing to remove/add callback.
*/
-class StatusBarSystemEventAnimator(
- val animatedView: View,
- resources: Resources
+
+open class StatusBarSystemEventDefaultAnimator @JvmOverloads constructor(
+ resources: Resources,
+ private val onAlphaChanged: (Float) -> Unit,
+ private val onTranslationXChanged: (Float) -> Unit,
+ var isAnimationRunning: Boolean = false
) : SystemStatusAnimationCallback {
private val translationXIn: Int = resources.getDimensionPixelSize(
R.dimen.ongoing_appops_chip_animation_in_status_bar_translation_x)
@@ -46,18 +66,19 @@
R.dimen.ongoing_appops_chip_animation_out_status_bar_translation_x)
override fun onSystemEventAnimationBegin(): Animator {
+ isAnimationRunning = true
val moveOut = ValueAnimator.ofFloat(0f, 1f).apply {
duration = 23.frames
interpolator = STATUS_BAR_X_MOVE_OUT
addUpdateListener {
- animatedView.translationX = -(translationXIn * animatedValue as Float)
+ onTranslationXChanged(-(translationXIn * animatedValue as Float))
}
}
val alphaOut = ValueAnimator.ofFloat(1f, 0f).apply {
duration = 8.frames
interpolator = null
addUpdateListener {
- animatedView.alpha = animatedValue as Float
+ onAlphaChanged(animatedValue as Float)
}
}
@@ -67,13 +88,13 @@
}
override fun onSystemEventAnimationFinish(hasPersistentDot: Boolean): Animator {
- animatedView.translationX = translationXOut.toFloat()
+ onTranslationXChanged(translationXOut.toFloat())
val moveIn = ValueAnimator.ofFloat(1f, 0f).apply {
duration = 23.frames
startDelay = 7.frames
interpolator = STATUS_BAR_X_MOVE_IN
addUpdateListener {
- animatedView.translationX = translationXOut * animatedValue as Float
+ onTranslationXChanged(translationXOut * animatedValue as Float)
}
}
val alphaIn = ValueAnimator.ofFloat(0f, 1f).apply {
@@ -81,13 +102,14 @@
startDelay = 11.frames
interpolator = null
addUpdateListener {
- animatedView.alpha = animatedValue as Float
+ onAlphaChanged(animatedValue as Float)
}
}
val animatorSet = AnimatorSet()
animatorSet.playTogether(moveIn, alphaIn)
-
+ animatorSet.doOnEnd { isAnimationRunning = false }
+ animatorSet.doOnCancel { isAnimationRunning = false }
return animatorSet
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java
index d5d3efd..3a7ac9c 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java
@@ -31,6 +31,9 @@
import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+
+import javax.inject.Inject;
/**
* If the attached USB accessory has a URL associated with it, and that URL is valid,
@@ -46,13 +49,27 @@
private UsbAccessory mAccessory;
private Uri mUri;
+ private final DeviceProvisionedController mDeviceProvisionedController;
+
+ @Inject
+ UsbAccessoryUriActivity(DeviceProvisionedController deviceProvisionedController) {
+ mDeviceProvisionedController = deviceProvisionedController;
+ }
+
@Override
public void onCreate(Bundle icicle) {
- getWindow().addSystemFlags(
+ getWindow().addSystemFlags(
WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
- super.onCreate(icicle);
+ super.onCreate(icicle);
- Intent intent = getIntent();
+ // Don't show this dialog during Setup Wizard
+ if (!mDeviceProvisionedController.isDeviceProvisioned()) {
+ Log.e(TAG, "device not provisioned");
+ finish();
+ return;
+ }
+
+ Intent intent = getIntent();
mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
String uriString = intent.getStringExtra("uri");
mUri = (uriString == null ? null : Uri.parse(uriString));
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
index 81ae6e8..c72853e 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
@@ -115,6 +115,17 @@
}
/**
+ * Provide a Long running Executor.
+ */
+ @Provides
+ @SysUISingleton
+ @LongRunning
+ public static DelayableExecutor provideLongRunningDelayableExecutor(
+ @LongRunning Looper looper) {
+ return new ExecutorImpl(looper);
+ }
+
+ /**
* Provide a Background-Thread Executor.
*/
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
index 8b925b7..b962148 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
@@ -35,7 +35,7 @@
import androidx.annotation.NonNull;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.LongRunning;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -61,17 +61,16 @@
private final UserTracker mUserTracker;
// used for most tasks (call canvas.drawBitmap, load/unload the bitmap)
- @Background
- private final DelayableExecutor mBackgroundExecutor;
+ @LongRunning
+ private final DelayableExecutor mLongExecutor;
// wait at least this duration before unloading the bitmap
private static final int DELAY_UNLOAD_BITMAP = 2000;
@Inject
- public ImageWallpaper(@Background DelayableExecutor backgroundExecutor,
- UserTracker userTracker) {
+ public ImageWallpaper(@LongRunning DelayableExecutor longExecutor, UserTracker userTracker) {
super();
- mBackgroundExecutor = backgroundExecutor;
+ mLongExecutor = longExecutor;
mUserTracker = userTracker;
}
@@ -105,7 +104,7 @@
setFixedSizeAllowed(true);
setShowForAllUsers(true);
mWallpaperLocalColorExtractor = new WallpaperLocalColorExtractor(
- mBackgroundExecutor,
+ mLongExecutor,
new WallpaperLocalColorExtractor.WallpaperLocalColorExtractorCallback() {
@Override
public void onColorsProcessed(List<RectF> regions,
@@ -202,7 +201,7 @@
}
private void drawFrame() {
- mBackgroundExecutor.execute(this::drawFrameSynchronized);
+ mLongExecutor.execute(this::drawFrameSynchronized);
}
private void drawFrameSynchronized() {
@@ -257,7 +256,7 @@
}
private void unloadBitmapIfNotUsed() {
- mBackgroundExecutor.execute(this::unloadBitmapIfNotUsedSynchronized);
+ mLongExecutor.execute(this::unloadBitmapIfNotUsedSynchronized);
}
private void unloadBitmapIfNotUsedSynchronized() {
@@ -341,7 +340,7 @@
* - the mini bitmap from color extractor is recomputed
* - the DELAY_UNLOAD_BITMAP has passed
*/
- mBackgroundExecutor.executeDelayed(
+ mLongExecutor.executeDelayed(
this::unloadBitmapIfNotUsedSynchronized, DELAY_UNLOAD_BITMAP);
}
// even if the bitmap cannot be loaded, call reportEngineShown
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java b/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java
index 988fd71..1e8446f 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java
@@ -29,7 +29,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
-import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.LongRunning;
import com.android.systemui.util.Assert;
import java.io.FileDescriptor;
@@ -66,8 +66,8 @@
private final List<RectF> mPendingRegions = new ArrayList<>();
private final Set<RectF> mProcessedRegions = new ArraySet<>();
- @Background
- private final Executor mBackgroundExecutor;
+ @LongRunning
+ private final Executor mLongExecutor;
private final WallpaperLocalColorExtractorCallback mWallpaperLocalColorExtractorCallback;
@@ -101,13 +101,13 @@
/**
* Creates a new color extractor.
- * @param backgroundExecutor the executor on which the color extraction will be performed
+ * @param longExecutor the executor on which the color extraction will be performed
* @param wallpaperLocalColorExtractorCallback an interface to handle the callbacks from
* the color extractor.
*/
- public WallpaperLocalColorExtractor(@Background Executor backgroundExecutor,
+ public WallpaperLocalColorExtractor(@LongRunning Executor longExecutor,
WallpaperLocalColorExtractorCallback wallpaperLocalColorExtractorCallback) {
- mBackgroundExecutor = backgroundExecutor;
+ mLongExecutor = longExecutor;
mWallpaperLocalColorExtractorCallback = wallpaperLocalColorExtractorCallback;
}
@@ -117,7 +117,7 @@
* not recomputed.
*/
public void setDisplayDimensions(int displayWidth, int displayHeight) {
- mBackgroundExecutor.execute(() ->
+ mLongExecutor.execute(() ->
setDisplayDimensionsSynchronized(displayWidth, displayHeight));
}
@@ -144,7 +144,7 @@
* @param bitmap the new wallpaper
*/
public void onBitmapChanged(@NonNull Bitmap bitmap) {
- mBackgroundExecutor.execute(() -> onBitmapChangedSynchronized(bitmap));
+ mLongExecutor.execute(() -> onBitmapChangedSynchronized(bitmap));
}
private void onBitmapChangedSynchronized(@NonNull Bitmap bitmap) {
@@ -167,7 +167,7 @@
* @param pages the total number of pages of the launcher
*/
public void onPageChanged(int pages) {
- mBackgroundExecutor.execute(() -> onPageChangedSynchronized(pages));
+ mLongExecutor.execute(() -> onPageChangedSynchronized(pages));
}
private void onPageChangedSynchronized(int pages) {
@@ -194,7 +194,7 @@
*/
public void addLocalColorsAreas(@NonNull List<RectF> regions) {
if (regions.size() > 0) {
- mBackgroundExecutor.execute(() -> addLocalColorsAreasSynchronized(regions));
+ mLongExecutor.execute(() -> addLocalColorsAreasSynchronized(regions));
} else {
Log.w(TAG, "Attempt to add colors with an empty list");
}
@@ -218,7 +218,7 @@
* @param regions The areas of interest in our wallpaper (in screen pixel coordinates)
*/
public void removeLocalColorAreas(@NonNull List<RectF> regions) {
- mBackgroundExecutor.execute(() -> removeLocalColorAreasSynchronized(regions));
+ mLongExecutor.execute(() -> removeLocalColorAreasSynchronized(regions));
}
private void removeLocalColorAreasSynchronized(@NonNull List<RectF> regions) {
@@ -236,7 +236,7 @@
* Clean up the memory (in particular, the mini bitmap) used by this class.
*/
public void cleanUp() {
- mBackgroundExecutor.execute(this::cleanUpSynchronized);
+ mLongExecutor.execute(this::cleanUpSynchronized);
}
private void cleanUpSynchronized() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index 1bbc199..531006d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -37,6 +37,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -160,6 +161,29 @@
}
@Test
+ public void testOnApplyWindowInsets_disappearAnimation_paddingNotSet() {
+ int paddingBottom = getContext().getResources()
+ .getDimensionPixelSize(R.dimen.keyguard_security_view_bottom_margin);
+ int imeInsetAmount = paddingBottom + 1;
+ int systemBarInsetAmount = 0;
+ initMode(MODE_DEFAULT);
+
+ Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount);
+ Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount);
+
+ WindowInsets insets = new WindowInsets.Builder()
+ .setInsets(ime(), imeInset)
+ .setInsetsIgnoringVisibility(systemBars(), systemBarInset)
+ .build();
+
+ ensureViewFlipperIsMocked();
+ mKeyguardSecurityContainer.startDisappearAnimation(
+ KeyguardSecurityModel.SecurityMode.Password);
+ mKeyguardSecurityContainer.onApplyWindowInsets(insets);
+ assertThat(mKeyguardSecurityContainer.getPaddingBottom()).isNotEqualTo(imeInsetAmount);
+ }
+
+ @Test
public void testDefaultViewMode() {
initMode(MODE_ONE_HANDED);
initMode(MODE_DEFAULT);
@@ -376,6 +400,17 @@
assertThat(mKeyguardSecurityContainer.getScaleY()).isEqualTo(1);
}
+ @Test
+ public void testDisappearAnimationPassword() {
+ ensureViewFlipperIsMocked();
+ KeyguardPasswordView keyguardPasswordView = mock(KeyguardPasswordView.class);
+ when(mSecurityViewFlipper.getSecurityView()).thenReturn(keyguardPasswordView);
+
+ mKeyguardSecurityContainer
+ .startDisappearAnimation(KeyguardSecurityModel.SecurityMode.Password);
+ verify(keyguardPasswordView).setDisappearAnimationListener(any());
+ }
+
private BackEvent createBackEvent(float touchX, float progress) {
return new BackEvent(0, 0, progress, BackEvent.EDGE_LEFT);
}
@@ -446,4 +481,12 @@
mUserSwitcherController, () -> {
}, mFalsingA11yDelegate);
}
+
+ private void ensureViewFlipperIsMocked() {
+ mSecurityViewFlipper = mock(KeyguardSecurityViewFlipper.class);
+ KeyguardPasswordView keyguardPasswordView = mock(KeyguardPasswordView.class);
+ when(mSecurityViewFlipper.getSecurityView()).thenReturn(keyguardPasswordView);
+ mKeyguardSecurityContainer.mSecurityViewFlipper = mSecurityViewFlipper;
+ }
+
}
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 2099281..c2fb904 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
@@ -446,7 +446,7 @@
mFeatureFlags.set(CLIPBOARD_REMOTE_BEHAVIOR, true);
when(mClipboardUtils.isRemoteCopy(any(Context.class), any(ClipData.class), anyString()))
.thenReturn(true);
- when(mClipboardUtils.getAction(any(CharSequence.class), any(TextLinks.class), anyString()))
+ when(mClipboardUtils.getAction(any(TextLinks.class), anyString()))
.thenReturn(Optional.of(Mockito.mock(RemoteAction.class)));
when(mClipboardOverlayView.post(any(Runnable.class))).thenAnswer(new Answer<Object>() {
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java
index aea6be3..3d8f04e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.when;
@@ -77,6 +78,74 @@
@Test
public void test_getAction_noLinks_returnsEmptyOptional() {
+ Optional<RemoteAction> action =
+ mClipboardUtils.getAction(Mockito.mock(TextLinks.class), "abc");
+
+ assertTrue(action.isEmpty());
+ }
+
+ @Test
+ public void test_getAction_returnsFirstLink() {
+ TextLinks links = getFakeTextLinksBuilder().build();
+ RemoteAction actionA = constructRemoteAction("abc");
+ RemoteAction actionB = constructRemoteAction("def");
+ TextClassification classificationA = Mockito.mock(TextClassification.class);
+ when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA));
+ TextClassification classificationB = Mockito.mock(TextClassification.class);
+ when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB));
+ when(mTextClassifier.classifyText(anyString(), anyInt(), anyInt(), isNull())).thenReturn(
+ classificationA, classificationB);
+
+ RemoteAction result = mClipboardUtils.getAction(links, "test").orElse(null);
+
+ assertEquals(actionA, result);
+ }
+
+ @Test
+ public void test_getAction_skipsMatchingComponent() {
+ TextLinks links = getFakeTextLinksBuilder().build();
+ RemoteAction actionA = constructRemoteAction("abc");
+ RemoteAction actionB = constructRemoteAction("def");
+ TextClassification classificationA = Mockito.mock(TextClassification.class);
+ when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA));
+ TextClassification classificationB = Mockito.mock(TextClassification.class);
+ when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB));
+ when(mTextClassifier.classifyText(anyString(), anyInt(), anyInt(), isNull())).thenReturn(
+ classificationA, classificationB);
+
+ RemoteAction result = mClipboardUtils.getAction(links, "abc").orElse(null);
+
+ assertEquals(actionB, result);
+ }
+
+ @Test
+ public void test_getAction_skipsShortEntity() {
+ TextLinks.Builder textLinks = new TextLinks.Builder("test text of length 22");
+ final Map<String, Float> scores = new ArrayMap<>();
+ scores.put(TextClassifier.TYPE_EMAIL, 1f);
+ textLinks.addLink(20, 22, scores);
+ textLinks.addLink(0, 22, scores);
+
+ RemoteAction actionA = constructRemoteAction("abc");
+ RemoteAction actionB = constructRemoteAction("def");
+ TextClassification classificationA = Mockito.mock(TextClassification.class);
+ when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA));
+ TextClassification classificationB = Mockito.mock(TextClassification.class);
+ when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB));
+ when(mTextClassifier.classifyText(anyString(), eq(20), eq(22), isNull())).thenReturn(
+ classificationA);
+ when(mTextClassifier.classifyText(anyString(), eq(0), eq(22), isNull())).thenReturn(
+ classificationB);
+
+ RemoteAction result = mClipboardUtils.getAction(textLinks.build(), "test").orElse(null);
+
+ assertEquals(actionB, result);
+ }
+
+ // TODO(b/267162944): Next four tests (marked "legacy") are obsolete once
+ // CLIPBOARD_MINIMIZED_LAYOUT flag is released and removed
+ @Test
+ public void test_getAction_noLinks_returnsEmptyOptional_legacy() {
ClipData.Item item = new ClipData.Item("no text links");
item.setTextLinks(Mockito.mock(TextLinks.class));
@@ -86,8 +155,8 @@
}
@Test
- public void test_getAction_returnsFirstLink() {
- when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinks());
+ public void test_getAction_returnsFirstLink_legacy() {
+ when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinksBuilder().build());
when(mClipDataItem.getText()).thenReturn("");
RemoteAction actionA = constructRemoteAction("abc");
RemoteAction actionB = constructRemoteAction("def");
@@ -98,14 +167,14 @@
when(mTextClassifier.classifyText(anyString(), anyInt(), anyInt(), isNull())).thenReturn(
classificationA, classificationB);
- RemoteAction result = mClipboardUtils.getAction(mClipDataItem, "def").orElse(null);
+ RemoteAction result = mClipboardUtils.getAction(mClipDataItem, "test").orElse(null);
assertEquals(actionA, result);
}
@Test
- public void test_getAction_skipsMatchingComponent() {
- when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinks());
+ public void test_getAction_skipsMatchingComponent_legacy() {
+ when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinksBuilder().build());
when(mClipDataItem.getText()).thenReturn("");
RemoteAction actionA = constructRemoteAction("abc");
RemoteAction actionB = constructRemoteAction("def");
@@ -122,6 +191,33 @@
}
@Test
+ public void test_getAction_skipsShortEntity_legacy() {
+ TextLinks.Builder textLinks = new TextLinks.Builder("test text of length 22");
+ final Map<String, Float> scores = new ArrayMap<>();
+ scores.put(TextClassifier.TYPE_EMAIL, 1f);
+ textLinks.addLink(20, 22, scores);
+ textLinks.addLink(0, 22, scores);
+
+ when(mClipDataItem.getTextLinks()).thenReturn(textLinks.build());
+ when(mClipDataItem.getText()).thenReturn(textLinks.build().getText());
+
+ RemoteAction actionA = constructRemoteAction("abc");
+ RemoteAction actionB = constructRemoteAction("def");
+ TextClassification classificationA = Mockito.mock(TextClassification.class);
+ when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA));
+ TextClassification classificationB = Mockito.mock(TextClassification.class);
+ when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB));
+ when(mTextClassifier.classifyText(anyString(), eq(20), eq(22), isNull())).thenReturn(
+ classificationA);
+ when(mTextClassifier.classifyText(anyString(), eq(0), eq(22), isNull())).thenReturn(
+ classificationB);
+
+ RemoteAction result = mClipboardUtils.getAction(mClipDataItem, "test").orElse(null);
+
+ assertEquals(actionB, result);
+ }
+
+ @Test
public void test_extra_withPackage_returnsTrue() {
PersistableBundle b = new PersistableBundle();
b.putBoolean(ClipDescription.EXTRA_IS_REMOTE_DEVICE, true);
@@ -184,12 +280,12 @@
return action;
}
- private static TextLinks getFakeTextLinks() {
- TextLinks.Builder textLinks = new TextLinks.Builder("test");
+ private static TextLinks.Builder getFakeTextLinksBuilder() {
+ TextLinks.Builder textLinks = new TextLinks.Builder("test text of length 22");
final Map<String, Float> scores = new ArrayMap<>();
scores.put(TextClassifier.TYPE_EMAIL, 1f);
- textLinks.addLink(0, 0, scores);
- textLinks.addLink(0, 0, scores);
- return textLinks.build();
+ textLinks.addLink(0, 22, scores);
+ textLinks.addLink(0, 22, scores);
+ return textLinks;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
index 3a168d4..d6dbd73 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
@@ -450,6 +450,15 @@
swipeToPosition(0f, Direction.DOWN, 0);
}
+ @Test
+ public void testTouchSessionOnRemovedCalledTwice() {
+ mTouchHandler.onSessionStart(mTouchSession);
+ ArgumentCaptor<DreamTouchHandler.TouchSession.Callback> onRemovedCallbackCaptor =
+ ArgumentCaptor.forClass(DreamTouchHandler.TouchSession.Callback.class);
+ verify(mTouchSession).registerCallback(onRemovedCallbackCaptor.capture());
+ onRemovedCallbackCaptor.getValue().onRemoved();
+ onRemovedCallbackCaptor.getValue().onRemoved();
+ }
private void swipeToPosition(float percent, Direction direction, float velocityY) {
Mockito.clearInvocations(mTouchSession);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt
new file mode 100644
index 0000000..ec94cde
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt
@@ -0,0 +1,73 @@
+/*
+ * 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.keyboard.backlight.domain.interactor
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository
+import com.android.systemui.keyboard.shared.model.BacklightModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.first
+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 KeyboardBacklightInteractorTest : SysuiTestCase() {
+
+ private val keyboardRepository = FakeKeyboardRepository()
+ private lateinit var underTest: KeyboardBacklightInteractor
+
+ @Before
+ fun setUp() {
+ underTest = KeyboardBacklightInteractor(keyboardRepository)
+ }
+
+ @Test
+ fun emitsNull_whenKeyboardJustConnected() = runTest {
+ val latest by collectLastValue(underTest.backlight)
+ keyboardRepository.setKeyboardConnected(true)
+
+ assertThat(latest).isNull()
+ }
+
+ @Test
+ fun emitsBacklight_whenKeyboardConnectedAndBacklightChanged() = runTest {
+ keyboardRepository.setKeyboardConnected(true)
+ keyboardRepository.setBacklight(BacklightModel(1, 5))
+
+ assertThat(underTest.backlight.first()).isEqualTo(BacklightModel(1, 5))
+ }
+
+ @Test
+ fun emitsNull_afterKeyboardDisconnecting() = runTest {
+ val latest by collectLastValue(underTest.backlight)
+ keyboardRepository.setKeyboardConnected(true)
+ keyboardRepository.setBacklight(BacklightModel(1, 5))
+
+ keyboardRepository.setKeyboardConnected(false)
+
+ assertThat(latest).isNull()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModelTest.kt
new file mode 100644
index 0000000..ec05d10
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModelTest.kt
@@ -0,0 +1,102 @@
+/*
+ * 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.keyboard.backlight.ui.viewmodel
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyboard.backlight.domain.interactor.KeyboardBacklightInteractor
+import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository
+import com.android.systemui.keyboard.shared.model.BacklightModel
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.test.advanceTimeBy
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class BacklightDialogViewModelTest : SysuiTestCase() {
+
+ private val keyboardRepository = FakeKeyboardRepository()
+ private lateinit var underTest: BacklightDialogViewModel
+ @Mock private lateinit var accessibilityManagerWrapper: AccessibilityManagerWrapper
+ private val timeoutMillis = 3000L
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ whenever(accessibilityManagerWrapper.getRecommendedTimeoutMillis(any(), any()))
+ .thenReturn(timeoutMillis.toInt())
+ underTest =
+ BacklightDialogViewModel(
+ KeyboardBacklightInteractor(keyboardRepository),
+ accessibilityManagerWrapper
+ )
+ keyboardRepository.setKeyboardConnected(true)
+ }
+
+ @Test
+ fun emitsViewModel_whenBacklightChanged() = runTest {
+ keyboardRepository.setBacklight(BacklightModel(1, 5))
+
+ assertThat(underTest.dialogContent.first()).isEqualTo(BacklightDialogContentViewModel(1, 5))
+ }
+
+ @Test
+ fun emitsNull_afterTimeout() = runTest {
+ val latest by collectLastValue(underTest.dialogContent)
+ keyboardRepository.setBacklight(BacklightModel(1, 5))
+
+ assertThat(latest).isEqualTo(BacklightDialogContentViewModel(1, 5))
+ advanceTimeBy(timeoutMillis + 1)
+ assertThat(latest).isNull()
+ }
+
+ @Test
+ fun emitsNull_after5secDelay_fromLastBacklightChange() = runTest {
+ val latest by collectLastValue(underTest.dialogContent)
+ keyboardRepository.setKeyboardConnected(true)
+
+ keyboardRepository.setBacklight(BacklightModel(1, 5))
+ assertThat(latest).isEqualTo(BacklightDialogContentViewModel(1, 5))
+
+ advanceTimeBy(timeoutMillis * 2 / 3)
+ // timeout yet to pass, no new emission
+ keyboardRepository.setBacklight(BacklightModel(2, 5))
+ assertThat(latest).isEqualTo(BacklightDialogContentViewModel(2, 5))
+
+ advanceTimeBy(timeoutMillis * 2 / 3)
+ // timeout refreshed because of last `setBacklight`, still content present
+ assertThat(latest).isEqualTo(BacklightDialogContentViewModel(2, 5))
+
+ advanceTimeBy(timeoutMillis * 2 / 3)
+ // finally timeout reached and null emitted
+ assertThat(latest).isNull()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
index 0e6f8d4..0469e77 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
@@ -219,29 +219,6 @@
}
@Test
- fun isKeyguardUnlocked() =
- runTest(UnconfinedTestDispatcher()) {
- whenever(keyguardStateController.isUnlocked).thenReturn(false)
- var latest: Boolean? = null
- val job = underTest.isKeyguardUnlocked.onEach { latest = it }.launchIn(this)
-
- assertThat(latest).isFalse()
-
- val captor = argumentCaptor<KeyguardStateController.Callback>()
- verify(keyguardStateController).addCallback(captor.capture())
-
- whenever(keyguardStateController.isUnlocked).thenReturn(true)
- captor.value.onUnlockedChanged()
- assertThat(latest).isTrue()
-
- whenever(keyguardStateController.isUnlocked).thenReturn(false)
- captor.value.onUnlockedChanged()
- assertThat(latest).isFalse()
-
- job.cancel()
- }
-
- @Test
fun isDozing() =
runTest(UnconfinedTestDispatcher()) {
var latest: Boolean? = null
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index fe9098f..ae7a928 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -19,8 +19,6 @@
import android.animation.ValueAnimator
import androidx.test.filters.FlakyTest
import androidx.test.filters.SmallTest
-import com.android.keyguard.KeyguardSecurityModel
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode.PIN
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.Interpolators
import com.android.systemui.flags.FakeFeatureFlags
@@ -42,7 +40,6 @@
import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.statusbar.CommandQueue
-import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.cancelChildren
@@ -54,8 +51,6 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.mockito.ArgumentMatchers.anyBoolean
-import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
@@ -82,7 +77,6 @@
// Used to verify transition requests for test output
@Mock private lateinit var mockTransitionRepository: KeyguardTransitionRepository
@Mock private lateinit var commandQueue: CommandQueue
- @Mock private lateinit var keyguardSecurityModel: KeyguardSecurityModel
private lateinit var fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor
private lateinit var fromDreamingTransitionInteractor: FromDreamingTransitionInteractor
@@ -108,8 +102,6 @@
transitionRepository = KeyguardTransitionRepositoryImpl()
runner = KeyguardTransitionRunner(transitionRepository)
- whenever(keyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(PIN)
-
val featureFlags = FakeFeatureFlags().apply { set(Flags.FACE_AUTH_REFACTOR, true) }
fromLockscreenTransitionInteractor =
FromLockscreenTransitionInteractor(
@@ -181,17 +173,16 @@
keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
- keyguardSecurityModel = keyguardSecurityModel,
)
fromPrimaryBouncerTransitionInteractor.start()
}
@Test
- fun `DREAMING to LOCKSCREEN`() =
+ fun `DREAMING to LOCKSCREEN - dreaming state changes first`() =
testScope.runTest {
- // GIVEN a device is dreaming
+ // GIVEN a device is dreaming and occluded
keyguardRepository.setDreamingWithOverlay(true)
- keyguardRepository.setWakefulnessModel(startingToWake())
+ keyguardRepository.setKeyguardOccluded(true)
runCurrent()
// GIVEN a prior transition has run to DREAMING
@@ -224,7 +215,56 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(mockTransitionRepository).startTransition(capture())
+ }
+ // THEN a transition to BOUNCER should occur
+ assertThat(info.ownerName).isEqualTo("FromDreamingTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.DREAMING)
+ assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun `DREAMING to LOCKSCREEN - occluded state changes first`() =
+ testScope.runTest {
+ // GIVEN a device is dreaming and occluded
+ keyguardRepository.setDreamingWithOverlay(true)
+ keyguardRepository.setKeyguardOccluded(true)
+ runCurrent()
+
+ // GIVEN a prior transition has run to DREAMING
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.DREAMING,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // WHEN doze is complete
+ keyguardRepository.setDozeTransitionModel(
+ DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
+ )
+ // AND occluded has stopped
+ keyguardRepository.setKeyguardOccluded(false)
+ advanceUntilIdle()
+ // AND then dreaming has stopped
+ keyguardRepository.setDreamingWithOverlay(false)
+ advanceUntilIdle()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture())
}
// THEN a transition to BOUNCER should occur
assertThat(info.ownerName).isEqualTo("FromDreamingTransitionInteractor")
@@ -264,7 +304,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(mockTransitionRepository).startTransition(capture())
}
// THEN a transition to PRIMARY_BOUNCER should occur
assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
@@ -305,7 +345,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(mockTransitionRepository).startTransition(capture())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
@@ -346,7 +386,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(mockTransitionRepository).startTransition(capture())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
@@ -387,7 +427,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(mockTransitionRepository).startTransition(capture())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
@@ -428,7 +468,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(mockTransitionRepository).startTransition(capture())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
@@ -465,7 +505,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(mockTransitionRepository).startTransition(capture())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromDozingTransitionInteractor")
@@ -502,7 +542,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(mockTransitionRepository).startTransition(capture())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromDozingTransitionInteractor")
@@ -543,7 +583,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(mockTransitionRepository).startTransition(capture())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
@@ -584,7 +624,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(mockTransitionRepository).startTransition(capture())
}
// THEN a transition to AOD should occur
assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
@@ -621,7 +661,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(mockTransitionRepository).startTransition(capture())
}
// THEN a transition to AOD should occur
assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
@@ -637,7 +677,6 @@
testScope.runTest {
// GIVEN a device that is not dreaming or dozing
keyguardRepository.setDreamingWithOverlay(false)
- keyguardRepository.setWakefulnessModel(startingToWake())
keyguardRepository.setDozeTransitionModel(
DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
)
@@ -665,7 +704,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(mockTransitionRepository).startTransition(capture())
}
// THEN a transition to DREAMING should occur
assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
@@ -702,7 +741,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(mockTransitionRepository).startTransition(capture())
}
// THEN a transition to PRIMARY_BOUNCER should occur
assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
@@ -745,7 +784,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(mockTransitionRepository).startTransition(capture())
}
// THEN a transition to AOD should occur
assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
@@ -789,7 +828,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(mockTransitionRepository).startTransition(capture())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
@@ -831,7 +870,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(mockTransitionRepository).startTransition(capture())
}
// THEN a transition to LOCKSCREEN should occur
assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
@@ -873,7 +912,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(mockTransitionRepository).startTransition(capture())
}
// THEN a transition to AOD should occur
assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
@@ -915,7 +954,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(mockTransitionRepository).startTransition(capture())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
@@ -956,7 +995,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(mockTransitionRepository).startTransition(capture())
}
// THEN a transition to LOCKSCREEN should occur
assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 52b0b6a..4f469f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -551,6 +551,7 @@
mNotificationStackSizeCalculator,
mUnlockedScreenOffAnimationController,
mShadeTransitionController,
+ mInteractionJankMonitor,
systemClock,
mKeyguardBottomAreaViewModel,
mKeyguardBottomAreaInteractor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 82a5743..0a401b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -33,7 +33,6 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel
-import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
import com.android.systemui.statusbar.LockscreenShadeTransitionController
import com.android.systemui.statusbar.NotificationInsetsController
@@ -66,32 +65,48 @@
@RunWith(AndroidTestingRunner::class)
@RunWithLooper(setAsMainLooper = true)
class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
- @Mock private lateinit var view: NotificationShadeWindowView
- @Mock private lateinit var sysuiStatusBarStateController: SysuiStatusBarStateController
- @Mock private lateinit var centralSurfaces: CentralSurfaces
- @Mock private lateinit var dockManager: DockManager
- @Mock private lateinit var notificationPanelViewController: NotificationPanelViewController
- @Mock private lateinit var notificationShadeDepthController: NotificationShadeDepthController
- @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController
- @Mock private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController
- @Mock private lateinit var ambientState: AmbientState
- @Mock private lateinit var keyguardBouncerViewModel: KeyguardBouncerViewModel
- @Mock private lateinit var stackScrollLayoutController: NotificationStackScrollLayoutController
- @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
- @Mock private lateinit var statusBarWindowStateController: StatusBarWindowStateController
+ @Mock
+ private lateinit var view: NotificationShadeWindowView
+ @Mock
+ private lateinit var sysuiStatusBarStateController: SysuiStatusBarStateController
+ @Mock
+ private lateinit var centralSurfaces: CentralSurfaces
+ @Mock
+ private lateinit var dockManager: DockManager
+ @Mock
+ private lateinit var notificationPanelViewController: NotificationPanelViewController
+ @Mock
+ private lateinit var notificationShadeDepthController: NotificationShadeDepthController
+ @Mock
+ private lateinit var notificationShadeWindowController: NotificationShadeWindowController
+ @Mock
+ private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController
+ @Mock
+ private lateinit var ambientState: AmbientState
+ @Mock
+ private lateinit var keyguardBouncerViewModel: KeyguardBouncerViewModel
+ @Mock
+ private lateinit var stackScrollLayoutController: NotificationStackScrollLayoutController
+ @Mock
+ private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
+ @Mock
+ private lateinit var statusBarWindowStateController: StatusBarWindowStateController
@Mock
private lateinit var lockscreenShadeTransitionController: LockscreenShadeTransitionController
- @Mock private lateinit var lockIconViewController: LockIconViewController
- @Mock private lateinit var phoneStatusBarViewController: PhoneStatusBarViewController
- @Mock private lateinit var pulsingGestureListener: PulsingGestureListener
- @Mock private lateinit var notificationInsetsController: NotificationInsetsController
- @Mock private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
+ @Mock
+ private lateinit var lockIconViewController: LockIconViewController
+ @Mock
+ private lateinit var phoneStatusBarViewController: PhoneStatusBarViewController
+ @Mock
+ private lateinit var pulsingGestureListener: PulsingGestureListener
+ @Mock
+ private lateinit var notificationInsetsController: NotificationInsetsController
+ @Mock
+ private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
@Mock lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory
@Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent
@Mock lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController
@Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
- @Mock
- lateinit var primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel
private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler>
private lateinit var interactionEventHandler: InteractionEventHandler
@@ -103,44 +118,43 @@
MockitoAnnotations.initMocks(this)
whenever(view.bottom).thenReturn(VIEW_BOTTOM)
whenever(view.findViewById<ViewGroup>(R.id.keyguard_bouncer_container))
- .thenReturn(mock(ViewGroup::class.java))
+ .thenReturn(mock(ViewGroup::class.java))
whenever(keyguardBouncerComponentFactory.create(any(ViewGroup::class.java)))
- .thenReturn(keyguardBouncerComponent)
+ .thenReturn(keyguardBouncerComponent)
whenever(keyguardBouncerComponent.securityContainerController)
- .thenReturn(keyguardSecurityContainerController)
+ .thenReturn(keyguardSecurityContainerController)
whenever(keyguardTransitionInteractor.lockscreenToDreamingTransition)
- .thenReturn(emptyFlow<TransitionStep>())
- underTest =
- NotificationShadeWindowViewController(
- lockscreenShadeTransitionController,
- FalsingCollectorFake(),
- sysuiStatusBarStateController,
- dockManager,
- notificationShadeDepthController,
- view,
- notificationPanelViewController,
- ShadeExpansionStateManager(),
- stackScrollLayoutController,
- statusBarKeyguardViewManager,
- statusBarWindowStateController,
- lockIconViewController,
- centralSurfaces,
- notificationShadeWindowController,
- keyguardUnlockAnimationController,
- notificationInsetsController,
- ambientState,
- pulsingGestureListener,
- keyguardBouncerViewModel,
- keyguardBouncerComponentFactory,
- alternateBouncerInteractor,
- keyguardTransitionInteractor,
- primaryBouncerToGoneTransitionViewModel,
- )
+ .thenReturn(emptyFlow<TransitionStep>())
+ underTest = NotificationShadeWindowViewController(
+ lockscreenShadeTransitionController,
+ FalsingCollectorFake(),
+ sysuiStatusBarStateController,
+ dockManager,
+ notificationShadeDepthController,
+ view,
+ notificationPanelViewController,
+ ShadeExpansionStateManager(),
+ stackScrollLayoutController,
+ statusBarKeyguardViewManager,
+ statusBarWindowStateController,
+ lockIconViewController,
+ centralSurfaces,
+ notificationShadeWindowController,
+ keyguardUnlockAnimationController,
+ notificationInsetsController,
+ ambientState,
+ pulsingGestureListener,
+ keyguardBouncerViewModel,
+ keyguardBouncerComponentFactory,
+ alternateBouncerInteractor,
+ keyguardTransitionInteractor,
+ )
underTest.setupExpandedStatusBar()
- interactionEventHandlerCaptor = ArgumentCaptor.forClass(InteractionEventHandler::class.java)
+ interactionEventHandlerCaptor =
+ ArgumentCaptor.forClass(InteractionEventHandler::class.java)
verify(view).setInteractionEventHandler(interactionEventHandlerCaptor.capture())
- interactionEventHandler = interactionEventHandlerCaptor.value
+ interactionEventHandler = interactionEventHandlerCaptor.value
}
// Note: So far, these tests only cover interactions with the status bar view controller. More
@@ -170,11 +184,14 @@
@Test
fun handleDispatchTouchEvent_downTouchBelowViewThenAnotherTouch_sendsTouchToSb() {
underTest.setStatusBarViewController(phoneStatusBarViewController)
- val downEvBelow =
- MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, VIEW_BOTTOM + 4f, 0)
+ val downEvBelow = MotionEvent.obtain(
+ 0L, 0L, MotionEvent.ACTION_DOWN, 0f, VIEW_BOTTOM + 4f, 0
+ )
interactionEventHandler.handleDispatchTouchEvent(downEvBelow)
- val nextEvent = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, VIEW_BOTTOM + 5f, 0)
+ val nextEvent = MotionEvent.obtain(
+ 0L, 0L, MotionEvent.ACTION_MOVE, 0f, VIEW_BOTTOM + 5f, 0
+ )
whenever(phoneStatusBarViewController.sendTouchToView(nextEvent)).thenReturn(true)
val returnVal = interactionEventHandler.handleDispatchTouchEvent(nextEvent)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
index faa6221..5d71979 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
@@ -46,7 +46,6 @@
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel;
-import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationInsetsController;
@@ -102,7 +101,6 @@
@Mock private NotificationInsetsController mNotificationInsetsController;
@Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
@Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
- @Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
@Captor private ArgumentCaptor<NotificationShadeWindowView.InteractionEventHandler>
mInteractionEventHandlerCaptor;
@@ -152,8 +150,7 @@
mKeyguardBouncerViewModel,
mKeyguardBouncerComponentFactory,
mAlternateBouncerInteractor,
- mKeyguardTransitionInteractor,
- mPrimaryBouncerToGoneTransitionViewModel
+ mKeyguardTransitionInteractor
);
mController.setupExpandedStatusBar();
mController.setDragDownHelper(mDragDownHelper);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 180d9f8..dc5a047 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -24,8 +24,6 @@
import static com.google.common.truth.Truth.assertThat;
-import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
-
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
@@ -60,12 +58,7 @@
import com.android.systemui.animation.ShadeInterpolation;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants;
-import com.android.systemui.keyguard.shared.model.KeyguardState;
-import com.android.systemui.keyguard.shared.model.TransitionState;
-import com.android.systemui.keyguard.shared.model.TransitionStep;
-import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.statusbar.policy.FakeConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -92,10 +85,8 @@
import java.util.HashSet;
import java.util.Map;
-import kotlinx.coroutines.CoroutineDispatcher;
-
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@TestableLooper.RunWithLooper
@SmallTest
public class ScrimControllerTest extends SysuiTestCase {
@@ -124,10 +115,6 @@
@Mock private DockManager mDockManager;
@Mock private ScreenOffAnimationController mScreenOffAnimationController;
@Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
- @Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
- @Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
- @Mock private CoroutineDispatcher mMainDispatcher;
-
// TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The
// event-dispatch-on-registration pattern caused some of these unit tests to fail.)
@Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@@ -238,20 +225,13 @@
when(mDelayedWakeLockBuilder.build()).thenReturn(mWakeLock);
when(mDockManager.isDocked()).thenReturn(false);
- when(mKeyguardTransitionInteractor.getPrimaryBouncerToGoneTransition())
- .thenReturn(emptyFlow());
- when(mPrimaryBouncerToGoneTransitionViewModel.getScrimAlpha()).thenReturn(emptyFlow());
-
mScrimController = new ScrimController(mLightBarController,
mDozeParameters, mAlarmManager, mKeyguardStateController, mDelayedWakeLockBuilder,
new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor,
mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()),
mScreenOffAnimationController,
mKeyguardUnlockAnimationController,
- mStatusBarKeyguardViewManager,
- mPrimaryBouncerToGoneTransitionViewModel,
- mKeyguardTransitionInteractor,
- mMainDispatcher);
+ mStatusBarKeyguardViewManager);
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
mScrimController.setAnimatorListener(mAnimatorListener);
@@ -881,10 +861,7 @@
mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()),
mScreenOffAnimationController,
mKeyguardUnlockAnimationController,
- mStatusBarKeyguardViewManager,
- mPrimaryBouncerToGoneTransitionViewModel,
- mKeyguardTransitionInteractor,
- mMainDispatcher);
+ mStatusBarKeyguardViewManager);
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
mScrimController.setAnimatorListener(mAnimatorListener);
@@ -1652,18 +1629,6 @@
assertScrimAlpha(mScrimBehind, 0);
}
- @Test
- public void ignoreTransitionRequestWhileKeyguardTransitionRunning() {
- mScrimController.transitionTo(ScrimState.UNLOCKED);
- mScrimController.mPrimaryBouncerToGoneTransition.accept(
- new TransitionStep(KeyguardState.PRIMARY_BOUNCER, KeyguardState.GONE, 0f,
- TransitionState.RUNNING, "ScrimControllerTest"));
-
- // This request should not happen
- mScrimController.transitionTo(ScrimState.BOUNCER);
- assertThat(mScrimController.getState()).isEqualTo(ScrimState.UNLOCKED);
- }
-
private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) {
mScrimController.setRawPanelExpansionFraction(expansion);
finishAnimationsImmediately();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
index 85cfef7..fd368eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
@@ -16,22 +16,24 @@
package com.android.systemui.unfold.updates
+import android.content.Context
+import android.hardware.display.DisplayManager
+import android.os.Looper
import android.testing.AndroidTestingRunner
-import android.view.IRotationWatcher
-import android.view.IWindowManager
+import android.view.Display
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.unfold.updates.RotationChangeProvider.RotationListener
-import com.android.systemui.util.concurrency.FakeExecutor
-import com.android.systemui.util.time.FakeSystemClock
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.utils.os.FakeHandler
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.any
-import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Captor
import org.mockito.Mock
+import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.MockitoAnnotations
@@ -42,19 +44,23 @@
private lateinit var rotationChangeProvider: RotationChangeProvider
- @Mock lateinit var windowManagerInterface: IWindowManager
+ @Mock lateinit var displayManager: DisplayManager
@Mock lateinit var listener: RotationListener
- @Captor lateinit var rotationWatcher: ArgumentCaptor<IRotationWatcher>
- private val fakeExecutor = FakeExecutor(FakeSystemClock())
+ @Mock lateinit var display: Display
+ @Captor lateinit var displayListener: ArgumentCaptor<DisplayManager.DisplayListener>
+ private val fakeHandler = FakeHandler(Looper.getMainLooper())
+
+ private lateinit var spyContext: Context
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- rotationChangeProvider =
- RotationChangeProvider(windowManagerInterface, context, fakeExecutor)
+ spyContext = spy(context)
+ whenever(spyContext.display).thenReturn(display)
+ rotationChangeProvider = RotationChangeProvider(displayManager, spyContext, fakeHandler)
rotationChangeProvider.addCallback(listener)
- fakeExecutor.runAllReady()
- verify(windowManagerInterface).watchRotation(rotationWatcher.capture(), anyInt())
+ fakeHandler.dispatchQueuedMessages()
+ verify(displayManager).registerDisplayListener(displayListener.capture(), any())
}
@Test
@@ -70,15 +76,16 @@
verify(listener).onRotationChanged(42)
rotationChangeProvider.removeCallback(listener)
- fakeExecutor.runAllReady()
+ fakeHandler.dispatchQueuedMessages()
sendRotationUpdate(43)
- verify(windowManagerInterface).removeRotationWatcher(any())
+ verify(displayManager).unregisterDisplayListener(any())
verifyNoMoreInteractions(listener)
}
private fun sendRotationUpdate(newRotation: Int) {
- rotationWatcher.value.onRotationChanged(newRotation)
- fakeExecutor.runAllReady()
+ whenever(display.rotation).thenReturn(newRotation)
+ displayListener.allValues.forEach { it.onDisplayChanged(display.displayId) }
+ fakeHandler.dispatchQueuedMessages()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
index 31cce4f..468c5a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
@@ -88,7 +88,7 @@
@Mock
private Bitmap mWallpaperBitmap;
FakeSystemClock mFakeSystemClock = new FakeSystemClock();
- FakeExecutor mFakeBackgroundExecutor = new FakeExecutor(mFakeSystemClock);
+ FakeExecutor mFakeExecutor = new FakeExecutor(mFakeSystemClock);
@Before
public void setUp() throws Exception {
@@ -125,7 +125,7 @@
@Test
public void testBitmapWallpaper_normal() {
- // Will use a image wallpaper with dimensions DISPLAY_WIDTH x DISPLAY_WIDTH.
+ // Will use an image wallpaper with dimensions DISPLAY_WIDTH x DISPLAY_WIDTH.
// Then we expect the surface size will be also DISPLAY_WIDTH x DISPLAY_WIDTH.
int bitmapSide = DISPLAY_WIDTH;
testSurfaceHelper(
@@ -137,7 +137,7 @@
@Test
public void testBitmapWallpaper_low_resolution() {
- // Will use a image wallpaper with dimensions BMP_WIDTH x BMP_HEIGHT.
+ // Will use an image wallpaper with dimensions BMP_WIDTH x BMP_HEIGHT.
// Then we expect the surface size will be also BMP_WIDTH x BMP_HEIGHT.
testSurfaceHelper(LOW_BMP_WIDTH /* bitmapWidth */,
LOW_BMP_HEIGHT /* bitmapHeight */,
@@ -161,13 +161,13 @@
ImageWallpaper.CanvasEngine spyEngine = getSpyEngine();
spyEngine.onCreate(mSurfaceHolder);
spyEngine.onSurfaceRedrawNeeded(mSurfaceHolder);
- assertThat(mFakeBackgroundExecutor.numPending()).isAtLeast(1);
+ assertThat(mFakeExecutor.numPending()).isAtLeast(1);
int n = 0;
- while (mFakeBackgroundExecutor.numPending() >= 1) {
+ while (mFakeExecutor.numPending() >= 1) {
n++;
assertThat(n).isAtMost(10);
- mFakeBackgroundExecutor.runNextReady();
+ mFakeExecutor.runNextReady();
mFakeSystemClock.advanceTime(1000);
}
@@ -176,7 +176,7 @@
}
private ImageWallpaper createImageWallpaper() {
- return new ImageWallpaper(mFakeBackgroundExecutor, mUserTracker) {
+ return new ImageWallpaper(mFakeExecutor, mUserTracker) {
@Override
public Engine onCreateEngine() {
return new CanvasEngine() {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/FakeKeyboardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/FakeKeyboardRepository.kt
new file mode 100644
index 0000000..4e43546
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/FakeKeyboardRepository.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.keyboard.data.repository
+
+import com.android.systemui.keyboard.shared.model.BacklightModel
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.filterNotNull
+
+class FakeKeyboardRepository : KeyboardRepository {
+
+ private val _keyboardConnected = MutableStateFlow(false)
+ override val keyboardConnected: Flow<Boolean> = _keyboardConnected
+
+ private val _backlightState: MutableStateFlow<BacklightModel?> = MutableStateFlow(null)
+ // filtering to make sure backlight doesn't have default initial value
+ override val backlight: Flow<BacklightModel> = _backlightState.filterNotNull()
+
+ fun setBacklight(state: BacklightModel) {
+ _backlightState.value = state
+ }
+
+ fun setKeyboardConnected(connected: Boolean) {
+ _keyboardConnected.value = connected
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 194ed02..1a371c7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -47,9 +47,6 @@
private val _isKeyguardShowing = MutableStateFlow(false)
override val isKeyguardShowing: Flow<Boolean> = _isKeyguardShowing
- private val _isKeyguardUnlocked = MutableStateFlow(false)
- override val isKeyguardUnlocked: Flow<Boolean> = _isKeyguardUnlocked
-
private val _isKeyguardOccluded = MutableStateFlow(false)
override val isKeyguardOccluded: Flow<Boolean> = _isKeyguardOccluded
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
index 16442bb..eac1bd1 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
@@ -37,7 +37,7 @@
_transitions.emit(step)
}
- override fun startTransition(info: TransitionInfo, resetIfCanceled: Boolean): UUID? {
+ override fun startTransition(info: TransitionInfo): UUID? {
return null
}
diff --git a/packages/SystemUI/unfold/Android.bp b/packages/SystemUI/unfold/Android.bp
index 180b611..2e0a946 100644
--- a/packages/SystemUI/unfold/Android.bp
+++ b/packages/SystemUI/unfold/Android.bp
@@ -35,6 +35,7 @@
],
kotlincflags: ["-Xjvm-default=enable"],
java_version: "1.8",
+ sdk_version: "current",
min_sdk_version: "current",
plugins: ["dagger2-compiler"],
}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
index 068347c..a079668 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
@@ -19,8 +19,8 @@
import android.content.ContentResolver
import android.content.Context
import android.hardware.SensorManager
+import android.hardware.display.DisplayManager
import android.os.Handler
-import android.view.IWindowManager
import com.android.systemui.unfold.config.UnfoldTransitionConfig
import com.android.systemui.unfold.dagger.UnfoldMain
import com.android.systemui.unfold.dagger.UnfoldSingleThreadBg
@@ -61,7 +61,7 @@
@BindsInstance @UnfoldMain executor: Executor,
@BindsInstance @UnfoldSingleThreadBg singleThreadBgExecutor: Executor,
@BindsInstance @UnfoldTransitionATracePrefix tracingTagPrefix: String,
- @BindsInstance windowManager: IWindowManager,
+ @BindsInstance displayManager: DisplayManager,
@BindsInstance contentResolver: ContentResolver = context.contentResolver
): UnfoldSharedComponent
}
@@ -84,8 +84,9 @@
@BindsInstance context: Context,
@BindsInstance config: UnfoldTransitionConfig,
@BindsInstance @UnfoldMain executor: Executor,
+ @BindsInstance @UnfoldMain handler: Handler,
@BindsInstance @UnfoldSingleThreadBg singleThreadBgExecutor: Executor,
- @BindsInstance windowManager: IWindowManager,
+ @BindsInstance displayManager: DisplayManager,
@BindsInstance @UnfoldTransitionATracePrefix tracingTagPrefix: String,
): RemoteUnfoldSharedComponent
}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
index 8eb79df..1839919 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
@@ -19,8 +19,8 @@
import android.content.Context
import android.hardware.SensorManager
+import android.hardware.display.DisplayManager
import android.os.Handler
-import android.view.IWindowManager
import com.android.systemui.unfold.config.UnfoldTransitionConfig
import com.android.systemui.unfold.updates.FoldProvider
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
@@ -47,7 +47,7 @@
mainExecutor: Executor,
singleThreadBgExecutor: Executor,
tracingTagPrefix: String,
- windowManager: IWindowManager,
+ displayManager: DisplayManager,
): UnfoldSharedComponent =
DaggerUnfoldSharedComponent.factory()
.create(
@@ -61,7 +61,7 @@
mainExecutor,
singleThreadBgExecutor,
tracingTagPrefix,
- windowManager,
+ displayManager,
)
/**
@@ -73,16 +73,18 @@
context: Context,
config: UnfoldTransitionConfig,
mainExecutor: Executor,
+ mainHandler: Handler,
singleThreadBgExecutor: Executor,
tracingTagPrefix: String,
- windowManager: IWindowManager,
+ displayManager: DisplayManager,
): RemoteUnfoldSharedComponent =
DaggerRemoteUnfoldSharedComponent.factory()
.create(
context,
config,
mainExecutor,
+ mainHandler,
singleThreadBgExecutor,
- windowManager,
+ displayManager,
tracingTagPrefix,
)
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
index d19b414..28e4936 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
@@ -16,7 +16,6 @@
package com.android.systemui.unfold.progress
import android.os.Trace
-import android.os.Trace.TRACE_TAG_APP
import android.util.Log
import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.dynamicanimation.animation.FloatPropertyCompat
@@ -110,7 +109,7 @@
if (DEBUG) {
Log.d(TAG, "onFoldUpdate = ${update.name()}")
- Trace.traceCounter(Trace.TRACE_TAG_APP, "fold_update", update)
+ Trace.setCounter("fold_update", update.toLong())
}
}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
index 82fd225..d653fc7 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
@@ -119,7 +119,7 @@
"lastHingeAngle: $lastHingeAngle, " +
"lastHingeAngleBeforeTransition: $lastHingeAngleBeforeTransition"
)
- Trace.traceCounter(Trace.TRACE_TAG_APP, "hinge_angle", angle.toInt())
+ Trace.setCounter( "hinge_angle", angle.toLong())
}
val currentDirection =
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
index 0cf8224..ce8f1a1 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
@@ -17,36 +17,32 @@
package com.android.systemui.unfold.updates
import android.content.Context
+import android.hardware.display.DisplayManager
+import android.os.Handler
import android.os.RemoteException
-import android.view.IRotationWatcher
-import android.view.IWindowManager
-import android.view.Surface.Rotation
import com.android.systemui.unfold.dagger.UnfoldMain
import com.android.systemui.unfold.util.CallbackController
-import java.util.concurrent.Executor
import javax.inject.Inject
/**
- * Allows to subscribe to rotation changes.
- *
- * This is needed as rotation updates from [IWindowManager] are received in a binder thread, while
- * most of the times we want them in the main one. Updates are provided for the display associated
+ * Allows to subscribe to rotation changes. Updates are provided for the display associated
* to [context].
*/
class RotationChangeProvider
@Inject
constructor(
- private val windowManagerInterface: IWindowManager,
+ private val displayManager: DisplayManager,
private val context: Context,
- @UnfoldMain private val mainExecutor: Executor,
+ @UnfoldMain private val mainHandler: Handler,
) : CallbackController<RotationChangeProvider.RotationListener> {
private val listeners = mutableListOf<RotationListener>()
- private val rotationWatcher = RotationWatcher()
+ private val displayListener = RotationDisplayListener()
+ private var lastRotation: Int? = null
override fun addCallback(listener: RotationListener) {
- mainExecutor.execute {
+ mainHandler.post {
if (listeners.isEmpty()) {
subscribeToRotation()
}
@@ -55,17 +51,18 @@
}
override fun removeCallback(listener: RotationListener) {
- mainExecutor.execute {
+ mainHandler.post {
listeners -= listener
if (listeners.isEmpty()) {
unsubscribeToRotation()
+ lastRotation = null
}
}
}
private fun subscribeToRotation() {
try {
- windowManagerInterface.watchRotation(rotationWatcher, context.displayId)
+ displayManager.registerDisplayListener(displayListener, mainHandler)
} catch (e: RemoteException) {
throw e.rethrowFromSystemServer()
}
@@ -73,7 +70,7 @@
private fun unsubscribeToRotation() {
try {
- windowManagerInterface.removeRotationWatcher(rotationWatcher)
+ displayManager.unregisterDisplayListener(displayListener)
} catch (e: RemoteException) {
throw e.rethrowFromSystemServer()
}
@@ -82,12 +79,25 @@
/** Gets notified of rotation changes. */
fun interface RotationListener {
/** Called once rotation changes. */
- fun onRotationChanged(@Rotation newRotation: Int)
+ fun onRotationChanged(newRotation: Int)
}
- private inner class RotationWatcher : IRotationWatcher.Stub() {
- override fun onRotationChanged(rotation: Int) {
- mainExecutor.execute { listeners.forEach { it.onRotationChanged(rotation) } }
+ private inner class RotationDisplayListener : DisplayManager.DisplayListener {
+
+ override fun onDisplayChanged(displayId: Int) {
+ val display = context.display ?: return
+
+ if (displayId == display.displayId) {
+ val currentRotation = display.rotation
+ if (lastRotation == null || lastRotation != currentRotation) {
+ listeners.forEach { it.onRotationChanged(currentRotation) }
+ lastRotation = currentRotation
+ }
+ }
}
+
+ override fun onDisplayAdded(displayId: Int) {}
+
+ override fun onDisplayRemoved(displayId: Int) {}
}
}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt
index 06ca153..ce5c5f9 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt
@@ -79,10 +79,9 @@
companion object {
fun ContentResolver.areAnimationsEnabled(): Boolean {
val animationScale =
- Settings.Global.getStringForUser(
+ Settings.Global.getString(
this,
Settings.Global.ANIMATOR_DURATION_SCALE,
- this.userId
)
?.toFloatOrNull()
?: 1f
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d78fe86..f0dac260 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3831,8 +3831,20 @@
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ final int callingAppId = UserHandle.getAppId(callingUid);
- userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+ ProcessRecord proc;
+ synchronized (mPidsSelfLocked) {
+ proc = mPidsSelfLocked.get(callingPid);
+ }
+ final boolean hasKillAllPermission = PERMISSION_GRANTED == checkPermission(
+ android.Manifest.permission.FORCE_STOP_PACKAGES, callingPid, callingUid)
+ || UserHandle.isCore(callingUid)
+ || (proc != null && proc.info.isSystemApp());
+
+ userId = mUserController.handleIncomingUser(callingPid, callingUid,
userId, true, ALLOW_FULL_ONLY, "killBackgroundProcesses", null);
final int[] userIds = mUserController.expandUserId(userId);
@@ -3847,7 +3859,7 @@
targetUserId));
} catch (RemoteException e) {
}
- if (appId == -1) {
+ if (appId == -1 || (!hasKillAllPermission && appId != callingAppId)) {
Slog.w(TAG, "Invalid packageName: " + packageName);
return;
}
@@ -3875,6 +3887,22 @@
throw new SecurityException(msg);
}
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+
+ ProcessRecord proc;
+ synchronized (mPidsSelfLocked) {
+ proc = mPidsSelfLocked.get(callingPid);
+ }
+ if (callingUid >= FIRST_APPLICATION_UID
+ && (proc == null || !proc.info.isSystemApp())) {
+ final String msg = "Permission Denial: killAllBackgroundProcesses() from pid="
+ + callingPid + ", uid=" + callingUid + " is not allowed";
+ Slog.w(TAG, msg);
+ // Silently return to avoid existing apps from crashing.
+ return;
+ }
+
final long callingId = Binder.clearCallingIdentity();
try {
synchronized (this) {
@@ -13089,12 +13117,17 @@
public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,
String callerFeatureId, String receiverId, IIntentReceiver receiver,
IntentFilter filter, String permission, int userId, int flags) {
+ enforceNotIsolatedCaller("registerReceiver");
+
// Allow Sandbox process to register only unexported receivers.
- if ((flags & Context.RECEIVER_NOT_EXPORTED) != 0) {
- enforceNotIsolatedCaller("registerReceiver");
- } else if (mSdkSandboxSettings.isBroadcastReceiverRestrictionsEnforced()) {
- enforceNotIsolatedOrSdkSandboxCaller("registerReceiver");
+ boolean unexported = (flags & Context.RECEIVER_NOT_EXPORTED) != 0;
+ if (mSdkSandboxSettings.isBroadcastReceiverRestrictionsEnforced()
+ && Process.isSdkSandboxUid(Binder.getCallingUid())
+ && !unexported) {
+ throw new SecurityException("SDK sandbox process not allowed to call "
+ + "registerReceiver");
}
+
ArrayList<Intent> stickyIntents = null;
ProcessRecord callerApp = null;
final boolean visibleToInstantApps
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 2f95716..207c10c 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -21,7 +21,6 @@
import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE;
import android.annotation.NonNull;
-import android.app.AlarmManager;
import android.app.StatsManager;
import android.app.usage.NetworkStatsManager;
import android.bluetooth.BluetoothActivityEnergyInfo;
@@ -357,16 +356,6 @@
mStats.setRadioScanningTimeoutLocked(mContext.getResources().getInteger(
com.android.internal.R.integer.config_radioScanningTimeout) * 1000L);
mStats.setPowerProfileLocked(mPowerProfile);
-
- final boolean resetOnUnplugHighBatteryLevel = context.getResources().getBoolean(
- com.android.internal.R.bool.config_batteryStatsResetOnUnplugHighBatteryLevel);
- final boolean resetOnUnplugAfterSignificantCharge = context.getResources().getBoolean(
- com.android.internal.R.bool.config_batteryStatsResetOnUnplugAfterSignificantCharge);
- mStats.setBatteryStatsConfig(
- new BatteryStatsImpl.BatteryStatsConfig.Builder()
- .setResetOnUnplugHighBatteryLevel(resetOnUnplugHighBatteryLevel)
- .setResetOnUnplugAfterSignificantCharge(resetOnUnplugAfterSignificantCharge)
- .build());
mStats.startTrackingSystemServerCpuTime();
if (BATTERY_USAGE_STORE_ENABLED) {
@@ -397,18 +386,6 @@
Slog.e(TAG, "Could not register INetworkManagement event observer " + e);
}
- final AlarmManager am = mContext.getSystemService(AlarmManager.class);
- mHandler.post(() -> {
- synchronized (mStats) {
- mStats.setLongPlugInAlarmInterface(new AlarmInterface(am, () -> {
- synchronized (mStats) {
- if (mStats.isOnBattery()) return;
- mStats.maybeResetWhilePluggedInLocked();
- }
- }));
- }
- });
-
synchronized (mPowerStatsLock) {
mPowerStatsInternal = LocalServices.getService(PowerStatsInternal.class);
if (mPowerStatsInternal != null) {
@@ -2282,32 +2259,6 @@
}
}
- final class AlarmInterface implements BatteryStatsImpl.AlarmInterface,
- AlarmManager.OnAlarmListener {
- private AlarmManager mAm;
- private Runnable mOnAlarm;
-
- AlarmInterface(AlarmManager am, Runnable onAlarm) {
- mAm = am;
- mOnAlarm = onAlarm;
- }
-
- @Override
- public void schedule(long rtcTimeMs, long windowLengthMs) {
- mAm.setWindow(AlarmManager.RTC, rtcTimeMs, windowLengthMs, TAG, this, mHandler);
- }
-
- @Override
- public void cancel() {
- mAm.cancel(this);
- }
-
- @Override
- public void onAlarm() {
- mOnAlarm.run();
- }
- }
-
private static native int nativeWaitWakeup(ByteBuffer outBuffer);
private void dumpHelp(PrintWriter pw) {
@@ -2494,8 +2445,7 @@
} else if ("--reset-all".equals(arg)) {
awaitCompletion();
synchronized (mStats) {
- mStats.resetAllStatsAndHistoryLocked(
- BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ mStats.resetAllStatsCmdLocked();
mBatteryUsageStatsStore.removeAllSnapshots();
pw.println("Battery stats and history reset.");
noOutput = true;
@@ -2503,8 +2453,7 @@
} else if ("--reset".equals(arg)) {
awaitCompletion();
synchronized (mStats) {
- mStats.resetAllStatsAndHistoryLocked(
- BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ mStats.resetAllStatsCmdLocked();
pw.println("Battery stats reset.");
noOutput = true;
}
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 350aa6b..2a807b2 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -608,6 +608,9 @@
/* package */ void updateRunningUserAndProfiles(int newActiveUserId) {
synchronized (mLock) {
if (mCurrentActiveUserId != newActiveUserId) {
+ Slog.i(TAG, TextUtils.formatSimple(
+ "switchUser | user: %d", newActiveUserId));
+
mCurrentActiveUserId = newActiveUserId;
for (int i = 0; i < mUserRecords.size(); i++) {
int userId = mUserRecords.keyAt(i);
@@ -679,6 +682,10 @@
userRecord.mHandler.sendMessage(
obtainMessage(UserHandler::notifyRouterRegistered,
userRecord.mHandler, routerRecord));
+
+ Slog.i(TAG, TextUtils.formatSimple(
+ "registerRouter2 | package: %s, uid: %d, pid: %d, router: %d",
+ packageName, uid, pid, routerRecord.mRouterId));
}
@GuardedBy("mLock")
@@ -689,6 +696,11 @@
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "unregisterRouter2 | package: %s, router: %d",
+ routerRecord.mPackageName,
+ routerRecord.mRouterId));
+
UserRecord userRecord = routerRecord.mUserRecord;
userRecord.mRouterRecords.remove(routerRecord);
routerRecord.mUserRecord.mHandler.sendMessage(
@@ -707,6 +719,11 @@
if (routerRecord.mDiscoveryPreference.equals(discoveryRequest)) {
return;
}
+
+ Slog.i(TAG, TextUtils.formatSimple(
+ "setDiscoveryRequestWithRouter2 | router: %d, discovery request: %s",
+ routerRecord.mRouterId, discoveryRequest.toString()));
+
routerRecord.mDiscoveryPreference = discoveryRequest;
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::notifyDiscoveryPreferenceChangedToManagers,
@@ -724,6 +741,10 @@
RouterRecord routerRecord = mAllRouterRecords.get(binder);
if (routerRecord != null) {
+ Slog.i(TAG, TextUtils.formatSimple(
+ "setRouteVolumeWithRouter2 | router: %d, volume: %d",
+ routerRecord.mRouterId, volume));
+
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::setRouteVolumeOnHandler,
routerRecord.mUserRecord.mHandler,
@@ -804,6 +825,10 @@
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "selectRouteWithRouter2 | router: %d, route: %s",
+ routerRecord.mRouterId, route.getId()));
+
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::selectRouteOnHandler,
routerRecord.mUserRecord.mHandler,
@@ -819,6 +844,10 @@
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "deselectRouteWithRouter2 | router: %d, route: %s",
+ routerRecord.mRouterId, route.getId()));
+
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::deselectRouteOnHandler,
routerRecord.mUserRecord.mHandler,
@@ -834,6 +863,10 @@
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "transferToRouteWithRouter2 | router: %d, route: %s",
+ routerRecord.mRouterId, route.getId()));
+
String defaultRouteId =
routerRecord.mUserRecord.mHandler.mSystemProvider.getDefaultRoute().getId();
if (route.isSystemRoute() && !routerRecord.mHasModifyAudioRoutingPermission
@@ -859,6 +892,10 @@
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "setSessionVolumeWithRouter2 | router: %d, session: %s, volume: %d",
+ routerRecord.mRouterId, uniqueSessionId, volume));
+
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::setSessionVolumeOnHandler,
routerRecord.mUserRecord.mHandler,
@@ -874,6 +911,10 @@
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "releaseSessionWithRouter2 | router: %d, session: %s",
+ routerRecord.mRouterId, uniqueSessionId));
+
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::releaseSessionOnHandler,
routerRecord.mUserRecord.mHandler,
@@ -916,6 +957,10 @@
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "registerManager | uid: %d, pid: %d, package: %s, user: %d",
+ uid, pid, packageName, userId));
+
mContext.enforcePermission(Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid,
"Must hold MEDIA_CONTENT_CONTROL permission.");
@@ -951,6 +996,13 @@
return;
}
UserRecord userRecord = managerRecord.mUserRecord;
+
+ Slog.i(TAG, TextUtils.formatSimple(
+ "unregisterManager | package: %s, user: %d, manager: %d",
+ managerRecord.mPackageName,
+ userRecord.mUserId,
+ managerRecord.mManagerId));
+
userRecord.mManagerRecords.remove(managerRecord);
managerRecord.dispose();
disposeUserIfNeededLocked(userRecord); // since manager removed from user
@@ -962,6 +1014,10 @@
if (managerRecord == null) {
return;
}
+
+ Slog.i(TAG, TextUtils.formatSimple(
+ "startScan | manager: %d", managerRecord.mManagerId));
+
managerRecord.startScan();
}
@@ -971,6 +1027,10 @@
if (managerRecord == null) {
return;
}
+
+ Slog.i(TAG, TextUtils.formatSimple(
+ "stopScan | manager: %d", managerRecord.mManagerId));
+
managerRecord.stopScan();
}
@@ -984,6 +1044,10 @@
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "setRouteVolumeWithManager | manager: %d, route: %s, volume: %d",
+ managerRecord.mManagerId, route.getId(), volume));
+
long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
managerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::setRouteVolumeOnHandler,
@@ -999,6 +1063,10 @@
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "requestCreateSessionWithManager | manager: %d, route: %s",
+ managerRecord.mManagerId, route.getId()));
+
String packageName = oldSession.getClientPackageName();
RouterRecord routerRecord = managerRecord.mUserRecord.findRouterRecordLocked(packageName);
@@ -1044,6 +1112,10 @@
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "selectRouteWithManager | manager: %d, session: %s, route: %s",
+ managerRecord.mManagerId, uniqueSessionId, route.getId()));
+
// Can be null if the session is system's or RCN.
RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
.findRouterWithSessionLocked(uniqueSessionId);
@@ -1065,6 +1137,10 @@
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "deselectRouteWithManager | manager: %d, session: %s, route: %s",
+ managerRecord.mManagerId, uniqueSessionId, route.getId()));
+
// Can be null if the session is system's or RCN.
RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
.findRouterWithSessionLocked(uniqueSessionId);
@@ -1086,6 +1162,10 @@
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "transferToRouteWithManager | manager: %d, session: %s, route: %s",
+ managerRecord.mManagerId, uniqueSessionId, route.getId()));
+
// Can be null if the session is system's or RCN.
RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
.findRouterWithSessionLocked(uniqueSessionId);
@@ -1107,6 +1187,10 @@
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "setSessionVolumeWithManager | manager: %d, session: %s, volume: %d",
+ managerRecord.mManagerId, uniqueSessionId, volume));
+
long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
managerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::setSessionVolumeOnHandler,
@@ -1124,6 +1208,10 @@
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "releaseSessionWithManager | manager: %d, session: %s",
+ managerRecord.mManagerId, uniqueSessionId));
+
RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
.findRouterWithSessionLocked(uniqueSessionId);
@@ -1484,6 +1572,24 @@
List<IMediaRouter2> routersWithModifyAudioRoutingPermission = getRouters(true);
List<IMediaRouter2> routersWithoutModifyAudioRoutingPermission = getRouters(false);
+
+ if (!addedRoutes.isEmpty()) {
+ // If routes were added, currentInfo cannot be null.
+ Slog.i(TAG,
+ toLoggingMessage(
+ /* source= */ "addProviderRoutes",
+ currentInfo.getUniqueId(),
+ (ArrayList) addedRoutes));
+ }
+ if (!removedRoutes.isEmpty()) {
+ // If routes were removed, prevInfo cannot be null.
+ Slog.i(TAG,
+ toLoggingMessage(
+ /* source= */ "removeProviderRoutes",
+ prevInfo.getUniqueId(),
+ (ArrayList) removedRoutes));
+ }
+
List<IMediaRouter2Manager> managers = getManagers();
List<MediaRoute2Info> defaultRoute = new ArrayList<>();
defaultRoute.add(mSystemProvider.getDefaultRoute());
@@ -1522,6 +1628,16 @@
}
}
+ private static String toLoggingMessage(
+ String source, String providerId, ArrayList<MediaRoute2Info> routes) {
+ String routesString =
+ routes.stream()
+ .map(it -> String.format("%s | %s", it.getOriginalId(), it.getName()))
+ .collect(Collectors.joining(/* delimiter= */ ", "));
+ return TextUtils.formatSimple("%s | provider: %s, routes: [%s]",
+ source, providerId, routesString);
+ }
+
private int getLastProviderInfoIndex(@NonNull String providerId) {
for (int i = 0; i < mLastProviderInfos.size(); i++) {
MediaRoute2ProviderInfo providerInfo = mLastProviderInfos.get(i);
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index b75ba75..c5a337d 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -21,7 +21,9 @@
import android.media.Session2Token;
import android.media.session.MediaSession;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.Log;
+import android.util.Slog;
import android.util.SparseArray;
import java.io.PrintWriter;
@@ -82,6 +84,10 @@
* @param record The record to add.
*/
public void addSession(MediaSessionRecordImpl record) {
+ Slog.i(TAG, TextUtils.formatSimple(
+ "addSession to bottom of stack | record: %s",
+ record
+ ));
mSessions.add(record);
clearCache(record.getUserId());
@@ -97,6 +103,10 @@
* @param record The record to remove.
*/
public void removeSession(MediaSessionRecordImpl record) {
+ Slog.i(TAG, TextUtils.formatSimple(
+ "removeSession | record: %s",
+ record
+ ));
mSessions.remove(record);
if (mMediaButtonSession == record) {
// When the media button session is removed, nullify the media button session and do not
@@ -142,6 +152,10 @@
public void onPlaybackStateChanged(
MediaSessionRecordImpl record, boolean shouldUpdatePriority) {
if (shouldUpdatePriority) {
+ Slog.i(TAG, TextUtils.formatSimple(
+ "onPlaybackStateChanged - Pushing session to top | record: %s",
+ record
+ ));
mSessions.remove(record);
mSessions.add(0, record);
clearCache(record.getUserId());