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

Commit c05f6ade authored by Bernardo Rufino's avatar Bernardo Rufino
Browse files

Add unit tests for ToastUI

Bug: 144754526
Fix: 147802103
Test: atest ToastUITest
Change-Id: I277db0d8770da62fcfeaa794a7df44e500396733
parent 40fd197d
Loading
Loading
Loading
Loading
+14 −4
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import android.widget.TextView;
import android.widget.Toast;

import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.SystemUI;
import com.android.systemui.statusbar.CommandQueue;

@@ -67,12 +68,21 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks {

    @Inject
    public ToastUI(Context context, CommandQueue commandQueue) {
        this(context, commandQueue,
                (WindowManager) context.getSystemService(Context.WINDOW_SERVICE),
                INotificationManager.Stub.asInterface(
                        ServiceManager.getService(Context.NOTIFICATION_SERVICE)),
                AccessibilityManager.getInstance(context));
    }

    @VisibleForTesting
    ToastUI(Context context, CommandQueue commandQueue, WindowManager windowManager,
            INotificationManager notificationManager, AccessibilityManager accessibilityManager) {
        super(context);
        mCommandQueue = commandQueue;
        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        mNotificationManager = INotificationManager.Stub.asInterface(
                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
        mAccessibilityManager = AccessibilityManager.getInstance(context);
        mWindowManager = windowManager;
        mNotificationManager = notificationManager;
        mAccessibilityManager = accessibilityManager;
    }

    @Override
+207 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.toast;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.INotificationManager;
import android.app.ITransientNotificationCallback;
import android.os.Binder;
import android.testing.AndroidTestingRunner;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;

import androidx.test.filters.SmallTest;

import com.android.internal.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.CommandQueue;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

@SmallTest
@RunWith(AndroidTestingRunner.class)
public class ToastUITest extends SysuiTestCase {
    private static final String PACKAGE_NAME_1 = "com.example1.test";
    private static final Binder TOKEN_1 = new Binder();
    private static final Binder WINDOW_TOKEN_1 = new Binder();
    private static final String PACKAGE_NAME_2 = "com.example2.test";
    private static final Binder TOKEN_2 = new Binder();
    private static final Binder WINDOW_TOKEN_2 = new Binder();
    private static final String TEXT = "Hello World";
    private static final int MESSAGE_RES_ID = R.id.message;

    @Mock private CommandQueue mCommandQueue;
    @Mock private WindowManager mWindowManager;
    @Mock private INotificationManager mNotificationManager;
    @Mock private AccessibilityManager mAccessibilityManager;
    @Mock private ITransientNotificationCallback mCallback;
    @Captor private ArgumentCaptor<View> mViewCaptor;
    @Captor private ArgumentCaptor<ViewGroup.LayoutParams> mParamsCaptor;
    private ToastUI mToastUI;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        mToastUI = new ToastUI(mContext, mCommandQueue, mWindowManager, mNotificationManager,
                mAccessibilityManager);
    }

    @Test
    public void testStart_addToastUIAsCallbackToCommandQueue() throws Exception {
        mToastUI.start();

        verify(mCommandQueue).addCallback(mToastUI);
    }

    @Test
    public void testShowToast_addsCorrectViewToWindowManager() throws Exception {
        mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, null);

        verify(mWindowManager).addView(mViewCaptor.capture(), any());
        View view = mViewCaptor.getValue();
        assertThat(((TextView) view.findViewById(MESSAGE_RES_ID)).getText()).isEqualTo(TEXT);
    }

    @Test
    public void testShowToast_addsViewWithCorrectLayoutParamsToWindowManager() throws Exception {
        mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, null);

        verify(mWindowManager).addView(any(), mParamsCaptor.capture());
        ViewGroup.LayoutParams params = mParamsCaptor.getValue();
        assertThat(params).isInstanceOf(WindowManager.LayoutParams.class);
        WindowManager.LayoutParams windowParams = (WindowManager.LayoutParams) params;
        assertThat(windowParams.packageName).isEqualTo(mContext.getPackageName());
        assertThat(windowParams.getTitle()).isEqualTo("Toast");
        assertThat(windowParams.token).isEqualTo(WINDOW_TOKEN_1);
    }

    @Test
    public void testShowToast_callsCallback() throws Exception {
        mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
                mCallback);

        verify(mCallback).onToastShown();
    }

    @Test
    public void testShowToast_sendsAccessibilityEvent() throws Exception {
        when(mAccessibilityManager.isEnabled()).thenReturn(true);

        mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, null);

        ArgumentCaptor<AccessibilityEvent> eventCaptor = ArgumentCaptor.forClass(
                AccessibilityEvent.class);
        verify(mAccessibilityManager).sendAccessibilityEvent(eventCaptor.capture());
        AccessibilityEvent event = eventCaptor.getValue();
        assertThat(event.getEventType()).isEqualTo(
                AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
        assertThat(event.getClassName()).isEqualTo(Toast.class.getName());
        assertThat(event.getPackageName()).isEqualTo(PACKAGE_NAME_1);
    }

    @Test
    public void testHideToast_removesView() throws Exception {
        mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
                mCallback);
        View view = verifyWmAddViewAndAttachToParent();

        mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);

        verify(mWindowManager).removeViewImmediate(view);
    }

    @Test
    public void testHideToast_finishesToken() throws Exception {
        mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
                mCallback);

        mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);

        verify(mNotificationManager).finishToken(PACKAGE_NAME_1, WINDOW_TOKEN_1);
    }

    @Test
    public void testHideToast_callsCallback() throws Exception {
        mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
                mCallback);

        mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);

        verify(mCallback).onToastHidden();
    }

    @Test
    public void testHideToast_whenNotCurrentToastToken_doesNotHideToast() throws Exception {
        mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
                mCallback);

        mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_2);

        verify(mCallback, never()).onToastHidden();
    }

    @Test
    public void testHideToast_whenNotCurrentToastPackage_doesNotHideToast() throws Exception {
        mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
                mCallback);

        mToastUI.hideToast(PACKAGE_NAME_2, TOKEN_1);

        verify(mCallback, never()).onToastHidden();
    }

    @Test
    public void testShowToast_afterShowToast_hidesCurrentToast() throws Exception {
        mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
                mCallback);
        View view = verifyWmAddViewAndAttachToParent();

        mToastUI.showToast(PACKAGE_NAME_2, TOKEN_2, TEXT, WINDOW_TOKEN_2, Toast.LENGTH_LONG, null);

        verify(mWindowManager).removeViewImmediate(view);
        verify(mNotificationManager).finishToken(PACKAGE_NAME_1, WINDOW_TOKEN_1);
        verify(mCallback).onToastHidden();
    }

    private View verifyWmAddViewAndAttachToParent() {
        ArgumentCaptor<View> viewCaptor = ArgumentCaptor.forClass(View.class);
        verify(mWindowManager).addView(viewCaptor.capture(), any());
        View view = viewCaptor.getValue();
        // Simulate attaching to view hierarchy
        ViewGroup parent = new FrameLayout(mContext);
        parent.addView(view);
        return view;
    }
}