Merge "Update the padding of MainSwitch layout and the MainSwitch's TextView margin to meet the spec." into sc-v2-dev
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index fca4c69..3712caed 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -1488,18 +1488,27 @@
mContext.getUserId());
if (fd != null) {
FileOutputStream fos = null;
- boolean ok = false;
+ final Bitmap tmp = BitmapFactory.decodeStream(resources.openRawResource(resid));
try {
- fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
- copyStreamToWallpaperFile(resources.openRawResource(resid), fos);
- // The 'close()' is the trigger for any server-side image manipulation,
- // so we must do that before waiting for completion.
- fos.close();
- completion.waitForCompletion();
+ // If the stream can't be decoded, treat it as an invalid input.
+ if (tmp != null) {
+ fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
+ tmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
+ // The 'close()' is the trigger for any server-side image manipulation,
+ // so we must do that before waiting for completion.
+ fos.close();
+ completion.waitForCompletion();
+ } else {
+ throw new IllegalArgumentException(
+ "Resource 0x" + Integer.toHexString(resid) + " is invalid");
+ }
} finally {
// Might be redundant but completion shouldn't wait unless the write
// succeeded; this is a fallback if it threw past the close+wait.
IoUtils.closeQuietly(fos);
+ if (tmp != null) {
+ tmp.recycle();
+ }
}
}
} catch (RemoteException e) {
@@ -1741,13 +1750,22 @@
result, which, completion, mContext.getUserId());
if (fd != null) {
FileOutputStream fos = null;
+ final Bitmap tmp = BitmapFactory.decodeStream(bitmapData);
try {
- fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
- copyStreamToWallpaperFile(bitmapData, fos);
- fos.close();
- completion.waitForCompletion();
+ // If the stream can't be decoded, treat it as an invalid input.
+ if (tmp != null) {
+ fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
+ tmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
+ fos.close();
+ completion.waitForCompletion();
+ } else {
+ throw new IllegalArgumentException("InputStream is invalid");
+ }
} finally {
IoUtils.closeQuietly(fos);
+ if (tmp != null) {
+ tmp.recycle();
+ }
}
}
} catch (RemoteException e) {
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 424632fe..6541b14 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -270,8 +270,6 @@
private Drawable mCaptionBackgroundDrawable;
private Drawable mUserCaptionBackgroundDrawable;
- private float mAvailableWidth;
-
String mLogTag = TAG;
private final Rect mFloatingInsets = new Rect();
private boolean mApplyFloatingVerticalInsets = false;
@@ -315,8 +313,6 @@
mSemiTransparentBarColor = context.getResources().getColor(
R.color.system_bar_background_semi_transparent, null /* theme */);
- updateAvailableWidth();
-
setWindow(window);
updateLogTag(params);
@@ -697,7 +693,8 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
+ final Resources res = getContext().getResources();
+ final DisplayMetrics metrics = res.getDisplayMetrics();
final boolean isPortrait =
getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT;
@@ -767,17 +764,19 @@
if (!fixedWidth && widthMode == AT_MOST) {
final TypedValue tv = isPortrait ? mWindow.mMinWidthMinor : mWindow.mMinWidthMajor;
+ final float availableWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ res.getConfiguration().screenWidthDp, metrics);
if (tv.type != TypedValue.TYPE_NULL) {
final int min;
if (tv.type == TypedValue.TYPE_DIMENSION) {
- min = (int)tv.getDimension(metrics);
+ min = (int) tv.getDimension(metrics);
} else if (tv.type == TypedValue.TYPE_FRACTION) {
- min = (int)tv.getFraction(mAvailableWidth, mAvailableWidth);
+ min = (int) tv.getFraction(availableWidth, availableWidth);
} else {
min = 0;
}
if (DEBUG_MEASURE) Log.d(mLogTag, "Adjust for min width: " + min + ", value::"
- + tv.coerceToString() + ", mAvailableWidth=" + mAvailableWidth);
+ + tv.coerceToString() + ", mAvailableWidth=" + availableWidth);
if (width < min) {
widthMeasureSpec = MeasureSpec.makeMeasureSpec(min, EXACTLY);
@@ -2144,7 +2143,6 @@
updateDecorCaptionStatus(newConfig);
- updateAvailableWidth();
initializeElevation();
}
@@ -2616,12 +2614,6 @@
mLogTag = TAG + "[" + getTitleSuffix(params) + "]";
}
- private void updateAvailableWidth() {
- Resources res = getResources();
- mAvailableWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- res.getConfiguration().screenWidthDp, res.getDisplayMetrics());
- }
-
/**
* @hide
*/
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index bf0dc7b..1343895 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -261,8 +261,6 @@
private void updateWifiState() {
state = mWifiManager.getWifiState();
enabled = state == WifiManager.WIFI_STATE_ENABLED;
- isCarrierMerged = false;
- subId = 0;
}
private void updateRssi(int newRssi) {
diff --git a/packages/SystemUI/res/drawable/ic_qs_drag_handle.xml b/packages/SystemUI/res/drawable/ic_qs_drag_handle.xml
deleted file mode 100644
index 9a69b33..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_drag_handle.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="36dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="?android:attr/textColorPrimary"
- android:pathData="M5.41,7.59L4,9l8,8 8,-8 -1.41,-1.41L12,14.17" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/media_output_dialog_button_background.xml b/packages/SystemUI/res/drawable/media_output_dialog_button_background.xml
index 363a022..eb08434 100644
--- a/packages/SystemUI/res/drawable/media_output_dialog_button_background.xml
+++ b/packages/SystemUI/res/drawable/media_output_dialog_button_background.xml
@@ -13,17 +13,20 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- android:shape="rectangle">
- <stroke
- android:color="?androidprv:attr/colorAccentPrimaryVariant"
- android:width="1dp"/>
- <corners android:radius="20dp"/>
- <padding
- android:left="16dp"
- android:right="16dp"
- android:top="8dp"
- android:bottom="8dp" />
- <solid android:color="@android:color/transparent" />
-</shape>
+ android:insetBottom="6dp"
+ android:insetTop="6dp">
+ <shape android:shape="rectangle">
+ <stroke
+ android:color="?androidprv:attr/colorAccentPrimaryVariant"
+ android:width="1dp"/>
+ <corners android:radius="20dp"/>
+ <padding
+ android:left="16dp"
+ android:right="16dp"
+ android:top="8dp"
+ android:bottom="8dp"/>
+ <solid android:color="@android:color/transparent"/>
+ </shape>
+</inset>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/media_output_dialog.xml b/packages/SystemUI/res/layout/media_output_dialog.xml
index a64ef3e..07fd1b0 100644
--- a/packages/SystemUI/res/layout/media_output_dialog.xml
+++ b/packages/SystemUI/res/layout/media_output_dialog.xml
@@ -24,9 +24,9 @@
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="96dp"
+ android:layout_height="wrap_content"
android:gravity="start|center_vertical"
- android:paddingStart="16dp"
+ android:paddingStart="24dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/header_icon"
@@ -36,7 +36,7 @@
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingTop="20dp"
android:paddingBottom="24dp"
@@ -59,7 +59,7 @@
android:gravity="center_vertical"
android:ellipsize="end"
android:maxLines="1"
- android:textColor="?android:attr/textColorTertiary"
+ android:textColor="?android:attr/textColorSecondary"
android:fontFamily="roboto-regular"
android:textSize="16sp"/>
</LinearLayout>
@@ -90,7 +90,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginStart="24dp"
- android:layout_marginBottom="18dp"
+ android:layout_marginBottom="24dp"
android:layout_marginEnd="24dp"
android:orientation="horizontal">
@@ -98,7 +98,7 @@
android:id="@+id/stop"
style="@style/MediaOutputRoundedOutlinedButton"
android:layout_width="wrap_content"
- android:layout_height="36dp"
+ android:layout_height="wrap_content"
android:minWidth="0dp"
android:text="@string/keyboard_key_media_stop"
android:visibility="gone"/>
@@ -112,7 +112,7 @@
android:id="@+id/done"
style="@style/MediaOutputRoundedOutlinedButton"
android:layout_width="wrap_content"
- android:layout_height="36dp"
+ android:layout_height="wrap_content"
android:minWidth="0dp"
android:text="@string/inline_done_button"/>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 2ac03c2..f5c6036 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -56,17 +56,4 @@
layout="@layout/qs_customize_panel"
android:visibility="gone" />
- <ImageView
- android:id="@+id/qs_drag_handle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:layout_marginTop="24dp"
- android:elevation="4dp"
- android:importantForAccessibility="no"
- android:scaleType="center"
- android:src="@drawable/ic_qs_drag_handle"
- android:tint="@color/qs_detail_button_white"
- tools:ignore="UseAppTint" />
-
</com.android.systemui.qs.QSContainerImpl>
diff --git a/packages/SystemUI/res/values-sw600dp-land/config.xml b/packages/SystemUI/res/values-sw600dp-land/config.xml
index 362e18d..dabc310 100644
--- a/packages/SystemUI/res/values-sw600dp-land/config.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/config.xml
@@ -18,11 +18,14 @@
<!-- Max number of columns for quick controls area -->
<integer name="controls_max_columns">2</integer>
+ <!-- The maximum number of rows in the QSPanel -->
+ <integer name="quick_settings_max_rows">3</integer>
+
<!-- The maximum number of rows in the QuickQSPanel -->
- <integer name="quick_qs_panel_max_rows">4</integer>
+ <integer name="quick_qs_panel_max_rows">3</integer>
<!-- The maximum number of tiles in the QuickQSPanel -->
- <integer name="quick_qs_panel_max_tiles">8</integer>
+ <integer name="quick_qs_panel_max_tiles">6</integer>
<!-- Whether to use the split 2-column notification shade -->
<bool name="config_use_split_notification_shade">true</bool>
diff --git a/packages/SystemUI/res/values-sw720dp-land/config.xml b/packages/SystemUI/res/values-sw720dp-land/config.xml
index e4573c6..e0b1614 100644
--- a/packages/SystemUI/res/values-sw720dp-land/config.xml
+++ b/packages/SystemUI/res/values-sw720dp-land/config.xml
@@ -18,11 +18,14 @@
<!-- Max number of columns for quick controls area -->
<integer name="controls_max_columns">2</integer>
+ <!-- The maximum number of rows in the QSPanel -->
+ <integer name="quick_settings_max_rows">3</integer>
+
<!-- The maximum number of rows in the QuickQSPanel -->
- <integer name="quick_qs_panel_max_rows">4</integer>
+ <integer name="quick_qs_panel_max_rows">3</integer>
<!-- The maximum number of tiles in the QuickQSPanel -->
- <integer name="quick_qs_panel_max_tiles">8</integer>
+ <integer name="quick_qs_panel_max_tiles">6</integer>
<!-- Whether to use the split 2-column notification shade -->
<bool name="config_use_split_notification_shade">true</bool>
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index f1deb30..e267c5c 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 = 200L; // 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,59 @@
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();
+ }
+
+ if (mVibrator != null) {
+ // play device entry haptic (same as biometric success haptic)
+ mVibrator.vibrate(
+ Process.myUid(),
+ getContext().getOpPackageName(),
+ UdfpsController.EFFECT_CLICK,
+ "lock-icon-device-entry",
+ VIBRATION_SONIFICATION_ATTRIBUTES);
+ }
+
+ 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/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index 03a0977..c12d48d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -63,13 +63,14 @@
View mDialogView;
private TextView mHeaderTitle;
private TextView mHeaderSubtitle;
- private ImageView mHeaderIcon;
private RecyclerView mDevicesRecyclerView;
private LinearLayout mDeviceListLayout;
private Button mDoneButton;
private Button mStopButton;
private int mListMaxHeight;
+ protected ImageView mHeaderIcon;
+
MediaOutputBaseAdapter mAdapter;
private final ViewTreeObserver.OnGlobalLayoutListener mDeviceListLayoutListener = () -> {
@@ -140,7 +141,6 @@
mMediaOutputController.stop();
}
- @VisibleForTesting
void refresh() {
// Update header icon
final int iconRes = getHeaderIconRes();
@@ -154,12 +154,6 @@
} else {
mHeaderIcon.setVisibility(View.GONE);
}
- if (mHeaderIcon.getVisibility() == View.VISIBLE) {
- final int size = getHeaderIconSize();
- final int padding = mContext.getResources().getDimensionPixelSize(
- R.dimen.media_output_dialog_header_icon_padding);
- mHeaderIcon.setLayoutParams(new LinearLayout.LayoutParams(size + padding, size));
- }
// Update title and subtitle
mHeaderTitle.setText(getHeaderText());
final CharSequence subTitle = getHeaderSubtitle();
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
index 1300400..b41e813 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
@@ -20,6 +20,7 @@
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
+import android.widget.LinearLayout;
import androidx.core.graphics.drawable.IconCompat;
@@ -76,6 +77,15 @@
}
@Override
+ void refresh() {
+ super.refresh();
+ final int size = getHeaderIconSize();
+ final int padding = mContext.getResources().getDimensionPixelSize(
+ R.dimen.media_output_dialog_header_icon_padding);
+ mHeaderIcon.setLayoutParams(new LinearLayout.LayoutParams(size + padding, size));
+ }
+
+ @Override
int getStopButtonVisibility() {
return View.VISIBLE;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index cdf770f..c3de3c5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -110,6 +110,16 @@
}
@Override
+ public int getTilesHeight() {
+ // Use the first page as that is the maximum height we need to show.
+ TileLayout tileLayout = mPages.get(0);
+ if (tileLayout == null) {
+ return 0;
+ }
+ return tileLayout.getTilesHeight();
+ }
+
+ @Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Pass configuration change to non-attached pages as well. Some config changes will cause
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 8588ddf..e230e1b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -27,7 +27,6 @@
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
-import android.widget.ImageView;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
@@ -53,7 +52,6 @@
private float mQsExpansion;
private QSCustomizer mQSCustomizer;
private NonInterceptingScrollView mQSPanelContainer;
- private ImageView mDragHandle;
private int mSideMargins;
private boolean mQsDisabled;
@@ -71,7 +69,6 @@
mQSDetail = findViewById(R.id.qs_detail);
mHeader = findViewById(R.id.header);
mQSCustomizer = findViewById(R.id.qs_customize);
- mDragHandle = findViewById(R.id.qs_drag_handle);
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
}
@@ -190,23 +187,14 @@
mQSDetail.setBottom(getTop() + scrollBottom);
int qsDetailBottomMargin = ((MarginLayoutParams) mQSDetail.getLayoutParams()).bottomMargin;
mQSDetail.setBottom(getTop() + scrollBottom - qsDetailBottomMargin);
- // Pin the drag handle to the bottom of the panel.
- mDragHandle.setTranslationY(scrollBottom - mDragHandle.getHeight());
}
protected int calculateContainerHeight() {
int heightOverride = mHeightOverride != -1 ? mHeightOverride : getMeasuredHeight();
// Need to add the dragHandle height so touches will be intercepted by it.
- int dragHandleHeight;
- if (mDragHandle.getVisibility() == VISIBLE) {
- dragHandleHeight = Math.round((1 - mQsExpansion) * mDragHandle.getHeight());
- } else {
- dragHandleHeight = 0;
- }
return mQSCustomizer.isCustomizing() ? mQSCustomizer.getHeight()
: Math.round(mQsExpansion * (heightOverride - mHeader.getHeight()))
- + mHeader.getHeight()
- + dragHandleHeight;
+ + mHeader.getHeight();
}
int calculateContainerBottom() {
@@ -221,8 +209,6 @@
public void setExpansion(float expansion) {
mQsExpansion = expansion;
mQSPanelContainer.setScrollingEnabled(expansion > 0f);
- mDragHandle.setAlpha(1.0f - expansion);
- mDragHandle.setClickable(expansion == 0f); // Only clickable when fully collapsed
updateExpansion();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index ee59ae6..e82e9d2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -33,7 +33,6 @@
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout.LayoutParams;
-import android.widget.ImageView;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
@@ -94,7 +93,6 @@
private float mLastPanelFraction;
private float mSquishinessFraction = 1;
private boolean mQsDisabled;
- private ImageView mQsDragHandler;
private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
private final CommandQueue mCommandQueue;
@@ -205,7 +203,6 @@
mHeader = view.findViewById(R.id.header);
mQSPanelController.setHeaderContainer(view.findViewById(R.id.header_text_container));
mFooter = qsFragmentComponent.getQSFooter();
- mQsDragHandler = view.findViewById(R.id.qs_drag_handle);
mQsDetailDisplayer.setQsPanelController(mQSPanelController);
@@ -249,11 +246,6 @@
mQSPanelController.getMediaHost().getHostView().setAlpha(1.0f);
mQSAnimator.requestAnimatorUpdate();
});
-
- mQsDragHandler.setOnClickListener(v -> {
- Log.d(TAG, "drag handler clicked");
- mCommandQueue.animateExpandSettingsPanel(null);
- });
}
@Override
@@ -385,30 +377,26 @@
}
private void updateQsState() {
- final boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling
+ final boolean expanded = mQsExpanded || mInSplitShade;
+ final boolean expandVisually = expanded || mStackScrollerOverscrolling
|| mHeaderAnimating;
- mQSPanelController.setExpanded(mQsExpanded);
- mQSDetail.setExpanded(mQsExpanded);
+ mQSPanelController.setExpanded(expanded);
+ mQSDetail.setExpanded(expanded);
boolean keyguardShowing = isKeyguardState();
- mHeader.setVisibility((mQsExpanded || !keyguardShowing || mHeaderAnimating
+ mHeader.setVisibility((expanded || !keyguardShowing || mHeaderAnimating
|| mShowCollapsedOnKeyguard)
? View.VISIBLE
: View.INVISIBLE);
mHeader.setExpanded((keyguardShowing && !mHeaderAnimating && !mShowCollapsedOnKeyguard)
- || (mQsExpanded && !mStackScrollerOverscrolling), mQuickQSPanelController);
- mFooter.setVisibility(!mQsDisabled && (mQsExpanded || !keyguardShowing || mHeaderAnimating
+ || (expanded && !mStackScrollerOverscrolling), mQuickQSPanelController);
+ mFooter.setVisibility(!mQsDisabled && (expanded || !keyguardShowing || mHeaderAnimating
|| mShowCollapsedOnKeyguard)
? View.VISIBLE
: View.INVISIBLE);
mFooter.setExpanded((keyguardShowing && !mHeaderAnimating && !mShowCollapsedOnKeyguard)
- || (mQsExpanded && !mStackScrollerOverscrolling));
+ || (expanded && !mStackScrollerOverscrolling));
mQSPanelController.setVisibility(
!mQsDisabled && expandVisually ? View.VISIBLE : View.INVISIBLE);
- mQsDragHandler.setVisibility((mQsExpanded || !keyguardShowing || mHeaderAnimating
- || mShowCollapsedOnKeyguard)
- && Utils.shouldUseSplitNotificationShade(getResources())
- ? View.VISIBLE
- : View.GONE);
}
private boolean isKeyguardState() {
@@ -418,7 +406,8 @@
}
private void updateShowCollapsedOnKeyguard() {
- boolean showCollapsed = mBypassController.getBypassEnabled() || mTransitioningToFullShade;
+ boolean showCollapsed = mBypassController.getBypassEnabled()
+ || (mTransitioningToFullShade && !mInSplitShade);
if (showCollapsed != mShowCollapsedOnKeyguard) {
mShowCollapsedOnKeyguard = showCollapsed;
updateQsState();
@@ -498,6 +487,8 @@
public void setInSplitShade(boolean inSplitShade) {
mInSplitShade = inSplitShade;
mQSAnimator.setTranslateWhileExpanding(inSplitShade);
+ updateShowCollapsedOnKeyguard();
+ updateQsState();
}
@Override
@@ -516,7 +507,8 @@
public void setQsExpansion(float expansion, float panelExpansionFraction,
float proposedTranslation, float squishinessFraction) {
float headerTranslation = mTransitioningToFullShade ? 0 : proposedTranslation;
- float progress = mTransitioningToFullShade ? mFullShadeProgress : panelExpansionFraction;
+ float progress = mTransitioningToFullShade || mState == StatusBarState.KEYGUARD
+ ? mFullShadeProgress : panelExpansionFraction;
setAlphaAnimationProgress(mInSplitShade ? progress : 1);
mContainer.setExpansion(expansion);
final float translationScaleY = (mInSplitShade
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index d69deef..20c0fdd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -258,13 +258,8 @@
}
private void updateViewPositions() {
- if (!(mTileLayout instanceof TileLayout)) {
- return;
- }
- TileLayout layout = (TileLayout) mTileLayout;
-
// Adjust view positions based on tile squishing
- int tileHeightOffset = layout.getTilesHeight() - layout.getHeight();
+ int tileHeightOffset = mTileLayout.getTilesHeight() - mTileLayout.getHeight();
boolean move = false;
for (int i = 0; i < getChildCount(); i++) {
@@ -787,6 +782,12 @@
/** */
void setListening(boolean listening, UiEventLogger uiEventLogger);
+ /** */
+ int getHeight();
+
+ /** */
+ int getTilesHeight();
+
/**
* Sets a size modifier for the tile. Where 0 means collapsed, and 1 expanded.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index 6794d5b..001c740e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -45,6 +45,7 @@
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.tuner.TunerService;
+import com.android.systemui.util.Utils;
import javax.inject.Inject;
import javax.inject.Named;
@@ -72,6 +73,7 @@
new QSPanel.OnConfigurationChangedListener() {
@Override
public void onConfigurationChange(Configuration newConfig) {
+ updateMediaExpansion();
mView.updateResources();
mQsSecurityFooter.onConfigurationChanged();
if (mView.isListening()) {
@@ -121,13 +123,17 @@
@Override
public void onInit() {
super.onInit();
- mMediaHost.setExpansion(1);
+ updateMediaExpansion();
mMediaHost.setShowsOnlyActiveMedia(false);
mMediaHost.init(MediaHierarchyManager.LOCATION_QS);
mQsCustomizerController.init();
mBrightnessSliderController.init();
}
+ private void updateMediaExpansion() {
+ mMediaHost.setExpansion(Utils.shouldUseSplitNotificationShade(getResources()) ? 0 : 1);
+ }
+
@Override
protected void onViewAttached() {
super.onViewAttached();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 7f08e5b..bff318a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -275,6 +275,7 @@
return Math.max(mColumns * mRows, 1);
}
+ @Override
public int getTilesHeight() {
return mLastTileBottom + getPaddingBottom();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index dca7f70..0fb08e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -174,7 +174,7 @@
internal fun canDragDown(): Boolean {
return (statusBarStateController.state == StatusBarState.KEYGUARD ||
nsslController.isInLockedDownShade()) &&
- qS.isFullyCollapsed
+ (qS.isFullyCollapsed || useSplitShade)
}
/**
@@ -285,7 +285,7 @@
internal val isDragDownAnywhereEnabled: Boolean
get() = (statusBarStateController.getState() == StatusBarState.KEYGUARD &&
!keyguardBypassController.bypassEnabled &&
- qS.isFullyCollapsed)
+ (qS.isFullyCollapsed || useSplitShade))
/**
* The amount in pixels that the user has dragged down.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java
index 103ca0e..ff9d919 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java
@@ -83,7 +83,7 @@
@Override
public void notifyListeners(SignalCallback callback) {
if (mCurrentState.isCarrierMerged) {
- if (mCurrentState.isDefault) {
+ if (mCurrentState.isDefault || !mNetworkController.isRadioOn()) {
notifyListenersForCarrierWifi(callback);
}
} else {
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/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 0312c30..20a771f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -2246,11 +2246,14 @@
private void updateQsExpansion() {
if (mQs == null) return;
- float qsExpansionFraction = computeQsExpansionFraction();
- float squishiness = mNotificationStackScrollLayoutController
- .getNotificationSquishinessFraction();
- mQs.setQsExpansion(qsExpansionFraction, getExpandedFraction(), getHeaderTranslation(),
- mQsExpandImmediate || mQsExpanded ? 1f : squishiness);
+ final float squishiness =
+ mQsExpandImmediate || mQsExpanded ? 1f : mNotificationStackScrollLayoutController
+ .getNotificationSquishinessFraction();
+ final float qsExpansionFraction = computeQsExpansionFraction();
+ final float adjustedExpansionFraction = mShouldUseSplitNotificationShade
+ ? 1f : computeQsExpansionFraction();
+ mQs.setQsExpansion(adjustedExpansionFraction, getExpandedFraction(), getHeaderTranslation(),
+ squishiness);
mSplitShadeHeaderController.setQsExpandedFraction(qsExpansionFraction);
mMediaHierarchyManager.setQsExpansion(qsExpansionFraction);
int qsPanelBottomY = calculateQsBottomPosition(qsExpansionFraction);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java
index a39971d..9f152e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java
@@ -269,6 +269,21 @@
}
@Test
+ public void testDisableWiFiWithVcnWithUnderlyingWifi() {
+ String testSsid = "Test VCN SSID";
+ setWifiEnabled(true);
+ verifyLastWifiIcon(false, WifiIcons.WIFI_NO_NETWORK);
+
+ mNetworkController.setNoNetworksAvailable(false);
+ setWifiStateForVcn(true, testSsid);
+ setWifiLevelForVcn(1);
+ verifyLastMobileDataIndicatorsForVcn(true, 1, TelephonyIcons.ICON_CWF, false);
+
+ setWifiEnabled(false);
+ verifyLastMobileDataIndicatorsForVcn(false, 1, 0, false);
+ }
+
+ @Test
public void testCallStrengh() {
if (true) return;
String testSsid = "Test SSID";
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 7dec4e7..51c3b33 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -77,6 +77,7 @@
import android.os.PowerManager.WakeLock;
import android.os.Process;
import android.os.SystemClock;
+import android.provider.Settings;
import android.util.ArraySet;
import android.util.Slog;
@@ -782,8 +783,19 @@
// TODO(b/179091925): Move the delayed-message handling to BaseState
// If underlying is null, all underlying networks have been lost. Disconnect VCN after a
- // timeout.
+ // timeout (or immediately if in airplane mode, since the device user has indicated that
+ // the radios should all be turned off).
if (underlying == null) {
+ if (mDeps.isAirplaneModeOn(mVcnContext)) {
+ sendMessageAndAcquireWakeLock(
+ EVENT_UNDERLYING_NETWORK_CHANGED,
+ TOKEN_ALL,
+ new EventUnderlyingNetworkChangedInfo(null));
+ sendDisconnectRequestedAndAcquireWakelock(
+ DISCONNECT_REASON_UNDERLYING_NETWORK_LOST, false /* shouldQuit */);
+ return;
+ }
+
setDisconnectRequestAlarm();
} else {
// Received a new Network so any previous alarm is irrelevant - cancel + clear it,
@@ -2414,6 +2426,12 @@
validationStatusCallback);
}
+ /** Checks if airplane mode is enabled. */
+ public boolean isAirplaneModeOn(@NonNull VcnContext vcnContext) {
+ return Settings.Global.getInt(vcnContext.getContext().getContentResolver(),
+ Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
+ }
+
/** Gets the elapsed real time since boot, in millis. */
public long getElapsedRealTime() {
return SystemClock.elapsedRealtime();
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index c9a8947a..7b5f0b1 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -118,6 +118,8 @@
@Test
public void testNullNetworkDoesNotTriggerDisconnect() throws Exception {
+ doReturn(false).when(mDeps).isAirplaneModeOn(any());
+
mGatewayConnection
.getUnderlyingNetworkTrackerCallback()
.onSelectedUnderlyingNetworkChanged(null);
@@ -129,6 +131,19 @@
}
@Test
+ public void testNullNetworkAirplaneModeDisconnects() throws Exception {
+ doReturn(true).when(mDeps).isAirplaneModeOn(any());
+
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(null);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+ verify(mIkeSession).kill();
+ }
+
+ @Test
public void testNewNetworkTriggersMigration() throws Exception {
mGatewayConnection
.getUnderlyingNetworkTrackerCallback()