1 /* 2 * Copyright (C) 2017 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.shortcut.backup.publisher4; 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.setDefaultLauncher; 21 22 import android.app.PendingIntent; 23 import android.content.BroadcastReceiver; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.content.pm.ShortcutInfo; 28 import android.content.pm.cts.shortcut.device.common.ShortcutManagerDeviceTestBase; 29 import android.os.PersistableBundle; 30 import android.text.TextUtils; 31 32 import java.security.SecureRandom; 33 import java.util.concurrent.CountDownLatch; 34 import java.util.concurrent.TimeUnit; 35 36 public class ShortcutManagerPostBackupTest extends ShortcutManagerDeviceTestBase { 37 public void testRestoredOnOldVersion() { 38 assertWith(getManager().getDynamicShortcuts()) 39 .isEmpty(); 40 41 assertWith(getManager().getPinnedShortcuts()) 42 .haveIds("ms1", "ms2") 43 .areAllEnabled(); 44 45 assertWith(getManager().getManifestShortcuts()) 46 .haveIds("ms1", "ms2") 47 .areAllPinned() 48 .areAllEnabled(); 49 50 // At this point, s1 and s2 don't look to exist to the publisher, so it can publish a 51 // dynamic shortcut and that should work. 52 // But updateShortcuts() don't. 53 54 final ShortcutInfo s1 = new ShortcutInfo.Builder(getContext(), "s1") 55 .setShortLabel("shortlabel1_new_one") 56 .setActivity(getActivity("MainActivity")) 57 .setIntents(new Intent[]{new Intent("main")}) 58 .build(); 59 60 assertTrue(getManager().addDynamicShortcuts(list(s1))); 61 62 final ShortcutInfo s2 = new ShortcutInfo.Builder(getContext(), "s2") 63 .setShortLabel("shortlabel2_updated") 64 .build(); 65 assertTrue(getManager().updateShortcuts(list(s2))); 66 67 assertWith(getManager().getDynamicShortcuts()) 68 .haveIds("s1") // s2 not in the list. 69 .areAllEnabled(); 70 71 assertWith(getManager().getPinnedShortcuts()) 72 .haveIds("ms1", "ms2", "s1") // s2 not in the list. 73 .areAllEnabled(); 74 75 } 76 77 public void testRestoredOnNewVersion() { 78 assertWith(getManager().getDynamicShortcuts()) 79 .haveIds("s1") 80 .areAllEnabled() 81 .areAllPinned(); 82 83 assertWith(getManager().getManifestShortcuts()) 84 .haveIds("ms1", "ms2") 85 .areAllPinned() 86 .areAllEnabled(); 87 88 assertWith(getManager().getPinnedShortcuts()) 89 .haveIds("ms1", "ms2", "s1", "s2") 90 .areAllEnabled(); 91 92 // This time, update should work. 93 final ShortcutInfo s2 = new ShortcutInfo.Builder(getContext(), "s2") 94 .setShortLabel("shortlabel2_updated") 95 .build(); 96 assertTrue(getManager().updateShortcuts(list(s2))); 97 98 assertWith(getManager().getPinnedShortcuts()) 99 .selectByIds("s2") 100 .forAllShortcuts(si -> { 101 assertEquals("shortlabel2_updated", si.getShortLabel()); 102 }); 103 } 104 105 public void testBackupDisabled() { 106 assertWith(getManager().getDynamicShortcuts()) 107 .isEmpty(); 108 109 assertWith(getManager().getPinnedShortcuts()) 110 .haveIds("ms1", "ms2") 111 .areAllEnabled(); 112 113 assertWith(getManager().getManifestShortcuts()) 114 .haveIds("ms1", "ms2") 115 .areAllPinned() 116 .areAllEnabled(); 117 118 // Backup was disabled, so either s1 nor s2 look to be restored to the app. 119 // So when the app publishes s1, it'll be published as new. 120 // But it'll still be pinned. 121 final ShortcutInfo s1 = new ShortcutInfo.Builder(getContext(), "s1") 122 .setShortLabel("shortlabel1_new_one") 123 .setActivity(getActivity("MainActivity")) 124 .setIntents(new Intent[]{new Intent("main")}) 125 .build(); 126 127 assertTrue(getManager().addDynamicShortcuts(list(s1))); 128 129 assertWith(getManager().getDynamicShortcuts()) 130 .haveIds("s1") // s2 not in the list. 131 .areAllPinned() 132 .areAllEnabled() 133 .forAllShortcuts(si -> { 134 // The app re-published the shortcut, not updated, so the fields that existed 135 // in the original shortcut is gone now. 136 assertNull(si.getExtras()); 137 }); 138 } 139 140 public void testRestoreWrongKey() { 141 // Restored pinned shortcuts are from a package with a different signature, so the dynamic 142 // pinned shortcuts should be disabled-invisible. 143 144 assertWith(getManager().getDynamicShortcuts()) 145 .isEmpty(); 146 147 assertWith(getManager().getPinnedShortcuts()) 148 .haveIds("ms1", "ms2"); 149 150 assertWith(getManager().getManifestShortcuts()) 151 .haveIds("ms1", "ms2") 152 .areAllPinned() 153 .areAllEnabled(); 154 155 final ShortcutInfo s1 = new ShortcutInfo.Builder(getContext(), "s1") 156 .setShortLabel("shortlabel1_new_one") 157 .setActivity(getActivity("MainActivity")) 158 .setIntents(new Intent[]{new Intent("main")}) 159 .build(); 160 161 assertTrue(getManager().addDynamicShortcuts(list(s1))); 162 163 final ShortcutInfo s2 = new ShortcutInfo.Builder(getContext(), "s2") 164 .setShortLabel("shortlabel2_updated") 165 .build(); 166 assertTrue(getManager().updateShortcuts(list(s2))); 167 168 assertWith(getManager().getDynamicShortcuts()) 169 .haveIds("s1") // s2 not in the list. 170 .areAllEnabled(); 171 } 172 173 /** 174 * Restored on an older version that have no manifest shortcuts. 175 * 176 * In this case, the publisher wouldn't see the manifest shortcuts, and they're overwritable. 177 */ 178 public void testRestoreNoManifestOnOldVersion() { 179 assertWith(getManager().getManifestShortcuts()) 180 .isEmpty(); 181 182 assertWith(getManager().getDynamicShortcuts()) 183 .isEmpty(); 184 185 assertWith(getManager().getPinnedShortcuts()) 186 .isEmpty(); 187 188 // ms1 was manifest/immutable, but can be overwritten. 189 final ShortcutInfo ms1 = new ShortcutInfo.Builder(getContext(), "ms1") 190 .setShortLabel("ms1_new_one") 191 .setActivity(getActivity("MainActivity")) 192 .setIntents(new Intent[]{new Intent("main")}) 193 .build(); 194 195 assertTrue(getManager().setDynamicShortcuts(list(ms1))); 196 197 assertWith(getManager().getDynamicShortcuts()) 198 .haveIds("ms1"); 199 assertWith(getManager().getPinnedShortcuts()) 200 .haveIds("ms1"); 201 202 // Adding s1 should also work. 203 final ShortcutInfo s1 = new ShortcutInfo.Builder(getContext(), "s1") 204 .setShortLabel("s1_new_one") 205 .setActivity(getActivity("MainActivity")) 206 .setIntents(new Intent[]{new Intent("main")}) 207 .build(); 208 209 assertTrue(getManager().addDynamicShortcuts(list(s1))); 210 211 assertWith(getManager().getDynamicShortcuts()) 212 .haveIds("s1", "ms1"); 213 assertWith(getManager().getPinnedShortcuts()) 214 .haveIds("s1", "ms1"); 215 216 // Update on ms2 should be no-op. 217 final ShortcutInfo ms2 = new ShortcutInfo.Builder(getContext(), "ms2") 218 .setShortLabel("ms2-updated") 219 .build(); 220 assertTrue(getManager().updateShortcuts(list(ms2))); 221 222 assertWith(getManager().getManifestShortcuts()) 223 .isEmpty(); 224 assertWith(getManager().getDynamicShortcuts()) 225 .haveIds("s1", "ms1") 226 .areAllEnabled() 227 .areAllPinned() 228 .areAllMutable() 229 230 .selectByIds("s1") 231 .forAllShortcuts(si -> { 232 assertEquals("s1_new_one", si.getShortLabel()); 233 }) 234 235 .revertToOriginalList() 236 .selectByIds("ms1") 237 .forAllShortcuts(si -> { 238 assertEquals("ms1_new_one", si.getShortLabel()); 239 }); 240 } 241 242 /** 243 * Restored on the same (or newer) version that have no manifest shortcuts. 244 * 245 * In this case, the publisher will see the manifest shortcuts (as immutable pinned), 246 * and they *cannot* be overwritten. 247 */ 248 public void testRestoreNoManifestOnNewVersion() { 249 assertWith(getManager().getManifestShortcuts()) 250 .isEmpty(); 251 252 assertWith(getManager().getDynamicShortcuts()) 253 .isEmpty(); 254 255 assertWith(getManager().getPinnedShortcuts()) 256 .haveIds("ms1", "ms2", "s1", "s2") 257 .selectByIds("ms1", "ms2") 258 .areAllDisabled() 259 260 .revertToOriginalList() 261 .selectByIds("s1", "s2") 262 .areAllEnabled(); 263 } 264 265 private void assertNoShortcuts() { 266 assertWith(getManager().getDynamicShortcuts()).isEmpty(); 267 assertWith(getManager().getPinnedShortcuts()).isEmpty(); 268 assertWith(getManager().getManifestShortcuts()).isEmpty(); 269 } 270 271 public void testInvisibleIgnored() throws Exception { 272 assertNoShortcuts(); 273 274 // Make sure "disable" won't change the disabled reason. Also make sure "enable" won't 275 // enable them. 276 getManager().disableShortcuts(list("s1", "s2", "ms1")); 277 assertNoShortcuts(); 278 279 getManager().enableShortcuts(list("ms1", "s2")); 280 assertNoShortcuts(); 281 282 getManager().enableShortcuts(list("ms1")); 283 assertNoShortcuts(); 284 285 getManager().removeDynamicShortcuts(list("s1", "ms1")); 286 assertNoShortcuts(); 287 288 getManager().removeAllDynamicShortcuts(); 289 assertNoShortcuts(); 290 291 292 // Force launcher 4 to be the default launcher so it'll receive the pin request. 293 setDefaultLauncher(getInstrumentation(), 294 "android.content.pm.cts.shortcut.backup.launcher4/.MainActivity"); 295 296 // Update, set and add have been tested already, so let's test "pin". 297 298 final CountDownLatch latch = new CountDownLatch(1); 299 300 PersistableBundle pb = new PersistableBundle(); 301 pb.putBoolean("acceptit", true); 302 303 final ShortcutInfo ms2 = new ShortcutInfo.Builder(getContext(), "ms2") 304 .setShortLabel("ms2_new_one") 305 .setActivity(getActivity("MainActivity")) 306 .setIntents(new Intent[]{new Intent("main2")}) 307 .setExtras(pb) 308 .build(); 309 310 final String myIntentAction = "cts-shortcut-intent_" + new SecureRandom().nextInt(); 311 final IntentFilter myFilter = new IntentFilter(myIntentAction); 312 313 final BroadcastReceiver onResult = new BroadcastReceiver() { 314 @Override 315 public void onReceive(Context context, Intent intent) { 316 latch.countDown(); 317 } 318 }; 319 getContext().registerReceiver(onResult, myFilter); 320 assertTrue(getManager().requestPinShortcut(ms2, 321 PendingIntent.getBroadcast(getContext(), 0, new Intent(myIntentAction), 322 PendingIntent.FLAG_CANCEL_CURRENT).getIntentSender())); 323 324 assertTrue("Didn't receive requestPinShortcut() callback.", 325 latch.await(30, TimeUnit.SECONDS)); 326 327 assertWith(getManager().getPinnedShortcuts()) 328 .haveIds("ms2") 329 .areAllNotDynamic() 330 .areAllNotManifest() 331 .areAllMutable() 332 .areAllPinned() 333 .forAllShortcuts(si -> { 334 // requestPinShortcut() acts as an update in this case, so even though 335 // the original shortcut hada long label, this one does not. 336 assertTrue(TextUtils.isEmpty(si.getLongLabel())); 337 }); 338 } 339 } 340