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