chromium/chrome/browser/ui/android/logo/java/src/org/chromium/chrome/browser/logo/LogoViewTest.java

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.logo;

import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import android.animation.ObjectAnimator;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewGroup.MarginLayoutParams;

import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.filters.MediumTest;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.Features.EnableFeatures;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.logo.LogoBridge.Logo;
import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
import org.chromium.components.search_engines.TemplateUrlService;
import org.chromium.ui.base.TestActivity;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor;

/** Instrumentation tests for {@link LogoView}. */
@RunWith(BaseRobolectricTestRunner.class)
public class LogoViewTest {
    @Rule
    public ActivityScenarioRule<TestActivity> mActivityScenarioRule =
            new ActivityScenarioRule<>(TestActivity.class);

    @Mock public TemplateUrlService mTemplateUrlService;
    @Mock public LogoView.ClickHandler mLogoClickHandler;

    private static final String LOGO_URL = "https://www.google.com";
    private static final String ANIMATED_LOGO_URL =
            "https://www.gstatic.com/chrome/ntp/doodle_test/ddljson_android4.json";
    private static final String ALT_TEXT = "Hello World!";

    private LogoView mView;
    private Bitmap mBitmap;
    private PropertyModelChangeProcessor mPropertyModelChangeProcessor;
    private PropertyModel mModel;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        mBitmap = Bitmap.createBitmap(1, 1, Config.ALPHA_8);
        TemplateUrlServiceFactory.setInstanceForTesting(mTemplateUrlService);

        mActivityScenarioRule
                .getScenario()
                .onActivity(
                        activity -> {
                            mView = new LogoView(activity, null);
                            LayoutParams params =
                                    new LayoutParams(
                                            LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
                            activity.setContentView(mView, params);
                            mModel = new PropertyModel(LogoProperties.ALL_KEYS);
                            mPropertyModelChangeProcessor =
                                    PropertyModelChangeProcessor.create(
                                            mModel, mView, new LogoViewBinder());
                        });
    }

    @Test
    public void testDefaultLogoView() {
        doReturn(true).when(mTemplateUrlService).isDefaultSearchEngineGoogle();
        mView.setDefaultGoogleLogo(
                new CachedTintedBitmap(R.drawable.google_logo, R.color.google_logo_tint_color)
                        .getBitmap(mView.getContext()));
        mView.updateLogo(null);
        mView.endAnimationsForTesting();

        Assert.assertFalse("Default logo should not be clickable.", mView.isClickable());
        Assert.assertFalse("Default logo should not be focusable.", mView.isFocusable());
        Assert.assertTrue(
                "Default logo should not have a content description.",
                TextUtils.isEmpty(mView.getContentDescription()));
    }

    @Test
    public void testLogoView_WithUrl() {
        Logo logo = new Logo(mBitmap, LOGO_URL, null, null);
        mView.updateLogo(logo);
        mView.endAnimationsForTesting();

        Assert.assertTrue("Logo with URL should be clickable.", mView.isClickable());
        Assert.assertTrue("Logo with URL should be focusable.", mView.isFocusable());
        Assert.assertTrue(
                "Logo should not have a content description.",
                TextUtils.isEmpty(mView.getContentDescription()));
    }

    @Test
    public void testLogoView_WithAnimatedUrl() {
        Logo logo = new Logo(mBitmap, null, null, ANIMATED_LOGO_URL);
        mView.updateLogo(logo);
        mView.endAnimationsForTesting();

        Assert.assertTrue("Logo with animated URL should be clickable.", mView.isClickable());
        Assert.assertTrue("Logo with animated URL should be focusable.", mView.isFocusable());
        Assert.assertTrue(
                "Logo should not have a content description.",
                TextUtils.isEmpty(mView.getContentDescription()));
    }

    @Test
    public void testLogoView_WithUrl_Clicked() {
        mView.setClickHandler(mLogoClickHandler);
        Logo logo = new Logo(mBitmap, LOGO_URL, null, null);
        mView.updateLogo(logo);
        mView.endAnimationsForTesting();
        mView.performClick();
        verify(mLogoClickHandler, times(1)).onLogoClicked(false);
    }

    @Test
    public void testLogoView_WithAltText() {
        Logo logo = new Logo(mBitmap, null, ALT_TEXT, null);
        mView.updateLogo(logo);
        mView.endAnimationsForTesting();

        Assert.assertFalse("Logo without URL should not be clickable.", mView.isClickable());
        Assert.assertTrue("Logo with alt text should be focusable.", mView.isFocusable());
        Assert.assertFalse(
                "Logo should have a content description.",
                TextUtils.isEmpty(mView.getContentDescription()));
    }

    @Test
    public void testShowLoadingView() {
        Logo logo = new Logo(Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8), null, null, null);
        mModel.set(LogoProperties.LOGO, logo);
        mView.endAnimationsForTesting();
        Assert.assertNotNull(mView.getLogoForTesting());
        mView.setLoadingViewVisibilityForTesting(View.VISIBLE);
        mModel.set(LogoProperties.SHOW_LOADING_VIEW, true);
        Assert.assertNull(mView.getLogoForTesting());
        Assert.assertEquals(View.GONE, mView.getLoadingViewVisibilityForTesting());
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.LOGO_POLISH})
    public void testDoodleAnimation() {
        mView.setIsLogoPolishFlagEnabledForTesting(true);
        Resources res = mView.getResources();
        int normalLogoHeight = res.getDimensionPixelSize(R.dimen.ntp_logo_height);
        int normalLogoTopMargin = res.getDimensionPixelSize(R.dimen.ntp_logo_margin_top);
        int logoHeightForLogoPolish = LogoUtils.getLogoHeightForLogoPolishWithSmallSize(res);
        int logoTopMarginForLogoPolish = LogoUtils.getTopMarginForLogoPolish(res);

        MarginLayoutParams logoLayoutParams = (MarginLayoutParams) mView.getLayoutParams();

        // Test default google logo.
        doReturn(true).when(mTemplateUrlService).isDefaultSearchEngineGoogle();
        mView.setDefaultGoogleLogo(
                new CachedTintedBitmap(R.drawable.google_logo, R.color.google_logo_tint_color)
                        .getBitmap(mView.getContext()));
        mView.updateLogo(null);
        mView.endAnimationsForTesting();
        Assert.assertEquals(normalLogoHeight, logoLayoutParams.height);
        Assert.assertEquals(normalLogoTopMargin, logoLayoutParams.topMargin);

        // Test doodle animation.
        Logo logo = new Logo(mBitmap, null, ALT_TEXT, null);
        mModel.set(LogoProperties.LOGO, logo);
        ObjectAnimator fadeAnimation = mView.getFadeAnimationForTesting();
        Assert.assertNotNull(fadeAnimation);

        fadeAnimation.pause();

        fadeAnimation.setCurrentFraction(0);
        Assert.assertEquals(normalLogoHeight, logoLayoutParams.height);
        Assert.assertEquals(normalLogoTopMargin, logoLayoutParams.topMargin);

        fadeAnimation.setCurrentFraction(0.3F);
        Assert.assertEquals(normalLogoHeight, logoLayoutParams.height);
        Assert.assertEquals(normalLogoTopMargin, logoLayoutParams.topMargin);

        fadeAnimation.setCurrentFraction(0.5F);
        Assert.assertEquals(normalLogoHeight, logoLayoutParams.height);
        Assert.assertEquals(normalLogoTopMargin, logoLayoutParams.topMargin);

        fadeAnimation.setCurrentFraction(0.65F);
        Assert.assertEquals(
                Math.round((normalLogoHeight + (logoHeightForLogoPolish - normalLogoHeight) * 0.3)),
                logoLayoutParams.height);
        Assert.assertEquals(
                Math.round(
                        (normalLogoTopMargin
                                + (logoTopMarginForLogoPolish - normalLogoTopMargin) * 0.3)),
                logoLayoutParams.topMargin);

        fadeAnimation.setCurrentFraction(0.75F);
        Assert.assertEquals(
                Math.round((normalLogoHeight + logoHeightForLogoPolish) * 0.5),
                logoLayoutParams.height);
        Assert.assertEquals(
                Math.round((normalLogoTopMargin + logoTopMarginForLogoPolish) * 0.5),
                logoLayoutParams.topMargin);

        fadeAnimation.setCurrentFraction(1);
        Assert.assertEquals(logoHeightForLogoPolish, logoLayoutParams.height);
        Assert.assertEquals(logoTopMarginForLogoPolish, logoLayoutParams.topMargin);
    }
}