diff options
| -rw-r--r-- | core/api/current.txt | 6 | ||||
| -rw-r--r-- | core/java/android/app/usage/UsageEventsQuery.java | 51 | ||||
| -rw-r--r-- | core/java/android/app/usage/UsageStatsManager.java | 5 | ||||
| -rw-r--r-- | core/tests/coretests/Android.bp | 1 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/app/usage/UsageEventsQueryTest.java | 25 | ||||
| -rw-r--r-- | services/usage/java/com/android/server/usage/UsageStatsService.java | 2 |
6 files changed, 53 insertions, 37 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index f55de5ae2d26..91cc9f99b44e 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -9379,15 +9379,15 @@ package android.app.usage { method public int describeContents(); method public long getBeginTimeMillis(); method public long getEndTimeMillis(); - method @NonNull public java.util.Set<java.lang.Integer> getEventTypes(); + method @NonNull public int[] getEventTypes(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.usage.UsageEventsQuery> CREATOR; } public static final class UsageEventsQuery.Builder { ctor public UsageEventsQuery.Builder(long, long); - method @NonNull public android.app.usage.UsageEventsQuery.Builder addEventTypes(@NonNull int...); method @NonNull public android.app.usage.UsageEventsQuery build(); + method @NonNull public android.app.usage.UsageEventsQuery.Builder setEventTypes(@NonNull int...); } public final class UsageStats implements android.os.Parcelable { @@ -9414,7 +9414,7 @@ package android.app.usage { method public java.util.List<android.app.usage.ConfigurationStats> queryConfigurations(int, long, long); method public java.util.List<android.app.usage.EventStats> queryEventStats(int, long, long); method public android.app.usage.UsageEvents queryEvents(long, long); - method @FlaggedApi("android.app.usage.filter_based_event_query_api") @NonNull @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public android.app.usage.UsageEvents queryEvents(@NonNull android.app.usage.UsageEventsQuery); + method @FlaggedApi("android.app.usage.filter_based_event_query_api") @Nullable @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public android.app.usage.UsageEvents queryEvents(@NonNull android.app.usage.UsageEventsQuery); method public android.app.usage.UsageEvents queryEventsForSelf(long, long); method public java.util.List<android.app.usage.UsageStats> queryUsageStats(int, long, long); field @FlaggedApi("android.app.usage.user_interaction_type_api") public static final String EXTRA_EVENT_ACTION = "android.app.usage.extra.EVENT_ACTION"; diff --git a/core/java/android/app/usage/UsageEventsQuery.java b/core/java/android/app/usage/UsageEventsQuery.java index 3cd292392694..df6324f744a8 100644 --- a/core/java/android/app/usage/UsageEventsQuery.java +++ b/core/java/android/app/usage/UsageEventsQuery.java @@ -29,9 +29,6 @@ import android.util.ArraySet; import com.android.internal.util.ArrayUtils; import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; /** * An Object-Oriented representation for a {@link UsageEvents} query. @@ -77,19 +74,17 @@ public final class UsageEventsQuery implements Parcelable { } /** - * Returns the set of usage event types for the query. - * <em>Note: An empty set indicates query for all usage events. </em> + * Retrieves the usage event types for the query. + * <p>Note that an empty array indicates querying all usage event types, and it may + * cause additional system overhead when calling + * {@link UsageStatsManager#queryEvents(UsageEventsQuery)}. Apps are encouraged to + * provide a list of event types via {@link Builder#setEventTypes(int...)}</p> + * + * @return an array contains the usage event types that was previously set using + * {@link Builder#setEventTypes(int...)} or an empty array if no value has been set. */ - public @NonNull Set<Integer> getEventTypes() { - if (ArrayUtils.isEmpty(mEventTypes)) { - return Collections.emptySet(); - } - - HashSet<Integer> eventTypeSet = new HashSet<>(); - for (int eventType : mEventTypes) { - eventTypeSet.add(eventType); - } - return eventTypeSet; + public @NonNull @Event.EventType int[] getEventTypes() { + return Arrays.copyOf(mEventTypes, mEventTypes.length); } /** @hide */ @@ -125,11 +120,6 @@ public final class UsageEventsQuery implements Parcelable { } }; - /** @hide */ - public int[] getEventTypeFilter() { - return Arrays.copyOf(mEventTypes, mEventTypes.length); - } - /** * Builder for UsageEventsQuery. */ @@ -166,12 +156,25 @@ public final class UsageEventsQuery implements Parcelable { } /** - * Specifies the list of usage event types to be included in the query. - * @param eventTypes List of the usage event types. See {@link UsageEvents.Event} + * Sets the list of usage event types to be included in the query. + * + * <p>Note: </p> An empty array will be returned by + * {@link UsageEventsQuery#getEventTypes()} without calling this method, which indicates + * querying for all event types. Apps are encouraged to provide a list of event types. + * Only the matching types supplied will be used to query. * - * @throws llegalArgumentException if the event type is not valid. + * @param eventTypes the array of the usage event types. See {@link UsageEvents.Event}. + * @throws NullPointerException if {@code eventTypes} is {@code null} or empty. + * @throws IllegalArgumentException if any of event types are invalid. + * @see UsageEventsQuery#getEventTypes() + * @see UsageStatsManager#queryEvents(UsageEventsQuery) */ - public @NonNull Builder addEventTypes(@NonNull @Event.EventType int... eventTypes) { + public @NonNull Builder setEventTypes(@NonNull @Event.EventType int... eventTypes) { + if (eventTypes == null || eventTypes.length == 0) { + throw new NullPointerException("eventTypes is null or empty"); + } + + mEventTypes.clear(); for (int i = 0; i < eventTypes.length; i++) { final int eventType = eventTypes[i]; if (eventType < Event.NONE || eventType > Event.MAX_EVENT_TYPE) { diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index 85d223d01ee8..8df913a4ca63 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -602,14 +602,15 @@ public final class UsageStatsManager { /** * Query for events with specific UsageEventsQuery object. + * * <em>Note: if the user's device is not in an unlocked state (as defined by * {@link UserManager#isUserUnlocked()}), then {@code null} will be returned.</em> * * @param query The query object used to specify the query parameters. - * @return A {@link UsageEvents}. + * @return A {@link UsageEvents} which contains the events matching the query parameters. */ @FlaggedApi(Flags.FLAG_FILTER_BASED_EVENT_QUERY_API) - @NonNull + @Nullable @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public UsageEvents queryEvents(@NonNull UsageEventsQuery query) { try { diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index e18de2e66399..d1a90aea835c 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -62,6 +62,7 @@ android_test { "frameworks-core-util-lib", "mockwebserver", "guava", + "android.app.usage.flags-aconfig-java", "android.view.accessibility.flags-aconfig-java", "androidx.core_core", "androidx.core_core-ktx", diff --git a/core/tests/coretests/src/android/app/usage/UsageEventsQueryTest.java b/core/tests/coretests/src/android/app/usage/UsageEventsQueryTest.java index 839b645cf352..4565978434ee 100644 --- a/core/tests/coretests/src/android/app/usage/UsageEventsQueryTest.java +++ b/core/tests/coretests/src/android/app/usage/UsageEventsQueryTest.java @@ -15,24 +15,34 @@ */ package android.app.usage; +import static android.app.usage.Flags.FLAG_FILTER_BASED_EVENT_QUERY_API; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import android.app.usage.UsageEvents.Event; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import java.util.Random; -import java.util.Set; @RunWith(AndroidJUnit4.class) @SmallTest public class UsageEventsQueryTest { + @Rule + public final CheckFlagsRule mCheckFlagsRule = + DeviceFlagsValueProvider.createCheckFlagsRule(); + @Test + @RequiresFlagsEnabled(FLAG_FILTER_BASED_EVENT_QUERY_API) public void testQueryDuration() { // Test with negative beginTimeMillis. long beginTimeMillis = -100; @@ -97,6 +107,7 @@ public class UsageEventsQueryTest { } @Test + @RequiresFlagsEnabled(FLAG_FILTER_BASED_EVENT_QUERY_API) public void testQueryEventTypes() { Random rnd = new Random(); UsageEventsQuery.Builder queryBuilder = new UsageEventsQuery.Builder(1000, 2000); @@ -104,7 +115,7 @@ public class UsageEventsQueryTest { // Test with invalid event type. int eventType = Event.NONE - 1; try { - queryBuilder.addEventTypes(eventType); + queryBuilder.setEventTypes(eventType); fail("Invalid event type: " + eventType); } catch (IllegalArgumentException e) { // Expected, fall through. @@ -112,7 +123,7 @@ public class UsageEventsQueryTest { eventType = Event.MAX_EVENT_TYPE + 1; try { - queryBuilder.addEventTypes(eventType); + queryBuilder.setEventTypes(eventType); fail("Invalid event type: " + eventType); } catch (IllegalArgumentException e) { // Expected, fall through. @@ -121,11 +132,11 @@ public class UsageEventsQueryTest { // Test with valid and duplicate event types. eventType = rnd.nextInt(Event.MAX_EVENT_TYPE + 1); try { - UsageEventsQuery query = queryBuilder.addEventTypes(eventType, eventType, eventType) + UsageEventsQuery query = queryBuilder.setEventTypes(eventType, eventType, eventType) .build(); - Set<Integer> eventTypeSet = query.getEventTypes(); - assertEquals(eventTypeSet.size(), 1); - int type = eventTypeSet.iterator().next(); + final int[] eventTypesArray = query.getEventTypes(); + assertEquals(eventTypesArray.length, 1); + int type = eventTypesArray[0]; assertEquals(type, eventType); } catch (IllegalArgumentException e) { fail("Valid event type: " + eventType); diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 08f719e91da9..9fc64feb4b25 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -2440,7 +2440,7 @@ public class UsageStatsService extends SystemService implements } return queryEventsHelper(userId, query.getBeginTimeMillis(), - query.getEndTimeMillis(), callingPackage, query.getEventTypeFilter()); + query.getEndTimeMillis(), callingPackage, query.getEventTypes()); } @Override |