summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt86
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt48
4 files changed, 106 insertions, 41 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index 4e57e44f38d7..1eccfd8e7254 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -162,6 +162,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);
mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area);
mClockView = mStatusBar.findViewById(R.id.clock);
+ mOngoingCallChip = mStatusBar.findViewById(R.id.ongoing_call_chip);
showSystemIconArea(false);
showClock(false);
initEmergencyCryptkeeperText();
@@ -182,7 +183,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
super.onResume();
mCommandQueue.addCallback(this);
mStatusBarStateController.addCallback(this);
- mOngoingCallController.addCallback(mOngoingCallListener);
+ initOngoingCallChip();
}
@Override
@@ -221,8 +222,6 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
}
statusBarCenteredIconArea.addView(mCenteredIconArea);
- initOngoingCallChip();
-
// Default to showing until we know otherwise.
showNotificationIconArea(false);
}
@@ -273,7 +272,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
state |= DISABLE_CLOCK;
}
- if (mOngoingCallController.getHasOngoingCall()) {
+ if (mOngoingCallController.hasOngoingCall()) {
state |= DISABLE_NOTIFICATION_ICONS;
}
@@ -448,7 +447,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
}
private void initOngoingCallChip() {
- mOngoingCallChip = mStatusBar.findViewById(R.id.ongoing_call_chip);
+ mOngoingCallController.addCallback(mOngoingCallListener);
mOngoingCallController.setChipView(mOngoingCallChip);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index 93ea77b8378c..96473c2a961c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone.ongoingcall
import android.app.Notification
import android.app.Notification.CallStyle.CALL_TYPE_ONGOING
+import android.content.Intent
import android.util.Log
import android.view.ViewGroup
import android.widget.Chronometer
@@ -44,8 +45,8 @@ class OngoingCallController @Inject constructor(
private val activityStarter: ActivityStarter
) : CallbackController<OngoingCallListener> {
- var hasOngoingCall = false
- private set
+ /** Null if there's no ongoing call. */
+ private var ongoingCallInfo: OngoingCallInfo? = null
private var chipView: ViewGroup? = null
private val mListeners: MutableList<OngoingCallListener> = mutableListOf()
@@ -53,35 +54,16 @@ class OngoingCallController @Inject constructor(
private val notifListener = object : NotifCollectionListener {
override fun onEntryUpdated(entry: NotificationEntry) {
if (isOngoingCallNotification(entry)) {
- val currentChipView = chipView
- val timeView =
- currentChipView?.findViewById<Chronometer>(R.id.ongoing_call_chip_time)
-
- if (currentChipView != null && timeView != null) {
- hasOngoingCall = true
- val callStartTime = entry.sbn.notification.`when`
- timeView.base = callStartTime -
- System.currentTimeMillis() +
- systemClock.elapsedRealtime()
- timeView.start()
-
- currentChipView.setOnClickListener {
- activityStarter.postStartActivityDismissingKeyguard(
- entry.sbn.notification.contentIntent.intent, 0,
- ActivityLaunchAnimator.Controller.fromView(it))
- }
-
- mListeners.forEach { l -> l.onOngoingCallStarted(animate = true) }
- } else if (DEBUG) {
- Log.w(TAG, "Ongoing call chip view could not be found; " +
- "Not displaying chip in status bar")
- }
+ ongoingCallInfo = OngoingCallInfo(
+ entry.sbn.notification.`when`,
+ entry.sbn.notification.contentIntent.intent)
+ updateChip()
}
}
override fun onEntryRemoved(entry: NotificationEntry, reason: Int) {
if (isOngoingCallNotification(entry)) {
- hasOngoingCall = false
+ ongoingCallInfo = null
mListeners.forEach { l -> l.onOngoingCallEnded(animate = true) }
}
}
@@ -93,10 +75,23 @@ class OngoingCallController @Inject constructor(
}
}
- fun setChipView(chipView: ViewGroup?) {
+ /**
+ * Sets the chip view that will contain ongoing call information.
+ *
+ * Should only be called from [CollapedStatusBarFragment].
+ */
+ fun setChipView(chipView: ViewGroup) {
this.chipView = chipView
+ if (hasOngoingCall()) {
+ updateChip()
+ }
}
+ /**
+ * Returns true if there's an active ongoing call that can be displayed in a status bar chip.
+ */
+ fun hasOngoingCall(): Boolean = ongoingCallInfo != null
+
override fun addCallback(listener: OngoingCallListener) {
synchronized(mListeners) {
if (!mListeners.contains(listener)) {
@@ -110,6 +105,43 @@ class OngoingCallController @Inject constructor(
mListeners.remove(listener)
}
}
+
+ private fun updateChip() {
+ val currentOngoingCallInfo = ongoingCallInfo ?: return
+
+ val currentChipView = chipView
+ val timeView =
+ currentChipView?.findViewById<Chronometer>(R.id.ongoing_call_chip_time)
+
+ if (currentChipView != null && timeView != null) {
+ timeView.base = currentOngoingCallInfo.callStartTime -
+ System.currentTimeMillis() +
+ systemClock.elapsedRealtime()
+ timeView.start()
+
+ currentChipView.setOnClickListener {
+ activityStarter.postStartActivityDismissingKeyguard(
+ currentOngoingCallInfo.intent, 0,
+ ActivityLaunchAnimator.Controller.fromView(it))
+ }
+
+ mListeners.forEach { l -> l.onOngoingCallStarted(animate = true) }
+ } else {
+ // If we failed to update the chip, don't store the ongoing call info. Then
+ // [hasOngoingCall] will return false and we fall back to typical notification handling.
+ ongoingCallInfo = null
+
+ if (DEBUG) {
+ Log.w(TAG, "Ongoing call chip view could not be found; " +
+ "Not displaying chip in status bar")
+ }
+ }
+ }
+
+ private class OngoingCallInfo(
+ val callStartTime: Long,
+ val intent: Intent
+ )
}
private fun isOngoingCallNotification(entry: NotificationEntry): Boolean {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
index 929a7e1543fb..0e3e0cc8ea97 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
@@ -184,7 +184,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
Mockito.verify(mOngoingCallController).addCallback(ongoingCallListenerCaptor.capture());
OngoingCallListener listener = Objects.requireNonNull(ongoingCallListenerCaptor.getValue());
- when(mOngoingCallController.getHasOngoingCall()).thenReturn(true);
+ when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
listener.onOngoingCallStarted(/* animate= */ false);
assertEquals(View.VISIBLE,
@@ -205,7 +205,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
Mockito.verify(mOngoingCallController).addCallback(ongoingCallListenerCaptor.capture());
OngoingCallListener listener = Objects.requireNonNull(ongoingCallListenerCaptor.getValue());
- when(mOngoingCallController.getHasOngoingCall()).thenReturn(false);
+ when(mOngoingCallController.hasOngoingCall()).thenReturn(false);
listener.onOngoingCallEnded(/* animate= */ false);
assertEquals(View.GONE,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
index 73fcc919eb81..c244290fdacd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
@@ -19,12 +19,13 @@ package com.android.systemui.statusbar.phone.ongoingcall
import android.app.Notification
import android.app.PendingIntent
import android.app.Person
+import android.content.Intent
import android.service.notification.NotificationListenerService.REASON_USER_STOPPED
-import androidx.test.filters.SmallTest
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.LayoutInflater
import android.widget.LinearLayout
+import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.plugins.ActivityStarter
@@ -44,6 +45,7 @@ import org.mockito.Mock
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.never
+import org.mockito.Mockito.times
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@@ -114,22 +116,24 @@ class OngoingCallControllerTest : SysuiTestCase() {
@Test
fun hasOngoingCall_noOngoingCallNotifSent_returnsFalse() {
- assertThat(controller.hasOngoingCall).isFalse()
+ assertThat(controller.hasOngoingCall()).isFalse()
}
@Test
fun hasOngoingCall_ongoingCallNotifSentAndChipViewSet_returnsTrue() {
notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
- assertThat(controller.hasOngoingCall).isTrue()
+ assertThat(controller.hasOngoingCall()).isTrue()
}
@Test
- fun hasOngoingCall_ongoingCallNotifSentButNoChipView_returnsFalse() {
- controller.setChipView(null)
+ fun hasOngoingCall_ongoingCallNotifSentButInvalidChipView_returnsFalse() {
+ val invalidChipView = LinearLayout(context)
+ controller.setChipView(invalidChipView)
+
notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
- assertThat(controller.hasOngoingCall).isFalse()
+ assertThat(controller.hasOngoingCall()).isFalse()
}
@Test
@@ -139,12 +143,42 @@ class OngoingCallControllerTest : SysuiTestCase() {
notifCollectionListener.onEntryUpdated(ongoingCallNotifEntry)
notifCollectionListener.onEntryRemoved(ongoingCallNotifEntry, REASON_USER_STOPPED)
- assertThat(controller.hasOngoingCall).isFalse()
+ assertThat(controller.hasOngoingCall()).isFalse()
+ }
+
+ /**
+ * This test fakes a theme change during an ongoing call.
+ *
+ * When a theme change happens, [CollapsedStatusBarFragment] and its views get re-created, so
+ * [OngoingCallController.setChipView] gets called with a new view. If there's an active ongoing
+ * call when the theme changes, the new view needs to be updated with the call information.
+ */
+ @Test
+ fun setChipView_whenHasOngoingCallIsTrue_listenerNotifiedWithNewView() {
+ // Start an ongoing call.
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+
+ lateinit var newChipView: LinearLayout
+ TestableLooper.get(this).runWithLooper {
+ newChipView = LayoutInflater.from(mContext)
+ .inflate(R.layout.ongoing_call_chip, null) as LinearLayout
+ }
+
+ // Change the chip view associated with the controller.
+ controller.setChipView(newChipView)
+
+ // Verify the listener was notified once for the initial call and again when the new view
+ // was set.
+ verify(mockOngoingCallListener, times(2)).onOngoingCallStarted(anyBoolean())
}
private fun createOngoingCallNotifEntry(): NotificationEntry {
val notificationEntryBuilder = NotificationEntryBuilder()
notificationEntryBuilder.modifyNotification(context).style = ongoingCallStyle
+
+ val contentIntent = mock(PendingIntent::class.java)
+ `when`(contentIntent.intent).thenReturn(mock(Intent::class.java))
+ notificationEntryBuilder.modifyNotification(context).setContentIntent(contentIntent)
return notificationEntryBuilder.build()
}