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:
Evan Laird
2021-04-27 17:57:11 -04:00
parent 01d373cec7
commit 5f59d2224c
9 changed files with 139 additions and 31 deletions

View File

@@ -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) {

View File

@@ -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()
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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();

View File

@@ -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)
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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),