Add SystemApi to change app launch time estimates.
An SystemApis that allow a prediction app to update app launch time estimates. Bug: 194532703 Test: atest CtsPermissionTestCases:AppIdleStatePermissionTest Test: atest CtsPermission2TestCases Change-Id: I0fde220fa038f7f1f4d543a8906e92ca625bf097
This commit is contained in:
@@ -83,6 +83,7 @@ package android {
|
||||
field public static final String CAPTURE_TV_INPUT = "android.permission.CAPTURE_TV_INPUT";
|
||||
field public static final String CAPTURE_VOICE_COMMUNICATION_OUTPUT = "android.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT";
|
||||
field public static final String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE";
|
||||
field public static final String CHANGE_APP_LAUNCH_TIME_ESTIMATE = "android.permission.CHANGE_APP_LAUNCH_TIME_ESTIMATE";
|
||||
field public static final String CHANGE_DEVICE_IDLE_TEMP_WHITELIST = "android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST";
|
||||
field public static final String CLEAR_APP_USER_DATA = "android.permission.CLEAR_APP_USER_DATA";
|
||||
field public static final String COMPANION_APPROVE_WIFI_CONNECTIONS = "android.permission.COMPANION_APPROVE_WIFI_CONNECTIONS";
|
||||
@@ -1923,6 +1924,8 @@ package android.app.usage {
|
||||
method public void reportUsageStop(@NonNull android.app.Activity, @NonNull String);
|
||||
method @RequiresPermission(android.Manifest.permission.CHANGE_APP_IDLE_STATE) public void setAppStandbyBucket(String, int);
|
||||
method @RequiresPermission(android.Manifest.permission.CHANGE_APP_IDLE_STATE) public void setAppStandbyBuckets(java.util.Map<java.lang.String,java.lang.Integer>);
|
||||
method @RequiresPermission(android.Manifest.permission.CHANGE_APP_LAUNCH_TIME_ESTIMATE) public void setEstimatedLaunchTime(@NonNull String, long);
|
||||
method @RequiresPermission(android.Manifest.permission.CHANGE_APP_LAUNCH_TIME_ESTIMATE) public void setEstimatedLaunchTimes(@NonNull java.util.Map<java.lang.String,java.lang.Long>);
|
||||
method @RequiresPermission(allOf={android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void unregisterAppUsageLimitObserver(int);
|
||||
method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void unregisterAppUsageObserver(int);
|
||||
method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void unregisterUsageSessionObserver(int);
|
||||
|
||||
72
core/java/android/app/usage/AppLaunchEstimateInfo.java
Normal file
72
core/java/android/app/usage/AppLaunchEstimateInfo.java
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.usage;
|
||||
|
||||
import android.annotation.CurrentTimeMillisLong;
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* A pair of {package, estimated launch time} to denote the estimated launch time for a given
|
||||
* package.
|
||||
* Used as a vehicle of data across the binder IPC.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class AppLaunchEstimateInfo implements Parcelable {
|
||||
|
||||
public final String packageName;
|
||||
@CurrentTimeMillisLong
|
||||
public final long estimatedLaunchTime;
|
||||
|
||||
private AppLaunchEstimateInfo(Parcel in) {
|
||||
packageName = in.readString();
|
||||
estimatedLaunchTime = in.readLong();
|
||||
}
|
||||
|
||||
public AppLaunchEstimateInfo(String packageName,
|
||||
@CurrentTimeMillisLong long estimatedLaunchTime) {
|
||||
this.packageName = packageName;
|
||||
this.estimatedLaunchTime = estimatedLaunchTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(packageName);
|
||||
dest.writeLong(estimatedLaunchTime);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Creator<AppLaunchEstimateInfo> CREATOR =
|
||||
new Creator<AppLaunchEstimateInfo>() {
|
||||
@Override
|
||||
public AppLaunchEstimateInfo createFromParcel(Parcel source) {
|
||||
return new AppLaunchEstimateInfo(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppLaunchEstimateInfo[] newArray(int size) {
|
||||
return new AppLaunchEstimateInfo[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -51,6 +51,8 @@ interface IUsageStatsManager {
|
||||
void setAppStandbyBucket(String packageName, int bucket, int userId);
|
||||
ParceledListSlice getAppStandbyBuckets(String callingPackage, int userId);
|
||||
void setAppStandbyBuckets(in ParceledListSlice appBuckets, int userId);
|
||||
void setEstimatedLaunchTime(String packageName, long estimatedLaunchTime, int userId);
|
||||
void setEstimatedLaunchTimes(in ParceledListSlice appLaunchTimes, int userId);
|
||||
void registerAppUsageObserver(int observerId, in String[] packages, long timeLimitMs,
|
||||
in PendingIntent callback, String callingPackage);
|
||||
void unregisterAppUsageObserver(int observerId, String callingPackage);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.app.usage;
|
||||
|
||||
import android.annotation.CurrentTimeMillisLong;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
@@ -771,6 +772,72 @@ public final class UsageStatsManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes an app's estimated launch time. An app is considered "launched" when a user opens
|
||||
* one of its {@link android.app.Activity Activities}. The provided time is persisted across
|
||||
* reboots and is used unless 1) the time is more than a week in the future and the platform
|
||||
* thinks the app will be launched sooner, 2) the estimated time has passed. Passing in
|
||||
* {@link Long#MAX_VALUE} effectively clears the previously set launch time for the app.
|
||||
*
|
||||
* @param packageName The package name of the app to set the bucket for.
|
||||
* @param estimatedLaunchTime The next time the app is expected to be launched. Units are in
|
||||
* milliseconds since epoch (the same as
|
||||
* {@link System#currentTimeMillis()}).
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(android.Manifest.permission.CHANGE_APP_LAUNCH_TIME_ESTIMATE)
|
||||
public void setEstimatedLaunchTime(@NonNull String packageName,
|
||||
@CurrentTimeMillisLong long estimatedLaunchTime) {
|
||||
if (packageName == null) {
|
||||
throw new NullPointerException("package name cannot be null");
|
||||
}
|
||||
if (estimatedLaunchTime <= 0) {
|
||||
throw new IllegalArgumentException("estimated launch time must be positive");
|
||||
}
|
||||
try {
|
||||
mService.setEstimatedLaunchTime(packageName, estimatedLaunchTime, mContext.getUserId());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the estimated launch times for multiple apps at once. The map is keyed by the
|
||||
* package name and the value is the estimated launch time.
|
||||
*
|
||||
* @param estimatedLaunchTimes A map of package name to estimated launch time.
|
||||
* @see #setEstimatedLaunchTime(String, long)
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(android.Manifest.permission.CHANGE_APP_LAUNCH_TIME_ESTIMATE)
|
||||
public void setEstimatedLaunchTimes(@NonNull Map<String, Long> estimatedLaunchTimes) {
|
||||
if (estimatedLaunchTimes == null) {
|
||||
throw new NullPointerException("estimatedLaunchTimes cannot be null");
|
||||
}
|
||||
final List<AppLaunchEstimateInfo> estimateList =
|
||||
new ArrayList<>(estimatedLaunchTimes.size());
|
||||
for (Map.Entry<String, Long> estimateEntry : estimatedLaunchTimes.entrySet()) {
|
||||
final String pkgName = estimateEntry.getKey();
|
||||
if (pkgName == null) {
|
||||
throw new NullPointerException("package name cannot be null");
|
||||
}
|
||||
final Long estimatedLaunchTime = estimateEntry.getValue();
|
||||
if (estimatedLaunchTime == null || estimatedLaunchTime <= 0) {
|
||||
throw new IllegalArgumentException("estimated launch time must be positive");
|
||||
}
|
||||
estimateList.add(new AppLaunchEstimateInfo(pkgName, estimatedLaunchTime));
|
||||
}
|
||||
final ParceledListSlice<AppLaunchEstimateInfo> slice =
|
||||
new ParceledListSlice<>(estimateList);
|
||||
try {
|
||||
mService.setEstimatedLaunchTimes(slice, mContext.getUserId());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Register an app usage limit observer that receives a callback on the provided intent when
|
||||
|
||||
@@ -4880,6 +4880,11 @@
|
||||
<permission android:name="android.permission.CHANGE_APP_IDLE_STATE"
|
||||
android:protectionLevel="signature|privileged" />
|
||||
|
||||
<!-- @hide @SystemApi Allows an application to change the estimated launch time of an app.
|
||||
<p>Not for use by third-party applications. -->
|
||||
<permission android:name="android.permission.CHANGE_APP_LAUNCH_TIME_ESTIMATE"
|
||||
android:protectionLevel="signature|privileged" />
|
||||
|
||||
<!-- @hide @SystemApi Allows an application to temporarily allowlist an inactive app to
|
||||
access the network and acquire wakelocks.
|
||||
<p>Not for use by third-party applications. -->
|
||||
|
||||
@@ -41,6 +41,7 @@ import android.app.AppOpsManager;
|
||||
import android.app.IUidObserver;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.admin.DevicePolicyManagerInternal;
|
||||
import android.app.usage.AppLaunchEstimateInfo;
|
||||
import android.app.usage.AppStandbyInfo;
|
||||
import android.app.usage.ConfigurationStats;
|
||||
import android.app.usage.EventStats;
|
||||
@@ -1554,6 +1555,52 @@ public class UsageStatsService extends SystemService implements
|
||||
}
|
||||
}
|
||||
|
||||
private void setEstimatedLaunchTime(int userId, String packageName,
|
||||
@CurrentTimeMillisLong long estimatedLaunchTime) {
|
||||
final long now = System.currentTimeMillis();
|
||||
if (estimatedLaunchTime <= now) {
|
||||
if (DEBUG) {
|
||||
Slog.w(TAG, "Ignoring new estimate for "
|
||||
+ userId + ":" + packageName + " because it's old");
|
||||
}
|
||||
return;
|
||||
}
|
||||
final long oldEstimatedLaunchTime = mAppStandby.getEstimatedLaunchTime(packageName, userId);
|
||||
if (estimatedLaunchTime != oldEstimatedLaunchTime) {
|
||||
mAppStandby.setEstimatedLaunchTime(packageName, userId, estimatedLaunchTime);
|
||||
mHandler.obtainMessage(
|
||||
MSG_NOTIFY_ESTIMATED_LAUNCH_TIME_CHANGED, userId, 0, packageName)
|
||||
.sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
private void setEstimatedLaunchTimes(int userId, List<AppLaunchEstimateInfo> launchEstimates) {
|
||||
final ArraySet<String> changedTimes = new ArraySet<>();
|
||||
final long now = System.currentTimeMillis();
|
||||
for (int i = launchEstimates.size() - 1; i >= 0; --i) {
|
||||
AppLaunchEstimateInfo estimate = launchEstimates.get(i);
|
||||
if (estimate.estimatedLaunchTime <= now) {
|
||||
if (DEBUG) {
|
||||
Slog.w(TAG, "Ignoring new estimate for "
|
||||
+ userId + ":" + estimate.packageName + " because it's old");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
final long oldEstimatedLaunchTime =
|
||||
mAppStandby.getEstimatedLaunchTime(estimate.packageName, userId);
|
||||
if (estimate.estimatedLaunchTime != oldEstimatedLaunchTime) {
|
||||
mAppStandby.setEstimatedLaunchTime(
|
||||
estimate.packageName, userId, estimate.estimatedLaunchTime);
|
||||
changedTimes.add(estimate.packageName);
|
||||
}
|
||||
}
|
||||
if (changedTimes.size() > 0) {
|
||||
mHandler.obtainMessage(
|
||||
MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED, userId, 0, changedTimes)
|
||||
.sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called via the local interface.
|
||||
*/
|
||||
@@ -2292,6 +2339,37 @@ public class UsageStatsService extends SystemService implements
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEstimatedLaunchTime(String packageName, long estimatedLaunchTime,
|
||||
int userId) {
|
||||
getContext().enforceCallingPermission(
|
||||
Manifest.permission.CHANGE_APP_LAUNCH_TIME_ESTIMATE,
|
||||
"No permission to change app launch estimates");
|
||||
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
UsageStatsService.this
|
||||
.setEstimatedLaunchTime(userId, packageName, estimatedLaunchTime);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEstimatedLaunchTimes(ParceledListSlice estimatedLaunchTimes, int userId) {
|
||||
getContext().enforceCallingPermission(
|
||||
Manifest.permission.CHANGE_APP_LAUNCH_TIME_ESTIMATE,
|
||||
"No permission to change app launch estimates");
|
||||
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
UsageStatsService.this
|
||||
.setEstimatedLaunchTimes(userId, estimatedLaunchTimes.getList());
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCarrierPrivilegedAppsChanged() {
|
||||
if (DEBUG) {
|
||||
|
||||
Reference in New Issue
Block a user