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.appOps; 19 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list; 20 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.retryUntil; 21 22 import android.app.AppOpsManager; 23 import android.app.usage.UsageEvents; 24 import android.app.usage.UsageEvents.Event; 25 import android.app.usage.UsageStatsManager; 26 import android.content.Context; 27 import android.content.pm.cts.shortcutmanager.common.Constants; 28 import android.test.suitebuilder.annotation.SmallTest; 29 import android.text.format.Time; 30 31 import com.android.compatibility.common.util.CddTest; 32 import com.android.compatibility.common.util.ShellIdentityUtils; 33 34 @CddTest(requirement="3.8.1/C-4-1") 35 @SmallTest 36 public class ShortcutManagerUsageTest extends ShortcutManagerCtsTestsBase { 37 private static final String APPOPS_SET_SHELL_COMMAND = "appops set {0} " + 38 AppOpsManager.OPSTR_GET_USAGE_STATS + " {1}"; 39 40 // We need some allowance due to b/30415390. 41 private static long USAGE_STATS_RANGE_ALLOWANCE = 60 * 1000; 42 43 private UsageStatsManager mUsageStatsManager; 44 45 @Override setUp()46 protected void setUp() throws Exception { 47 super.setUp(); 48 49 appOps(getInstrumentation(), getTestContext().getPackageName(), 50 AppOpsManager.OPSTR_GET_USAGE_STATS, "allow"); 51 52 mUsageStatsManager = getTestContext().getSystemService(UsageStatsManager.class); 53 } 54 55 @Override tearDown()56 protected void tearDown() throws Exception { 57 appOps(getInstrumentation(), getTestContext().getPackageName(), 58 AppOpsManager.OPSTR_GET_USAGE_STATS, "deny"); 59 60 super.tearDown(); 61 } 62 generateRandomId(String signature)63 private static String generateRandomId(String signature) { 64 Time tobj = new Time(); 65 tobj.set(System.currentTimeMillis()); 66 return tobj.format("%Y-%m-%d %H:%M:%S") + "." + signature + "." 67 + Constants.sRandom.nextLong(); 68 } 69 hasEvent(UsageEvents events, String packageName, String id)70 private boolean hasEvent(UsageEvents events, String packageName, String id) { 71 final Event e = new Event(); 72 while (events.hasNextEvent()) { 73 if (!events.getNextEvent(e)) { 74 break; 75 } 76 if (e.getEventType() == Event.SHORTCUT_INVOCATION 77 && packageName.equals(e.getPackageName()) 78 && id.equals(e.getShortcutId())) { 79 return true; 80 } 81 } 82 return false; 83 } 84 testReportShortcutUsed()85 public void testReportShortcutUsed() throws InterruptedException { 86 87 runWithCallerWithStrictMode(mPackageContext1, () -> { 88 enableManifestActivity("Launcher_manifest_2", true); 89 90 retryUntil(() -> getManager().getManifestShortcuts().size() > 0, 91 "Manifest shortcuts didn't show up"); 92 }); 93 94 final String id1 = generateRandomId("id1"); 95 final String id2 = generateRandomId("id2"); 96 final String id3 = generateRandomId("id3"); 97 98 final String idManifest = "ms21"; 99 final String idNonexistance = "nonexistence"; 100 101 runWithCallerWithStrictMode(mPackageContext1, () -> { 102 assertTrue(getManager().setDynamicShortcuts(list( 103 makeShortcut(id1), 104 makeShortcut(id2) 105 ))); 106 }); 107 runWithCallerWithStrictMode(mPackageContext2, () -> { 108 assertTrue(getManager().setDynamicShortcuts(list( 109 makeShortcut(id1), 110 makeShortcut(id3) 111 ))); 112 }); 113 114 // Report usage. 115 final long start1 = System.currentTimeMillis() - USAGE_STATS_RANGE_ALLOWANCE; 116 runWithCallerWithStrictMode(mPackageContext2, () -> getManager().reportShortcutUsed(id3)); 117 final long end1 = System.currentTimeMillis() + USAGE_STATS_RANGE_ALLOWANCE; 118 119 // Check the log. 120 checkEventReported(start1, end1, mPackageContext2, id3, "Events weren't populated"); 121 122 // Report usage. 123 final long start2 = System.currentTimeMillis() - USAGE_STATS_RANGE_ALLOWANCE; 124 runWithCallerWithStrictMode(mPackageContext1, () -> getManager().reportShortcutUsed(id1)); 125 final long end2 = System.currentTimeMillis() + USAGE_STATS_RANGE_ALLOWANCE; 126 127 // Check the log. 128 checkEventReported(start2, end2, mPackageContext1, id1, "Events weren't populated"); 129 130 // Report usage. 131 final long start3 = System.currentTimeMillis() - USAGE_STATS_RANGE_ALLOWANCE; 132 runWithCallerWithStrictMode(mPackageContext1, () -> getManager().reportShortcutUsed(idNonexistance)); 133 runWithCallerWithStrictMode(mPackageContext1, () -> getManager().reportShortcutUsed(idManifest)); 134 final long end3 = System.currentTimeMillis() + USAGE_STATS_RANGE_ALLOWANCE; 135 136 // Check the log. 137 checkEventReported(start3, end3, mPackageContext1, idManifest, "Events weren't populated"); 138 // Ensure that the nonexistent shortcut is not reported, even after the other one is. 139 assertFalse(hasEvent(ShellIdentityUtils.invokeMethodWithShellPermissions( 140 mUsageStatsManager, (usm) -> usm.queryEvents(start3, end3)), 141 mPackageContext1.getPackageName(), idNonexistance)); 142 } 143 testShortcutInvocationEventIsVisible()144 public void testShortcutInvocationEventIsVisible() { 145 final String id1 = generateRandomId("id1"); 146 final String id2 = generateRandomId("id2"); 147 runWithCallerWithStrictMode(mPackageContext1, 148 () -> assertTrue(getManager().setDynamicShortcuts( 149 list(makeShortcut(id1), makeShortcut(id2))))); 150 151 // report shortcut usage 152 final long start = System.currentTimeMillis() - USAGE_STATS_RANGE_ALLOWANCE; 153 runWithCallerWithStrictMode(mPackageContext1, () -> getManager().reportShortcutUsed(id1)); 154 final long end = System.currentTimeMillis() + USAGE_STATS_RANGE_ALLOWANCE; 155 156 // ensure visibility of SHORTCUT_INVOCATION event 157 checkEventReported(start, end, mPackageContext1, id1, 158 "SHORTCUT_INVOCATION event was not reported."); 159 } 160 testShortcutInvocationEventIsNotVisible()161 public void testShortcutInvocationEventIsNotVisible() { 162 final String id1 = generateRandomId("id1"); 163 final String id2 = generateRandomId("id2"); 164 runWithCallerWithStrictMode(mPackageContext1, 165 () -> assertTrue(getManager().setDynamicShortcuts( 166 list(makeShortcut(id1), makeShortcut(id2))))); 167 168 // report shortcut usage 169 final long start = System.currentTimeMillis() - USAGE_STATS_RANGE_ALLOWANCE; 170 runWithCallerWithStrictMode(mPackageContext1, () -> getManager().reportShortcutUsed(id1)); 171 final long end = System.currentTimeMillis() + USAGE_STATS_RANGE_ALLOWANCE; 172 173 // SHORTCUT_INVOCATION event should not be visible 174 assertFalse("SHORTCUT_INVOCATION event was visible.", 175 hasEvent(mUsageStatsManager.queryEvents(start, end), 176 mPackageContext1.getPackageName(), id1)); 177 } 178 checkEventReported(long start, long end, Context packageContext, String id, String failureMessage)179 private void checkEventReported(long start, long end, Context packageContext, String id, 180 String failureMessage) { 181 retryUntil(() -> hasEvent( 182 ShellIdentityUtils.invokeMethodWithShellPermissions(mUsageStatsManager, 183 (usm) -> usm.queryEvents(start, end)), packageContext.getPackageName(), id), 184 failureMessage); 185 } 186 } 187