• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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