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