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.PendingIntent; 19 import android.appwidget.AppWidgetManager; 20 import android.content.Intent; 21 import android.graphics.Color; 22 import android.support.test.filters.LargeTest; 23 import android.support.test.runner.AndroidJUnit4; 24 import android.support.test.uiautomator.By; 25 import android.support.test.uiautomator.UiObject2; 26 import android.support.test.uiautomator.Until; 27 import android.view.View; 28 29 import com.android.launcher3.ItemInfo; 30 import com.android.launcher3.LauncherAppWidgetInfo; 31 import com.android.launcher3.LauncherSettings.Favorites; 32 import com.android.launcher3.R; 33 import com.android.launcher3.ShortcutInfo; 34 import com.android.launcher3.Utilities; 35 import com.android.launcher3.Workspace.ItemOperator; 36 import com.android.launcher3.shortcuts.ShortcutKey; 37 import com.android.launcher3.testcomponent.AppWidgetNoConfig; 38 import com.android.launcher3.testcomponent.AppWidgetWithConfig; 39 import com.android.launcher3.testcomponent.RequestPinItemActivity; 40 import com.android.launcher3.ui.AbstractLauncherUiTest; 41 import com.android.launcher3.util.Condition; 42 import com.android.launcher3.util.Wait; 43 import com.android.launcher3.util.rule.LauncherActivityRule; 44 import com.android.launcher3.util.rule.ShellCommandRule; 45 import com.android.launcher3.widget.WidgetCell; 46 47 import org.junit.Before; 48 import org.junit.Rule; 49 import org.junit.Test; 50 import org.junit.runner.RunWith; 51 52 import java.util.UUID; 53 54 import static org.junit.Assert.assertNotNull; 55 import static org.junit.Assert.assertNotSame; 56 import static org.junit.Assert.assertTrue; 57 58 /** 59 * Test to verify pin item request flow. 60 */ 61 @LargeTest 62 @RunWith(AndroidJUnit4.class) 63 public class RequestPinItemTest extends AbstractLauncherUiTest { 64 65 @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule(); 66 @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grandWidgetBind(); 67 @Rule public ShellCommandRule mDefaultLauncherRule = ShellCommandRule.setDefaultLauncher(); 68 69 private String mCallbackAction; 70 private String mShortcutId; 71 private int mAppWidgetId; 72 73 @Override 74 @Before setUp()75 public void setUp() throws Exception { 76 super.setUp(); 77 mCallbackAction = UUID.randomUUID().toString(); 78 mShortcutId = UUID.randomUUID().toString(); 79 } 80 81 @Test testPinWidgetNoConfig()82 public void testPinWidgetNoConfig() throws Throwable { 83 runTest("pinWidgetNoConfig", true, new ItemOperator() { 84 @Override 85 public boolean evaluate(ItemInfo info, View view) { 86 return info instanceof LauncherAppWidgetInfo && 87 ((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId && 88 ((LauncherAppWidgetInfo) info).providerName.getClassName() 89 .equals(AppWidgetNoConfig.class.getName()); 90 } 91 }); 92 } 93 94 @Test testPinWidgetNoConfig_customPreview()95 public void testPinWidgetNoConfig_customPreview() throws Throwable { 96 // Command to set custom preview 97 Intent command = RequestPinItemActivity.getCommandIntent( 98 RequestPinItemActivity.class, "setRemoteViewColor").putExtra( 99 RequestPinItemActivity.EXTRA_PARAM + "0", Color.RED); 100 101 runTest("pinWidgetNoConfig", true, new ItemOperator() { 102 @Override 103 public boolean evaluate(ItemInfo info, View view) { 104 return info instanceof LauncherAppWidgetInfo && 105 ((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId && 106 ((LauncherAppWidgetInfo) info).providerName.getClassName() 107 .equals(AppWidgetNoConfig.class.getName()); 108 } 109 }, command); 110 } 111 112 @Test testPinWidgetWithConfig()113 public void testPinWidgetWithConfig() throws Throwable { 114 runTest("pinWidgetWithConfig", true, new ItemOperator() { 115 @Override 116 public boolean evaluate(ItemInfo info, View view) { 117 return info instanceof LauncherAppWidgetInfo && 118 ((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId && 119 ((LauncherAppWidgetInfo) info).providerName.getClassName() 120 .equals(AppWidgetWithConfig.class.getName()); 121 } 122 }); 123 } 124 125 @Test testPinShortcut()126 public void testPinShortcut() throws Throwable { 127 // Command to set the shortcut id 128 Intent command = RequestPinItemActivity.getCommandIntent( 129 RequestPinItemActivity.class, "setShortcutId").putExtra( 130 RequestPinItemActivity.EXTRA_PARAM + "0", mShortcutId); 131 132 runTest("pinShortcut", false, new ItemOperator() { 133 @Override 134 public boolean evaluate(ItemInfo info, View view) { 135 return info instanceof ShortcutInfo && 136 info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT && 137 ShortcutKey.fromItemInfo(info).getId().equals(mShortcutId); 138 } 139 }, command); 140 } 141 runTest(String activityMethod, boolean isWidget, ItemOperator itemMatcher, Intent... commandIntents)142 private void runTest(String activityMethod, boolean isWidget, ItemOperator itemMatcher, 143 Intent... commandIntents) throws Throwable { 144 if (!Utilities.ATLEAST_OREO) { 145 return; 146 } 147 lockRotation(true); 148 149 clearHomescreen(); 150 mActivityMonitor.startLauncher(); 151 152 // Open all apps and wait for load complete 153 final UiObject2 appsContainer = openAllApps(); 154 assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT)); 155 156 // Open Pin item activity 157 BlockingBroadcastReceiver openMonitor = new BlockingBroadcastReceiver( 158 RequestPinItemActivity.class.getName()); 159 scrollAndFind(appsContainer, By.text("Test Pin Item")).click(); 160 assertNotNull(openMonitor.blockingGetExtraIntent()); 161 162 // Set callback 163 PendingIntent callback = PendingIntent.getBroadcast(mTargetContext, 0, 164 new Intent(mCallbackAction), PendingIntent.FLAG_ONE_SHOT); 165 mTargetContext.sendBroadcast(RequestPinItemActivity.getCommandIntent( 166 RequestPinItemActivity.class, "setCallback").putExtra( 167 RequestPinItemActivity.EXTRA_PARAM + "0", callback)); 168 169 for (Intent command : commandIntents) { 170 mTargetContext.sendBroadcast(command); 171 } 172 173 // call the requested method to start the flow 174 mTargetContext.sendBroadcast(RequestPinItemActivity.getCommandIntent( 175 RequestPinItemActivity.class, activityMethod)); 176 UiObject2 widgetCell = mDevice.wait( 177 Until.findObject(By.clazz(WidgetCell.class)), DEFAULT_ACTIVITY_TIMEOUT); 178 assertNotNull(widgetCell); 179 180 // Accept confirmation: 181 BlockingBroadcastReceiver resultReceiver = new BlockingBroadcastReceiver(mCallbackAction); 182 mDevice.wait(Until.findObject(By.text(mTargetContext.getString( 183 R.string.place_automatically).toUpperCase())), DEFAULT_UI_TIMEOUT).click(); 184 Intent result = resultReceiver.blockingGetIntent(); 185 assertNotNull(result); 186 mAppWidgetId = result.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); 187 if (isWidget) { 188 assertNotSame(-1, mAppWidgetId); 189 } 190 191 // Go back to home 192 mActivityMonitor.returnToHome(); 193 assertTrue(Wait.atMost(new ItemSearchCondition(itemMatcher), DEFAULT_ACTIVITY_TIMEOUT)); 194 } 195 196 /** 197 * Condition for for an item 198 */ 199 private class ItemSearchCondition extends Condition { 200 201 private final ItemOperator mOp; 202 ItemSearchCondition(ItemOperator op)203 ItemSearchCondition(ItemOperator op) { 204 mOp = op; 205 } 206 207 @Override isTrue()208 public boolean isTrue() throws Throwable { 209 return mMainThreadExecutor.submit(mActivityMonitor.itemExists(mOp)).get(); 210 } 211 } 212 } 213