1 /* 2 * Copyright (C) 2022 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 17 package com.android.server.notification; 18 19 import android.app.job.JobInfo; 20 import android.app.job.JobParameters; 21 import android.app.job.JobScheduler; 22 import android.app.job.JobService; 23 import android.content.ComponentName; 24 import android.content.Context; 25 26 import com.android.internal.annotations.VisibleForTesting; 27 import com.android.server.LocalServices; 28 29 /** 30 * JobService implementation for scheduling the notification informing users about 31 * notification permissions updates and taking them to review their existing permissions. 32 * @hide 33 */ 34 public class ReviewNotificationPermissionsJobService extends JobService { 35 public static final String TAG = "ReviewNotificationPermissionsJobService"; 36 37 @VisibleForTesting 38 protected static final int JOB_ID = 225373531; 39 40 /** 41 * Schedule a new job that will show a notification the specified amount of time in the future. 42 */ scheduleJob(Context context, long rescheduleTimeMillis)43 public static void scheduleJob(Context context, long rescheduleTimeMillis) { 44 JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); 45 // if the job already exists for some reason, cancel & reschedule 46 if (jobScheduler.getPendingJob(JOB_ID) != null) { 47 jobScheduler.cancel(JOB_ID); 48 } 49 ComponentName component = new ComponentName( 50 context, ReviewNotificationPermissionsJobService.class); 51 JobInfo newJob = new JobInfo.Builder(JOB_ID, component) 52 .setPersisted(true) // make sure it'll still get rescheduled after reboot 53 .setMinimumLatency(rescheduleTimeMillis) // run after specified amount of time 54 .build(); 55 jobScheduler.schedule(newJob); 56 } 57 58 @Override onStartJob(JobParameters params)59 public boolean onStartJob(JobParameters params) { 60 // While jobs typically should be run on different threads, this 61 // job only posts a notification, which is not a long-running operation 62 // as notification posting is asynchronous. 63 NotificationManagerInternal nmi = 64 LocalServices.getService(NotificationManagerInternal.class); 65 nmi.sendReviewPermissionsNotification(); 66 67 // once the notification is posted, the job is done, so no need to 68 // keep it alive afterwards 69 return false; 70 } 71 72 @Override onStopJob(JobParameters params)73 public boolean onStopJob(JobParameters params) { 74 // If we're interrupted for some reason, try again (though this may not 75 // ever happen due to onStartJob not leaving a job running after being 76 // called) 77 return true; 78 } 79 } 80