• 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 android.appwidget.AppWidgetManager;
19 import android.content.Intent;
20 import android.support.test.filters.LargeTest;
21 import android.support.test.runner.AndroidJUnit4;
22 import android.support.test.uiautomator.By;
23 import android.support.test.uiautomator.UiObject2;
24 import android.view.View;
25 
26 import com.android.launcher3.ItemInfo;
27 import com.android.launcher3.LauncherAppWidgetInfo;
28 import com.android.launcher3.LauncherAppWidgetProviderInfo;
29 import com.android.launcher3.Workspace;
30 import com.android.launcher3.testcomponent.WidgetConfigActivity;
31 import com.android.launcher3.ui.AbstractLauncherUiTest;
32 import com.android.launcher3.util.Condition;
33 import com.android.launcher3.util.Wait;
34 import com.android.launcher3.util.rule.LauncherActivityRule;
35 import com.android.launcher3.util.rule.ShellCommandRule;
36 import com.android.launcher3.widget.WidgetCell;
37 
38 import org.junit.Before;
39 import org.junit.Rule;
40 import org.junit.Test;
41 import org.junit.runner.RunWith;
42 
43 import static org.junit.Assert.assertEquals;
44 import static org.junit.Assert.assertNotNull;
45 import static org.junit.Assert.assertNotSame;
46 import static org.junit.Assert.assertTrue;
47 
48 /**
49  * Test to verify widget configuration is properly shown.
50  */
51 @LargeTest
52 @RunWith(AndroidJUnit4.class)
53 public class AddConfigWidgetTest extends AbstractLauncherUiTest {
54 
55     @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
56     @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grandWidgetBind();
57 
58     private LauncherAppWidgetProviderInfo mWidgetInfo;
59     private AppWidgetManager mAppWidgetManager;
60 
61     private int mWidgetId;
62 
63     @Override
64     @Before
setUp()65     public void setUp() throws Exception {
66         super.setUp();
67         mWidgetInfo = findWidgetProvider(true /* hasConfigureScreen */);
68         mAppWidgetManager = AppWidgetManager.getInstance(mTargetContext);
69     }
70 
71     @Test
testWidgetConfig()72     public void testWidgetConfig() throws Throwable {
73         runTest(false, true);
74     }
75 
76     @Test
testWidgetConfig_rotate()77     public void testWidgetConfig_rotate() throws Throwable {
78         runTest(true, true);
79     }
80 
81     @Test
testConfigCancelled()82     public void testConfigCancelled() throws Throwable {
83         runTest(false, false);
84     }
85 
86     @Test
testConfigCancelled_rotate()87     public void testConfigCancelled_rotate() throws Throwable {
88         runTest(true, false);
89     }
90 
91     /**
92      * @param rotateConfig should the config screen be rotated
93      * @param acceptConfig accept the config activity
94      */
runTest(boolean rotateConfig, boolean acceptConfig)95     private void runTest(boolean rotateConfig, boolean acceptConfig) throws Throwable {
96         lockRotation(true);
97 
98         clearHomescreen();
99         mActivityMonitor.startLauncher();
100 
101         // Open widget tray and wait for load complete.
102         final UiObject2 widgetContainer = openWidgetsTray();
103         assertTrue(Wait.atMost(Condition.minChildCount(widgetContainer, 2), DEFAULT_UI_TIMEOUT));
104 
105         // Drag widget to homescreen
106         WidgetConfigStartupMonitor monitor = new WidgetConfigStartupMonitor();
107         UiObject2 widget = scrollAndFind(widgetContainer, By.clazz(WidgetCell.class)
108                 .hasDescendant(By.text(mWidgetInfo.getLabel(mTargetContext.getPackageManager()))));
109         dragToWorkspace(widget, false);
110         // Widget id for which the config activity was opened
111         mWidgetId = monitor.getWidgetId();
112 
113         if (rotateConfig) {
114             // Rotate the screen and verify that the config activity is recreated
115             monitor = new WidgetConfigStartupMonitor();
116             lockRotation(false);
117             assertEquals(mWidgetId, monitor.getWidgetId());
118         }
119 
120         // Verify that the widget id is valid and bound
121         assertNotNull(mAppWidgetManager.getAppWidgetInfo(mWidgetId));
122 
123         setResult(acceptConfig);
124         if (acceptConfig) {
125             assertTrue(Wait.atMost(new WidgetSearchCondition(), DEFAULT_ACTIVITY_TIMEOUT));
126             assertNotNull(mAppWidgetManager.getAppWidgetInfo(mWidgetId));
127         } else {
128             // Verify that the widget id is deleted.
129             assertTrue(Wait.atMost(new Condition() {
130                 @Override
131                 public boolean isTrue() throws Throwable {
132                     return mAppWidgetManager.getAppWidgetInfo(mWidgetId) == null;
133                 }
134             }, DEFAULT_ACTIVITY_TIMEOUT));
135         }
136     }
137 
setResult(boolean success)138     private void setResult(boolean success) {
139 
140         getInstrumentation().getTargetContext().sendBroadcast(
141                 WidgetConfigActivity.getCommandIntent(WidgetConfigActivity.class,
142                         success ? "clickOK" : "clickCancel"));
143     }
144 
145     /**
146      * Condition for searching widget id
147      */
148     private class WidgetSearchCondition extends Condition
149             implements 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.equals(mWidgetInfo.provider) &&
160                     ((LauncherAppWidgetInfo) info).appWidgetId == mWidgetId;
161         }
162     }
163 
164     /**
165      * Broadcast receiver for receiving widget config activity status.
166      */
167     private class WidgetConfigStartupMonitor extends BlockingBroadcastReceiver {
168 
WidgetConfigStartupMonitor()169         public WidgetConfigStartupMonitor() {
170             super(WidgetConfigActivity.class.getName());
171         }
172 
getWidgetId()173         public int getWidgetId() throws InterruptedException {
174             Intent intent = blockingGetExtraIntent();
175             assertNotNull(intent);
176             assertEquals(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE, intent.getAction());
177             int widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
178                     LauncherAppWidgetInfo.NO_ID);
179             assertNotSame(widgetId, LauncherAppWidgetInfo.NO_ID);
180             return widgetId;
181         }
182     }
183 }
184