Privacy chip (2/many)
- Introduce StatusBarLocationPublisher to decouple the controlling of the privacy dots and the status bar itself. - Fix some code comments - Fix RTL (mostly) for animations - Animate the chip into the status bar left/right sides (based on rtl) so it always shows in the system area Test: atest SystemUITests Bug: 177323724 Change-Id: Ib76e9e19f4f70b77f30011b2aceebbeb6c870f81
This commit is contained in:
@@ -29,6 +29,8 @@ import com.android.systemui.animation.Interpolators
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.statusbar.phone.StatusBarLocationPublisher
|
||||
import com.android.systemui.statusbar.phone.StatusBarMarginUpdatedListener
|
||||
|
||||
import java.lang.IllegalStateException
|
||||
import java.util.concurrent.Executor
|
||||
@@ -51,8 +53,9 @@ import javax.inject.Inject
|
||||
|
||||
@SysUISingleton
|
||||
class PrivacyDotViewController @Inject constructor(
|
||||
@Main val mainExecutor: Executor,
|
||||
val animationScheduler: SystemStatusAnimationScheduler
|
||||
@Main private val mainExecutor: Executor,
|
||||
private val locationPublisher: StatusBarLocationPublisher,
|
||||
private val animationScheduler: SystemStatusAnimationScheduler
|
||||
) {
|
||||
private var rotation = 0
|
||||
private var leftSize = 0
|
||||
@@ -80,12 +83,21 @@ class PrivacyDotViewController @Inject constructor(
|
||||
private val views: Sequence<View>
|
||||
get() = if (!this::tl.isInitialized) sequenceOf() else sequenceOf(tl, tr, br, bl)
|
||||
|
||||
init {
|
||||
locationPublisher.addCallback(object : StatusBarMarginUpdatedListener {
|
||||
override fun onStatusBarMarginUpdated(marginLeft: Int, marginRight: Int) {
|
||||
setStatusBarMargins(marginLeft, marginRight)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun setUiExecutor(e: Executor) {
|
||||
uiExecutor = e
|
||||
}
|
||||
|
||||
@UiThread
|
||||
fun updateRotation(rot: Int) {
|
||||
dlog("updateRotation: ")
|
||||
if (rot == rotation) {
|
||||
return
|
||||
}
|
||||
@@ -248,7 +260,7 @@ class PrivacyDotViewController @Inject constructor(
|
||||
* @param left the space between the status bar contents and the left side of the screen
|
||||
* @param right space between the status bar contents and the right side of the screen
|
||||
*/
|
||||
fun setStatusBarMargins(left: Int, right: Int) {
|
||||
private fun setStatusBarMargins(left: Int, right: Int) {
|
||||
leftSize = left
|
||||
rightSize = right
|
||||
|
||||
@@ -262,6 +274,7 @@ class PrivacyDotViewController @Inject constructor(
|
||||
}
|
||||
|
||||
private fun doUpdates(rot: Boolean, height: Boolean, width: Boolean) {
|
||||
dlog("doUpdates: ")
|
||||
var newDesignatedCorner: View? = null
|
||||
|
||||
if (rot) {
|
||||
@@ -324,12 +337,19 @@ class PrivacyDotViewController @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun dlog(s: String) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, s)
|
||||
}
|
||||
}
|
||||
|
||||
const val TOP_LEFT = 0
|
||||
const val TOP_RIGHT = 1
|
||||
const val BOTTOM_RIGHT = 2
|
||||
const val BOTTOM_LEFT = 3
|
||||
private const val DURATION = 160L
|
||||
private const val TAG = "PrivacyDotViewController"
|
||||
private const val DEBUG = false
|
||||
|
||||
private fun Int.toGravity(): Int {
|
||||
return when (this) {
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.widget.FrameLayout
|
||||
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.statusbar.SuperStatusBarViewFactory
|
||||
import com.android.systemui.statusbar.phone.StatusBarLocationPublisher
|
||||
import com.android.systemui.statusbar.phone.StatusBarWindowController
|
||||
import com.android.systemui.statusbar.phone.StatusBarWindowView
|
||||
|
||||
@@ -39,7 +40,8 @@ import javax.inject.Inject
|
||||
class SystemEventChipAnimationController @Inject constructor(
|
||||
private val context: Context,
|
||||
private val statusBarViewFactory: SuperStatusBarViewFactory,
|
||||
private val statusBarWindowController: StatusBarWindowController
|
||||
private val statusBarWindowController: StatusBarWindowController,
|
||||
private val locationPublisher: StatusBarLocationPublisher
|
||||
) : SystemStatusChipAnimationCallback {
|
||||
var showPersistentDot = false
|
||||
set(value) {
|
||||
@@ -64,13 +66,15 @@ class SystemEventChipAnimationController @Inject constructor(
|
||||
|
||||
if (state == ANIMATING_IN) {
|
||||
currentAnimatedView = viewCreator(context)
|
||||
animationWindowView.addView(currentAnimatedView, layoutParamsDefault)
|
||||
animationWindowView.addView(currentAnimatedView, layoutParamsDefault())
|
||||
|
||||
// We are animating IN; chip comes in from View.END
|
||||
currentAnimatedView?.apply {
|
||||
translationX = width.toFloat()
|
||||
val translation = width.toFloat()
|
||||
translationX = if (isLayoutRtl) -translation else translation
|
||||
alpha = 0f
|
||||
visibility = View.VISIBLE
|
||||
setPadding(locationPublisher.marginLeft, 0, locationPublisher.marginRight, 0)
|
||||
}
|
||||
} else {
|
||||
// We are animating away
|
||||
@@ -109,7 +113,7 @@ class SystemEventChipAnimationController @Inject constructor(
|
||||
|
||||
val w = width
|
||||
val translation = (1 - amt) * w
|
||||
translationX = translation
|
||||
translationX = if (isLayoutRtl) -translation else translation
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +135,13 @@ class SystemEventChipAnimationController @Inject constructor(
|
||||
statusBarWindowView.addView(animationWindowView, lp)
|
||||
}
|
||||
|
||||
private val layoutParamsDefault = FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).also {
|
||||
it.gravity = Gravity.END or Gravity.CENTER_VERTICAL
|
||||
private fun start() = if (animationWindowView.isLayoutRtl) right() else left()
|
||||
private fun right() = locationPublisher.marginRight
|
||||
private fun left() = locationPublisher.marginLeft
|
||||
|
||||
private fun layoutParamsDefault(): FrameLayout.LayoutParams =
|
||||
FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).also {
|
||||
it.gravity = Gravity.END or Gravity.CENTER_VERTICAL
|
||||
it.marginStart = start()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,7 +127,6 @@ class SystemStatusAnimationScheduler @Inject constructor(
|
||||
}
|
||||
|
||||
private fun isTooEarly(): Boolean {
|
||||
Log.d(TAG, "time=> ${systemClock.uptimeMillis() - Process.getStartUptimeMillis()}")
|
||||
return systemClock.uptimeMillis() - Process.getStartUptimeMillis() < MIN_UPTIME
|
||||
}
|
||||
|
||||
@@ -339,4 +338,4 @@ private const val ENTRANCE_ANIM_LENGTH = 500L
|
||||
private const val CHIP_ANIM_LENGTH = 500L
|
||||
private const val MIN_UPTIME: Long = 5 * 1000
|
||||
|
||||
private const val DEBUG = false
|
||||
private const val DEBUG = false
|
||||
|
||||
@@ -43,7 +43,6 @@ import com.android.systemui.animation.Interpolators;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.statusbar.CommandQueue;
|
||||
import com.android.systemui.statusbar.StatusBarState;
|
||||
import com.android.systemui.statusbar.events.PrivacyDotViewController;
|
||||
import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
|
||||
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
|
||||
import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;
|
||||
@@ -92,7 +91,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
|
||||
private CommandQueue mCommandQueue;
|
||||
private OngoingCallController mOngoingCallController;
|
||||
private final SystemStatusAnimationScheduler mAnimationScheduler;
|
||||
private final PrivacyDotViewController mDotViewController;
|
||||
private final StatusBarLocationPublisher mLocationPublisher;
|
||||
private NotificationIconAreaController mNotificationIconAreaController;
|
||||
|
||||
private List<String> mBlockedIcons = new ArrayList<>();
|
||||
@@ -120,12 +119,12 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
|
||||
public CollapsedStatusBarFragment(
|
||||
OngoingCallController ongoingCallController,
|
||||
SystemStatusAnimationScheduler animationScheduler,
|
||||
PrivacyDotViewController dotViewController,
|
||||
StatusBarLocationPublisher locationPublisher,
|
||||
NotificationIconAreaController notificationIconAreaController
|
||||
) {
|
||||
mOngoingCallController = ongoingCallController;
|
||||
mAnimationScheduler = animationScheduler;
|
||||
mDotViewController = dotViewController;
|
||||
mLocationPublisher = locationPublisher;
|
||||
mNotificationIconAreaController = notificationIconAreaController;
|
||||
}
|
||||
|
||||
@@ -540,7 +539,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
|
||||
int leftMargin = left - mStatusBar.getLeft();
|
||||
int rightMargin = mStatusBar.getRight() - right;
|
||||
|
||||
mDotViewController.setStatusBarMargins(leftMargin, rightMargin);
|
||||
mLocationPublisher.updateStatusBarMargin(leftMargin, rightMargin);
|
||||
}
|
||||
|
||||
// Listen for view end changes of PhoneStatusBarView and publish that to the privacy dot
|
||||
|
||||
@@ -209,7 +209,6 @@ import com.android.systemui.statusbar.SuperStatusBarViewFactory;
|
||||
import com.android.systemui.statusbar.SysuiStatusBarStateController;
|
||||
import com.android.systemui.statusbar.VibratorHelper;
|
||||
import com.android.systemui.statusbar.charging.WiredChargingRippleController;
|
||||
import com.android.systemui.statusbar.events.PrivacyDotViewController;
|
||||
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
|
||||
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
|
||||
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
|
||||
@@ -429,7 +428,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
private NotificationsController mNotificationsController;
|
||||
private final OngoingCallController mOngoingCallController;
|
||||
private final SystemStatusAnimationScheduler mAnimationScheduler;
|
||||
private final PrivacyDotViewController mDotViewController;
|
||||
private final StatusBarLocationPublisher mStatusBarLocationPublisher;
|
||||
|
||||
// expanded notifications
|
||||
// the sliding/resizing panel within the notification window
|
||||
@@ -799,7 +798,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
WiredChargingRippleController chargingRippleAnimationController,
|
||||
OngoingCallController ongoingCallController,
|
||||
SystemStatusAnimationScheduler animationScheduler,
|
||||
PrivacyDotViewController dotViewController,
|
||||
StatusBarLocationPublisher locationPublisher,
|
||||
FeatureFlags featureFlags,
|
||||
KeyguardUnlockAnimationController keyguardUnlockAnimationController) {
|
||||
super(context);
|
||||
@@ -882,7 +881,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
mChargingRippleAnimationController = chargingRippleAnimationController;
|
||||
mOngoingCallController = ongoingCallController;
|
||||
mAnimationScheduler = animationScheduler;
|
||||
mDotViewController = dotViewController;
|
||||
mStatusBarLocationPublisher = locationPublisher;
|
||||
mFeatureFlags = featureFlags;
|
||||
|
||||
mExpansionChangedListeners = new ArrayList<>();
|
||||
@@ -1175,7 +1174,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
new CollapsedStatusBarFragment(
|
||||
mOngoingCallController,
|
||||
mAnimationScheduler,
|
||||
mDotViewController,
|
||||
mStatusBarLocationPublisher,
|
||||
mNotificationIconAreaController),
|
||||
CollapsedStatusBarFragment.TAG)
|
||||
.commit();
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.systemui.statusbar.phone
|
||||
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.statusbar.policy.CallbackController
|
||||
import java.lang.ref.WeakReference
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Publishes updates to the status bar's margins.
|
||||
*
|
||||
* While the status bar view consumes the entire width of the device, the status bar
|
||||
* contents are laid out with margins for rounded corners, padding from the absolute
|
||||
* edges, and potentially display cutouts in the corner.
|
||||
*/
|
||||
@SysUISingleton
|
||||
class StatusBarLocationPublisher @Inject constructor()
|
||||
: CallbackController<StatusBarMarginUpdatedListener> {
|
||||
private val listeners = mutableSetOf<WeakReference<StatusBarMarginUpdatedListener>>()
|
||||
|
||||
var marginLeft: Int = 0
|
||||
private set
|
||||
var marginRight: Int = 0
|
||||
private set
|
||||
|
||||
override fun addCallback(listener: StatusBarMarginUpdatedListener) {
|
||||
listeners.add(WeakReference(listener))
|
||||
}
|
||||
|
||||
override fun removeCallback(listener: StatusBarMarginUpdatedListener) {
|
||||
var toRemove: WeakReference<StatusBarMarginUpdatedListener>? = null
|
||||
for (l in listeners) {
|
||||
if (l.get() == listener) {
|
||||
toRemove = l
|
||||
}
|
||||
}
|
||||
|
||||
if (toRemove != null) {
|
||||
listeners.remove(toRemove)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateStatusBarMargin(left: Int, right: Int) {
|
||||
marginLeft = left
|
||||
marginRight = right
|
||||
|
||||
notifyListeners()
|
||||
}
|
||||
|
||||
private fun notifyListeners() {
|
||||
var listenerList: List<WeakReference<StatusBarMarginUpdatedListener>>
|
||||
synchronized(this) {
|
||||
listenerList = listeners.toList()
|
||||
}
|
||||
|
||||
listenerList.forEach { wrapper ->
|
||||
if (wrapper.get() == null) {
|
||||
listeners.remove(wrapper)
|
||||
}
|
||||
|
||||
wrapper.get()?.onStatusBarMarginUpdated(marginLeft, marginRight)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface StatusBarMarginUpdatedListener {
|
||||
fun onStatusBarMarginUpdated(marginLeft: Int, marginRight: Int)
|
||||
}
|
||||
@@ -62,7 +62,6 @@ import com.android.systemui.statusbar.SuperStatusBarViewFactory;
|
||||
import com.android.systemui.statusbar.SysuiStatusBarStateController;
|
||||
import com.android.systemui.statusbar.VibratorHelper;
|
||||
import com.android.systemui.statusbar.charging.WiredChargingRippleController;
|
||||
import com.android.systemui.statusbar.events.PrivacyDotViewController;
|
||||
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
|
||||
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
|
||||
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
|
||||
@@ -91,6 +90,7 @@ import com.android.systemui.statusbar.phone.ShadeController;
|
||||
import com.android.systemui.statusbar.phone.StatusBar;
|
||||
import com.android.systemui.statusbar.phone.StatusBarIconController;
|
||||
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
|
||||
import com.android.systemui.statusbar.phone.StatusBarLocationPublisher;
|
||||
import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter;
|
||||
import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
|
||||
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
|
||||
@@ -212,7 +212,7 @@ public interface StatusBarPhoneModule {
|
||||
WiredChargingRippleController chargingRippleAnimationController,
|
||||
OngoingCallController ongoingCallController,
|
||||
SystemStatusAnimationScheduler animationScheduler,
|
||||
PrivacyDotViewController dotViewController,
|
||||
StatusBarLocationPublisher locationPublisher,
|
||||
FeatureFlags featureFlags,
|
||||
KeyguardUnlockAnimationController keyguardUnlockAnimationController) {
|
||||
return new StatusBar(
|
||||
@@ -298,7 +298,7 @@ public interface StatusBarPhoneModule {
|
||||
chargingRippleAnimationController,
|
||||
ongoingCallController,
|
||||
animationScheduler,
|
||||
dotViewController,
|
||||
locationPublisher,
|
||||
featureFlags,
|
||||
keyguardUnlockAnimationController);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ import androidx.test.filters.SmallTest;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiBaseFragmentTest;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.statusbar.events.PrivacyDotViewController;
|
||||
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
|
||||
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
|
||||
|
||||
@@ -57,7 +56,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
|
||||
private StatusBarStateController mStatusBarStateController;
|
||||
private OngoingCallController mOngoingCallController;
|
||||
private SystemStatusAnimationScheduler mAnimationScheduler;
|
||||
private PrivacyDotViewController mDotViewController;
|
||||
private StatusBarLocationPublisher mLocationPublisher;
|
||||
|
||||
public CollapsedStatusBarFragmentTest() {
|
||||
super(CollapsedStatusBarFragment.class);
|
||||
@@ -224,12 +223,12 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
|
||||
protected Fragment instantiate(Context context, String className, Bundle arguments) {
|
||||
mOngoingCallController = mock(OngoingCallController.class);
|
||||
mAnimationScheduler = mock(SystemStatusAnimationScheduler.class);
|
||||
mDotViewController = mock(PrivacyDotViewController.class);
|
||||
mLocationPublisher = mock(StatusBarLocationPublisher.class);
|
||||
setUpNotificationIconAreaController();
|
||||
return new CollapsedStatusBarFragment(
|
||||
mOngoingCallController,
|
||||
mAnimationScheduler,
|
||||
mDotViewController,
|
||||
mLocationPublisher,
|
||||
mMockNotificationAreaController);
|
||||
}
|
||||
|
||||
|
||||
@@ -115,7 +115,6 @@ import com.android.systemui.statusbar.StatusBarStateControllerImpl;
|
||||
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
|
||||
import com.android.systemui.statusbar.VibratorHelper;
|
||||
import com.android.systemui.statusbar.charging.WiredChargingRippleController;
|
||||
import com.android.systemui.statusbar.events.PrivacyDotViewController;
|
||||
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
|
||||
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryListener;
|
||||
@@ -267,7 +266,7 @@ public class StatusBarTest extends SysuiTestCase {
|
||||
@Mock private WiredChargingRippleController mWiredChargingRippleController;
|
||||
@Mock private OngoingCallController mOngoingCallController;
|
||||
@Mock private SystemStatusAnimationScheduler mAnimationScheduler;
|
||||
@Mock private PrivacyDotViewController mDotViewController;
|
||||
@Mock private StatusBarLocationPublisher mLocationPublisher;
|
||||
@Mock private FeatureFlags mFeatureFlags;
|
||||
@Mock private IWallpaperManager mWallpaperManager;
|
||||
@Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
|
||||
@@ -437,7 +436,7 @@ public class StatusBarTest extends SysuiTestCase {
|
||||
mWiredChargingRippleController,
|
||||
mOngoingCallController,
|
||||
mAnimationScheduler,
|
||||
mDotViewController,
|
||||
mLocationPublisher,
|
||||
mFeatureFlags,
|
||||
mKeyguardUnlockAnimationController);
|
||||
when(mKeyguardViewMediator.registerStatusBar(any(StatusBar.class), any(ViewGroup.class),
|
||||
|
||||
Reference in New Issue
Block a user