[Ongoing Call Chip] Add an ongoing call chip in the status bar.
Light mode: https://screenshot.googleplex.com/3uehhoJ4EYHQr47 Dark mode: https://screenshot.googleplex.com/7ymFjTNUhQmUhZA Bug: 183229367 Test: New tests added, atest, and manual Change-Id: Id9d9e8f0436e228beb3f2c5f5a9a81f6a07aa033
This commit is contained in:
20
packages/SystemUI/res/drawable/ongoing_call_chip_bg.xml
Normal file
20
packages/SystemUI/res/drawable/ongoing_call_chip_bg.xml
Normal file
@@ -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>
|
||||
50
packages/SystemUI/res/layout/ongoing_call_chip.xml
Normal file
50
packages/SystemUI/res/layout/ongoing_call_chip.xml
Normal file
@@ -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>
|
||||
@@ -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"
|
||||
|
||||
@@ -1441,4 +1441,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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
Reference in New Issue
Block a user