diff options
17 files changed, 483 insertions, 62 deletions
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 4b4b73dae91e..5d240f173d17 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 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt // 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 f91c90ec636f..b87844ea74a1 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.app.KeyguardManager; 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.Debug; 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 @@ public class CarVolumeDialogImpl implements VolumeDialog { 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 class CarVolumeDialogImpl implements VolumeDialog { 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 class CarVolumeDialogImpl implements VolumeDialog { 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 4fae3c500a45..f8db97dbf800 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 a91493003bb5..9d56e08bc555 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 78318cb7e858..6758efac7e2a 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 000000000000..24fa91b9e838 --- /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 f38b4f259c88..3a8524a3ee7d 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.Animator; 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.Intent; 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.Path; 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 @@ public class ScreenDecorations extends SystemUI implements Tunable, 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 @@ public class ScreenDecorations extends SystemUI implements Tunable, 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 @@ public class ScreenDecorations extends SystemUI implements Tunable, 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 @@ public class ScreenDecorations extends SystemUI implements Tunable, 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 @@ public class ScreenDecorations extends SystemUI implements Tunable, 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 @@ public class ScreenDecorations extends SystemUI implements Tunable, 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 @@ public class ScreenDecorations extends SystemUI implements Tunable, } 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 @@ public class ScreenDecorations extends SystemUI implements Tunable, 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 @@ public class ScreenDecorations extends SystemUI implements Tunable, 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 @@ public class ScreenDecorations extends SystemUI implements Tunable, 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 @@ public class ScreenDecorations extends SystemUI implements Tunable, 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 @@ public class ScreenDecorations extends SystemUI implements Tunable, 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 026a62528c8d..b7c8f707b850 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 androidx.annotation.VisibleForTesting; 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 @@ public class DozeSensors { final AlarmTimeout mCooldownTimer; final AlwaysOnDisplayPolicy mPolicy; final Sensor mSensor; + private final float mSensorThreshold; final boolean mUsingBrightnessSensor; public ProxSensor(AlwaysOnDisplayPolicy policy) { @@ -297,11 +298,14 @@ public class DozeSensors { // 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 @@ public class DozeSensors { 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 6199a0deb31f..c7a133dc530a 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.MetricsLogger; 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 @@ public class DozeTriggers implements DozeMachine.Part { 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 @@ public class DozeTriggers implements DozeMachine.Part { 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 496aa0e572ae..837f90ec23c6 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.Intent; 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.SysUiServiceProvider; 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 @@ public class QSDetail extends LinearLayout { } } + @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 a7d5acaac765..111309fb2236 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 @@ public final class PhoneStatusBarTransitions extends BarTransitions { 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 8efd952e67c5..32402e1f3042 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 @@ public class PhoneStatusBarView extends PanelBar { 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 class PhoneStatusBarView extends PanelBar { 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 @@ public class PhoneStatusBarView extends PanelBar { @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 c6dee5e9bdf5..ea04bcccc6b1 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 @@ public class StatusBar extends SystemUI implements DemoMode, } protected BarTransitions getStatusBarTransitions() { - return mStatusBarView.getBarTransitions(); + return mStatusBarWindow.getBarTransitions(); } protected @TransitionMode int computeBarMode(int oldVis, int newVis) { @@ -2288,8 +2288,8 @@ public class StatusBar extends SystemUI implements DemoMode, } 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, -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 6789930ab76e..0ab2af864383 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.R; 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 @@ public class StatusBarWindowView extends FrameLayout { 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 class StatusBarWindowView extends FrameLayout { 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 a905eba1f0ed..4cd38febc5dd 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 @@ public class ProximitySensor { 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 @@ public class ProximitySensor { @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 @@ public class ProximitySensor { } 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 @@ public class ProximitySensor { 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 @@ public class ProximitySensor { } /** + * 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 @@ public class ProximitySensor { } 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 3b5e12c4ef96..11b256a4da01 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.ScreenDecorations.rectsToRegion; 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 static org.mockito.Mockito.when; 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 @@ public class ScreenDecorationsTest extends SysuiTestCase { 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,55 @@ public class ScreenDecorationsTest extends SysuiTestCase { 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). + 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()); + } + + @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). @@ -177,6 +231,10 @@ public class ScreenDecorationsTest extends SysuiTestCase { 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 @@ -224,6 +282,9 @@ public class ScreenDecorationsTest extends SysuiTestCase { 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 @@ public class ScreenDecorationsTest extends SysuiTestCase { 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 @@ public class ScreenDecorationsTest extends SysuiTestCase { 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 1994ccc74b74..81042f4a34bf 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -3151,6 +3151,25 @@ public class CarrierConfigManager { "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 @@ public class CarrierConfigManager { 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); } /** |