• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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