/* * 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.launcher3.ui.workspace; import static com.android.launcher3.AbstractFloatingView.TYPE_ACTION_POPUP; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.TestConstants.AppNames.TEST_APP_NAME; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import android.content.ContentResolver; import android.content.ContentValues; import android.net.Uri; import android.view.ViewGroup; import androidx.test.filters.LargeTest; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BubbleTextView; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.allapps.AllAppsRecyclerView; import com.android.launcher3.celllayout.FavoriteItemsTransaction; import com.android.launcher3.dagger.LauncherComponentProvider; import com.android.launcher3.icons.mono.ThemedIconDrawable; import com.android.launcher3.popup.ArrowPopup; import com.android.launcher3.util.BaseLauncherActivityTest; import com.android.launcher3.util.Executors; import com.android.launcher3.util.TestUtil; import org.junit.Test; /** * Tests for theme icon support in Launcher * * Note running these tests will clear the workspace on the device. */ @LargeTest public class ThemeIconsTest extends BaseLauncherActivityTest { private static final String APP_NAME = "IconThemedActivity"; private static final String SHORTCUT_NAME = "Shortcut 1"; @Test public void testIconWithoutTheme() throws Exception { setThemeEnabled(false); new FavoriteItemsTransaction(targetContext()).commit(); loadLauncherSync(); switchToAllApps(); scrollToAppIcon(APP_NAME); BubbleTextView btv = getFromLauncher( l -> verifyIconTheme(APP_NAME, l.getAppsView(), false)); addToWorkspace(btv); executeOnLauncher(l -> verifyIconTheme(APP_NAME, l.getWorkspace(), false)); } @Test public void testShortcutIconWithoutTheme() throws Exception { setThemeEnabled(false); new FavoriteItemsTransaction(targetContext()).commit(); loadLauncherSync(); switchToAllApps(); scrollToAppIcon(TEST_APP_NAME); BubbleTextView btv = getFromLauncher(l -> findBtv(TEST_APP_NAME, l.getAppsView())); TestUtil.runOnExecutorSync(MAIN_EXECUTOR, btv::performLongClick); BubbleTextView menuItem = getOnceNotNull("Popup menu not open", l -> (AbstractFloatingView.getOpenView(l, TYPE_ACTION_POPUP) instanceof ArrowPopup ap) ? findBtv(SHORTCUT_NAME, ap) : null); addToWorkspace(menuItem); executeOnLauncher(l -> verifyIconTheme(SHORTCUT_NAME, l.getWorkspace(), false)); } @Test public void testIconWithTheme() throws Exception { setThemeEnabled(true); new FavoriteItemsTransaction(targetContext()).commit(); loadLauncherSync(); switchToAllApps(); scrollToAppIcon(APP_NAME); BubbleTextView btv = getFromLauncher(l -> verifyIconTheme(APP_NAME, l.getAppsView(), false)); addToWorkspace(btv); executeOnLauncher(l -> verifyIconTheme(APP_NAME, l.getWorkspace(), true)); } @Test public void testShortcutIconWithTheme() throws Exception { setThemeEnabled(true); loadLauncherSync(); switchToAllApps(); scrollToAppIcon(TEST_APP_NAME); BubbleTextView btv = getFromLauncher(l -> findBtv(TEST_APP_NAME, l.getAppsView())); TestUtil.runOnExecutorSync(MAIN_EXECUTOR, btv::performLongClick); BubbleTextView menuItem = getOnceNotNull("Popup menu not open", l -> (AbstractFloatingView.getOpenView(l, TYPE_ACTION_POPUP) instanceof ArrowPopup ap) ? findBtv(SHORTCUT_NAME, ap) : null); addToWorkspace(menuItem); executeOnLauncher(l -> verifyIconTheme(SHORTCUT_NAME, l.getWorkspace(), true)); } private BubbleTextView findBtv(String title, ViewGroup parent) { // Wait for Launcher model to be completed try { Executors.MODEL_EXECUTOR.submit(() -> { }).get(); } catch (Exception e) { throw new RuntimeException(e); } return (BubbleTextView) searchView(parent, v -> v instanceof BubbleTextView btv && btv.getContentDescription() != null && title.equals(btv.getContentDescription().toString())); } private BubbleTextView verifyIconTheme(String title, ViewGroup parent, boolean isThemed) { BubbleTextView icon = findBtv(title, parent); assertNotNull(icon.getIcon()); assertEquals(isThemed, icon.getIcon() instanceof ThemedIconDrawable); return icon; } private void setThemeEnabled(boolean isEnabled) { Uri uri = new Uri.Builder() .scheme(ContentResolver.SCHEME_CONTENT) .authority(targetContext().getPackageName() + ".grid_control") .appendPath("set_icon_themed") .build(); ContentValues values = new ContentValues(); values.put("boolean_value", isEnabled); int result = LauncherComponentProvider.get(targetContext()).getGridCustomizationsProxy() .update(uri, values, null, null); assertTrue(result > 0); } private void switchToAllApps() { goToState(LauncherState.ALL_APPS); waitForState("Launcher internal state didn't switch to All Apps", () -> LauncherState.ALL_APPS); freezeAllApps(); } private void scrollToAppIcon(String appName) { executeOnLauncher(l -> { l.hideKeyboard(); AllAppsRecyclerView rv = l.getAppsView().getActiveRecyclerView(); int pos = rv.getApps().getAdapterItems().indexOf(rv.getApps().getAdapterItems().stream() .filter(i -> i.itemInfo != null && appName.equals(i.itemInfo.title.toString())) .findFirst() .get()); rv.getLayoutManager().scrollToPosition(pos); }); } }