Add a new intent to navigate to the long background tasks page.
Also add a new API in JobScheduler to check if apps hold the permission.
Bug: 255821578
Test: manually
Change-Id: I4beeb7eb40b5e19fc95784b4a54031467e9bc780
diff --git a/apex/jobscheduler/framework/java/android/app/JobSchedulerImpl.java b/apex/jobscheduler/framework/java/android/app/JobSchedulerImpl.java
index f59e7a4..c6d4a892 100644
--- a/apex/jobscheduler/framework/java/android/app/JobSchedulerImpl.java
+++ b/apex/jobscheduler/framework/java/android/app/JobSchedulerImpl.java
@@ -103,6 +103,15 @@
}
@Override
+ public boolean hasRunLongJobsPermission(String packageName, int userId) {
+ try {
+ return mBinder.hasRunLongJobsPermission(packageName, userId);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ @Override
public List<JobInfo> getStartedJobs() {
try {
return mBinder.getStartedJobs();
diff --git a/apex/jobscheduler/framework/java/android/app/job/IJobScheduler.aidl b/apex/jobscheduler/framework/java/android/app/job/IJobScheduler.aidl
index 3006f50..452fb04 100644
--- a/apex/jobscheduler/framework/java/android/app/job/IJobScheduler.aidl
+++ b/apex/jobscheduler/framework/java/android/app/job/IJobScheduler.aidl
@@ -33,6 +33,7 @@
void cancelAll();
ParceledListSlice getAllPendingJobs();
JobInfo getPendingJob(int jobId);
+ boolean hasRunLongJobsPermission(String packageName, int userId);
List<JobInfo> getStartedJobs();
ParceledListSlice getAllJobSnapshots();
}
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
index 7448686..807f32d 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
@@ -22,6 +22,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.UserIdInt;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.content.ClipData;
@@ -249,6 +250,15 @@
public abstract @Nullable JobInfo getPendingJob(int jobId);
/**
+ * Returns {@code true} if the app currently holds the
+ * {@link android.Manifest.permission#RUN_LONG_JOBS} permission, allowing it to run long jobs.
+ * @hide
+ */
+ public boolean hasRunLongJobsPermission(@NonNull String packageName, @UserIdInt int userId) {
+ return false;
+ }
+
+ /**
* <b>For internal system callers only!</b>
* Returns a list of all currently-executing jobs.
* @hide
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index d9fe30d..56f318f6 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -28,6 +28,7 @@
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
+import android.app.AppOpsManager;
import android.app.IUidObserver;
import android.app.compat.CompatChanges;
import android.app.job.IJobScheduler;
@@ -304,6 +305,7 @@
final JobHandler mHandler;
final JobSchedulerStub mJobSchedulerStub;
+ private AppOpsManager mAppOps;
PackageManagerInternal mLocalPM;
ActivityManagerInternal mActivityManagerInternal;
DeviceIdleInternal mLocalDeviceIdleController;
@@ -1804,6 +1806,8 @@
controller.onSystemServicesReady();
}
+ mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
+
mAppStateTracker = (AppStateTrackerImpl) Objects.requireNonNull(
LocalServices.getService(AppStateTracker.class));
@@ -3409,6 +3413,21 @@
}
}
+ @Override
+ public boolean hasRunLongJobsPermission(@NonNull String packageName,
+ @UserIdInt int userId) {
+ final int uid = mLocalPM.getPackageUid(packageName, 0, userId);
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid != uid && !UserHandle.isCore(callingUid)) {
+ throw new SecurityException("Uid " + callingUid
+ + " cannot query canRunLongJobs for package " + packageName);
+ }
+
+ final int mode = mAppOps.checkOpNoThrow(AppOpsManager.OP_RUN_LONG_JOBS, uid,
+ packageName);
+ return mode == AppOpsManager.MODE_ALLOWED || mode == AppOpsManager.MODE_DEFAULT;
+ }
+
/**
* "dumpsys" infrastructure
*/
diff --git a/core/api/current.txt b/core/api/current.txt
index a3738f7..75bea40 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -35818,6 +35818,7 @@
field public static final String ACTION_MANAGE_ALL_SIM_PROFILES_SETTINGS = "android.settings.MANAGE_ALL_SIM_PROFILES_SETTINGS";
field public static final String ACTION_MANAGE_APPLICATIONS_SETTINGS = "android.settings.MANAGE_APPLICATIONS_SETTINGS";
field public static final String ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION = "android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION";
+ field public static final String ACTION_MANAGE_APP_LONG_JOBS = "android.settings.MANAGE_APP_LONG_JOBS";
field public static final String ACTION_MANAGE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS";
field public static final String ACTION_MANAGE_OVERLAY_PERMISSION = "android.settings.action.MANAGE_OVERLAY_PERMISSION";
field public static final String ACTION_MANAGE_SUPERVISOR_RESTRICTED_SETTING = "android.settings.MANAGE_SUPERVISOR_RESTRICTED_SETTING";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 52b1adb..dfa41b3 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -585,6 +585,22 @@
"android.settings.REQUEST_MANAGE_MEDIA";
/**
+ * Activity Action: Show settings to allow configuration of
+ * {@link Manifest.permission#RUN_LONG_JOBS} permission
+ *
+ * Input: Optionally, the Intent's data URI can specify the application package name to
+ * directly invoke the management GUI specific to the package name. For example
+ * "package:com.my.app".
+ * <p>
+ * Output: When a package data uri is passed as input, the activity result is set to
+ * {@link android.app.Activity#RESULT_OK} if the permission was granted to the app. Otherwise,
+ * the result is set to {@link android.app.Activity#RESULT_CANCELED}.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_MANAGE_APP_LONG_JOBS =
+ "android.settings.MANAGE_APP_LONG_JOBS";
+
+ /**
* Activity Action: Show settings to allow configuration of cross-profile access for apps
*
* Input: Optionally, the Intent's data URI can specify the application package name to