• 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.app.Activity;
19 import android.app.Application;
20 import android.appwidget.AppWidgetManager;
21 import android.content.Intent;
22 import android.support.test.uiautomator.By;
23 import android.support.test.uiautomator.UiObject2;
24 import android.test.suitebuilder.annotation.LargeTest;
25 import android.view.View;
26 
27 import com.android.launcher3.ItemInfo;
28 import com.android.launcher3.Launcher;
29 import com.android.launcher3.LauncherAppWidgetInfo;
30 import com.android.launcher3.LauncherAppWidgetProviderInfo;
31 import com.android.launcher3.MainThreadExecutor;
32 import com.android.launcher3.Workspace;
33 import com.android.launcher3.testcomponent.WidgetConfigActivity;
34 import com.android.launcher3.ui.LauncherInstrumentationTestCase;
35 import com.android.launcher3.util.Condition;
36 import com.android.launcher3.util.SimpleActivityMonitor;
37 import com.android.launcher3.util.Wait;
38 import com.android.launcher3.widget.WidgetCell;
39 
40 import java.util.concurrent.Callable;
41 
42 /**
43  * Test to verify widget configuration is properly shown.
44  */
45 @LargeTest
46 public class AddConfigWidgetTest extends LauncherInstrumentationTestCase {
47 
48     private LauncherAppWidgetProviderInfo mWidgetInfo;
49     private SimpleActivityMonitor mActivityMonitor;
50     private MainThreadExecutor mMainThreadExecutor;
51     private AppWidgetManager mAppWidgetManager;
52 
53     private int mWidgetId;
54 
55     @Override
setUp()56     protected void setUp() throws Exception {
57         super.setUp();
58         mWidgetInfo = findWidgetProvider(true /* hasConfigureScreen */);
59         mActivityMonitor = new SimpleActivityMonitor();
60         ((Application) getInstrumentation().getTargetContext().getApplicationContext())
61                 .registerActivityLifecycleCallbacks(mActivityMonitor);
62         mMainThreadExecutor = new MainThreadExecutor();
63         mAppWidgetManager = AppWidgetManager.getInstance(mTargetContext);
64 
65         grantWidgetPermission();
66     }
67 
68     @Override
tearDown()69     protected void tearDown() throws Exception {
70         ((Application) getInstrumentation().getTargetContext().getApplicationContext())
71                 .unregisterActivityLifecycleCallbacks(mActivityMonitor);
72         super.tearDown();
73     }
74 
testWidgetConfig()75     public void testWidgetConfig() throws Throwable {
76         runTest(false, true);
77     }
78 
testWidgetConfig_rotate()79     public void testWidgetConfig_rotate() throws Throwable {
80         runTest(true, true);
81     }
82 
testConfigCancelled()83     public void testConfigCancelled() throws Throwable {
84         runTest(false, false);
85     }
86 
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         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 Callable<Boolean>, Workspace.ItemOperator {
150 
151         @Override
isTrue()152         public boolean isTrue() throws Throwable {
153             return mMainThreadExecutor.submit(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         @Override
call()164         public Boolean call() throws Exception {
165             // Find the resumed launcher
166             Launcher launcher = null;
167             for (Activity a : mActivityMonitor.resumed) {
168                 if (a instanceof Launcher) {
169                     launcher = (Launcher) a;
170                 }
171             }
172             if (launcher == null) {
173                 return false;
174             }
175             return launcher.getWorkspace().getFirstMatch(this) != null;
176         }
177     }
178 
179     /**
180      * Broadcast receiver for receiving widget config activity status.
181      */
182     private class WidgetConfigStartupMonitor extends BlockingBroadcastReceiver {
183 
WidgetConfigStartupMonitor()184         public WidgetConfigStartupMonitor() {
185             super(WidgetConfigActivity.class.getName());
186         }
187 
getWidgetId()188         public int getWidgetId() throws InterruptedException {
189             Intent intent = blockingGetExtraIntent();
190             assertNotNull(intent);
191             assertEquals(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE, intent.getAction());
192             int widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
193                     LauncherAppWidgetInfo.NO_ID);
194             assertNotSame(widgetId, LauncherAppWidgetInfo.NO_ID);
195             return widgetId;
196         }
197     }
198 }
199