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 android.app.PendingIntent.FLAG_MUTABLE; 19 import static android.app.PendingIntent.FLAG_ONE_SHOT; 20 21 import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName; 22 23 import static org.junit.Assert.assertNotNull; 24 import static org.junit.Assert.assertNotSame; 25 26 import android.app.PendingIntent; 27 import android.appwidget.AppWidgetManager; 28 import android.content.Intent; 29 import android.graphics.Color; 30 import android.view.View; 31 32 import androidx.test.filters.LargeTest; 33 import androidx.test.runner.AndroidJUnit4; 34 35 import com.android.launcher3.Launcher; 36 import com.android.launcher3.LauncherSettings.Favorites; 37 import com.android.launcher3.celllayout.FavoriteItemsTransaction; 38 import com.android.launcher3.model.data.ItemInfo; 39 import com.android.launcher3.model.data.LauncherAppWidgetInfo; 40 import com.android.launcher3.model.data.WorkspaceItemInfo; 41 import com.android.launcher3.shortcuts.ShortcutKey; 42 import com.android.launcher3.tapl.AddToHomeScreenPrompt; 43 import com.android.launcher3.testcomponent.AppWidgetNoConfig; 44 import com.android.launcher3.testcomponent.AppWidgetWithConfig; 45 import com.android.launcher3.testcomponent.RequestPinItemActivity; 46 import com.android.launcher3.ui.AbstractLauncherUiTest; 47 import com.android.launcher3.ui.TaplTestsLauncher3; 48 import com.android.launcher3.util.LauncherBindableItemsContainer.ItemOperator; 49 import com.android.launcher3.util.Wait; 50 import com.android.launcher3.util.Wait.Condition; 51 import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord; 52 import com.android.launcher3.util.rule.ShellCommandRule; 53 54 import org.junit.Before; 55 import org.junit.Rule; 56 import org.junit.Test; 57 import org.junit.runner.RunWith; 58 59 import java.util.UUID; 60 61 /** 62 * Test to verify pin item request flow. 63 */ 64 @LargeTest 65 @RunWith(AndroidJUnit4.class) 66 public class RequestPinItemTest extends AbstractLauncherUiTest { 67 68 @Rule 69 public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind(); 70 71 private String mCallbackAction; 72 private String mShortcutId; 73 private int mAppWidgetId; 74 75 @Override 76 @Before setUp()77 public void setUp() throws Exception { 78 super.setUp(); 79 mCallbackAction = UUID.randomUUID().toString(); 80 mShortcutId = UUID.randomUUID().toString(); 81 TaplTestsLauncher3.initialize(this); 82 } 83 84 @Test testEmpty()85 public void testEmpty() throws Throwable { /* needed while the broken tests are being fixed */ } 86 87 @Test 88 @ScreenRecord // b/215673732 testPinWidgetNoConfig()89 public void testPinWidgetNoConfig() throws Throwable { 90 runTest("pinWidgetNoConfig", true, (info, view) -> info instanceof LauncherAppWidgetInfo && 91 ((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId && 92 ((LauncherAppWidgetInfo) info).providerName.getClassName() 93 .equals(AppWidgetNoConfig.class.getName())); 94 } 95 96 @Test 97 @ScreenRecord // b/215673732 testPinWidgetNoConfig_customPreview()98 public void testPinWidgetNoConfig_customPreview() throws Throwable { 99 // Command to set custom preview 100 Intent command = RequestPinItemActivity.getCommandIntent( 101 RequestPinItemActivity.class, "setRemoteViewColor").putExtra( 102 RequestPinItemActivity.EXTRA_PARAM + "0", Color.RED); 103 104 runTest("pinWidgetNoConfig", true, (info, view) -> info instanceof LauncherAppWidgetInfo && 105 ((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId && 106 ((LauncherAppWidgetInfo) info).providerName.getClassName() 107 .equals(AppWidgetNoConfig.class.getName()), command); 108 } 109 110 @Test 111 @ScreenRecord // b/215673732 testPinWidgetWithConfig()112 public void testPinWidgetWithConfig() throws Throwable { 113 runTest("pinWidgetWithConfig", true, 114 (info, view) -> info instanceof LauncherAppWidgetInfo && 115 ((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId && 116 ((LauncherAppWidgetInfo) info).providerName.getClassName() 117 .equals(AppWidgetWithConfig.class.getName())); 118 } 119 120 @Test testPinShortcut()121 public void testPinShortcut() throws Throwable { 122 // Command to set the shortcut id 123 Intent command = RequestPinItemActivity.getCommandIntent( 124 RequestPinItemActivity.class, "setShortcutId").putExtra( 125 RequestPinItemActivity.EXTRA_PARAM + "0", mShortcutId); 126 127 runTest("pinShortcut", false, new ItemOperator() { 128 @Override 129 public boolean evaluate(ItemInfo info, View view) { 130 return info instanceof WorkspaceItemInfo && 131 info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT && 132 ShortcutKey.fromItemInfo(info).getId().equals(mShortcutId); 133 } 134 }, command); 135 } 136 runTest(String activityMethod, boolean isWidget, ItemOperator itemMatcher, Intent... commandIntents)137 private void runTest(String activityMethod, boolean isWidget, ItemOperator itemMatcher, 138 Intent... commandIntents) throws Throwable { 139 new FavoriteItemsTransaction(mTargetContext).commitAndLoadHome(mLauncher); 140 141 // Open Pin item activity 142 BlockingBroadcastReceiver openMonitor = new BlockingBroadcastReceiver( 143 RequestPinItemActivity.class.getName()); 144 mLauncher. 145 getWorkspace(). 146 switchToAllApps(). 147 getAppIcon("Test Pin Item"). 148 launch(getAppPackageName()); 149 assertNotNull(openMonitor.blockingGetExtraIntent()); 150 151 // Set callback 152 PendingIntent callback = PendingIntent.getBroadcast(mTargetContext, 0, 153 new Intent(mCallbackAction).setPackage(mTargetContext.getPackageName()), 154 FLAG_ONE_SHOT | FLAG_MUTABLE); 155 mTargetContext.sendBroadcast(RequestPinItemActivity.getCommandIntent( 156 RequestPinItemActivity.class, "setCallback").putExtra( 157 RequestPinItemActivity.EXTRA_PARAM + "0", callback)); 158 159 for (Intent command : commandIntents) { 160 mTargetContext.sendBroadcast(command); 161 } 162 163 // call the requested method to start the flow 164 mTargetContext.sendBroadcast(RequestPinItemActivity.getCommandIntent( 165 RequestPinItemActivity.class, activityMethod)); 166 final AddToHomeScreenPrompt addToHomeScreenPrompt = mLauncher.getAddToHomeScreenPrompt(); 167 168 // Accept confirmation: 169 BlockingBroadcastReceiver resultReceiver = new BlockingBroadcastReceiver(mCallbackAction); 170 addToHomeScreenPrompt.addAutomatically(); 171 Intent result = resultReceiver.blockingGetIntent(); 172 assertNotNull(result); 173 mAppWidgetId = result.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); 174 if (isWidget) { 175 assertNotSame(-1, mAppWidgetId); 176 } 177 178 // Go back to home 179 mLauncher.goHome(); 180 Wait.atMost("", new ItemSearchCondition(itemMatcher), DEFAULT_ACTIVITY_TIMEOUT, 181 mLauncher); 182 } 183 184 /** 185 * Condition for for an item 186 */ 187 private class ItemSearchCondition implements Condition { 188 189 private final ItemOperator mOp; 190 ItemSearchCondition(ItemOperator op)191 ItemSearchCondition(ItemOperator op) { 192 mOp = op; 193 } 194 195 @Override isTrue()196 public boolean isTrue() throws Throwable { 197 return mMainThreadExecutor.submit(() -> { 198 Launcher l = Launcher.ACTIVITY_TRACKER.getCreatedActivity(); 199 return l != null && l.getWorkspace().getFirstMatch(mOp) != null; 200 }).get(); 201 } 202 } 203 } 204