Merge "Immediately tear down VCN network when entering Airplane Mode" into sc-v2-dev
diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java
index 046232a..2dac81c 100644
--- a/core/java/android/view/RemoteAnimationTarget.java
+++ b/core/java/android/view/RemoteAnimationTarget.java
@@ -129,7 +129,11 @@
* The index of the element in the tree in prefix order. This should be used for z-layering
* to preserve original z-layer order in the hierarchy tree assuming no "boosting" needs to
* happen.
+ * @deprecated WindowManager may set a z-order different from the prefix order, and has set the
+ * correct layer for the animation leash already, so this should not be used for
+ * layer any more.
*/
+ @Deprecated
@UnsupportedAppUsage
public final int prefixOrderIndex;
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index 7020603..fb80f1c 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -436,7 +436,6 @@
.withAlpha(1f)
.withMatrix(matrix)
.withWindowCrop(windowCrop)
- .withLayer(window.prefixOrderIndex)
.withCornerRadius(cornerRadius)
.withVisibility(true)
.build()
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index f1deb30..60cc57d 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -35,13 +35,14 @@
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.media.AudioAttributes;
import android.os.Process;
+import android.os.VibrationEffect;
import android.os.Vibrator;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.util.MathUtils;
-import android.view.GestureDetector;
-import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.LayoutInflater;
import android.view.MotionEvent;
+import android.view.VelocityTracker;
import android.view.View;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
@@ -83,6 +84,7 @@
*/
@StatusBarComponent.StatusBarScope
public class LockIconViewController extends ViewController<LockIconView> implements Dumpable {
+ private static final String TAG = "LockIconViewController";
private static final float sDefaultDensity =
(float) DisplayMetrics.DENSITY_DEVICE_STABLE / (float) DisplayMetrics.DENSITY_DEFAULT;
private static final int sLockIconRadiusPx = (int) (sDefaultDensity * 36);
@@ -91,6 +93,7 @@
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.build();
+ private static final long LONG_PRESS_TIMEOUT = 150L; // milliseconds
@NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@NonNull private final KeyguardViewController mKeyguardViewController;
@@ -112,6 +115,12 @@
@Nullable private final Vibrator mVibrator;
@Nullable private final AuthRippleController mAuthRippleController;
+ // Tracks the velocity of a touch to help filter out the touches that move too fast.
+ private VelocityTracker mVelocityTracker;
+ // The ID of the pointer for which ACTION_DOWN has occurred. -1 means no pointer is active.
+ private int mActivePointerId = -1;
+ private VibrationEffect mTick;
+
private boolean mIsDozing;
private boolean mIsBouncerShowing;
private boolean mRunningFPS;
@@ -122,6 +131,7 @@
private boolean mUserUnlockedWithBiometric;
private Runnable mCancelDelayedUpdateVisibilityRunnable;
private Runnable mOnGestureDetectedRunnable;
+ private Runnable mLongPressCancelRunnable;
private boolean mUdfpsSupported;
private float mHeightPixels;
@@ -181,7 +191,7 @@
mView.setImageDrawable(mIcon);
mUnlockedLabel = resources.getString(R.string.accessibility_unlock_button);
mLockedLabel = resources.getString(R.string.accessibility_lock_icon);
- dumpManager.registerDumpable("LockIconViewController", this);
+ dumpManager.registerDumpable(TAG, this);
}
@Override
@@ -320,7 +330,7 @@
getResources().getString(R.string.accessibility_enter_hint));
public void onInitializeAccessibilityNodeInfo(View v, AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(v, info);
- if (isClickable()) {
+ if (isActionable()) {
if (mShowLockIcon) {
info.addAction(mAccessibilityAuthenticateHint);
} else if (mShowUnlockIcon) {
@@ -475,7 +485,7 @@
@Override
public void onKeyguardVisibilityChanged(boolean showing) {
// reset mIsBouncerShowing state in case it was preemptively set
- // onAffordanceClick
+ // onLongPress
mIsBouncerShowing = mKeyguardViewController.isBouncerShowing();
updateVisibility();
}
@@ -569,104 +579,79 @@
}
};
- private final GestureDetector mGestureDetector =
- new GestureDetector(new SimpleOnGestureListener() {
- public boolean onDown(MotionEvent e) {
- if (!isClickable()) {
- mDownDetected = false;
- return false;
- }
-
- // intercept all following touches until we see MotionEvent.ACTION_CANCEL UP or
- // MotionEvent.ACTION_UP (see #onTouchEvent)
- if (mVibrator != null && !mDownDetected) {
- mVibrator.vibrate(
- Process.myUid(),
- getContext().getOpPackageName(),
- UdfpsController.EFFECT_CLICK,
- "lockIcon-onDown",
- VIBRATION_SONIFICATION_ATTRIBUTES);
- }
-
- mDownDetected = true;
- return true;
- }
-
- public void onLongPress(MotionEvent e) {
- if (!wasClickableOnDownEvent()) {
- return;
- }
-
- if (onAffordanceClick() && mVibrator != null) {
- // only vibrate if the click went through and wasn't intercepted by falsing
- mVibrator.vibrate(
- Process.myUid(),
- getContext().getOpPackageName(),
- UdfpsController.EFFECT_CLICK,
- "lockIcon-onLongPress",
- VIBRATION_SONIFICATION_ATTRIBUTES);
- }
- }
-
- public boolean onSingleTapUp(MotionEvent e) {
- if (!wasClickableOnDownEvent()) {
- return false;
- }
- onAffordanceClick();
- return true;
- }
-
- public boolean onFling(MotionEvent e1, MotionEvent e2,
- float velocityX, float velocityY) {
- if (!wasClickableOnDownEvent()) {
- return false;
- }
- onAffordanceClick();
- return true;
- }
-
- private boolean wasClickableOnDownEvent() {
- return mDownDetected;
- }
-
- /**
- * Whether we tried to launch the affordance.
- *
- * If falsing intercepts the click, returns false.
- */
- private boolean onAffordanceClick() {
- if (mFalsingManager.isFalseTouch(LOCK_ICON)) {
- return false;
- }
-
- // pre-emptively set to true to hide view
- mIsBouncerShowing = true;
- if (mUdfpsSupported && mShowUnlockIcon && mAuthRippleController != null) {
- mAuthRippleController.showRipple(FINGERPRINT);
- }
- updateVisibility();
- if (mOnGestureDetectedRunnable != null) {
- mOnGestureDetectedRunnable.run();
- }
- mKeyguardViewController.showBouncer(/* scrim */ true);
- return true;
- }
- });
-
/**
- * Send touch events to this view and handles it if the touch is within this view and we are
- * in a 'clickable' state
- * @return whether to intercept the touch event
+ * Handles the touch if it is within the lock icon view and {@link #isActionable()} is true.
+ * Subsequently, will trigger {@link #onLongPress()} if a touch is continuously in the lock icon
+ * area for {@link #LONG_PRESS_TIMEOUT} ms.
+ *
+ * Touch speed debouncing mimics logic from the velocity tracker in {@link UdfpsController}.
*/
public boolean onTouchEvent(MotionEvent event, Runnable onGestureDetectedRunnable) {
- if (onInterceptTouchEvent(event)) {
- mOnGestureDetectedRunnable = onGestureDetectedRunnable;
- mGestureDetector.onTouchEvent(event);
- return true;
+ if (!onInterceptTouchEvent(event)) {
+ cancelTouches();
+ return false;
}
- mDownDetected = false;
- return false;
+ mOnGestureDetectedRunnable = onGestureDetectedRunnable;
+ switch(event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_HOVER_ENTER:
+ if (mVibrator != null && !mDownDetected) {
+ if (mTick == null) {
+ mTick = UdfpsController.lowTick(getContext(), true,
+ LONG_PRESS_TIMEOUT);
+ }
+ mVibrator.vibrate(
+ Process.myUid(),
+ getContext().getOpPackageName(),
+ mTick,
+ "lock-icon-tick",
+ VIBRATION_SONIFICATION_ATTRIBUTES);
+ }
+
+ // The pointer that causes ACTION_DOWN is always at index 0.
+ // We need to persist its ID to track it during ACTION_MOVE that could include
+ // data for many other pointers because of multi-touch support.
+ mActivePointerId = event.getPointerId(0);
+ if (mVelocityTracker == null) {
+ // To simplify the lifecycle of the velocity tracker, make sure it's never null
+ // after ACTION_DOWN, and always null after ACTION_CANCEL or ACTION_UP.
+ mVelocityTracker = VelocityTracker.obtain();
+ } else {
+ // ACTION_UP or ACTION_CANCEL is not guaranteed to be called before a new
+ // ACTION_DOWN, in that case we should just reuse the old instance.
+ mVelocityTracker.clear();
+ }
+ mVelocityTracker.addMovement(event);
+
+ mDownDetected = true;
+ mLongPressCancelRunnable = mExecutor.executeDelayed(
+ this::onLongPress, LONG_PRESS_TIMEOUT);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ case MotionEvent.ACTION_HOVER_MOVE:
+ mVelocityTracker.addMovement(event);
+ // Compute pointer velocity in pixels per second.
+ mVelocityTracker.computeCurrentVelocity(1000);
+ float velocity = UdfpsController.computePointerSpeed(mVelocityTracker,
+ mActivePointerId);
+ if (event.getClassification() != MotionEvent.CLASSIFICATION_DEEP_PRESS
+ && UdfpsController.exceedsVelocityThreshold(velocity)) {
+ Log.v(TAG, "lock icon long-press rescheduled due to "
+ + "high pointer velocity=" + velocity);
+ mLongPressCancelRunnable.run();
+ mLongPressCancelRunnable = mExecutor.executeDelayed(
+ this::onLongPress, LONG_PRESS_TIMEOUT);
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_HOVER_EXIT:
+ cancelTouches();
+ break;
+ }
+
+ return true;
}
/**
@@ -674,7 +659,7 @@
* bounds.
*/
public boolean onInterceptTouchEvent(MotionEvent event) {
- if (!inLockIconArea(event) || !isClickable()) {
+ if (!inLockIconArea(event) || !isActionable()) {
return false;
}
@@ -685,13 +670,48 @@
return mDownDetected;
}
+ private void onLongPress() {
+ cancelTouches();
+ if (mFalsingManager.isFalseTouch(LOCK_ICON)) {
+ Log.v(TAG, "lock icon long-press rejected by the falsing manager.");
+ return;
+ }
+
+ // pre-emptively set to true to hide view
+ mIsBouncerShowing = true;
+ if (mUdfpsSupported && mShowUnlockIcon && mAuthRippleController != null) {
+ mAuthRippleController.showRipple(FINGERPRINT);
+ }
+ updateVisibility();
+ if (mOnGestureDetectedRunnable != null) {
+ mOnGestureDetectedRunnable.run();
+ }
+ mKeyguardViewController.showBouncer(/* scrim */ true);
+ }
+
+
+ private void cancelTouches() {
+ mDownDetected = false;
+ if (mLongPressCancelRunnable != null) {
+ mLongPressCancelRunnable.run();
+ }
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
+ if (mVibrator != null) {
+ mVibrator.cancel();
+ }
+ }
+
+
private boolean inLockIconArea(MotionEvent event) {
return mSensorTouchLocation.contains((int) event.getX(), (int) event.getY())
&& (mView.getVisibility() == View.VISIBLE
|| (mAodFp != null && mAodFp.getVisibility() == View.VISIBLE));
}
- private boolean isClickable() {
+ private boolean isActionable() {
return mUdfpsSupported || mShowUnlockIcon;
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 09f2af4..9808045 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -103,6 +103,7 @@
public class UdfpsController implements DozeReceiver {
private static final String TAG = "UdfpsController";
private static final long AOD_INTERRUPT_TIMEOUT_MILLIS = 1000;
+ private static final long DEFAULT_VIBRATION_DURATION = 1000; // milliseconds
// Minimum required delay between consecutive touch logs in milliseconds.
private static final long MIN_TOUCH_LOG_INTERVAL = 50;
@@ -164,8 +165,7 @@
private boolean mAttemptedToDismissKeyguard;
private Set<Callback> mCallbacks = new HashSet<>();
- // by default, use low tick
- private int mPrimitiveTick = VibrationEffect.Composition.PRIMITIVE_LOW_TICK;
+ private static final int DEFAULT_TICK = VibrationEffect.Composition.PRIMITIVE_LOW_TICK;
private final VibrationEffect mTick;
@VisibleForTesting
@@ -327,12 +327,23 @@
}
}
- private static float computePointerSpeed(@NonNull VelocityTracker tracker, int pointerId) {
+ /**
+ * Calculate the pointer speed given a velocity tracker and the pointer id.
+ * This assumes that the velocity tracker has already been passed all relevant motion events.
+ */
+ public static float computePointerSpeed(@NonNull VelocityTracker tracker, int pointerId) {
final float vx = tracker.getXVelocity(pointerId);
final float vy = tracker.getYVelocity(pointerId);
return (float) Math.sqrt(Math.pow(vx, 2.0) + Math.pow(vy, 2.0));
}
+ /**
+ * Whether the velocity exceeds the acceptable UDFPS debouncing threshold.
+ */
+ public static boolean exceedsVelocityThreshold(float velocity) {
+ return velocity > 750f;
+ }
+
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -467,7 +478,7 @@
final float v = computePointerSpeed(mVelocityTracker, mActivePointerId);
final float minor = event.getTouchMinor(idx);
final float major = event.getTouchMajor(idx);
- final boolean exceedsVelocityThreshold = v > 750f;
+ final boolean exceedsVelocityThreshold = exceedsVelocityThreshold(v);
final String touchInfo = String.format(
"minor: %.1f, major: %.1f, v: %.1f, exceedsVelocityThreshold: %b",
minor, major, v, exceedsVelocityThreshold);
@@ -575,7 +586,7 @@
mConfigurationController = configurationController;
mSystemClock = systemClock;
mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
- mTick = lowTick();
+ mTick = lowTick(context, false /* useShortRampup */, DEFAULT_VIBRATION_DURATION);
mSensorProps = findFirstUdfps();
// At least one UDFPS sensor exists
@@ -610,32 +621,43 @@
udfpsHapticsSimulator.setUdfpsController(this);
}
- private VibrationEffect lowTick() {
- boolean useLowTickDefault = mContext.getResources()
+ /**
+ * Returns the continuous low tick effect that starts playing on the udfps finger-down event.
+ */
+ public static VibrationEffect lowTick(
+ Context context,
+ boolean useShortRampUp,
+ long duration
+ ) {
+ boolean useLowTickDefault = context.getResources()
.getBoolean(R.bool.config_udfpsUseLowTick);
+ int primitiveTick = DEFAULT_TICK;
if (Settings.Global.getFloat(
- mContext.getContentResolver(),
+ context.getContentResolver(),
"tick-low", useLowTickDefault ? 1 : 0) == 0) {
- mPrimitiveTick = VibrationEffect.Composition.PRIMITIVE_TICK;
+ primitiveTick = VibrationEffect.Composition.PRIMITIVE_TICK;
}
float tickIntensity = Settings.Global.getFloat(
- mContext.getContentResolver(),
+ context.getContentResolver(),
"tick-intensity",
- mContext.getResources().getFloat(R.dimen.config_udfpsTickIntensity));
+ context.getResources().getFloat(R.dimen.config_udfpsTickIntensity));
int tickDelay = Settings.Global.getInt(
- mContext.getContentResolver(),
+ context.getContentResolver(),
"tick-delay",
- mContext.getResources().getInteger(R.integer.config_udfpsTickDelay));
+ context.getResources().getInteger(R.integer.config_udfpsTickDelay));
VibrationEffect.Composition composition = VibrationEffect.startComposition();
- composition.addPrimitive(mPrimitiveTick, tickIntensity, 0);
- int primitives = 1000 / tickDelay;
+ composition.addPrimitive(primitiveTick, tickIntensity, 0);
+ int primitives = (int) (duration / tickDelay);
float[] rampUp = new float[]{.48f, .58f, .69f, .83f};
+ if (useShortRampUp) {
+ rampUp = new float[]{.5f, .7f};
+ }
for (int i = 0; i < rampUp.length; i++) {
- composition.addPrimitive(mPrimitiveTick, tickIntensity * rampUp[i], tickDelay);
+ composition.addPrimitive(primitiveTick, tickIntensity * rampUp[i], tickDelay);
}
for (int i = rampUp.length; i < primitives; i++) {
- composition.addPrimitive(mPrimitiveTick, tickIntensity, tickDelay);
+ composition.addPrimitive(primitiveTick, tickIntensity, tickDelay);
}
return composition.compose();
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java
index 71edbc0..d17eadd 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java
@@ -19,6 +19,7 @@
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DIAGONAL_HORIZONTAL_ANGLE_RANGE;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DIAGONAL_VERTICAL_ANGLE_RANGE;
import static com.android.systemui.classifier.Classifier.LEFT_AFFORDANCE;
+import static com.android.systemui.classifier.Classifier.LOCK_ICON;
import static com.android.systemui.classifier.Classifier.RIGHT_AFFORDANCE;
import android.provider.DeviceConfig;
@@ -71,7 +72,9 @@
return Result.passed(0);
}
- if (interactionType == LEFT_AFFORDANCE || interactionType == RIGHT_AFFORDANCE) {
+ if (interactionType == LEFT_AFFORDANCE
+ || interactionType == RIGHT_AFFORDANCE
+ || interactionType == LOCK_ICON) {
return Result.passed(0);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index ab08865..5477c19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -119,6 +119,7 @@
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@@ -726,38 +727,59 @@
}
if (DEBUG) {
- int y = mTopPadding;
- mDebugPaint.setColor(Color.RED);
- canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
-
- y = getLayoutHeight();
- mDebugPaint.setColor(Color.YELLOW);
- canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
-
- y = (int) mMaxLayoutHeight;
- mDebugPaint.setColor(Color.MAGENTA);
- canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
-
- if (mKeyguardBottomPadding >= 0) {
- y = getHeight() - (int) mKeyguardBottomPadding;
- mDebugPaint.setColor(Color.GRAY);
- canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
- }
-
- y = getHeight() - getEmptyBottomMargin();
- mDebugPaint.setColor(Color.GREEN);
- canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
-
- y = (int) (mAmbientState.getStackY());
- mDebugPaint.setColor(Color.CYAN);
- canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
-
- y = (int) (mAmbientState.getStackY() + mAmbientState.getStackHeight());
- mDebugPaint.setColor(Color.BLUE);
- canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
+ onDrawDebug(canvas);
}
}
+ /** Used to track the Y positions that were already used to draw debug text labels. */
+ private static final Set<Integer> DEBUG_TEXT_USED_Y_POSITIONS =
+ DEBUG ? new HashSet<>() : Collections.emptySet();
+
+ private void onDrawDebug(Canvas canvas) {
+ DEBUG_TEXT_USED_Y_POSITIONS.clear();
+
+ int y = mTopPadding;
+ drawDebugInfo(canvas, y, Color.RED, /* label= */ "mTopPadding");
+
+ y = getLayoutHeight();
+ drawDebugInfo(canvas, y, Color.YELLOW, /* label= */ "getLayoutHeight()");
+
+ y = (int) mMaxLayoutHeight;
+ drawDebugInfo(canvas, y, Color.MAGENTA, /* label= */ "mMaxLayoutHeight");
+
+ if (mKeyguardBottomPadding >= 0) {
+ y = getHeight() - (int) mKeyguardBottomPadding;
+ drawDebugInfo(canvas, y, Color.GRAY,
+ /* label= */ "getHeight() - mKeyguardBottomPadding");
+ }
+
+ y = getHeight() - getEmptyBottomMargin();
+ drawDebugInfo(canvas, y, Color.GREEN, /* label= */ "getHeight() - getEmptyBottomMargin()");
+
+ y = (int) (mAmbientState.getStackY());
+ drawDebugInfo(canvas, y, Color.CYAN, /* label= */ "mAmbientState.getStackY()");
+
+ y = (int) (mAmbientState.getStackY() + mAmbientState.getStackHeight());
+ drawDebugInfo(canvas, y, Color.BLUE,
+ /* label= */ "mAmbientState.getStackY() + mAmbientState.getStackHeight()");
+ }
+
+ private void drawDebugInfo(Canvas canvas, int y, int color, String label) {
+ mDebugPaint.setColor(color);
+ canvas.drawLine(/* startX= */ 0, /* startY= */ y, /* stopX= */ getWidth(), /* stopY= */ y,
+ mDebugPaint);
+ canvas.drawText(label, /* x= */ 0, /* y= */ computeDebugYTextPosition(y), mDebugPaint);
+ }
+
+ private int computeDebugYTextPosition(int lineY) {
+ int textY = lineY;
+ while (DEBUG_TEXT_USED_Y_POSITIONS.contains(textY)) {
+ textY = (int) (textY + mDebugPaint.getTextSize());
+ }
+ DEBUG_TEXT_USED_Y_POSITIONS.add(textY);
+ return textY;
+ }
+
@ShadeViewRefactor(RefactorComponent.DECORATOR)
private void drawBackground(Canvas canvas) {
int lockScreenLeft = mSidePaddings;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ba11e9c..7a70bfe 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -24299,24 +24299,24 @@
}
enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
true /* checkShell */, "stop package");
- boolean shouldUnhibernate = false;
// writer
synchronized (mLock) {
final PackageSetting ps = mSettings.getPackageLPr(packageName);
- if (ps != null && ps.getStopped(userId) && !stopped) {
- shouldUnhibernate = true;
- }
if (!shouldFilterApplicationLocked(ps, callingUid, userId)
&& mSettings.setPackageStoppedStateLPw(this, packageName, stopped, userId)) {
scheduleWritePackageRestrictionsLocked(userId);
}
}
- if (shouldUnhibernate) {
+ // If this would cause the app to leave force-stop, then also make sure to unhibernate the
+ // app if needed.
+ if (!stopped) {
mHandler.post(() -> {
AppHibernationManagerInternal ah =
mInjector.getLocalService(AppHibernationManagerInternal.class);
- ah.setHibernatingForUser(packageName, userId, false);
- ah.setHibernatingGlobally(packageName, false);
+ if (ah != null && ah.isHibernatingForUser(packageName, userId)) {
+ ah.setHibernatingForUser(packageName, userId, false);
+ ah.setHibernatingGlobally(packageName, false);
+ }
});
}
}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 2be29d4..dfff76d 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -50,6 +50,10 @@
import static android.util.MathUtils.constrain;
import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
+import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON;
+import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_FLOATING_MENU;
+import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_GESTURE;
+import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__UNKNOWN_TYPE;
import static com.android.internal.util.FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER__OPPORTUNISTIC_DATA_SUB__NOT_OPPORTUNISTIC;
import static com.android.internal.util.FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER__OPPORTUNISTIC_DATA_SUB__OPPORTUNISTIC;
import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__GEO;
@@ -4387,8 +4391,9 @@
final int userId = userInfo.getUserHandle().getIdentifier();
if (isAccessibilityShortcutUser(mContext, userId)) {
- final int software_shortcut_type = Settings.Secure.getIntForUser(resolver,
- Settings.Secure.ACCESSIBILITY_BUTTON_MODE, 0, userId);
+ final int software_shortcut_type = convertToAccessibilityShortcutType(
+ Settings.Secure.getIntForUser(resolver,
+ Settings.Secure.ACCESSIBILITY_BUTTON_MODE, 0, userId));
final String software_shortcut_list = Settings.Secure.getStringForUser(resolver,
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, userId);
final int software_shortcut_service_num = countAccessibilityServices(
@@ -4509,6 +4514,19 @@
&& !TextUtils.isEmpty(software_string);
}
+ private int convertToAccessibilityShortcutType(int shortcutType) {
+ switch (shortcutType) {
+ case Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR:
+ return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON;
+ case Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU:
+ return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_FLOATING_MENU;
+ case Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE:
+ return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_GESTURE;
+ default:
+ return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__UNKNOWN_TYPE;
+ }
+ }
+
// Thermal event received from vendor thermal management subsystem
private static final class ThermalEventListener extends IThermalEventListener.Stub {
@Override
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
index fd97557..e053dc3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
@@ -29,6 +29,7 @@
import com.android.server.apphibernation.AppHibernationService
import com.android.server.extendedtestutils.wheneverStatic
import com.android.server.testutils.whenever
+import org.junit.Assert
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
@@ -100,8 +101,11 @@
rule.system().dataAppDirectory)
val pm = createPackageManagerService()
rule.system().validateFinalState()
- val ps = pm.getPackageSetting(TEST_PACKAGE_NAME)
- ps!!.setStopped(true, TEST_USER_ID)
+
+ TestableLooper.get(this).processAllMessages()
+
+ whenever(appHibernationManager.isHibernatingForUser(TEST_PACKAGE_NAME, TEST_USER_ID))
+ .thenReturn(true)
pm.setPackageStoppedState(TEST_PACKAGE_NAME, false, TEST_USER_ID)
@@ -112,6 +116,31 @@
}
@Test
+ fun testExitForceStop_nonExistingAppHibernationManager_doesNotThrowException() {
+ whenever(rule.mocks().injector.getLocalService(AppHibernationManagerInternal::class.java))
+ .thenReturn(null)
+
+ rule.system().stageScanExistingPackage(
+ TEST_PACKAGE_NAME,
+ 1L,
+ rule.system().dataAppDirectory)
+ val pm = createPackageManagerService()
+ rule.system().validateFinalState()
+
+ TestableLooper.get(this).processAllMessages()
+
+ whenever(appHibernationManager.isHibernatingForUser(TEST_PACKAGE_NAME, TEST_USER_ID))
+ .thenReturn(true)
+
+ try {
+ pm.setPackageStoppedState(TEST_PACKAGE_NAME, false, TEST_USER_ID)
+ TestableLooper.get(this).processAllMessages()
+ } catch (e: Exception) {
+ Assert.fail("Method throws exception when AppHibernationManager is not ready.\n$e")
+ }
+ }
+
+ @Test
fun testGetOptimizablePackages_ExcludesGloballyHibernatingPackages() {
rule.system().stageScanExistingPackage(
TEST_PACKAGE_NAME,