1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of 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, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.content.pm.cts.shortcutmanager; 17 18 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith; 19 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list; 20 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.retryUntil; 21 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.setDefaultLauncher; 22 23 import android.content.Context; 24 import android.content.pm.LauncherApps; 25 import android.content.pm.ShortcutInfo; 26 import android.os.Handler; 27 import android.os.Looper; 28 import android.os.UserHandle; 29 import android.test.suitebuilder.annotation.SmallTest; 30 import android.util.Log; 31 32 import com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.ShortcutListAsserter; 33 34 import java.util.ArrayList; 35 import java.util.Arrays; 36 import java.util.HashSet; 37 import java.util.List; 38 import java.util.concurrent.atomic.AtomicBoolean; 39 import java.util.function.Predicate; 40 41 import com.android.compatibility.common.util.CddTest; 42 43 @CddTest(requirement="3.8.1/C-2-3") 44 @SmallTest 45 public class ShortcutManagerLauncherCallbackTest extends ShortcutManagerCtsTestsBase { 46 47 private static class MyCallback extends LauncherApps.Callback { 48 private final HashSet<String> mInterestedPackages = new HashSet<String>(); 49 private boolean called; 50 private String lastPackage; 51 private final List<ShortcutInfo> lastShortcuts = new ArrayList<>(); 52 MyCallback(String... interestedPackages)53 public MyCallback(String... interestedPackages) { 54 mInterestedPackages.addAll(Arrays.asList(interestedPackages)); 55 } 56 57 @Override onPackageRemoved(String packageName, UserHandle user)58 public void onPackageRemoved(String packageName, UserHandle user) { 59 } 60 61 @Override onPackageAdded(String packageName, UserHandle user)62 public void onPackageAdded(String packageName, UserHandle user) { 63 } 64 65 @Override onPackageChanged(String packageName, UserHandle user)66 public void onPackageChanged(String packageName, UserHandle user) { 67 } 68 69 @Override onPackagesAvailable(String[] packageNames, UserHandle user, boolean replacing)70 public void onPackagesAvailable(String[] packageNames, UserHandle user, boolean replacing) { 71 } 72 73 @Override onPackagesUnavailable(String[] packageNames, UserHandle user, boolean replacing)74 public void onPackagesUnavailable(String[] packageNames, UserHandle user, 75 boolean replacing) { 76 } 77 78 @Override onShortcutsChanged( String packageName, List<ShortcutInfo> shortcuts, UserHandle user)79 public synchronized void onShortcutsChanged( 80 String packageName, List<ShortcutInfo> shortcuts, UserHandle user) { 81 if (!mInterestedPackages.contains(packageName)) { 82 return; // Ignore other packages. 83 } 84 85 final StringBuilder sb = new StringBuilder(); 86 for (ShortcutInfo si : shortcuts) { 87 if (sb.length() > 0) { 88 sb.append(", "); 89 } 90 sb.append(si.getId()); 91 } 92 93 Log.i(TAG, "onShortcutsChanged: package=" 94 + packageName + " shortcuts=" + sb.toString()); 95 for (ShortcutInfo si : shortcuts) { 96 Log.i(TAG, " " + si); 97 } 98 lastPackage = packageName; 99 lastShortcuts.clear(); 100 lastShortcuts.addAll(shortcuts); 101 called = true; 102 } 103 reset()104 public synchronized void reset() { 105 lastPackage = null; 106 lastShortcuts.clear(); 107 called = false; 108 } 109 isCalled()110 public synchronized boolean isCalled() { 111 return called; 112 } 113 assertCalled(Context clientContext)114 public synchronized ShortcutListAsserter assertCalled(Context clientContext) { 115 assertEquals(clientContext.getPackageName(), lastPackage); 116 return assertWith(lastShortcuts); 117 } 118 getList()119 public synchronized List<ShortcutInfo> getList() { 120 return lastShortcuts; 121 } 122 isShortcutById(String id, Predicate<ShortcutInfo> predicate)123 public synchronized boolean isShortcutById(String id, Predicate<ShortcutInfo> predicate) { 124 for (ShortcutInfo si : lastShortcuts) { 125 if (id.equals(si.getId()) && predicate.test(si)) { 126 return true; 127 } 128 } 129 return false; 130 } 131 } 132 testRegisterAndUnRegister()133 public void testRegisterAndUnRegister() { 134 final MyCallback c = new MyCallback(); 135 final Handler handler = new Handler(Looper.getMainLooper()); 136 getLauncherApps().registerCallback(c, handler); 137 getLauncherApps().unregisterCallback(c); 138 } 139 testCallbacks()140 public void testCallbacks() { 141 final MyCallback c = new MyCallback(mPackageContext1.getPackageName()); 142 143 setDefaultLauncher(getInstrumentation(), mLauncherContext1); 144 145 final Handler handler = new Handler(Looper.getMainLooper()); 146 147 final AtomicBoolean registered = new AtomicBoolean(false); 148 149 final Runnable reset = () -> { 150 runWithCaller(mLauncherContext1, () -> { 151 if (registered.get()) { 152 getLauncherApps().unregisterCallback(c); 153 registered.set(false); 154 } 155 c.reset(); 156 getLauncherApps().registerCallback(c, handler); 157 registered.set(true); 158 }); 159 }; 160 reset.run(); 161 try { 162 //----------------------- 163 Log.i(TAG, "testCallbacks: setDynamicShortcuts"); 164 runWithCaller(mPackageContext1, () -> { 165 assertTrue(getManager().setDynamicShortcuts(list( 166 makeShortcut("s1"), 167 makeShortcut("s2") 168 ))); 169 }); 170 retryUntil(() -> c.isCalled(), "callback not called."); 171 c.assertCalled(mPackageContext1) 172 .haveIds("s1", "s2") 173 .areAllEnabled(); 174 reset.run(); 175 176 //----------------------- 177 Log.i(TAG, "testCallbacks: addDynamicShortcuts"); 178 runWithCaller(mPackageContext1, () -> { 179 assertTrue(getManager().addDynamicShortcuts(list( 180 makeShortcutWithRank("sx", 1) 181 ))); 182 }); 183 retryUntil(() -> c.isCalled(), "callback not called."); 184 c.assertCalled(mPackageContext1) 185 .haveIds("s1", "s2", "sx") 186 .areAllEnabled(); 187 reset.run(); 188 189 //----------------------- 190 Log.i(TAG, "testCallbacks: updateShortcuts 1"); 191 runWithCaller(mPackageContext1, () -> { 192 assertTrue(getManager().updateShortcuts(list( 193 makeShortcut("s2") 194 ))); 195 }); 196 retryUntil(() -> c.isCalled(), "callback not called."); 197 c.assertCalled(mPackageContext1) 198 .haveIds("s1", "s2", "sx") 199 .areAllEnabled(); 200 reset.run(); 201 202 //----------------------- 203 Log.i(TAG, "testCallbacks: updateShortcuts 2"); 204 runWithCaller(mPackageContext1, () -> { 205 assertTrue(getManager().updateShortcuts(list( 206 makeShortcut("sx") 207 ))); 208 }); 209 retryUntil(() -> c.isCalled(), "callback not called."); 210 c.assertCalled(mPackageContext1) 211 .haveIds("s1", "s2", "sx") 212 .areAllEnabled(); 213 reset.run(); 214 215 //----------------------- 216 Log.i(TAG, "testCallbacks: enableManifestActivity 1"); 217 runWithCaller(mPackageContext1, () -> { 218 enableManifestActivity("Launcher_manifest_1", true); 219 retryUntil(() -> getManager().getManifestShortcuts().size() == 1, 220 "Manifest shortcuts didn't show up"); 221 }); 222 retryUntil(() -> c.isCalled(), "callback not called."); 223 c.assertCalled(mPackageContext1) 224 .haveIds("s1", "s2", "sx", "ms1") 225 .areAllEnabled(); 226 reset.run(); 227 228 //----------------------- 229 Log.i(TAG, "testCallbacks: enableManifestActivity 2"); 230 runWithCaller(mPackageContext1, () -> { 231 enableManifestActivity("Launcher_manifest_2", true); 232 retryUntil(() -> getManager().getManifestShortcuts().size() == 3, 233 "Manifest shortcuts didn't show up"); 234 }); 235 retryUntil(() -> c.isCalled(), "callback not called."); 236 c.assertCalled(mPackageContext1) 237 .haveIds("s1", "s2", "sx", "ms1", "ms21", "ms22") 238 .areAllEnabled(); 239 reset.run(); 240 241 //----------------------- 242 // Pin some shortcuts. 243 Log.i(TAG, "testCallbacks: pinShortcuts"); 244 runWithCaller(mLauncherContext1, () -> { 245 getLauncherApps().pinShortcuts(mPackageContext1.getPackageName(), 246 list("s1", "ms1", "ms21"), getUserHandle()); 247 }); 248 249 setDefaultLauncher(getInstrumentation(), mLauncherContext2); 250 runWithCaller(mLauncherContext2, () -> { 251 getLauncherApps().pinShortcuts(mPackageContext1.getPackageName(), 252 list("s1", "s2", "s3", "ms22"), getUserHandle()); 253 }); 254 255 setDefaultLauncher(getInstrumentation(), mLauncherContext1); 256 reset.run(); 257 258 //----------------------- 259 Log.i(TAG, "testCallbacks: removeDynamicShortcuts"); 260 runWithCaller(mPackageContext1, () -> { 261 getManager().removeDynamicShortcuts(list("s1", "s2")); 262 }); 263 retryUntil(() -> c.isCalled(), "callback not called."); 264 265 // s2 is still pinned by L2, but not visible to L1. 266 c.assertCalled(mPackageContext1) 267 .haveIds("s1", "sx", "ms1", "ms21", "ms22") 268 .areAllEnabled(); 269 reset.run(); 270 271 //----------------------- 272 Log.i(TAG, "testCallbacks: enableManifestActivity"); 273 runWithCaller(mPackageContext1, () -> { 274 enableManifestActivity("Launcher_manifest_2", false); 275 276 retryUntil(() -> getManager().getManifestShortcuts().size() == 1, 277 "Manifest shortcuts didn't show up"); 278 }); 279 retryUntil(() -> c.isCalled(), "callback not called."); 280 c.assertCalled(mPackageContext1) 281 .haveIds("s1", "sx", "ms1", "ms21") 282 283 .selectByIds("s1", "sx", "ms1") 284 .areAllEnabled() 285 286 .revertToOriginalList() 287 .selectByIds("ms21") 288 .areAllDisabled(); 289 reset.run(); 290 291 //----------------------- 292 Log.i(TAG, "testCallbacks: disableShortcuts"); 293 runWithCaller(mPackageContext1, () -> { 294 getManager().disableShortcuts(list("s1")); 295 }); 296 retryUntil(() -> (c.isCalled() && c.isShortcutById("s1", si -> !si.isEnabled())), 297 "s1 not disabled"); 298 299 c.assertCalled(mPackageContext1) 300 .haveIds("s1", "sx", "ms1", "ms21") 301 302 .selectByIds("sx", "ms1") 303 .areAllEnabled() 304 305 .revertToOriginalList() 306 .selectByIds("s1", "ms21") 307 .areAllDisabled(); 308 reset.run(); 309 310 //----------------------- 311 Log.i(TAG, "testCallbacks: enableShortcuts 1"); 312 runWithCaller(mPackageContext1, () -> { 313 getManager().enableShortcuts(list("s1")); 314 }); 315 retryUntil(() -> (c.isCalled() && c.isShortcutById("s1", si -> si.isEnabled())), 316 "s1 not enabled"); 317 318 c.assertCalled(mPackageContext1) 319 .haveIds("s1", "sx", "ms1", "ms21") 320 321 .selectByIds("s1", "sx", "ms1") 322 .areAllEnabled() 323 324 .revertToOriginalList() 325 .selectByIds("ms21") 326 .areAllDisabled(); 327 reset.run(); 328 329 //----------------------- 330 Log.i(TAG, "testCallbacks: enableShortcuts 2"); 331 runWithCaller(mPackageContext1, () -> { 332 getManager().enableShortcuts(list("s2")); 333 }); 334 retryUntil(() -> c.isCalled(), "callback not called."); 335 c.assertCalled(mPackageContext1) 336 .haveIds("s1", "sx", "ms1", "ms21") 337 338 .selectByIds("s1", "sx", "ms1") 339 .areAllEnabled() 340 341 .revertToOriginalList() 342 .selectByIds("ms21") 343 .areAllDisabled(); 344 reset.run(); 345 346 } finally { 347 runWithCaller(mLauncherContext1, () -> { 348 if (registered.get()) { 349 getLauncherApps().unregisterCallback(c); 350 registered.set(false); 351 } 352 }); 353 } 354 } 355 } 356