1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 package com.android.launcher3.ui.widget; 17 18 import static androidx.test.InstrumentationRegistry.getInstrumentation; 19 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertNotNull; 22 import static org.junit.Assert.assertNotSame; 23 24 import android.appwidget.AppWidgetManager; 25 import android.content.Intent; 26 import android.view.View; 27 28 import androidx.test.filters.LargeTest; 29 import androidx.test.runner.AndroidJUnit4; 30 import androidx.test.uiautomator.By; 31 import androidx.test.uiautomator.UiObject2; 32 33 import com.android.launcher3.ItemInfo; 34 import com.android.launcher3.LauncherAppWidgetInfo; 35 import com.android.launcher3.LauncherAppWidgetProviderInfo; 36 import com.android.launcher3.Workspace; 37 import com.android.launcher3.testcomponent.WidgetConfigActivity; 38 import com.android.launcher3.ui.AbstractLauncherUiTest; 39 import com.android.launcher3.ui.TestViewHelpers; 40 import com.android.launcher3.util.Condition; 41 import com.android.launcher3.util.Wait; 42 import com.android.launcher3.util.rule.ShellCommandRule; 43 import com.android.launcher3.widget.WidgetCell; 44 45 import org.junit.Before; 46 import org.junit.Ignore; 47 import org.junit.Rule; 48 import org.junit.Test; 49 import org.junit.runner.RunWith; 50 51 /** 52 * Test to verify widget configuration is properly shown. 53 */ 54 @LargeTest 55 @RunWith(AndroidJUnit4.class) 56 public class AddConfigWidgetTest extends AbstractLauncherUiTest { 57 58 @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind(); 59 60 private LauncherAppWidgetProviderInfo mWidgetInfo; 61 private AppWidgetManager mAppWidgetManager; 62 63 private int mWidgetId; 64 65 @Override 66 @Before setUp()67 public void setUp() throws Exception { 68 super.setUp(); 69 mWidgetInfo = TestViewHelpers.findWidgetProvider(this, true /* hasConfigureScreen */); 70 mAppWidgetManager = AppWidgetManager.getInstance(mTargetContext); 71 } 72 73 @Test 74 // Convert test to TAPL b/131116002 testWidgetConfig()75 public void testWidgetConfig() throws Throwable { 76 runTest(false, true); 77 } 78 79 @Test 80 @Ignore // b/121280703 testWidgetConfig_rotate()81 public void testWidgetConfig_rotate() throws Throwable { 82 runTest(true, true); 83 } 84 85 @Test 86 // Convert test to TAPL b/131116002 testConfigCancelled()87 public void testConfigCancelled() throws Throwable { 88 runTest(false, false); 89 } 90 91 @Test 92 @Ignore // b/121280703 testConfigCancelled_rotate()93 public void testConfigCancelled_rotate() throws Throwable { 94 runTest(true, false); 95 } 96 97 /** 98 * @param rotateConfig should the config screen be rotated 99 * @param acceptConfig accept the config activity 100 */ runTest(boolean rotateConfig, boolean acceptConfig)101 private void runTest(boolean rotateConfig, boolean acceptConfig) throws Throwable { 102 lockRotation(true); 103 104 clearHomescreen(); 105 mActivityMonitor.startLauncher(); 106 107 // Open widget tray and wait for load complete. 108 final UiObject2 widgetContainer = TestViewHelpers.openWidgetsTray(); 109 Wait.atMost(null, Condition.minChildCount(widgetContainer, 2), DEFAULT_UI_TIMEOUT); 110 111 // Drag widget to homescreen 112 WidgetConfigStartupMonitor monitor = new WidgetConfigStartupMonitor(); 113 UiObject2 widget = scrollAndFind(widgetContainer, By.clazz(WidgetCell.class) 114 .hasDescendant(By.text(mWidgetInfo.getLabel(mTargetContext.getPackageManager())))); 115 TestViewHelpers.dragToWorkspace(widget, false); 116 // Widget id for which the config activity was opened 117 mWidgetId = monitor.getWidgetId(); 118 119 if (rotateConfig) { 120 // Rotate the screen and verify that the config activity is recreated 121 monitor = new WidgetConfigStartupMonitor(); 122 lockRotation(false); 123 assertEquals(mWidgetId, monitor.getWidgetId()); 124 } 125 126 // Verify that the widget id is valid and bound 127 assertNotNull(mAppWidgetManager.getAppWidgetInfo(mWidgetId)); 128 129 setResult(acceptConfig); 130 if (acceptConfig) { 131 Wait.atMost(null, new WidgetSearchCondition(), DEFAULT_ACTIVITY_TIMEOUT); 132 assertNotNull(mAppWidgetManager.getAppWidgetInfo(mWidgetId)); 133 } else { 134 // Verify that the widget id is deleted. 135 Wait.atMost(null, () -> mAppWidgetManager.getAppWidgetInfo(mWidgetId) == null, 136 DEFAULT_ACTIVITY_TIMEOUT); 137 } 138 } 139 setResult(boolean success)140 private void setResult(boolean success) { 141 getInstrumentation().getTargetContext().sendBroadcast( 142 WidgetConfigActivity.getCommandIntent(WidgetConfigActivity.class, 143 success ? "clickOK" : "clickCancel")); 144 } 145 146 /** 147 * Condition for searching widget id 148 */ 149 private class WidgetSearchCondition implements Condition, Workspace.ItemOperator { 150 151 @Override isTrue()152 public boolean isTrue() throws Throwable { 153 return mMainThreadExecutor.submit(mActivityMonitor.itemExists(this)).get(); 154 } 155 156 @Override evaluate(ItemInfo info, View view)157 public boolean evaluate(ItemInfo info, View view) { 158 return info instanceof LauncherAppWidgetInfo && 159 ((LauncherAppWidgetInfo) info).providerName.getClassName().equals( 160 mWidgetInfo.provider.getClassName()) && 161 ((LauncherAppWidgetInfo) info).appWidgetId == mWidgetId; 162 } 163 } 164 165 /** 166 * Broadcast receiver for receiving widget config activity status. 167 */ 168 private class WidgetConfigStartupMonitor extends BlockingBroadcastReceiver { 169 WidgetConfigStartupMonitor()170 public WidgetConfigStartupMonitor() { 171 super(WidgetConfigActivity.class.getName()); 172 } 173 getWidgetId()174 public int getWidgetId() throws InterruptedException { 175 Intent intent = blockingGetExtraIntent(); 176 assertNotNull(intent); 177 assertEquals(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE, intent.getAction()); 178 int widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 179 LauncherAppWidgetInfo.NO_ID); 180 assertNotSame(widgetId, LauncherAppWidgetInfo.NO_ID); 181 return widgetId; 182 } 183 } 184 } 185