1*90c8c64dSAndroid Build Coastguard Worker /* 2*90c8c64dSAndroid Build Coastguard Worker * Copyright 2013 The Android Open Source Project 3*90c8c64dSAndroid Build Coastguard Worker * 4*90c8c64dSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*90c8c64dSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*90c8c64dSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*90c8c64dSAndroid Build Coastguard Worker * 8*90c8c64dSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*90c8c64dSAndroid Build Coastguard Worker * 10*90c8c64dSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*90c8c64dSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*90c8c64dSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*90c8c64dSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*90c8c64dSAndroid Build Coastguard Worker * limitations under the License. 15*90c8c64dSAndroid Build Coastguard Worker */ 16*90c8c64dSAndroid Build Coastguard Worker 17*90c8c64dSAndroid Build Coastguard Worker package com.example.android.jobscheduler; 18*90c8c64dSAndroid Build Coastguard Worker 19*90c8c64dSAndroid Build Coastguard Worker import android.app.Activity; 20*90c8c64dSAndroid Build Coastguard Worker import android.app.job.JobInfo; 21*90c8c64dSAndroid Build Coastguard Worker import android.app.job.JobScheduler; 22*90c8c64dSAndroid Build Coastguard Worker import android.content.ComponentName; 23*90c8c64dSAndroid Build Coastguard Worker import android.content.Context; 24*90c8c64dSAndroid Build Coastguard Worker import android.content.Intent; 25*90c8c64dSAndroid Build Coastguard Worker import android.os.Bundle; 26*90c8c64dSAndroid Build Coastguard Worker import android.os.Handler; 27*90c8c64dSAndroid Build Coastguard Worker import android.os.Message; 28*90c8c64dSAndroid Build Coastguard Worker import android.os.Messenger; 29*90c8c64dSAndroid Build Coastguard Worker import android.os.PersistableBundle; 30*90c8c64dSAndroid Build Coastguard Worker import android.support.annotation.ColorRes; 31*90c8c64dSAndroid Build Coastguard Worker import android.support.annotation.Nullable; 32*90c8c64dSAndroid Build Coastguard Worker import android.text.TextUtils; 33*90c8c64dSAndroid Build Coastguard Worker import android.util.Log; 34*90c8c64dSAndroid Build Coastguard Worker import android.view.View; 35*90c8c64dSAndroid Build Coastguard Worker import android.widget.CheckBox; 36*90c8c64dSAndroid Build Coastguard Worker import android.widget.EditText; 37*90c8c64dSAndroid Build Coastguard Worker import android.widget.RadioButton; 38*90c8c64dSAndroid Build Coastguard Worker import android.widget.TextView; 39*90c8c64dSAndroid Build Coastguard Worker import android.widget.Toast; 40*90c8c64dSAndroid Build Coastguard Worker 41*90c8c64dSAndroid Build Coastguard Worker import com.example.android.jobscheduler.service.MyJobService; 42*90c8c64dSAndroid Build Coastguard Worker 43*90c8c64dSAndroid Build Coastguard Worker import java.lang.ref.WeakReference; 44*90c8c64dSAndroid Build Coastguard Worker import java.util.List; 45*90c8c64dSAndroid Build Coastguard Worker 46*90c8c64dSAndroid Build Coastguard Worker 47*90c8c64dSAndroid Build Coastguard Worker /** 48*90c8c64dSAndroid Build Coastguard Worker * Schedules and configures jobs to be executed by a {@link JobScheduler}. 49*90c8c64dSAndroid Build Coastguard Worker * <p> 50*90c8c64dSAndroid Build Coastguard Worker * {@link MyJobService} can send messages to this via a {@link Messenger} 51*90c8c64dSAndroid Build Coastguard Worker * that is sent in the Intent that starts the Service. 52*90c8c64dSAndroid Build Coastguard Worker */ 53*90c8c64dSAndroid Build Coastguard Worker public class MainActivity extends Activity { 54*90c8c64dSAndroid Build Coastguard Worker 55*90c8c64dSAndroid Build Coastguard Worker private static final String TAG = MainActivity.class.getSimpleName(); 56*90c8c64dSAndroid Build Coastguard Worker 57*90c8c64dSAndroid Build Coastguard Worker public static final int MSG_UNCOLOR_START = 0; 58*90c8c64dSAndroid Build Coastguard Worker public static final int MSG_UNCOLOR_STOP = 1; 59*90c8c64dSAndroid Build Coastguard Worker public static final int MSG_COLOR_START = 2; 60*90c8c64dSAndroid Build Coastguard Worker public static final int MSG_COLOR_STOP = 3; 61*90c8c64dSAndroid Build Coastguard Worker 62*90c8c64dSAndroid Build Coastguard Worker public static final String MESSENGER_INTENT_KEY 63*90c8c64dSAndroid Build Coastguard Worker = BuildConfig.APPLICATION_ID + ".MESSENGER_INTENT_KEY"; 64*90c8c64dSAndroid Build Coastguard Worker public static final String WORK_DURATION_KEY = 65*90c8c64dSAndroid Build Coastguard Worker BuildConfig.APPLICATION_ID + ".WORK_DURATION_KEY"; 66*90c8c64dSAndroid Build Coastguard Worker 67*90c8c64dSAndroid Build Coastguard Worker private EditText mDelayEditText; 68*90c8c64dSAndroid Build Coastguard Worker private EditText mDeadlineEditText; 69*90c8c64dSAndroid Build Coastguard Worker private EditText mDurationTimeEditText; 70*90c8c64dSAndroid Build Coastguard Worker private RadioButton mWiFiConnectivityRadioButton; 71*90c8c64dSAndroid Build Coastguard Worker private RadioButton mAnyConnectivityRadioButton; 72*90c8c64dSAndroid Build Coastguard Worker private CheckBox mRequiresChargingCheckBox; 73*90c8c64dSAndroid Build Coastguard Worker private CheckBox mRequiresIdleCheckbox; 74*90c8c64dSAndroid Build Coastguard Worker 75*90c8c64dSAndroid Build Coastguard Worker private ComponentName mServiceComponent; 76*90c8c64dSAndroid Build Coastguard Worker 77*90c8c64dSAndroid Build Coastguard Worker private int mJobId = 0; 78*90c8c64dSAndroid Build Coastguard Worker 79*90c8c64dSAndroid Build Coastguard Worker // Handler for incoming messages from the service. 80*90c8c64dSAndroid Build Coastguard Worker private IncomingMessageHandler mHandler; 81*90c8c64dSAndroid Build Coastguard Worker 82*90c8c64dSAndroid Build Coastguard Worker @Override onCreate(Bundle savedInstanceState)83*90c8c64dSAndroid Build Coastguard Worker public void onCreate(Bundle savedInstanceState) { 84*90c8c64dSAndroid Build Coastguard Worker super.onCreate(savedInstanceState); 85*90c8c64dSAndroid Build Coastguard Worker setContentView(R.layout.sample_main); 86*90c8c64dSAndroid Build Coastguard Worker 87*90c8c64dSAndroid Build Coastguard Worker // Set up UI. 88*90c8c64dSAndroid Build Coastguard Worker mDelayEditText = (EditText) findViewById(R.id.delay_time); 89*90c8c64dSAndroid Build Coastguard Worker mDurationTimeEditText = (EditText) findViewById(R.id.duration_time); 90*90c8c64dSAndroid Build Coastguard Worker mDeadlineEditText = (EditText) findViewById(R.id.deadline_time); 91*90c8c64dSAndroid Build Coastguard Worker mWiFiConnectivityRadioButton = (RadioButton) findViewById(R.id.checkbox_unmetered); 92*90c8c64dSAndroid Build Coastguard Worker mAnyConnectivityRadioButton = (RadioButton) findViewById(R.id.checkbox_any); 93*90c8c64dSAndroid Build Coastguard Worker mRequiresChargingCheckBox = (CheckBox) findViewById(R.id.checkbox_charging); 94*90c8c64dSAndroid Build Coastguard Worker mRequiresIdleCheckbox = (CheckBox) findViewById(R.id.checkbox_idle); 95*90c8c64dSAndroid Build Coastguard Worker mServiceComponent = new ComponentName(this, MyJobService.class); 96*90c8c64dSAndroid Build Coastguard Worker 97*90c8c64dSAndroid Build Coastguard Worker mHandler = new IncomingMessageHandler(this); 98*90c8c64dSAndroid Build Coastguard Worker } 99*90c8c64dSAndroid Build Coastguard Worker 100*90c8c64dSAndroid Build Coastguard Worker @Override onStop()101*90c8c64dSAndroid Build Coastguard Worker protected void onStop() { 102*90c8c64dSAndroid Build Coastguard Worker // A service can be "started" and/or "bound". In this case, it's "started" by this Activity 103*90c8c64dSAndroid Build Coastguard Worker // and "bound" to the JobScheduler (also called "Scheduled" by the JobScheduler). This call 104*90c8c64dSAndroid Build Coastguard Worker // to stopService() won't prevent scheduled jobs to be processed. However, failing 105*90c8c64dSAndroid Build Coastguard Worker // to call stopService() would keep it alive indefinitely. 106*90c8c64dSAndroid Build Coastguard Worker stopService(new Intent(this, MyJobService.class)); 107*90c8c64dSAndroid Build Coastguard Worker super.onStop(); 108*90c8c64dSAndroid Build Coastguard Worker } 109*90c8c64dSAndroid Build Coastguard Worker 110*90c8c64dSAndroid Build Coastguard Worker @Override onStart()111*90c8c64dSAndroid Build Coastguard Worker protected void onStart() { 112*90c8c64dSAndroid Build Coastguard Worker super.onStart(); 113*90c8c64dSAndroid Build Coastguard Worker // Start service and provide it a way to communicate with this class. 114*90c8c64dSAndroid Build Coastguard Worker Intent startServiceIntent = new Intent(this, MyJobService.class); 115*90c8c64dSAndroid Build Coastguard Worker Messenger messengerIncoming = new Messenger(mHandler); 116*90c8c64dSAndroid Build Coastguard Worker startServiceIntent.putExtra(MESSENGER_INTENT_KEY, messengerIncoming); 117*90c8c64dSAndroid Build Coastguard Worker startService(startServiceIntent); 118*90c8c64dSAndroid Build Coastguard Worker } 119*90c8c64dSAndroid Build Coastguard Worker 120*90c8c64dSAndroid Build Coastguard Worker /** 121*90c8c64dSAndroid Build Coastguard Worker * Executed when user clicks on SCHEDULE JOB. 122*90c8c64dSAndroid Build Coastguard Worker */ scheduleJob(View v)123*90c8c64dSAndroid Build Coastguard Worker public void scheduleJob(View v) { 124*90c8c64dSAndroid Build Coastguard Worker JobInfo.Builder builder = new JobInfo.Builder(mJobId++, mServiceComponent); 125*90c8c64dSAndroid Build Coastguard Worker 126*90c8c64dSAndroid Build Coastguard Worker String delay = mDelayEditText.getText().toString(); 127*90c8c64dSAndroid Build Coastguard Worker if (!TextUtils.isEmpty(delay)) { 128*90c8c64dSAndroid Build Coastguard Worker builder.setMinimumLatency(Long.valueOf(delay) * 1000); 129*90c8c64dSAndroid Build Coastguard Worker } 130*90c8c64dSAndroid Build Coastguard Worker String deadline = mDeadlineEditText.getText().toString(); 131*90c8c64dSAndroid Build Coastguard Worker if (!TextUtils.isEmpty(deadline)) { 132*90c8c64dSAndroid Build Coastguard Worker builder.setOverrideDeadline(Long.valueOf(deadline) * 1000); 133*90c8c64dSAndroid Build Coastguard Worker } 134*90c8c64dSAndroid Build Coastguard Worker boolean requiresUnmetered = mWiFiConnectivityRadioButton.isChecked(); 135*90c8c64dSAndroid Build Coastguard Worker boolean requiresAnyConnectivity = mAnyConnectivityRadioButton.isChecked(); 136*90c8c64dSAndroid Build Coastguard Worker if (requiresUnmetered) { 137*90c8c64dSAndroid Build Coastguard Worker builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED); 138*90c8c64dSAndroid Build Coastguard Worker } else if (requiresAnyConnectivity) { 139*90c8c64dSAndroid Build Coastguard Worker builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); 140*90c8c64dSAndroid Build Coastguard Worker } 141*90c8c64dSAndroid Build Coastguard Worker builder.setRequiresDeviceIdle(mRequiresIdleCheckbox.isChecked()); 142*90c8c64dSAndroid Build Coastguard Worker builder.setRequiresCharging(mRequiresChargingCheckBox.isChecked()); 143*90c8c64dSAndroid Build Coastguard Worker 144*90c8c64dSAndroid Build Coastguard Worker // Extras, work duration. 145*90c8c64dSAndroid Build Coastguard Worker PersistableBundle extras = new PersistableBundle(); 146*90c8c64dSAndroid Build Coastguard Worker String workDuration = mDurationTimeEditText.getText().toString(); 147*90c8c64dSAndroid Build Coastguard Worker if (TextUtils.isEmpty(workDuration)) { 148*90c8c64dSAndroid Build Coastguard Worker workDuration = "1"; 149*90c8c64dSAndroid Build Coastguard Worker } 150*90c8c64dSAndroid Build Coastguard Worker extras.putLong(WORK_DURATION_KEY, Long.valueOf(workDuration) * 1000); 151*90c8c64dSAndroid Build Coastguard Worker 152*90c8c64dSAndroid Build Coastguard Worker builder.setExtras(extras); 153*90c8c64dSAndroid Build Coastguard Worker 154*90c8c64dSAndroid Build Coastguard Worker // Schedule job 155*90c8c64dSAndroid Build Coastguard Worker Log.d(TAG, "Scheduling job"); 156*90c8c64dSAndroid Build Coastguard Worker JobScheduler tm = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); 157*90c8c64dSAndroid Build Coastguard Worker tm.schedule(builder.build()); 158*90c8c64dSAndroid Build Coastguard Worker } 159*90c8c64dSAndroid Build Coastguard Worker 160*90c8c64dSAndroid Build Coastguard Worker /** 161*90c8c64dSAndroid Build Coastguard Worker * Executed when user clicks on CANCEL ALL. 162*90c8c64dSAndroid Build Coastguard Worker */ cancelAllJobs(View v)163*90c8c64dSAndroid Build Coastguard Worker public void cancelAllJobs(View v) { 164*90c8c64dSAndroid Build Coastguard Worker JobScheduler tm = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); 165*90c8c64dSAndroid Build Coastguard Worker tm.cancelAll(); 166*90c8c64dSAndroid Build Coastguard Worker Toast.makeText(MainActivity.this, R.string.all_jobs_cancelled, Toast.LENGTH_SHORT).show(); 167*90c8c64dSAndroid Build Coastguard Worker } 168*90c8c64dSAndroid Build Coastguard Worker 169*90c8c64dSAndroid Build Coastguard Worker /** 170*90c8c64dSAndroid Build Coastguard Worker * Executed when user clicks on FINISH LAST TASK. 171*90c8c64dSAndroid Build Coastguard Worker */ finishJob(View v)172*90c8c64dSAndroid Build Coastguard Worker public void finishJob(View v) { 173*90c8c64dSAndroid Build Coastguard Worker JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); 174*90c8c64dSAndroid Build Coastguard Worker List<JobInfo> allPendingJobs = jobScheduler.getAllPendingJobs(); 175*90c8c64dSAndroid Build Coastguard Worker if (allPendingJobs.size() > 0) { 176*90c8c64dSAndroid Build Coastguard Worker // Finish the last one 177*90c8c64dSAndroid Build Coastguard Worker int jobId = allPendingJobs.get(0).getId(); 178*90c8c64dSAndroid Build Coastguard Worker jobScheduler.cancel(jobId); 179*90c8c64dSAndroid Build Coastguard Worker Toast.makeText( 180*90c8c64dSAndroid Build Coastguard Worker MainActivity.this, String.format(getString(R.string.cancelled_job), jobId), 181*90c8c64dSAndroid Build Coastguard Worker Toast.LENGTH_SHORT).show(); 182*90c8c64dSAndroid Build Coastguard Worker } else { 183*90c8c64dSAndroid Build Coastguard Worker Toast.makeText( 184*90c8c64dSAndroid Build Coastguard Worker MainActivity.this, getString(R.string.no_jobs_to_cancel), 185*90c8c64dSAndroid Build Coastguard Worker Toast.LENGTH_SHORT).show(); 186*90c8c64dSAndroid Build Coastguard Worker } 187*90c8c64dSAndroid Build Coastguard Worker } 188*90c8c64dSAndroid Build Coastguard Worker 189*90c8c64dSAndroid Build Coastguard Worker /** 190*90c8c64dSAndroid Build Coastguard Worker * A {@link Handler} allows you to send messages associated with a thread. A {@link Messenger} 191*90c8c64dSAndroid Build Coastguard Worker * uses this handler to communicate from {@link MyJobService}. It's also used to make 192*90c8c64dSAndroid Build Coastguard Worker * the start and stop views blink for a short period of time. 193*90c8c64dSAndroid Build Coastguard Worker */ 194*90c8c64dSAndroid Build Coastguard Worker private static class IncomingMessageHandler extends Handler { 195*90c8c64dSAndroid Build Coastguard Worker 196*90c8c64dSAndroid Build Coastguard Worker // Prevent possible leaks with a weak reference. 197*90c8c64dSAndroid Build Coastguard Worker private WeakReference<MainActivity> mActivity; 198*90c8c64dSAndroid Build Coastguard Worker IncomingMessageHandler(MainActivity activity)199*90c8c64dSAndroid Build Coastguard Worker IncomingMessageHandler(MainActivity activity) { 200*90c8c64dSAndroid Build Coastguard Worker super(/* default looper */); 201*90c8c64dSAndroid Build Coastguard Worker this.mActivity = new WeakReference<>(activity); 202*90c8c64dSAndroid Build Coastguard Worker } 203*90c8c64dSAndroid Build Coastguard Worker 204*90c8c64dSAndroid Build Coastguard Worker @Override handleMessage(Message msg)205*90c8c64dSAndroid Build Coastguard Worker public void handleMessage(Message msg) { 206*90c8c64dSAndroid Build Coastguard Worker MainActivity mainActivity = mActivity.get(); 207*90c8c64dSAndroid Build Coastguard Worker if (mainActivity == null) { 208*90c8c64dSAndroid Build Coastguard Worker // Activity is no longer available, exit. 209*90c8c64dSAndroid Build Coastguard Worker return; 210*90c8c64dSAndroid Build Coastguard Worker } 211*90c8c64dSAndroid Build Coastguard Worker View showStartView = mainActivity.findViewById(R.id.onstart_textview); 212*90c8c64dSAndroid Build Coastguard Worker View showStopView = mainActivity.findViewById(R.id.onstop_textview); 213*90c8c64dSAndroid Build Coastguard Worker Message m; 214*90c8c64dSAndroid Build Coastguard Worker switch (msg.what) { 215*90c8c64dSAndroid Build Coastguard Worker /* 216*90c8c64dSAndroid Build Coastguard Worker * Receives callback from the service when a job has landed 217*90c8c64dSAndroid Build Coastguard Worker * on the app. Turns on indicator and sends a message to turn it off after 218*90c8c64dSAndroid Build Coastguard Worker * a second. 219*90c8c64dSAndroid Build Coastguard Worker */ 220*90c8c64dSAndroid Build Coastguard Worker case MSG_COLOR_START: 221*90c8c64dSAndroid Build Coastguard Worker // Start received, turn on the indicator and show text. 222*90c8c64dSAndroid Build Coastguard Worker showStartView.setBackgroundColor(getColor(R.color.start_received)); 223*90c8c64dSAndroid Build Coastguard Worker updateParamsTextView(msg.obj, "started"); 224*90c8c64dSAndroid Build Coastguard Worker 225*90c8c64dSAndroid Build Coastguard Worker // Send message to turn it off after a second. 226*90c8c64dSAndroid Build Coastguard Worker m = Message.obtain(this, MSG_UNCOLOR_START); 227*90c8c64dSAndroid Build Coastguard Worker sendMessageDelayed(m, 1000L); 228*90c8c64dSAndroid Build Coastguard Worker break; 229*90c8c64dSAndroid Build Coastguard Worker /* 230*90c8c64dSAndroid Build Coastguard Worker * Receives callback from the service when a job that previously landed on the 231*90c8c64dSAndroid Build Coastguard Worker * app must stop executing. Turns on indicator and sends a message to turn it 232*90c8c64dSAndroid Build Coastguard Worker * off after two seconds. 233*90c8c64dSAndroid Build Coastguard Worker */ 234*90c8c64dSAndroid Build Coastguard Worker case MSG_COLOR_STOP: 235*90c8c64dSAndroid Build Coastguard Worker // Stop received, turn on the indicator and show text. 236*90c8c64dSAndroid Build Coastguard Worker showStopView.setBackgroundColor(getColor(R.color.stop_received)); 237*90c8c64dSAndroid Build Coastguard Worker updateParamsTextView(msg.obj, "stopped"); 238*90c8c64dSAndroid Build Coastguard Worker 239*90c8c64dSAndroid Build Coastguard Worker // Send message to turn it off after a second. 240*90c8c64dSAndroid Build Coastguard Worker m = obtainMessage(MSG_UNCOLOR_STOP); 241*90c8c64dSAndroid Build Coastguard Worker sendMessageDelayed(m, 2000L); 242*90c8c64dSAndroid Build Coastguard Worker break; 243*90c8c64dSAndroid Build Coastguard Worker case MSG_UNCOLOR_START: 244*90c8c64dSAndroid Build Coastguard Worker showStartView.setBackgroundColor(getColor(R.color.none_received)); 245*90c8c64dSAndroid Build Coastguard Worker updateParamsTextView(null, ""); 246*90c8c64dSAndroid Build Coastguard Worker break; 247*90c8c64dSAndroid Build Coastguard Worker case MSG_UNCOLOR_STOP: 248*90c8c64dSAndroid Build Coastguard Worker showStopView.setBackgroundColor(getColor(R.color.none_received)); 249*90c8c64dSAndroid Build Coastguard Worker updateParamsTextView(null, ""); 250*90c8c64dSAndroid Build Coastguard Worker break; 251*90c8c64dSAndroid Build Coastguard Worker } 252*90c8c64dSAndroid Build Coastguard Worker } 253*90c8c64dSAndroid Build Coastguard Worker updateParamsTextView(@ullable Object jobId, String action)254*90c8c64dSAndroid Build Coastguard Worker private void updateParamsTextView(@Nullable Object jobId, String action) { 255*90c8c64dSAndroid Build Coastguard Worker TextView paramsTextView = (TextView) mActivity.get().findViewById(R.id.task_params); 256*90c8c64dSAndroid Build Coastguard Worker if (jobId == null) { 257*90c8c64dSAndroid Build Coastguard Worker paramsTextView.setText(""); 258*90c8c64dSAndroid Build Coastguard Worker return; 259*90c8c64dSAndroid Build Coastguard Worker } 260*90c8c64dSAndroid Build Coastguard Worker String jobIdText = String.valueOf(jobId); 261*90c8c64dSAndroid Build Coastguard Worker paramsTextView.setText(String.format("Job ID %s %s", jobIdText, action)); 262*90c8c64dSAndroid Build Coastguard Worker } 263*90c8c64dSAndroid Build Coastguard Worker getColor(@olorRes int color)264*90c8c64dSAndroid Build Coastguard Worker private int getColor(@ColorRes int color) { 265*90c8c64dSAndroid Build Coastguard Worker return mActivity.get().getResources().getColor(color); 266*90c8c64dSAndroid Build Coastguard Worker } 267*90c8c64dSAndroid Build Coastguard Worker } 268*90c8c64dSAndroid Build Coastguard Worker } 269