Loading src/com/android/launcher3/widget/custom/CustomWidgetManager.java +16 −1 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.launcher3.R; import com.android.launcher3.util.MainThreadInitializedObject; Loading @@ -45,6 +46,7 @@ import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Consumer; import java.util.stream.Stream; Loading @@ -62,9 +64,16 @@ public class CustomWidgetManager implements PluginListener<CustomWidgetPlugin>, private final HashMap<ComponentName, CustomWidgetPlugin> mPlugins; private final List<CustomAppWidgetProviderInfo> mCustomWidgets; private Consumer<PackageUserKey> mWidgetRefreshCallback; private final @NonNull AppWidgetManager mAppWidgetManager; private CustomWidgetManager(Context context) { this(context, AppWidgetManager.getInstance(context)); } @VisibleForTesting CustomWidgetManager(Context context, @NonNull AppWidgetManager widgetManager) { mContext = context; mAppWidgetManager = widgetManager; mPlugins = new HashMap<>(); mCustomWidgets = new ArrayList<>(); PluginManagerWrapper.INSTANCE.get(context) Loading Loading @@ -94,7 +103,7 @@ public class CustomWidgetManager implements PluginListener<CustomWidgetPlugin>, @Override public void onPluginConnected(CustomWidgetPlugin plugin, Context context) { List<AppWidgetProviderInfo> providers = AppWidgetManager.getInstance(context) List<AppWidgetProviderInfo> providers = mAppWidgetManager .getInstalledProvidersForProfile(Process.myUserHandle()); if (providers.isEmpty()) return; Parcel parcel = Parcel.obtain(); Loading @@ -113,6 +122,12 @@ public class CustomWidgetManager implements PluginListener<CustomWidgetPlugin>, mCustomWidgets.removeIf(w -> w.getComponent().equals(cn)); } @VisibleForTesting @NonNull Map<ComponentName, CustomWidgetPlugin> getPlugins() { return mPlugins; } /** * Inject a callback function to refresh the widgets. */ Loading tests/multivalentTests/src/com/android/launcher3/widget/custom/CustomWidgetManagerTest.kt 0 → 100644 +144 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.widget.custom import android.appwidget.AppWidgetManager import android.content.ComponentName import android.os.Process import android.platform.test.flag.junit.SetFlagsRule import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext import com.android.launcher3.util.PluginManagerWrapper import com.android.launcher3.util.WidgetUtils import com.android.launcher3.widget.LauncherAppWidgetHostView import com.android.launcher3.widget.LauncherAppWidgetProviderInfo import com.android.systemui.plugins.CustomWidgetPlugin import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito.mock import org.mockito.MockitoAnnotations import org.mockito.kotlin.any import org.mockito.kotlin.doReturn import org.mockito.kotlin.eq import org.mockito.kotlin.same import org.mockito.kotlin.verify import org.mockito.kotlin.whenever @SmallTest @RunWith(AndroidJUnit4::class) class CustomWidgetManagerTest { @get:Rule val setFlagsRule = SetFlagsRule() private val context = SandboxModelContext() private lateinit var underTest: CustomWidgetManager @Mock private lateinit var pluginManager: PluginManagerWrapper @Mock private lateinit var mockAppWidgetManager: AppWidgetManager @Before fun setUp() { MockitoAnnotations.initMocks(this) context.putObject(PluginManagerWrapper.INSTANCE, pluginManager) underTest = CustomWidgetManager(context, mockAppWidgetManager) } @After fun tearDown() { underTest.close() } @Test fun plugin_manager_added_after_initialization() { verify(pluginManager) .addPluginListener(same(underTest), same(CustomWidgetPlugin::class.java), eq(true)) } @Test fun close_widget_manager_should_remove_plugin_listener() { underTest.close() verify(pluginManager).removePluginListener(same(underTest)) } @Test fun on_plugin_connected_no_provider_info() { doReturn(emptyList<LauncherAppWidgetProviderInfo>()) .whenever(mockAppWidgetManager) .getInstalledProvidersForProfile(any()) val mockPlugin = mock(CustomWidgetPlugin::class.java) underTest.onPluginConnected(mockPlugin, context) assertEquals(0, underTest.plugins.size) } @Test fun on_plugin_connected_exist_provider_info() { doReturn(listOf(WidgetUtils.createAppWidgetProviderInfo(TEST_COMPONENT_NAME))) .whenever(mockAppWidgetManager) .getInstalledProvidersForProfile(eq(Process.myUserHandle())) val mockPlugin = mock(CustomWidgetPlugin::class.java) underTest.onPluginConnected(mockPlugin, context) assertEquals(1, underTest.plugins.size) } @Test fun on_plugin_disconnected() { doReturn(listOf(WidgetUtils.createAppWidgetProviderInfo(TEST_COMPONENT_NAME))) .whenever(mockAppWidgetManager) .getInstalledProvidersForProfile(eq(Process.myUserHandle())) val mockPlugin = mock(CustomWidgetPlugin::class.java) underTest.onPluginConnected(mockPlugin, context) underTest.onPluginDisconnected(mockPlugin) assertEquals(0, underTest.plugins.size) } @Test fun on_view_created() { val mockPlugin = mock(CustomWidgetPlugin::class.java) val mockWidgetView = mock(LauncherAppWidgetHostView::class.java) val mockProviderInfo = mock(CustomAppWidgetProviderInfo::class.java) doReturn(mockProviderInfo).whenever(mockWidgetView).appWidgetInfo mockProviderInfo.provider = TEST_COMPONENT_NAME underTest.plugins.put(TEST_COMPONENT_NAME, mockPlugin) underTest.onViewCreated(mockWidgetView) verify(mockPlugin).onViewCreated(eq(mockWidgetView)) } @Test fun generate_stream() { assertTrue(underTest.stream().toList().isEmpty()) doReturn(listOf(WidgetUtils.createAppWidgetProviderInfo(TEST_COMPONENT_NAME))) .whenever(mockAppWidgetManager) .getInstalledProvidersForProfile(eq(Process.myUserHandle())) val mockPlugin = mock(CustomWidgetPlugin::class.java) underTest.onPluginConnected(mockPlugin, context) assertEquals(1, underTest.stream().toList().size) } companion object { private const val TEST_CLASS = "TEST_CLASS" private val TEST_COMPONENT_NAME = ComponentName(getInstrumentation().targetContext.packageName, TEST_CLASS) } } Loading
src/com/android/launcher3/widget/custom/CustomWidgetManager.java +16 −1 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.launcher3.R; import com.android.launcher3.util.MainThreadInitializedObject; Loading @@ -45,6 +46,7 @@ import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Consumer; import java.util.stream.Stream; Loading @@ -62,9 +64,16 @@ public class CustomWidgetManager implements PluginListener<CustomWidgetPlugin>, private final HashMap<ComponentName, CustomWidgetPlugin> mPlugins; private final List<CustomAppWidgetProviderInfo> mCustomWidgets; private Consumer<PackageUserKey> mWidgetRefreshCallback; private final @NonNull AppWidgetManager mAppWidgetManager; private CustomWidgetManager(Context context) { this(context, AppWidgetManager.getInstance(context)); } @VisibleForTesting CustomWidgetManager(Context context, @NonNull AppWidgetManager widgetManager) { mContext = context; mAppWidgetManager = widgetManager; mPlugins = new HashMap<>(); mCustomWidgets = new ArrayList<>(); PluginManagerWrapper.INSTANCE.get(context) Loading Loading @@ -94,7 +103,7 @@ public class CustomWidgetManager implements PluginListener<CustomWidgetPlugin>, @Override public void onPluginConnected(CustomWidgetPlugin plugin, Context context) { List<AppWidgetProviderInfo> providers = AppWidgetManager.getInstance(context) List<AppWidgetProviderInfo> providers = mAppWidgetManager .getInstalledProvidersForProfile(Process.myUserHandle()); if (providers.isEmpty()) return; Parcel parcel = Parcel.obtain(); Loading @@ -113,6 +122,12 @@ public class CustomWidgetManager implements PluginListener<CustomWidgetPlugin>, mCustomWidgets.removeIf(w -> w.getComponent().equals(cn)); } @VisibleForTesting @NonNull Map<ComponentName, CustomWidgetPlugin> getPlugins() { return mPlugins; } /** * Inject a callback function to refresh the widgets. */ Loading
tests/multivalentTests/src/com/android/launcher3/widget/custom/CustomWidgetManagerTest.kt 0 → 100644 +144 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.widget.custom import android.appwidget.AppWidgetManager import android.content.ComponentName import android.os.Process import android.platform.test.flag.junit.SetFlagsRule import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext import com.android.launcher3.util.PluginManagerWrapper import com.android.launcher3.util.WidgetUtils import com.android.launcher3.widget.LauncherAppWidgetHostView import com.android.launcher3.widget.LauncherAppWidgetProviderInfo import com.android.systemui.plugins.CustomWidgetPlugin import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito.mock import org.mockito.MockitoAnnotations import org.mockito.kotlin.any import org.mockito.kotlin.doReturn import org.mockito.kotlin.eq import org.mockito.kotlin.same import org.mockito.kotlin.verify import org.mockito.kotlin.whenever @SmallTest @RunWith(AndroidJUnit4::class) class CustomWidgetManagerTest { @get:Rule val setFlagsRule = SetFlagsRule() private val context = SandboxModelContext() private lateinit var underTest: CustomWidgetManager @Mock private lateinit var pluginManager: PluginManagerWrapper @Mock private lateinit var mockAppWidgetManager: AppWidgetManager @Before fun setUp() { MockitoAnnotations.initMocks(this) context.putObject(PluginManagerWrapper.INSTANCE, pluginManager) underTest = CustomWidgetManager(context, mockAppWidgetManager) } @After fun tearDown() { underTest.close() } @Test fun plugin_manager_added_after_initialization() { verify(pluginManager) .addPluginListener(same(underTest), same(CustomWidgetPlugin::class.java), eq(true)) } @Test fun close_widget_manager_should_remove_plugin_listener() { underTest.close() verify(pluginManager).removePluginListener(same(underTest)) } @Test fun on_plugin_connected_no_provider_info() { doReturn(emptyList<LauncherAppWidgetProviderInfo>()) .whenever(mockAppWidgetManager) .getInstalledProvidersForProfile(any()) val mockPlugin = mock(CustomWidgetPlugin::class.java) underTest.onPluginConnected(mockPlugin, context) assertEquals(0, underTest.plugins.size) } @Test fun on_plugin_connected_exist_provider_info() { doReturn(listOf(WidgetUtils.createAppWidgetProviderInfo(TEST_COMPONENT_NAME))) .whenever(mockAppWidgetManager) .getInstalledProvidersForProfile(eq(Process.myUserHandle())) val mockPlugin = mock(CustomWidgetPlugin::class.java) underTest.onPluginConnected(mockPlugin, context) assertEquals(1, underTest.plugins.size) } @Test fun on_plugin_disconnected() { doReturn(listOf(WidgetUtils.createAppWidgetProviderInfo(TEST_COMPONENT_NAME))) .whenever(mockAppWidgetManager) .getInstalledProvidersForProfile(eq(Process.myUserHandle())) val mockPlugin = mock(CustomWidgetPlugin::class.java) underTest.onPluginConnected(mockPlugin, context) underTest.onPluginDisconnected(mockPlugin) assertEquals(0, underTest.plugins.size) } @Test fun on_view_created() { val mockPlugin = mock(CustomWidgetPlugin::class.java) val mockWidgetView = mock(LauncherAppWidgetHostView::class.java) val mockProviderInfo = mock(CustomAppWidgetProviderInfo::class.java) doReturn(mockProviderInfo).whenever(mockWidgetView).appWidgetInfo mockProviderInfo.provider = TEST_COMPONENT_NAME underTest.plugins.put(TEST_COMPONENT_NAME, mockPlugin) underTest.onViewCreated(mockWidgetView) verify(mockPlugin).onViewCreated(eq(mockWidgetView)) } @Test fun generate_stream() { assertTrue(underTest.stream().toList().isEmpty()) doReturn(listOf(WidgetUtils.createAppWidgetProviderInfo(TEST_COMPONENT_NAME))) .whenever(mockAppWidgetManager) .getInstalledProvidersForProfile(eq(Process.myUserHandle())) val mockPlugin = mock(CustomWidgetPlugin::class.java) underTest.onPluginConnected(mockPlugin, context) assertEquals(1, underTest.stream().toList().size) } companion object { private const val TEST_CLASS = "TEST_CLASS" private val TEST_COMPONENT_NAME = ComponentName(getInstrumentation().targetContext.packageName, TEST_CLASS) } }