chromium/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/minimizedcustomtab/MinimizedFeatureUtilsUnitTest.java

// Copyright 2023 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.customtabs.features.minimizedcustomtab;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;

import static org.chromium.chrome.browser.flags.ActivityType.CUSTOM_TAB;
import static org.chromium.chrome.browser.flags.ActivityType.WEBAPP;

import android.app.AppOpsManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;

import org.chromium.base.SysUtils;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.Features.EnableFeatures;
import org.chromium.base.test.util.HistogramWatcher;
import org.chromium.chrome.browser.IntentHandler;
import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider;
import org.chromium.chrome.browser.customtabs.features.minimizedcustomtab.MinimizedFeatureUtils.MinimizedFeatureAvailability;
import org.chromium.chrome.browser.customtabs.features.minimizedcustomtab.MinimizedFeatureUtilsUnitTest.ShadowSysUtils;
import org.chromium.chrome.browser.flags.ChromeFeatureList;

/** Unit tests for {@link MinimizedFeatureUtils}. */
@RunWith(BaseRobolectricTestRunner.class)
@Config(
        manifest = Config.NONE,
        shadows = {ShadowSysUtils.class})
@EnableFeatures({ChromeFeatureList.CCT_MINIMIZED})
public class MinimizedFeatureUtilsUnitTest {
    @Implements(SysUtils.class)
    static class ShadowSysUtils {
        public static boolean sIsLowEndDevice;

        @Implementation
        public static boolean isLowEndDevice() {
            return sIsLowEndDevice;
        }
    }

    private static final String NAME = "Chrome";
    private static final int UID = 101;
    private static final String HISTOGRAM = "CustomTabs.MinimizedFeatureAvailability";

    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();

    @Mock private Context mContext;
    @Mock private PackageManager mPackageManager;
    @Mock private AppOpsManager mAppOpsManager;
    @Mock private BrowserServicesIntentDataProvider mIntentDataProvider;
    @Mock private Intent mIntent;

    private final ApplicationInfo mApplicationInfo = new ApplicationInfo();

    @Before
    public void setUp() {
        ShadowSysUtils.sIsLowEndDevice = false;
        mApplicationInfo.uid = UID;
        when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo);
        when(mContext.getPackageName()).thenReturn(NAME);
        when(mPackageManager.hasSystemFeature(eq(PackageManager.FEATURE_PICTURE_IN_PICTURE)))
                .thenReturn(true);
        when(mContext.getPackageManager()).thenReturn(mPackageManager);
        when(mAppOpsManager.checkOpNoThrow(
                        eq(AppOpsManager.OPSTR_PICTURE_IN_PICTURE), eq(UID), eq(NAME)))
                .thenReturn(AppOpsManager.MODE_ALLOWED);
        when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOpsManager);
    }

    @After
    public void tearDown() {
        ShadowSysUtils.sIsLowEndDevice = false;
    }

    @Test
    public void testSdkLevel_OAndAbove() {
        try (var ignored =
                HistogramWatcher.newSingleRecordWatcher(
                        HISTOGRAM, MinimizedFeatureAvailability.AVAILABLE)) {
            assertTrue(MinimizedFeatureUtils.isMinimizedCustomTabAvailable(mContext, null));
        }
    }

    @Test
    public void testLowEndDevice() {
        ShadowSysUtils.sIsLowEndDevice = true;
        try (var ignored =
                HistogramWatcher.newSingleRecordWatcher(
                        HISTOGRAM, MinimizedFeatureAvailability.UNAVAILABLE_LOW_END_DEVICE)) {
            assertFalse(MinimizedFeatureUtils.isMinimizedCustomTabAvailable(mContext, null));
        }
    }

    @Test
    public void testHasSystemFeatureFalse() {
        when(mPackageManager.hasSystemFeature(eq(PackageManager.FEATURE_PICTURE_IN_PICTURE)))
                .thenReturn(false);
        try (var ignored =
                HistogramWatcher.newSingleRecordWatcher(
                        HISTOGRAM, MinimizedFeatureAvailability.UNAVAILABLE_SYSTEM_FEATURE)) {
            assertFalse(MinimizedFeatureUtils.isMinimizedCustomTabAvailable(mContext, null));
        }
    }

    @Test
    public void testPipAllowedFalse() {
        when(mAppOpsManager.checkOpNoThrow(
                        eq(AppOpsManager.OPSTR_PICTURE_IN_PICTURE), eq(UID), eq(NAME)))
                .thenReturn(AppOpsManager.MODE_IGNORED);
        try (var ignored =
                HistogramWatcher.newSingleRecordWatcher(
                        HISTOGRAM, MinimizedFeatureAvailability.UNAVAILABLE_PIP_PERMISSION)) {
            assertFalse(MinimizedFeatureUtils.isMinimizedCustomTabAvailable(mContext, null));
        }
    }

    @Test
    public void testShouldEnableMinimizedCustomTabs() {
        // True for regular Custom Tabs
        when(mIntentDataProvider.getIntent()).thenReturn(mIntent);
        when(mIntent.getIntExtra(eq(IntentHandler.EXTRA_FEDCM_ID), anyInt())).thenReturn(-1);
        when(mIntentDataProvider.getActivityType()).thenReturn(CUSTOM_TAB);
        assertTrue(MinimizedFeatureUtils.shouldEnableMinimizedCustomTabs(mIntentDataProvider));
        // False for Webapps
        when(mIntentDataProvider.getActivityType()).thenReturn(WEBAPP);
        assertFalse(MinimizedFeatureUtils.shouldEnableMinimizedCustomTabs(mIntentDataProvider));
        // False for FedCM
        when(mIntentDataProvider.getActivityType()).thenReturn(CUSTOM_TAB);
        when(mIntentDataProvider.isTrustedIntent()).thenReturn(true);
        when(mIntent.getIntExtra(eq(IntentHandler.EXTRA_FEDCM_ID), anyInt())).thenReturn(100);
        assertFalse(MinimizedFeatureUtils.shouldEnableMinimizedCustomTabs(mIntentDataProvider));
        // False for AuthTab
        when(mIntent.getIntExtra(eq(IntentHandler.EXTRA_FEDCM_ID), anyInt())).thenReturn(-1);
        when(mIntentDataProvider.isTrustedIntent()).thenReturn(false);
        when(mIntentDataProvider.isAuthTab()).thenReturn(true);
        assertFalse(MinimizedFeatureUtils.shouldEnableMinimizedCustomTabs(mIntentDataProvider));
    }
}