Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3650a601 authored by Yining Liu's avatar Yining Liu
Browse files

Convert NotificationContentViewTest to Kotlin

Conversion from Java to Kotlin to enable future added tests written with Kotlin.

Bug: 244522899

Test: `atest NotificationContentViewTest`
Change-Id: Ib02c2c45682b8977004748a2a134b7520abe4a49
parent 17f47db7
Loading
Loading
Loading
Loading
+0 −202
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 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.notification.row;

import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.view.NotificationHeaderView;
import android.view.View;
import android.view.ViewPropertyAnimator;

import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import com.android.internal.R;
import com.android.internal.widget.NotificationActionListLayout;
import com.android.internal.widget.NotificationExpandButton;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.statusbar.notification.FeedbackIcon;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

@SmallTest
@RunWith(AndroidJUnit4.class)
public class NotificationContentViewTest extends SysuiTestCase {

    NotificationContentView mView;

    @Before
    @UiThreadTest
    public void setup() {
        mDependency.injectMockDependency(MediaOutputDialogFactory.class);

        mView = new NotificationContentView(mContext, null);
        ExpandableNotificationRow row = new ExpandableNotificationRow(mContext, null);
        ExpandableNotificationRow mockRow = spy(row);
        doReturn(10).when(mockRow).getIntrinsicHeight();

        mView.setContainingNotification(mockRow);
        mView.setHeights(10, 20, 30);

        mView.setContractedChild(createViewWithHeight(10));
        mView.setExpandedChild(createViewWithHeight(20));
        mView.setHeadsUpChild(createViewWithHeight(30));

        mView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
        mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
    }

    private View createViewWithHeight(int height) {
        View view = new View(mContext, null);
        view.setMinimumHeight(height);
        return view;
    }

    @Test
    @UiThreadTest
    public void testSetFeedbackIcon() {
        View mockContracted = mock(NotificationHeaderView.class);
        when(mockContracted.findViewById(com.android.internal.R.id.feedback))
                .thenReturn(mockContracted);
        when(mockContracted.getContext()).thenReturn(mContext);
        View mockExpanded = mock(NotificationHeaderView.class);
        when(mockExpanded.findViewById(com.android.internal.R.id.feedback))
                .thenReturn(mockExpanded);
        when(mockExpanded.getContext()).thenReturn(mContext);
        View mockHeadsUp = mock(NotificationHeaderView.class);
        when(mockHeadsUp.findViewById(com.android.internal.R.id.feedback))
                .thenReturn(mockHeadsUp);
        when(mockHeadsUp.getContext()).thenReturn(mContext);

        mView.setContractedChild(mockContracted);
        mView.setExpandedChild(mockExpanded);
        mView.setHeadsUpChild(mockHeadsUp);

        mView.setFeedbackIcon(new FeedbackIcon(R.drawable.ic_feedback_alerted,
                R.string.notification_feedback_indicator_alerted));

        verify(mockContracted, times(1)).setVisibility(View.VISIBLE);
        verify(mockExpanded, times(1)).setVisibility(View.VISIBLE);
        verify(mockHeadsUp, times(1)).setVisibility(View.VISIBLE);
    }

    @Test
    @UiThreadTest
    public void testExpandButtonFocusIsCalled() {
        View mockContractedEB = mock(NotificationExpandButton.class);
        View mockContracted = mock(NotificationHeaderView.class);
        when(mockContracted.animate()).thenReturn(mock(ViewPropertyAnimator.class));
        when(mockContracted.findViewById(com.android.internal.R.id.expand_button)).thenReturn(
                mockContractedEB);
        when(mockContracted.getContext()).thenReturn(mContext);

        View mockExpandedEB = mock(NotificationExpandButton.class);
        View mockExpanded = mock(NotificationHeaderView.class);
        when(mockExpanded.animate()).thenReturn(mock(ViewPropertyAnimator.class));
        when(mockExpanded.findViewById(com.android.internal.R.id.expand_button)).thenReturn(
                mockExpandedEB);
        when(mockExpanded.getContext()).thenReturn(mContext);

        View mockHeadsUpEB = mock(NotificationExpandButton.class);
        View mockHeadsUp = mock(NotificationHeaderView.class);
        when(mockHeadsUp.animate()).thenReturn(mock(ViewPropertyAnimator.class));
        when(mockHeadsUp.findViewById(com.android.internal.R.id.expand_button)).thenReturn(
                mockHeadsUpEB);
        when(mockHeadsUp.getContext()).thenReturn(mContext);

        // Set up all 3 child forms
        mView.setContractedChild(mockContracted);
        mView.setExpandedChild(mockExpanded);
        mView.setHeadsUpChild(mockHeadsUp);

        // This is required to call requestAccessibilityFocus()
        mView.setFocusOnVisibilityChange();

        // The following will initialize the view and switch from not visible to expanded.
        // (heads-up is actually an alternate form of contracted, hence this enters expanded state)
        mView.setHeadsUp(true);

        verify(mockContractedEB, times(0)).requestAccessibilityFocus();
        verify(mockExpandedEB, times(1)).requestAccessibilityFocus();
        verify(mockHeadsUpEB, times(0)).requestAccessibilityFocus();
    }

    @Test
    @UiThreadTest
    public void testRemoteInputVisibleSetsActionsUnimportantHideDescendantsForAccessibility() {
        View mockContracted = mock(NotificationHeaderView.class);

        View mockExpandedActions = mock(NotificationActionListLayout.class);
        View mockExpanded = mock(NotificationHeaderView.class);
        when(mockExpanded.findViewById(com.android.internal.R.id.actions)).thenReturn(
                mockExpandedActions);

        View mockHeadsUpActions = mock(NotificationActionListLayout.class);
        View mockHeadsUp = mock(NotificationHeaderView.class);
        when(mockHeadsUp.findViewById(com.android.internal.R.id.actions)).thenReturn(
                mockHeadsUpActions);

        mView.setContractedChild(mockContracted);
        mView.setExpandedChild(mockExpanded);
        mView.setHeadsUpChild(mockHeadsUp);

        mView.setRemoteInputVisible(true);

        verify(mockContracted, times(0)).findViewById(0);
        verify(mockExpandedActions, times(1)).setImportantForAccessibility(
                View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
        verify(mockHeadsUpActions, times(1)).setImportantForAccessibility(
                View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
    }

    @Test
    @UiThreadTest
    public void testRemoteInputInvisibleSetsActionsAutoImportantForAccessibility() {
        View mockContracted = mock(NotificationHeaderView.class);

        View mockExpandedActions = mock(NotificationActionListLayout.class);
        View mockExpanded = mock(NotificationHeaderView.class);
        when(mockExpanded.findViewById(com.android.internal.R.id.actions)).thenReturn(
                mockExpandedActions);

        View mockHeadsUpActions = mock(NotificationActionListLayout.class);
        View mockHeadsUp = mock(NotificationHeaderView.class);
        when(mockHeadsUp.findViewById(com.android.internal.R.id.actions)).thenReturn(
                mockHeadsUpActions);

        mView.setContractedChild(mockContracted);
        mView.setExpandedChild(mockExpanded);
        mView.setHeadsUpChild(mockHeadsUp);

        mView.setRemoteInputVisible(false);

        verify(mockContracted, times(0)).findViewById(0);
        verify(mockExpandedActions, times(1)).setImportantForAccessibility(
                View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
        verify(mockHeadsUpActions, times(1)).setImportantForAccessibility(
                View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
    }
}
+186 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.notification.row

import android.testing.AndroidTestingRunner
import android.view.NotificationHeaderView
import android.view.View
import androidx.test.filters.SmallTest
import com.android.internal.R
import com.android.internal.widget.NotificationActionListLayout
import com.android.internal.widget.NotificationExpandButton
import com.android.systemui.SysuiTestCase
import com.android.systemui.media.dialog.MediaOutputDialogFactory
import com.android.systemui.statusbar.notification.FeedbackIcon
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.never
import org.mockito.Mockito.verify

@SmallTest
@RunWith(AndroidTestingRunner::class)
class NotificationContentViewTest : SysuiTestCase() {
    private lateinit var view: NotificationContentView

    @Before
    fun setup() {
        mDependency.injectMockDependency(MediaOutputDialogFactory::class.java)

        view = NotificationContentView(mContext, /* attrs= */ null)
        val row = ExpandableNotificationRow(mContext, /* attrs= */ null)
        val spyRow = Mockito.spy(row)
        doReturn(10).whenever(spyRow).intrinsicHeight

        with(view) {
            setContainingNotification(spyRow)
            setHeights(/* smallHeight= */ 10, /* headsUpMaxHeight= */ 20, /* maxHeight= */ 30)
            contractedChild = createViewWithHeight(10)
            expandedChild = createViewWithHeight(20)
            headsUpChild = createViewWithHeight(30)
            measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
            layout(0, 0, view.measuredWidth, view.measuredHeight)
        }
    }

    private fun createViewWithHeight(height: Int) =
        View(mContext, /* attrs= */ null).apply { minimumHeight = height }

    @Test
    fun testSetFeedbackIcon() {
        // Given: contractedChild, enpandedChild, and headsUpChild being set
        val mockContracted = createMockNotificationHeaderView()
        val mockExpanded = createMockNotificationHeaderView()
        val mockHeadsUp = createMockNotificationHeaderView()

        with(view) {
            contractedChild = mockContracted
            expandedChild = mockExpanded
            headsUpChild = mockHeadsUp
        }

        // When: FeedBackIcon is set
        view.setFeedbackIcon(
            FeedbackIcon(
                R.drawable.ic_feedback_alerted,
                R.string.notification_feedback_indicator_alerted
            )
        )

        // Then: contractedChild, enpandedChild, and headsUpChild should be set to be visible
        verify(mockContracted).visibility = View.VISIBLE
        verify(mockExpanded).visibility = View.VISIBLE
        verify(mockHeadsUp).visibility = View.VISIBLE
    }

    private fun createMockNotificationHeaderView() =
        mock<NotificationHeaderView>().apply {
            whenever(this.findViewById<View>(R.id.feedback)).thenReturn(this)
            whenever(this.context).thenReturn(mContext)
        }

    @Test
    fun testExpandButtonFocusIsCalled() {
        val mockContractedEB = mock<NotificationExpandButton>()
        val mockContracted = createMockNotificationHeaderView(mockContractedEB)

        val mockExpandedEB = mock<NotificationExpandButton>()
        val mockExpanded = createMockNotificationHeaderView(mockExpandedEB)

        val mockHeadsUpEB = mock<NotificationExpandButton>()
        val mockHeadsUp = createMockNotificationHeaderView(mockHeadsUpEB)

        // Set up all 3 child forms
        view.contractedChild = mockContracted
        view.expandedChild = mockExpanded
        view.headsUpChild = mockHeadsUp

        // This is required to call requestAccessibilityFocus()
        view.setFocusOnVisibilityChange()

        // The following will initialize the view and switch from not visible to expanded.
        // (heads-up is actually an alternate form of contracted, hence this enters expanded state)
        view.setHeadsUp(true)
        verify(mockContractedEB, never()).requestAccessibilityFocus()
        verify(mockExpandedEB).requestAccessibilityFocus()
        verify(mockHeadsUpEB, never()).requestAccessibilityFocus()
    }

    private fun createMockNotificationHeaderView(mockExpandedEB: NotificationExpandButton) =
        mock<NotificationHeaderView>().apply {
            whenever(this.animate()).thenReturn(mock())
            whenever(this.findViewById<View>(R.id.expand_button)).thenReturn(mockExpandedEB)
            whenever(this.context).thenReturn(mContext)
        }

    @Test
    fun testRemoteInputVisibleSetsActionsUnimportantHideDescendantsForAccessibility() {
        val mockContracted = mock<NotificationHeaderView>()

        val mockExpandedActions = mock<NotificationActionListLayout>()
        val mockExpanded = mock<NotificationHeaderView>()
        whenever(mockExpanded.findViewById<View>(R.id.actions)).thenReturn(mockExpandedActions)

        val mockHeadsUpActions = mock<NotificationActionListLayout>()
        val mockHeadsUp = mock<NotificationHeaderView>()
        whenever(mockHeadsUp.findViewById<View>(R.id.actions)).thenReturn(mockHeadsUpActions)

        with(view) {
            contractedChild = mockContracted
            expandedChild = mockExpanded
            headsUpChild = mockHeadsUp
        }

        view.setRemoteInputVisible(true)

        verify(mockContracted, never()).findViewById<View>(0)
        verify(mockExpandedActions).importantForAccessibility =
            View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
        verify(mockHeadsUpActions).importantForAccessibility =
            View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
    }

    @Test
    fun testRemoteInputInvisibleSetsActionsAutoImportantForAccessibility() {
        val mockContracted = mock<NotificationHeaderView>()

        val mockExpandedActions = mock<NotificationActionListLayout>()
        val mockExpanded = mock<NotificationHeaderView>()
        whenever(mockExpanded.findViewById<View>(R.id.actions)).thenReturn(mockExpandedActions)

        val mockHeadsUpActions = mock<NotificationActionListLayout>()
        val mockHeadsUp = mock<NotificationHeaderView>()
        whenever(mockHeadsUp.findViewById<View>(R.id.actions)).thenReturn(mockHeadsUpActions)

        with(view) {
            contractedChild = mockContracted
            expandedChild = mockExpanded
            headsUpChild = mockHeadsUp
        }

        view.setRemoteInputVisible(false)

        verify(mockContracted, never()).findViewById<View>(0)
        verify(mockExpandedActions).importantForAccessibility =
            View.IMPORTANT_FOR_ACCESSIBILITY_AUTO
        verify(mockHeadsUpActions).importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_AUTO
    }
}
+4 −1
Original line number Diff line number Diff line
@@ -26,7 +26,9 @@ package com.android.systemui.util.mockito
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatcher
import org.mockito.Mockito
import org.mockito.Mockito.`when`
import org.mockito.stubbing.OngoingStubbing
import org.mockito.stubbing.Stubber

/**
 * Returns Mockito.eq() as nullable type to avoid java.lang.IllegalStateException when
@@ -89,7 +91,8 @@ inline fun <reified T : Any> mock(apply: T.() -> Unit = {}): T = Mockito.mock(T:
 *
 * @see Mockito.when
 */
fun <T> whenever(methodCall: T): OngoingStubbing<T> = Mockito.`when`(methodCall)
fun <T> whenever(methodCall: T): OngoingStubbing<T> = `when`(methodCall)
fun <T> Stubber.whenever(mock: T): T = `when`(mock)

/**
 * A kotlin implemented wrapper of [ArgumentCaptor] which prevents the following exception when