Merge "DO NOT MERGE Hold onto NotificationListener when reconnecting notifications UI." into qt-qpr1-dev
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 4b4b73d..5d240f1 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -485,6 +485,15 @@
// CarFacetButtonController was reset therefore we need to re-add the status bar elements
// to the controller.
mCarFacetButtonController.addAllFacetButtons(mStatusBarWindow);
+
+ // Upon restarting the Navigation Bar, CarFacetButtonController should immediately apply the
+ // selection state that reflects the current task stack.
+ try {
+ mCarFacetButtonController.taskChanged(
+ ActivityTaskManager.getService().getAllStackInfos());
+ } catch (Exception e) {
+ Log.e(TAG, "Getting StackInfo from activity manager failed", e);
+ }
}
private void addTemperatureViewToController(View v) {
diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
index f91c90e..b87844e 100644
--- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -26,8 +26,11 @@
import android.car.Car;
import android.car.Car.CarServiceLifecycleListener;
import android.car.media.CarAudioManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.Color;
@@ -39,6 +42,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.UserHandle;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
@@ -175,6 +179,17 @@
mCarAudioManager.registerCarVolumeCallback(mVolumeChangeCallback);
};
+ private final BroadcastReceiver mHomeButtonPressedBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!intent.getAction().equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
+ return;
+ }
+
+ dismiss(Events.DISMISS_REASON_VOLUME_CONTROLLER);
+ }
+ };
+
public CarVolumeDialogImpl(Context context) {
mContext = context;
mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
@@ -204,6 +219,10 @@
public void init(int windowType, Callback callback) {
initDialog();
+ mContext.registerReceiverAsUser(mHomeButtonPressedBroadcastReceiver, UserHandle.CURRENT,
+ new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), /* broadcastPermission= */
+ null, /* scheduler= */ null);
+
((CarSystemUIFactory) SystemUIFactory.getInstance()).getCarServiceProvider(mContext)
.addListener(mCarServiceLifecycleListener);
}
@@ -212,6 +231,8 @@
public void destroy() {
mHandler.removeCallbacksAndMessages(/* token= */ null);
+ mContext.unregisterReceiver(mHomeButtonPressedBroadcastReceiver);
+
cleanupAudioManager();
}
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 4fae3c5..f8db97d 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -24,7 +24,6 @@
android:layout_width="match_parent"
android:layout_height="@dimen/status_bar_height"
android:id="@+id/status_bar"
- android:background="@drawable/system_bar_background"
android:orientation="vertical"
android:focusable="false"
android:descendantFocusability="afterDescendants"
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index a9149300..9d56e08 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -54,7 +54,8 @@
<FrameLayout
android:id="@+id/status_bar_container"
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:background="@drawable/system_bar_background" />
<include layout="@layout/status_bar_expanded"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 78318cb..6758efa 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -201,6 +201,14 @@
always-on display) -->
<string name="doze_brightness_sensor_type" translatable="false"></string>
+ <!-- Override value to use for proximity sensor. -->
+ <string name="proximity_sensor_type" translatable="false">@string/doze_brightness_sensor_type</string>
+
+ <!-- If using proximity_sensor_type, specifies a threshold value to distinguish near and
+ far break points. A sensor value less than or equal to this is considered "near". -->
+ <item name="proximity_sensor_threshold" translatable="false" format="float" type="dimen">
+ 0</item>
+
<!-- Doze: pulse parameter - how long does it take to fade in? -->
<integer name="doze_pulse_duration_in">130</integer>
@@ -480,4 +488,24 @@
<!-- Preferred refresh rate at keyguard, if supported by the display -->
<integer name="config_keyguardRefreshRate">-1</integer>
+ <!-- Respect the drawable/rounded.xml that allow to customize as multiple radius corner path -->
+ <bool name="config_roundedCornerMultipleRadius">false</bool>
+
+ <!-- A path similar to frameworks/base/core/res/res/values/config.xml
+ config_mainBuiltInDisplayCutout that describes a path larger than the exact path of a display
+ cutout. If present as well as config_enableDisplayCutoutProtection is set to true, then
+ SystemUI will draw this "protection path" instead of the display cutout path that is normally
+ used for anti-aliasing.
+
+ This path will only be drawn when the front-facing camera turns on, otherwise the main
+ DisplayCutout path will be rendered
+ -->
+ <string translatable="false" name="config_frontBuiltInDisplayCutoutProtection"></string>
+
+ <!-- ID for the camera that needs extra protection -->
+ <string translatable="false" name="config_protectedCameraId"></string>
+
+ <!-- Flag to turn on the rendering of the above path or not -->
+ <bool name="config_enableDisplayCutoutProtection">false</bool>
+
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt b/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt
new file mode 100644
index 0000000..24fa91b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui
+
+import android.content.Context
+import android.graphics.Path
+import android.graphics.Rect
+import android.graphics.RectF
+import android.hardware.camera2.CameraManager
+import android.util.PathParser
+import java.util.concurrent.Executor
+
+import kotlin.math.roundToInt
+
+const val TAG = "CameraOpTransitionController"
+
+/**
+ * Listens for usage of the Camera and controls the ScreenDecorations transition to show extra
+ * protection around a display cutout based on config_frontBuiltInDisplayCutoutProtection and
+ * config_enableDisplayCutoutProtection
+ */
+class CameraAvailabilityListener(
+ private val cameraManager: CameraManager,
+ private val cutoutProtectionPath: Path,
+ private val targetCameraId: String,
+ private val executor: Executor
+) {
+ private var cutoutBounds = Rect()
+ private val listeners = mutableListOf<CameraTransitionCallback>()
+ private val availabilityCallback: CameraManager.AvailabilityCallback =
+ object : CameraManager.AvailabilityCallback() {
+ override fun onCameraAvailable(cameraId: String) {
+ if (targetCameraId == cameraId) {
+ notifyCameraInactive()
+ }
+ }
+
+ override fun onCameraUnavailable(cameraId: String) {
+ if (targetCameraId == cameraId) {
+ notifyCameraActive()
+ }
+ }
+ }
+
+ init {
+ val computed = RectF()
+ cutoutProtectionPath.computeBounds(computed, false /* unused */)
+ cutoutBounds.set(
+ computed.left.roundToInt(),
+ computed.top.roundToInt(),
+ computed.right.roundToInt(),
+ computed.bottom.roundToInt())
+ }
+
+ /**
+ * Start listening for availability events, and maybe notify listeners
+ *
+ * @return true if we started listening
+ */
+ fun startListening() {
+ registerCameraListener()
+ }
+
+ fun stop() {
+ unregisterCameraListener()
+ }
+
+ fun addTransitionCallback(callback: CameraTransitionCallback) {
+ listeners.add(callback)
+ }
+
+ fun removeTransitionCallback(callback: CameraTransitionCallback) {
+ listeners.remove(callback)
+ }
+
+ private fun registerCameraListener() {
+ cameraManager.registerAvailabilityCallback(executor, availabilityCallback)
+ }
+
+ private fun unregisterCameraListener() {
+ cameraManager.unregisterAvailabilityCallback(availabilityCallback)
+ }
+
+ private fun notifyCameraActive() {
+ listeners.forEach { it.onApplyCameraProtection(cutoutProtectionPath, cutoutBounds) }
+ }
+
+ private fun notifyCameraInactive() {
+ listeners.forEach { it.onHideCameraProtection() }
+ }
+
+ /**
+ * Callbacks to tell a listener that a relevant camera turned on and off.
+ */
+ interface CameraTransitionCallback {
+ fun onApplyCameraProtection(protectionPath: Path, bounds: Rect)
+ fun onHideCameraProtection()
+ }
+
+ companion object Factory {
+ fun build(context: Context, executor: Executor): CameraAvailabilityListener {
+ val manager = context
+ .getSystemService(Context.CAMERA_SERVICE) as CameraManager
+ val res = context.resources
+ val pathString = res.getString(R.string.config_frontBuiltInDisplayCutoutProtection)
+ val cameraId = res.getString(R.string.config_protectedCameraId)
+
+ return CameraAvailabilityListener(
+ manager, pathFromString(pathString), cameraId, executor)
+ }
+
+ private fun pathFromString(pathString: String): Path {
+ val spec = pathString.trim()
+ val p: Path
+ try {
+ p = PathParser.createPathFromPathData(spec)
+ } catch (e: Throwable) {
+ throw IllegalArgumentException("Invalid protection path", e)
+ }
+
+ return p
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index f38b4f2..3a8524a 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -29,6 +29,7 @@
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.annotation.Dimension;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.Fragment;
import android.content.BroadcastReceiver;
@@ -37,6 +38,7 @@
import android.content.IntentFilter;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
@@ -45,6 +47,7 @@
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Region;
+import android.graphics.drawable.VectorDrawable;
import android.hardware.display.DisplayManager;
import android.os.Handler;
import android.os.HandlerThread;
@@ -105,9 +108,11 @@
private static final boolean DEBUG_SCREENSHOT_ROUNDED_CORNERS =
SystemProperties.getBoolean("debug.screenshot_rounded_corners", false);
private static final boolean VERBOSE = false;
+ private static final boolean DEBUG_COLOR = DEBUG_SCREENSHOT_ROUNDED_CORNERS;
private DisplayManager mDisplayManager;
private DisplayManager.DisplayListener mDisplayListener;
+ private CameraAvailabilityListener mCameraListener;
@VisibleForTesting
protected int mRoundedDefault;
@@ -129,6 +134,26 @@
private boolean mAssistHintBlocked = false;
private boolean mIsReceivingNavBarColor = false;
private boolean mInGesturalMode;
+ private boolean mIsRoundedCornerMultipleRadius;
+
+ private CameraAvailabilityListener.CameraTransitionCallback mCameraTransitionCallback =
+ new CameraAvailabilityListener.CameraTransitionCallback() {
+ @Override
+ public void onApplyCameraProtection(@NonNull Path protectionPath, @NonNull Rect bounds) {
+ // Show the extra protection around the front facing camera if necessary
+ mCutoutTop.setProtection(protectionPath, bounds);
+ mCutoutTop.setShowProtection(true);
+ mCutoutBottom.setProtection(protectionPath, bounds);
+ mCutoutBottom.setShowProtection(true);
+ }
+
+ @Override
+ public void onHideCameraProtection() {
+ // Go back to the regular anti-aliasing
+ mCutoutTop.setShowProtection(false);
+ mCutoutBottom.setShowProtection(false);
+ }
+ };
/**
* Converts a set of {@link Rect}s into a {@link Region}
@@ -323,9 +348,12 @@
private void startOnScreenDecorationsThread() {
mRotation = RotationUtils.getExactRotation(mContext);
mWindowManager = mContext.getSystemService(WindowManager.class);
+ mIsRoundedCornerMultipleRadius = mContext.getResources().getBoolean(
+ R.bool.config_roundedCornerMultipleRadius);
updateRoundedCornerRadii();
if (hasRoundedCorners() || shouldDrawCutout() || shouldHostHandles()) {
setupDecorations();
+ setupCameraListener();
}
mDisplayListener = new DisplayManager.DisplayListener() {
@@ -441,6 +469,16 @@
new ValidatingPreDrawListener(mBottomOverlay));
}
+ private void setupCameraListener() {
+ Resources res = mContext.getResources();
+ boolean enabled = res.getBoolean(R.bool.config_enableDisplayCutoutProtection);
+ if (enabled) {
+ mCameraListener = CameraAvailabilityListener.Factory.build(mContext, mHandler::post);
+ mCameraListener.addTransitionCallback(mCameraTransitionCallback);
+ mCameraListener.startListening();
+ }
+ }
+
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -457,6 +495,9 @@
private void updateColorInversion(int colorsInvertedValue) {
int tint = colorsInvertedValue != 0 ? Color.WHITE : Color.BLACK;
+ if (DEBUG_COLOR) {
+ tint = Color.RED;
+ }
ColorStateList tintList = ColorStateList.valueOf(tint);
((ImageView) mOverlay.findViewById(R.id.left)).setImageTintList(tintList);
((ImageView) mOverlay.findViewById(R.id.right)).setImageTintList(tintList);
@@ -528,17 +569,24 @@
com.android.internal.R.dimen.rounded_corner_radius_top);
final int newRoundedDefaultBottom = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.rounded_corner_radius_bottom);
-
final boolean roundedCornersChanged = mRoundedDefault != newRoundedDefault
|| mRoundedDefaultBottom != newRoundedDefaultBottom
|| mRoundedDefaultTop != newRoundedDefaultTop;
if (roundedCornersChanged) {
- mRoundedDefault = newRoundedDefault;
- mRoundedDefaultTop = newRoundedDefaultTop;
- mRoundedDefaultBottom = newRoundedDefaultBottom;
- onTuningChanged(SIZE, null);
+ // If config_roundedCornerMultipleRadius set as true, ScreenDecorations respect the
+ // max(width, height) size of drawable/rounded.xml instead of rounded_corner_radius
+ if (mIsRoundedCornerMultipleRadius) {
+ final VectorDrawable d = (VectorDrawable) mContext.getDrawable(R.drawable.rounded);
+ mRoundedDefault = Math.max(d.getIntrinsicWidth(), d.getIntrinsicHeight());
+ mRoundedDefaultTop = mRoundedDefaultBottom = mRoundedDefault;
+ } else {
+ mRoundedDefault = newRoundedDefault;
+ mRoundedDefaultTop = newRoundedDefaultTop;
+ mRoundedDefaultBottom = newRoundedDefaultBottom;
+ }
}
+ onTuningChanged(SIZE, null);
}
private void updateViews() {
@@ -637,7 +685,8 @@
}
private boolean hasRoundedCorners() {
- return mRoundedDefault > 0 || mRoundedDefaultBottom > 0 || mRoundedDefaultTop > 0;
+ return mRoundedDefault > 0 || mRoundedDefaultBottom > 0 || mRoundedDefaultTop > 0
+ || mIsRoundedCornerMultipleRadius;
}
private boolean shouldDrawCutout() {
@@ -825,6 +874,13 @@
private final List<Rect> mBounds = new ArrayList();
private final Rect mBoundingRect = new Rect();
private final Path mBoundingPath = new Path();
+ // Don't initialize these because they are cached elsewhere and may not exist
+ private Rect mProtectionRect;
+ private Path mProtectionPath;
+ private Rect mTotalBounds = new Rect();
+ // Whether or not to show the cutout protection path
+ private boolean mShowProtection = false;
+
private final int[] mLocation = new int[2];
private final boolean mInitialStart;
private final Runnable mVisibilityChangedListener;
@@ -871,7 +927,13 @@
super.onDraw(canvas);
getLocationOnScreen(mLocation);
canvas.translate(-mLocation[0], -mLocation[1]);
- if (!mBoundingPath.isEmpty()) {
+
+ if (mShowProtection && !mProtectionRect.isEmpty()) {
+ mPaint.setColor(mColor);
+ mPaint.setStyle(Paint.Style.FILL);
+ mPaint.setAntiAlias(true);
+ canvas.drawPath(mProtectionPath, mPaint);
+ } else if (!mBoundingPath.isEmpty()) {
mPaint.setColor(mColor);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setAntiAlias(true);
@@ -899,6 +961,22 @@
update();
}
+ void setProtection(Path protectionPath, Rect pathBounds) {
+ mProtectionPath = protectionPath;
+ mProtectionRect = pathBounds;
+ }
+
+ void setShowProtection(boolean shouldShow) {
+ if (mShowProtection == shouldShow) {
+ return;
+ }
+
+ mShowProtection = shouldShow;
+ updateBoundingPath();
+ requestLayout();
+ invalidate();
+ }
+
private boolean isStart() {
final boolean flipped = (mRotation == RotationUtils.ROTATION_SEASCAPE
|| mRotation == RotationUtils.ROTATION_UPSIDE_DOWN);
@@ -945,6 +1023,9 @@
Matrix m = new Matrix();
transformPhysicalToLogicalCoordinates(mInfo.rotation, dw, dh, m);
mBoundingPath.transform(m);
+ if (mProtectionPath != null) {
+ mProtectionPath.transform(m);
+ }
}
private static void transformPhysicalToLogicalCoordinates(@Surface.Rotation int rotation,
@@ -1002,9 +1083,19 @@
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
- setMeasuredDimension(
- resolveSizeAndState(mBoundingRect.width(), widthMeasureSpec, 0),
- resolveSizeAndState(mBoundingRect.height(), heightMeasureSpec, 0));
+
+ if (mShowProtection) {
+ // Make sure that our measured height encompases the protection
+ mTotalBounds.union(mBoundingRect);
+ mTotalBounds.union(mProtectionRect);
+ setMeasuredDimension(
+ resolveSizeAndState(mTotalBounds.width(), widthMeasureSpec, 0),
+ resolveSizeAndState(mTotalBounds.height(), heightMeasureSpec, 0));
+ } else {
+ setMeasuredDimension(
+ resolveSizeAndState(mBoundingRect.width(), widthMeasureSpec, 0),
+ resolveSizeAndState(mBoundingRect.height(), heightMeasureSpec, 0));
+ }
}
public static void boundsFromDirection(DisplayCutout displayCutout, int gravity,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 026a625..b7c8f70 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -43,11 +43,11 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
-import com.android.systemui.R;
import com.android.systemui.plugins.SensorManagerPlugin;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.AlarmTimeout;
import com.android.systemui.util.AsyncSensorManager;
+import com.android.systemui.util.ProximitySensor;
import com.android.systemui.util.wakelock.WakeLock;
import java.io.PrintWriter;
@@ -288,6 +288,7 @@
final AlarmTimeout mCooldownTimer;
final AlwaysOnDisplayPolicy mPolicy;
final Sensor mSensor;
+ private final float mSensorThreshold;
final boolean mUsingBrightnessSensor;
public ProxSensor(AlwaysOnDisplayPolicy policy) {
@@ -297,11 +298,14 @@
// The default prox sensor can be noisy, so let's use a prox gated brightness sensor
// if available.
- Sensor sensor = DozeSensors.findSensorWithType(mSensorManager,
- mContext.getString(R.string.doze_brightness_sensor_type));
+ Sensor sensor = ProximitySensor.findCustomProxSensor(mContext, mSensorManager);
mUsingBrightnessSensor = sensor != null;
- if (sensor == null) {
+ if (mUsingBrightnessSensor) {
+ mSensorThreshold = ProximitySensor.getBrightnessSensorThreshold(
+ mContext.getResources());
+ } else {
sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
+ mSensorThreshold = sensor.getMaximumRange();
}
mSensor = sensor;
}
@@ -343,11 +347,9 @@
if (DEBUG) Log.d(TAG, "onSensorChanged " + event);
if (mUsingBrightnessSensor) {
- // The custom brightness sensor is gated by the proximity sensor and will return 0
- // whenever prox is covered.
- mCurrentlyFar = event.values[0] > 0;
+ mCurrentlyFar = event.values[0] > mSensorThreshold;
} else {
- mCurrentlyFar = event.values[0] >= event.sensor.getMaximumRange();
+ mCurrentlyFar = event.values[0] >= mSensorThreshold;
}
mProxCallback.accept(mCurrentlyFar);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 6199a0d..c7a133d 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -41,10 +41,10 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.Preconditions;
import com.android.systemui.Dependency;
-import com.android.systemui.R;
import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.Assert;
+import com.android.systemui.util.ProximitySensor;
import com.android.systemui.util.wakelock.WakeLock;
import java.io.PrintWriter;
@@ -431,15 +431,18 @@
private boolean mFinished;
private float mMaxRange;
private boolean mUsingBrightnessSensor;
+ private float mSensorThreshold;
protected abstract void onProximityResult(int result);
public void check() {
Preconditions.checkState(!mFinished && !mRegistered);
- Sensor sensor = DozeSensors.findSensorWithType(mSensorManager,
- mContext.getString(R.string.doze_brightness_sensor_type));
+ Sensor sensor = ProximitySensor.findCustomProxSensor(mContext, mSensorManager);
mUsingBrightnessSensor = sensor != null;
- if (sensor == null) {
+ if (mUsingBrightnessSensor) {
+ mSensorThreshold = ProximitySensor.getBrightnessSensorThreshold(
+ mContext.getResources());
+ } else {
sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
}
if (sensor == null) {
@@ -473,7 +476,7 @@
if (mUsingBrightnessSensor) {
// The custom brightness sensor is gated by the proximity sensor and will
// return 0 whenever prox is covered.
- isNear = event.values[0] == 0;
+ isNear = event.values[0] <= mSensorThreshold;
} else {
isNear = event.values[0] < mMaxRange;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index 496aa0e..837f90e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -25,9 +25,12 @@
import android.content.res.Configuration;
import android.graphics.drawable.Animatable;
import android.util.AttributeSet;
+import android.util.Pair;
import android.util.SparseArray;
+import android.view.DisplayCutout;
import android.view.View;
import android.view.ViewGroup;
+import android.view.WindowInsets;
import android.view.accessibility.AccessibilityEvent;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -42,6 +45,7 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.phone.PhoneStatusBarView;
public class QSDetail extends LinearLayout {
@@ -142,6 +146,25 @@
}
}
+ @Override
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ DisplayCutout cutout = insets.getDisplayCutout();
+ Pair<Integer, Integer> padding = PhoneStatusBarView.cornerCutoutMargins(
+ cutout, getDisplay());
+ if (padding == null) {
+ mQsDetailHeader.setPaddingRelative(
+ getResources().getDimensionPixelSize(R.dimen.qs_detail_header_padding),
+ getPaddingTop(),
+ getResources().getDimensionPixelSize(R.dimen.qs_detail_header_padding),
+ getPaddingBottom()
+ );
+ } else {
+ mQsDetailHeader.setPadding(padding.first, getPaddingTop(),
+ padding.second, getPaddingBottom());
+ }
+ return super.onApplyWindowInsets(insets);
+ }
+
private void updateDetailText() {
mDetailDoneButton.setText(R.string.quick_settings_done);
mDetailSettingsButton.setText(R.string.quick_settings_more_settings);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
index a7d5aca..111309f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
@@ -29,23 +29,21 @@
private static final float ICON_ALPHA_WHEN_LIGHTS_OUT_BATTERY_CLOCK = 0.5f;
private static final float ICON_ALPHA_WHEN_LIGHTS_OUT_NON_BATTERY_CLOCK = 0;
- private final PhoneStatusBarView mView;
private final float mIconAlphaWhenOpaque;
- private View mLeftSide, mStatusIcons, mBattery, mClock;
+ private View mLeftSide, mStatusIcons, mBattery;
private Animator mCurrentAnimation;
- public PhoneStatusBarTransitions(PhoneStatusBarView view) {
- super(view, R.drawable.status_background);
- mView = view;
- final Resources res = mView.getContext().getResources();
+ /**
+ * @param backgroundView view to apply the background drawable
+ */
+ public PhoneStatusBarTransitions(PhoneStatusBarView statusBarView, View backgroundView) {
+ super(backgroundView, R.drawable.status_background);
+ final Resources res = statusBarView.getContext().getResources();
mIconAlphaWhenOpaque = res.getFraction(R.dimen.status_bar_icon_drawing_alpha, 1, 1);
- }
-
- public void init() {
- mLeftSide = mView.findViewById(R.id.status_bar_left_side);
- mStatusIcons = mView.findViewById(R.id.statusIcons);
- mBattery = mView.findViewById(R.id.battery);
+ mLeftSide = statusBarView.findViewById(R.id.status_bar_left_side);
+ mStatusIcons = statusBarView.findViewById(R.id.statusIcons);
+ mBattery = statusBarView.findViewById(R.id.battery);
applyModeBackground(-1, getMode(), false /*animate*/);
applyMode(getMode(), false /*animate*/);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 8efd952..32402e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -59,7 +59,6 @@
StatusBar mBar;
boolean mIsFullyOpenedPanel = false;
- private final PhoneStatusBarTransitions mBarTransitions;
private ScrimController mScrimController;
private float mMinFraction;
private Runnable mHideExpandedRunnable = new Runnable() {
@@ -87,14 +86,9 @@
public PhoneStatusBarView(Context context, AttributeSet attrs) {
super(context, attrs);
- mBarTransitions = new PhoneStatusBarTransitions(this);
mCommandQueue = getComponent(context, CommandQueue.class);
}
- public BarTransitions getBarTransitions() {
- return mBarTransitions;
- }
-
public void setBar(StatusBar bar) {
mBar = bar;
}
@@ -105,7 +99,6 @@
@Override
public void onFinishInflate() {
- mBarTransitions.init();
mBattery = findViewById(R.id.battery);
mCutoutSpace = findViewById(R.id.cutout_space_view);
mCenterIconSpace = findViewById(R.id.centered_icon_area);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index c6dee5e..ea04bcc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -2238,7 +2238,7 @@
}
protected BarTransitions getStatusBarTransitions() {
- return mStatusBarView.getBarTransitions();
+ return mStatusBarWindow.getBarTransitions();
}
protected @TransitionMode int computeBarMode(int oldVis, int newVis) {
@@ -2288,8 +2288,8 @@
}
private void finishBarAnimations() {
- if (mStatusBarView != null) {
- mStatusBarView.getBarTransitions().finishAnimations();
+ if (mStatusBarWindow != null && mStatusBarWindow.getBarTransitions() != null) {
+ mStatusBarWindow.getBarTransitions().finishAnimations();
}
mNavigationBarController.finishBarAnimations(mDisplayId);
}
@@ -2367,8 +2367,8 @@
Settings.Global.ZEN_MODE_OFF)));
pw.print(" mWallpaperSupported= "); pw.println(mWallpaperSupported);
- if (mStatusBarView != null) {
- dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions());
+ if (mStatusBarWindow != null) {
+ dumpBarTransitions(pw, "mStatusBarWindow", mStatusBarWindow.getBarTransitions());
}
pw.println(" StatusBarWindowView: ");
if (mStatusBarWindow != null) {
@@ -3012,8 +3012,8 @@
-1;
if (barMode != -1) {
boolean animate = true;
- if (mStatusBarView != null) {
- mStatusBarView.getBarTransitions().transitionTo(barMode, animate);
+ if (mStatusBarWindow != null && mStatusBarWindow.getBarTransitions() != null) {
+ mStatusBarWindow.getBarTransitions().transitionTo(barMode, animate);
}
mNavigationBarController.transitionTo(mDisplayId, barMode, animate);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 6789930..0ab2af8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -65,8 +65,6 @@
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.DragDownHelper;
-import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.phone.ScrimController.ScrimVisibility;
import com.android.systemui.tuner.TunerService;
@@ -91,6 +89,7 @@
private View mBrightnessMirror;
private LockIcon mLockIcon;
private PhoneStatusBarView mStatusBarView;
+ private PhoneStatusBarTransitions mBarTransitions;
private int mRightInset = 0;
private int mLeftInset = 0;
@@ -282,6 +281,12 @@
public void setStatusBarView(PhoneStatusBarView statusBarView) {
mStatusBarView = statusBarView;
+ mBarTransitions = new PhoneStatusBarTransitions(statusBarView,
+ findViewById(R.id.status_bar_container));
+ }
+
+ public PhoneStatusBarTransitions getBarTransitions() {
+ return mBarTransitions;
}
public void setService(StatusBar service) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/ProximitySensor.java
index a905eba..4cd38fe 100644
--- a/packages/SystemUI/src/com/android/systemui/util/ProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/ProximitySensor.java
@@ -17,6 +17,7 @@
package com.android.systemui.util;
import android.content.Context;
+import android.content.res.Resources;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
@@ -40,7 +41,7 @@
private final Sensor mSensor;
private final AsyncSensorManager mSensorManager;
private final boolean mUsingBrightnessSensor;
- private final float mMaxRange;
+ private final float mThreshold;
private SensorEventListener mSensorEventListener = new SensorEventListener() {
@Override
@@ -59,7 +60,7 @@
@Inject
public ProximitySensor(Context context, AsyncSensorManager sensorManager) {
mSensorManager = sensorManager;
- Sensor sensor = findBrightnessSensor(context, sensorManager);
+ Sensor sensor = findCustomProxSensor(context, sensorManager);
if (sensor == null) {
mUsingBrightnessSensor = false;
@@ -69,9 +70,13 @@
}
mSensor = sensor;
if (mSensor != null) {
- mMaxRange = mSensor.getMaximumRange();
+ if (mUsingBrightnessSensor) {
+ mThreshold = getBrightnessSensorThreshold(context.getResources());
+ } else {
+ mThreshold = mSensor.getMaximumRange();
+ }
} else {
- mMaxRange = 0;
+ mThreshold = 0;
}
}
@@ -79,8 +84,18 @@
mTag = tag;
}
- private Sensor findBrightnessSensor(Context context, SensorManager sensorManager) {
- String sensorType = context.getString(R.string.doze_brightness_sensor_type);
+ /**
+ * Returns a brightness sensor that can be used for proximity purposes.
+ *
+ * @deprecated This method exists for legacy purposes. Use the containing class directly.
+ */
+ @Deprecated
+ public static Sensor findCustomProxSensor(Context context, SensorManager sensorManager) {
+ String sensorType = context.getString(R.string.proximity_sensor_type);
+ if (sensorType.isEmpty()) {
+ return null;
+ }
+
List<Sensor> sensorList = sensorManager.getSensorList(Sensor.TYPE_ALL);
Sensor sensor = null;
for (Sensor s : sensorList) {
@@ -94,6 +109,16 @@
}
/**
+ * Returns a threshold value that can be used along with {@link #findCustomProxSensor}
+ *
+ * @deprecated This method exists for legacy purposes. Use the containing class directly.
+ */
+ @Deprecated
+ public static float getBrightnessSensorThreshold(Resources resources) {
+ return resources.getFloat(R.dimen.proximity_sensor_threshold);
+ }
+
+ /**
* Returns {@code false} if a Proximity sensor is not available.
*/
public boolean getSensorAvailable() {
@@ -141,11 +166,11 @@
}
private void onSensorEvent(SensorEvent event) {
- boolean near = event.values[0] < mMaxRange;
if (mUsingBrightnessSensor) {
- near = event.values[0] == 0;
+ mNear = event.values[0] <= mThreshold;
+ } else {
+ mNear = event.values[0] < mThreshold;
}
- mNear = near;
mListeners.forEach(proximitySensorListener ->
proximitySensorListener.onProximitySensorEvent(
new ProximityEvent(mNear, event.timestamp)));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index 3b5e12c..11b256a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -20,6 +20,8 @@
import static com.android.systemui.tuner.TunablePadding.FLAG_END;
import static com.android.systemui.tuner.TunablePadding.FLAG_START;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
@@ -38,6 +40,7 @@
import android.app.Fragment;
import android.content.res.Configuration;
import android.graphics.Rect;
+import android.graphics.drawable.VectorDrawable;
import android.os.Handler;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -148,6 +151,8 @@
com.android.internal.R.dimen.rounded_corner_radius_bottom, 0);
mContext.getOrCreateTestableResources()
.addOverride(dimen.rounded_corner_content_padding, 0);
+ mContext.getOrCreateTestableResources()
+ .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
mScreenDecorations.start();
// No views added.
@@ -166,6 +171,8 @@
com.android.internal.R.dimen.rounded_corner_radius, 20);
mContext.getOrCreateTestableResources()
.addOverride(dimen.rounded_corner_content_padding, 20);
+ mContext.getOrCreateTestableResources()
+ .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
mScreenDecorations.start();
// Add 2 windows for rounded corners (top and bottom).
@@ -180,6 +187,57 @@
}
@Test
+ public void testRoundingRadius() {
+ final int testRadius = 1;
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.dimen.rounded_corner_radius, testRadius);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.dimen.rounded_corner_radius_top, testRadius);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.dimen.rounded_corner_radius_bottom, testRadius);
+ mContext.getOrCreateTestableResources()
+ .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+
+ mScreenDecorations.start();
+ // Size of corner view should same as rounded_corner_radius{_top|_bottom}
+ assertThat(mScreenDecorations.mRoundedDefault).isEqualTo(testRadius);
+ assertThat(mScreenDecorations.mRoundedDefaultTop).isEqualTo(testRadius);
+ assertThat(mScreenDecorations.mRoundedDefaultBottom).isEqualTo(testRadius);
+ }
+
+ @Test
+ public void testRoundingMultipleRadius() {
+ final VectorDrawable d = (VectorDrawable) mContext.getDrawable(R.drawable.rounded);
+ final int multipleRadiusSize = Math.max(d.getIntrinsicWidth(), d.getIntrinsicHeight());
+
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.dimen.rounded_corner_radius, 9999);
+ mContext.getOrCreateTestableResources()
+ .addOverride(dimen.rounded_corner_content_padding, 9999);
+ mContext.getOrCreateTestableResources()
+ .addOverride(R.bool.config_roundedCornerMultipleRadius, true);
+
+ mScreenDecorations.start();
+ // Add 2 windows for rounded corners (top and bottom).
+ verify(mWindowManager, times(2)).addView(any(), any());
+
+ // Add 2 tag listeners for each of the fragments that are needed.
+ verify(mFragmentHostManager, times(2)).addTagListener(any(), any());
+ // One tunable.
+ verify(mTunerService, times(1)).addTunable(any(), any());
+ // One TunablePadding.
+ verify(mTunablePaddingService, times(1)).add(any(), anyString(), anyInt(), anyInt());
+ // Size of corner view should exactly match max(width, height) of R.drawable.rounded
+ assertThat(mScreenDecorations.mRoundedDefault).isEqualTo(multipleRadiusSize);
+ assertThat(mScreenDecorations.mRoundedDefaultTop).isEqualTo(multipleRadiusSize);
+ assertThat(mScreenDecorations.mRoundedDefaultBottom).isEqualTo(multipleRadiusSize);
+ }
+
+ @Test
public void testCutout() {
mContext.getOrCreateTestableResources().addOverride(
com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, true);
@@ -224,6 +282,9 @@
com.android.internal.R.dimen.rounded_corner_radius_bottom, 0);
mContext.getOrCreateTestableResources()
.addOverride(dimen.rounded_corner_content_padding, 0);
+ mContext.getOrCreateTestableResources()
+ .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+
when(mNavigationModeController.addListener(any())).thenReturn(
WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL);
@@ -245,6 +306,8 @@
com.android.internal.R.dimen.rounded_corner_radius_bottom, 0);
mContext.getOrCreateTestableResources()
.addOverride(dimen.rounded_corner_content_padding, 0);
+ mContext.getOrCreateTestableResources()
+ .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
when(mNavigationModeController.addListener(any())).thenReturn(
WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON);
@@ -296,6 +359,8 @@
com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
mContext.getOrCreateTestableResources().addOverride(
com.android.internal.R.dimen.rounded_corner_radius, 20);
+ mContext.getOrCreateTestableResources()
+ .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
mScreenDecorations.start();
assertEquals(mScreenDecorations.mRoundedDefault, 20);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 1994ccc..81042f4 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3151,6 +3151,25 @@
"subscription_group_uuid_string";
/**
+ * Data switch validation minimal gap time, in milliseconds.
+ *
+ * Which means, if the same subscription on the same network (based on MCC+MNC+TAC+subId)
+ * was recently validated (within this time gap), and Telephony receives a request to switch to
+ * it again, Telephony will skip the validation part and switch to it as soon as connection
+ * is setup, as if it's already validated.
+ *
+ * If the network was validated within the gap but the latest validation result is false, the
+ * validation will not be skipped.
+ *
+ * If not set or set to 0, validation will never be skipped.
+ * The max acceptable value of this config is 24 hours.
+ *
+ * @hide
+ */
+ public static final String KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG =
+ "data_switch_validation_min_gap_LONG";
+
+ /**
* A boolean property indicating whether this subscription should be managed as an opportunistic
* subscription.
*
@@ -3628,6 +3647,7 @@
sDefaults.putBoolean(KEY_SUPPORT_WPS_OVER_IMS_BOOL, true);
sDefaults.putStringArray(KEY_CARRIER_CERTIFICATE_STRING_ARRAY, null);
sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_TIMEOUT_LONG, 2000);
+ sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG, 0);
}
/**