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