1 /* 2 * Copyright (C) 2017 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 android.jobscheduler.cts.jobtestapp; 18 19 import android.app.AlarmManager; 20 import android.app.Notification; 21 import android.app.NotificationChannel; 22 import android.app.NotificationManager; 23 import android.app.PendingIntent; 24 import android.app.job.JobInfo; 25 import android.app.job.JobScheduler; 26 import android.app.job.JobService; 27 import android.content.BroadcastReceiver; 28 import android.content.ComponentName; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.os.Bundle; 32 import android.os.SystemClock; 33 import android.util.Log; 34 35 /** 36 * Schedules jobs for this package but does not, by itself, occupy a foreground uid state 37 * while doing so. 38 */ 39 public class TestJobSchedulerReceiver extends BroadcastReceiver { 40 private static final String TAG = TestJobSchedulerReceiver.class.getSimpleName(); 41 static final String PACKAGE_NAME = "android.jobscheduler.cts.jobtestapp"; 42 private static final String NOTIFICATION_CHANNEL_ID = TAG + "_channel"; 43 44 public static final String ACTION_JOB_SCHEDULE_RESULT = 45 PACKAGE_NAME + ".action.SCHEDULE_RESULT"; 46 public static final String EXTRA_SCHEDULE_RESULT = PACKAGE_NAME + ".extra.SCHEDULE_RESULT"; 47 48 public static final String EXTRA_JOB_ID_KEY = PACKAGE_NAME + ".extra.JOB_ID"; 49 public static final String EXTRA_ALLOW_IN_IDLE = PACKAGE_NAME + ".extra.ALLOW_IN_IDLE"; 50 public static final String EXTRA_REQUIRED_NETWORK_TYPE = 51 PACKAGE_NAME + ".extra.REQUIRED_NETWORK_TYPE"; 52 public static final String EXTRA_AS_EXPEDITED = PACKAGE_NAME + ".extra.AS_EXPEDITED"; 53 public static final String EXTRA_AS_USER_INITIATED = PACKAGE_NAME + ".extra.AS_USER_INITIATED"; 54 public static final String EXTRA_REQUEST_JOB_UID_STATE = 55 PACKAGE_NAME + ".extra.REQUEST_JOB_UID_STATE"; 56 public static final String EXTRA_SET_NOTIFICATION = PACKAGE_NAME + ".extra.SET_NOTIFICATION"; 57 public static final String EXTRA_SET_NOTIFICATION_JOB_END_POLICY = 58 PACKAGE_NAME + ".extra.SET_NOTIFICATION_JOB_END_POLICY"; 59 public static final String EXTRA_SLOW_START = PACKAGE_NAME + ".extra.SLOW_START"; 60 public static final String EXTRA_SLOW_STOP = PACKAGE_NAME + ".extra.SLOW_STOP"; 61 public static final String ACTION_SCHEDULE_JOB = PACKAGE_NAME + ".action.SCHEDULE_JOB"; 62 public static final String ACTION_CANCEL_JOBS = PACKAGE_NAME + ".action.CANCEL_JOBS"; 63 public static final String ACTION_POST_UI_INITIATING_NOTIFICATION = 64 PACKAGE_NAME + ".action.POST_UI_INITIATING_NOTIFICATION"; 65 public static final String ACTION_SCHEDULE_FGS_START_ALARM = 66 PACKAGE_NAME + ".action.SCHEDULE_FGS_START_ALARM"; 67 public static final String ACTION_START_FGS = PACKAGE_NAME + ".action.START_FGS"; 68 public static final String ACTION_NOTIFICATION_POSTED = 69 PACKAGE_NAME + ".action.NOTIFICATION_POSTED"; 70 public static final String ACTION_ALARM_SCHEDULED = 71 PACKAGE_NAME + ".action.ALARM_SCHEDULED"; 72 public static final int JOB_INITIAL_BACKOFF = 10_000; 73 74 @Override onReceive(Context context, Intent intent)75 public void onReceive(Context context, Intent intent) { 76 Log.d(TAG, "Processing intent: " + intent.getAction()); 77 final ComponentName jobServiceComponent = new ComponentName(context, TestJobService.class); 78 final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); 79 switch (intent.getAction()) { 80 case ACTION_CANCEL_JOBS: 81 jobScheduler.cancelAll(); 82 Log.d(TAG, "Cancelled all jobs for " + context.getPackageName()); 83 break; 84 case ACTION_SCHEDULE_JOB: 85 final int jobId = intent.getIntExtra(EXTRA_JOB_ID_KEY, hashCode()); 86 final boolean allowInIdle = intent.getBooleanExtra(EXTRA_ALLOW_IN_IDLE, false); 87 final int networkType = 88 intent.getIntExtra(EXTRA_REQUIRED_NETWORK_TYPE, JobInfo.NETWORK_TYPE_NONE); 89 final boolean expedited = intent.getBooleanExtra(EXTRA_AS_EXPEDITED, false); 90 final boolean userInitiated = 91 intent.getBooleanExtra(EXTRA_AS_USER_INITIATED, false); 92 final int backoffPolicy = userInitiated ? JobInfo.BACKOFF_POLICY_EXPONENTIAL 93 : JobInfo.BACKOFF_POLICY_LINEAR; 94 final boolean requestJobUidState = intent.getBooleanExtra( 95 EXTRA_REQUEST_JOB_UID_STATE, false); 96 final Bundle extras = new Bundle(); 97 extras.putBoolean(EXTRA_REQUEST_JOB_UID_STATE, requestJobUidState); 98 extras.putBoolean(EXTRA_SET_NOTIFICATION, 99 intent.getBooleanExtra(EXTRA_SET_NOTIFICATION, false)); 100 extras.putInt(EXTRA_SET_NOTIFICATION_JOB_END_POLICY, 101 intent.getIntExtra(EXTRA_SET_NOTIFICATION_JOB_END_POLICY, 102 JobService.JOB_END_NOTIFICATION_POLICY_REMOVE)); 103 extras.putBoolean(EXTRA_SLOW_START, 104 intent.getBooleanExtra(EXTRA_SLOW_START, false)); 105 extras.putBoolean(EXTRA_SLOW_STOP, intent.getBooleanExtra(EXTRA_SLOW_STOP, false)); 106 JobInfo.Builder jobBuilder = new JobInfo.Builder(jobId, jobServiceComponent) 107 .setBackoffCriteria(JOB_INITIAL_BACKOFF, backoffPolicy) 108 .setTransientExtras(extras) 109 .setImportantWhileForeground(allowInIdle) 110 .setExpedited(expedited) 111 .setUserInitiated(userInitiated) 112 .setRequiredNetworkType(networkType); 113 final int result = jobScheduler.schedule(jobBuilder.build()); 114 if (result != JobScheduler.RESULT_SUCCESS) { 115 Log.e(TAG, "Could not schedule job " + jobId); 116 } else { 117 Log.d(TAG, "Successfully scheduled job with id " + jobId); 118 } 119 120 final Intent scheduleJobResultIntent = new Intent(ACTION_JOB_SCHEDULE_RESULT); 121 scheduleJobResultIntent.putExtra(EXTRA_JOB_ID_KEY, jobId); 122 scheduleJobResultIntent.putExtra(EXTRA_SCHEDULE_RESULT, result); 123 context.sendBroadcast(scheduleJobResultIntent); 124 break; 125 case ACTION_POST_UI_INITIATING_NOTIFICATION: 126 NotificationManager notificationManager = 127 context.getSystemService(NotificationManager.class); 128 NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, 129 TestJobSchedulerReceiver.class.getSimpleName(), 130 NotificationManager.IMPORTANCE_DEFAULT); 131 notificationManager.createNotificationChannel(channel); 132 133 final Intent scheduleJobIntent = new Intent(intent); 134 scheduleJobIntent.setAction(ACTION_SCHEDULE_JOB); 135 136 final PendingIntent scheduleJobPendingIntent = PendingIntent.getBroadcast( 137 context, 1, scheduleJobIntent, 138 PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT); 139 Notification notification = 140 new Notification.Builder(context, NOTIFICATION_CHANNEL_ID) 141 .setContentTitle("Test title") 142 .setSmallIcon(android.R.mipmap.sym_def_app_icon) 143 .setContentText("Click to start UI job!") 144 .setContentIntent(scheduleJobPendingIntent) 145 .build(); 146 notificationManager.notify(0, notification); 147 148 final Intent completionIntent = new Intent(ACTION_NOTIFICATION_POSTED); 149 context.sendBroadcast(completionIntent); 150 break; 151 case ACTION_SCHEDULE_FGS_START_ALARM: { 152 final Intent startFgsIntent = new Intent(ACTION_START_FGS); 153 ComponentName testComponentName = new ComponentName(context, TestFgsService.class); 154 startFgsIntent.setComponent(testComponentName); 155 156 PendingIntent startFgsPendingIntent = PendingIntent.getForegroundService( 157 context, 2, startFgsIntent, 158 PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT); 159 160 AlarmManager alarmManager = context.getSystemService(AlarmManager.class); 161 alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, 162 SystemClock.elapsedRealtime(), // Get the alarm to fire immediately 163 startFgsPendingIntent); 164 165 final Intent alarmScheduledIntent = new Intent(ACTION_ALARM_SCHEDULED); 166 context.sendBroadcast(alarmScheduledIntent); 167 break; 168 } 169 case ACTION_START_FGS: { 170 final Intent startFgsIntent = new Intent(); 171 ComponentName testComponentName = new ComponentName(context, TestFgsService.class); 172 startFgsIntent.setComponent(testComponentName); 173 174 context.startForegroundService(startFgsIntent); 175 break; 176 } 177 default: 178 Log.e(TAG, "Unknown action " + intent.getAction()); 179 } 180 } 181 } 182