summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Caitlin Cassidy <ccassidy@google.com> 2021-04-08 20:49:49 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2021-04-08 20:49:49 +0000
commit1ba1dd34067e3e643bc65506981047bf4c1f59d5 (patch)
tree02897e4cc03a842e3a71ac8df89782b519e919f4
parent5b6504f6c7e24f61595981c8ce3f71a888cd1b15 (diff)
parent2cbafc1941f5225ec35a5ca9405a69dd46b1dc9e (diff)
Merge "[Ongoing Call Chip] Add an ongoing call chip in the status bar." into sc-dev
-rw-r--r--packages/SystemUI/res/drawable/ongoing_call_chip_bg.xml20
-rw-r--r--packages/SystemUI/res/layout/ongoing_call_chip.xml50
-rw-r--r--packages/SystemUI/res/layout/status_bar.xml2
-rw-r--r--packages/SystemUI/res/values/dimens.xml7
-rw-r--r--packages/SystemUI/res/values/flags.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt55
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallListener.kt26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java50
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt153
11 files changed, 391 insertions, 10 deletions
diff --git a/packages/SystemUI/res/drawable/ongoing_call_chip_bg.xml b/packages/SystemUI/res/drawable/ongoing_call_chip_bg.xml
new file mode 100644
index 000000000000..bdd6270bb50b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ongoing_call_chip_bg.xml
@@ -0,0 +1,20 @@
+<!--
+ ~ 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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="?android:attr/colorAccent" />
+ <corners android:radius="@dimen/ongoing_call_chip_corner_radius" />
+</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/ongoing_call_chip.xml b/packages/SystemUI/res/layout/ongoing_call_chip.xml
new file mode 100644
index 000000000000..c90fc3151ee7
--- /dev/null
+++ b/packages/SystemUI/res/layout/ongoing_call_chip.xml
@@ -0,0 +1,50 @@
+<!--
+ ~ 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.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/ongoing_call_chip"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/ongoing_appops_chip_height"
+ android:layout_gravity="center_vertical|start"
+ android:gravity="center_vertical"
+ android:background="@drawable/ongoing_call_chip_bg"
+ android:paddingStart="@dimen/ongoing_call_chip_side_padding"
+ android:paddingEnd="@dimen/ongoing_call_chip_side_padding"
+ android:visibility="gone"
+>
+
+ <ImageView
+ android:src="@*android:drawable/ic_phone"
+ android:layout_width="@dimen/ongoing_call_chip_icon_size"
+ android:layout_height="@dimen/ongoing_call_chip_icon_size"
+ android:paddingEnd="@dimen/ongoing_call_chip_icon_text_padding"
+ android:tint="?android:attr/colorPrimary"
+ />
+
+ <!-- TODO(b/183229367): The text in this view isn't quite centered within the chip. -->
+ <!-- TODO(b/183229367): This text view's width shouldn't change as the time increases. -->
+ <Chronometer
+ android:id="@+id/ongoing_call_chip_time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:gravity="center"
+ android:textAppearance="@android:style/TextAppearance.Material.Small"
+ android:fontFamily="@*android:string/config_headlineFontFamily"
+ android:textColor="?android:attr/colorPrimary"
+ />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index f8db97dbf800..8b244c757649 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -82,6 +82,8 @@
android:gravity="center_vertical|start"
/>
+ <include layout="@layout/ongoing_call_chip" />
+
<com.android.systemui.statusbar.AlphaOptimizedFrameLayout
android:id="@+id/notification_icon_area"
android:layout_width="0dp"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 237edf8c973b..e834f3f18c10 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1442,4 +1442,11 @@
<dimen name="wallet_empty_state_corner_radius">24dp</dimen>
<dimen name="wallet_tile_card_view_height">32dp</dimen>
<dimen name="wallet_tile_card_view_width">50dp</dimen>
+
+ <!-- Ongoing call chip -->
+ <dimen name="ongoing_call_chip_side_padding">12dp</dimen>
+ <dimen name="ongoing_call_chip_icon_size">16dp</dimen>
+ <!-- The padding between the icon and the text. -->
+ <dimen name="ongoing_call_chip_icon_text_padding">4dp</dimen>
+ <dimen name="ongoing_call_chip_corner_radius">28dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index c39db941af38..bbf204844e29 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -49,7 +49,7 @@
<bool name="flag_charging_ripple">false</bool>
- <bool name="flag_ongoing_call_status_bar_chip">false</bool>
+ <bool name="flag_ongoing_call_status_bar_chip">true</bool>
<bool name="flag_smartspace">false</bool>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index 14c73b5cbb4c..20383feff9bc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -63,6 +63,7 @@ import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.util.time.SystemClock;
import com.android.wm.shell.bubbles.Bubbles;
import java.util.Optional;
@@ -234,9 +235,11 @@ public interface StatusBarDependenciesModule {
@Provides
@SysUISingleton
static OngoingCallController provideOngoingCallController(
- CommonNotifCollection notifCollection, FeatureFlags featureFlags) {
+ CommonNotifCollection notifCollection,
+ FeatureFlags featureFlags,
+ SystemClock systemClock) {
OngoingCallController ongoingCallController =
- new OngoingCallController(notifCollection, featureFlags);
+ new OngoingCallController(notifCollection, featureFlags, systemClock);
ongoingCallController.init();
return ongoingCallController;
}
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 f64a0e03698a..9d1c60928106 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -38,6 +38,7 @@ import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
+import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallListener;
import com.android.systemui.statusbar.policy.EncryptionHelper;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.NetworkController;
@@ -67,6 +68,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
private NetworkController mNetworkController;
private LinearLayout mSystemIconArea;
private View mClockView;
+ private ViewGroup mOngoingCallChip;
private View mNotificationIconAreaInner;
private View mCenteredIconArea;
private int mDisabled1;
@@ -86,6 +88,20 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
}
};
+ private final OngoingCallListener mOngoingCallListener = new OngoingCallListener() {
+ @Override
+ public void onOngoingCallStarted(boolean animate) {
+ disable(getContext().getDisplayId(), mDisabled1, mDisabled2, animate);
+ animateShow(mOngoingCallChip, animate);
+ }
+
+ @Override
+ public void onOngoingCallEnded(boolean animate) {
+ disable(getContext().getDisplayId(), mDisabled1, mDisabled2, animate);
+ animateHiddenState(mOngoingCallChip, View.GONE, animate);
+ }
+ };
+
@Inject
public CollapsedStatusBarFragment(OngoingCallController ongoingCallController) {
mOngoingCallController = ongoingCallController;
@@ -142,6 +158,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
super.onResume();
mCommandQueue.addCallback(this);
mStatusBarStateController.addCallback(this);
+ mOngoingCallController.addCallback(mOngoingCallListener);
}
@Override
@@ -149,6 +166,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
super.onPause();
mCommandQueue.removeCallback(this);
mStatusBarStateController.removeCallback(this);
+ mOngoingCallController.removeCallback(mOngoingCallListener);
}
@Override
@@ -179,6 +197,8 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
}
statusBarCenteredIconArea.addView(mCenteredIconArea);
+ initOngoingCallChip();
+
// Default to showing until we know otherwise.
showNotificationIconArea(false);
}
@@ -228,6 +248,10 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
state |= DISABLE_CLOCK;
}
+ if (mOngoingCallController.getHasOngoingCall()) {
+ state |= DISABLE_NOTIFICATION_ICONS;
+ }
+
if (!mKeyguardStateController.isLaunchTransitionFadingAway()
&& !mKeyguardStateController.isKeyguardFadingAway()
&& shouldHideNotificationIcons()
@@ -395,6 +419,11 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
}
}
+ private void initOngoingCallChip() {
+ mOngoingCallChip = mStatusBar.findViewById(R.id.ongoing_call_chip);
+ mOngoingCallController.setChipView(mOngoingCallChip);
+ }
+
@Override
public void onStateChanged(int newState) {
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 60d3ea3a7093..b55db6fd1e7d 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
@@ -19,11 +19,16 @@ package com.android.systemui.statusbar.phone.ongoingcall
import android.app.Notification
import android.app.Notification.CallStyle.CALL_TYPE_ONGOING
import android.util.Log
+import android.view.ViewGroup
+import android.widget.Chronometer
+import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.FeatureFlags
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
+import com.android.systemui.statusbar.policy.CallbackController
+import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
/**
@@ -32,19 +37,39 @@ import javax.inject.Inject
@SysUISingleton
class OngoingCallController @Inject constructor(
private val notifCollection: CommonNotifCollection,
- private val featureFlags: FeatureFlags
-) {
+ private val featureFlags: FeatureFlags,
+ private val systemClock: SystemClock
+) : CallbackController<OngoingCallListener> {
+
+ var hasOngoingCall = false
+ private set
+ private var chipView: ViewGroup? = null
+
+ private val mListeners: MutableList<OngoingCallListener> = mutableListOf()
private val notifListener = object : NotifCollectionListener {
override fun onEntryUpdated(entry: NotificationEntry) {
- if (isOngoingCallNotification(entry) && DEBUG) {
- Log.d(TAG, "Ongoing call notification updated")
+ if (isOngoingCallNotification(entry)) {
+ val timeView = chipView?.findViewById<Chronometer>(R.id.ongoing_call_chip_time)
+ if (timeView != null) {
+ hasOngoingCall = true
+ val callStartTime = entry.sbn.notification.`when`
+ timeView.base = callStartTime -
+ System.currentTimeMillis() +
+ systemClock.elapsedRealtime()
+ timeView.start()
+ 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")
+ }
}
}
override fun onEntryRemoved(entry: NotificationEntry, reason: Int) {
- if (isOngoingCallNotification(entry) && DEBUG) {
- Log.d(TAG, "Ongoing call notification removed")
+ if (isOngoingCallNotification(entry)) {
+ hasOngoingCall = false
+ mListeners.forEach { l -> l.onOngoingCallEnded(animate = true) }
}
}
}
@@ -54,6 +79,24 @@ class OngoingCallController @Inject constructor(
notifCollection.addCollectionListener(notifListener)
}
}
+
+ fun setChipView(chipView: ViewGroup?) {
+ this.chipView = chipView
+ }
+
+ override fun addCallback(listener: OngoingCallListener) {
+ synchronized(mListeners) {
+ if (!mListeners.contains(listener)) {
+ mListeners.add(listener)
+ }
+ }
+ }
+
+ override fun removeCallback(listener: OngoingCallListener) {
+ synchronized(mListeners) {
+ mListeners.remove(listener)
+ }
+ }
}
private fun isOngoingCallNotification(entry: NotificationEntry): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallListener.kt
new file mode 100644
index 000000000000..7c583a1491e0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallListener.kt
@@ -0,0 +1,26 @@
+/*
+ * 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.ongoingcall
+
+/** A listener that's notified when an ongoing call is started or ended. */
+interface OngoingCallListener {
+ /** Called when an ongoing call is started. */
+ fun onOngoingCallStarted(animate: Boolean)
+
+ /** Called when an ongoing call is ended. */
+ fun onOngoingCallEnded(animate: 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 96cdaf98d964..67fd5eb1acac 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
@@ -38,12 +38,16 @@ import com.android.systemui.R;
import com.android.systemui.SysuiBaseFragmentTest;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
+import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallListener;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
+import java.util.Objects;
+
@RunWith(AndroidTestingRunner.class)
@RunWithLooper(setAsMainLooper = true)
@SmallTest
@@ -53,6 +57,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
private View mNotificationAreaInner;
private View mCenteredNotificationAreaView;
private StatusBarStateController mStatusBarStateController;
+ private OngoingCallController mOngoingCallController;
public CollapsedStatusBarFragmentTest() {
super(CollapsedStatusBarFragment.class);
@@ -162,8 +167,51 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.VISIBLE));
}
+ @Test
+ public void onOngoingCallStarted_notificationsHiddenAndOngoingCallChipDisplayed() {
+ mFragments.dispatchResume();
+ processAllMessages();
+
+ CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
+ fragment.initNotificationIconArea(mMockNotificiationAreaController);
+
+ ArgumentCaptor<OngoingCallListener> ongoingCallListenerCaptor = ArgumentCaptor.forClass(
+ OngoingCallListener.class);
+ Mockito.verify(mOngoingCallController).addCallback(ongoingCallListenerCaptor.capture());
+ OngoingCallListener listener = Objects.requireNonNull(ongoingCallListenerCaptor.getValue());
+
+ when(mOngoingCallController.getHasOngoingCall()).thenReturn(true);
+ listener.onOngoingCallStarted(/* animate= */ false);
+
+ assertEquals(View.VISIBLE,
+ mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
+ Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.INVISIBLE));
+ }
+
+ @Test
+ public void onOngoingCallEnded_notificationsDisplayedAndOngoingCallChipHidden() {
+ mFragments.dispatchResume();
+ processAllMessages();
+
+ CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
+ fragment.initNotificationIconArea(mMockNotificiationAreaController);
+
+ ArgumentCaptor<OngoingCallListener> ongoingCallListenerCaptor = ArgumentCaptor.forClass(
+ OngoingCallListener.class);
+ Mockito.verify(mOngoingCallController).addCallback(ongoingCallListenerCaptor.capture());
+ OngoingCallListener listener = Objects.requireNonNull(ongoingCallListenerCaptor.getValue());
+
+ when(mOngoingCallController.getHasOngoingCall()).thenReturn(false);
+ listener.onOngoingCallEnded(/* animate= */ false);
+
+ assertEquals(View.GONE,
+ mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
+ Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.VISIBLE));
+ }
+
@Override
protected Fragment instantiate(Context context, String className, Bundle arguments) {
- return new CollapsedStatusBarFragment(mock(OngoingCallController.class));
+ mOngoingCallController = mock(OngoingCallController.class);
+ return new CollapsedStatusBarFragment(mOngoingCallController);
}
}
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
new file mode 100644
index 000000000000..d87d1d1b92db
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
@@ -0,0 +1,153 @@
+/*
+ * 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.ongoingcall
+
+import android.app.Notification
+import android.app.PendingIntent
+import android.app.Person
+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 com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.never
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class OngoingCallControllerTest : SysuiTestCase() {
+
+ private lateinit var controller: OngoingCallController
+ private lateinit var notifCollectionListener: NotifCollectionListener
+
+ @Mock private lateinit var mockOngoingCallListener: OngoingCallListener
+
+ private lateinit var chipView: LinearLayout
+
+ @Before
+ fun setUp() {
+ allowTestableLooperAsMainThread()
+ TestableLooper.get(this).runWithLooper {
+ chipView = LayoutInflater.from(mContext)
+ .inflate(R.layout.ongoing_call_chip, null) as LinearLayout
+ }
+
+ MockitoAnnotations.initMocks(this)
+ val featureFlags = mock(FeatureFlags::class.java)
+ `when`(featureFlags.isOngoingCallStatusBarChipEnabled).thenReturn(true)
+ val notificationCollection = mock(CommonNotifCollection::class.java)
+
+ controller = OngoingCallController(notificationCollection, featureFlags, FakeSystemClock())
+ controller.init()
+ controller.addCallback(mockOngoingCallListener)
+ controller.setChipView(chipView)
+
+ val collectionListenerCaptor = ArgumentCaptor.forClass(NotifCollectionListener::class.java)
+ verify(notificationCollection).addCollectionListener(collectionListenerCaptor.capture())
+ notifCollectionListener = collectionListenerCaptor.value!!
+ }
+
+ @Test
+ fun onEntryUpdated_isOngoingCallNotif_listenerNotifiedWithRightCallTime() {
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+
+ verify(mockOngoingCallListener).onOngoingCallStarted(anyBoolean())
+ }
+
+ @Test
+ fun onEntryUpdated_notOngoingCallNotif_listenerNotNotified() {
+ notifCollectionListener.onEntryUpdated(createNotCallNotifEntry())
+
+ verify(mockOngoingCallListener, never()).onOngoingCallStarted(anyBoolean())
+ }
+
+ @Test
+ fun onEntryRemoved_ongoingCallNotif_listenerNotified() {
+ notifCollectionListener.onEntryRemoved(createOngoingCallNotifEntry(), REASON_USER_STOPPED)
+
+ verify(mockOngoingCallListener).onOngoingCallEnded(anyBoolean())
+ }
+
+ @Test
+ fun onEntryRemoved_notOngoingCallNotif_listenerNotNotified() {
+ notifCollectionListener.onEntryRemoved(createNotCallNotifEntry(), REASON_USER_STOPPED)
+
+ verify(mockOngoingCallListener, never()).onOngoingCallEnded(anyBoolean())
+ }
+
+ @Test
+ fun hasOngoingCall_noOngoingCallNotifSent_returnsFalse() {
+ assertThat(controller.hasOngoingCall).isFalse()
+ }
+
+ @Test
+ fun hasOngoingCall_ongoingCallNotifSentAndChipViewSet_returnsTrue() {
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+
+ assertThat(controller.hasOngoingCall).isTrue()
+ }
+
+ @Test
+ fun hasOngoingCall_ongoingCallNotifSentButNoChipView_returnsFalse() {
+ controller.setChipView(null)
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+
+ assertThat(controller.hasOngoingCall).isFalse()
+ }
+
+ @Test
+ fun hasOngoingCall_ongoingCallNotifSentThenRemoved_returnsFalse() {
+ val ongoingCallNotifEntry = createOngoingCallNotifEntry()
+
+ notifCollectionListener.onEntryUpdated(ongoingCallNotifEntry)
+ notifCollectionListener.onEntryRemoved(ongoingCallNotifEntry, REASON_USER_STOPPED)
+
+ assertThat(controller.hasOngoingCall).isFalse()
+ }
+
+ private fun createOngoingCallNotifEntry(): NotificationEntry {
+ val notificationEntryBuilder = NotificationEntryBuilder()
+ notificationEntryBuilder.modifyNotification(context).style = ongoingCallStyle
+ return notificationEntryBuilder.build()
+ }
+
+ private fun createNotCallNotifEntry() = NotificationEntryBuilder().build()
+}
+
+private val ongoingCallStyle = Notification.CallStyle.forOngoingCall(
+ Person.Builder().setName("name").build(),
+ /* hangUpIntent= */ mock(PendingIntent::class.java))