diff --git a/app/src/main/java/app/attestation/auditor/AttestationActivity.java b/app/src/main/java/app/attestation/auditor/AttestationActivity.java index c84cec43a..8dc1d2b70 100644 --- a/app/src/main/java/app/attestation/auditor/AttestationActivity.java +++ b/app/src/main/java/app/attestation/auditor/AttestationActivity.java @@ -63,8 +63,10 @@ public class AttestationActivity extends AppCompatActivity { private static final int PERMISSIONS_REQUEST_CAMERA = 0; private static final int PERMISSIONS_REQUEST_POST_NOTIFICATIONS_REMOTE_VERIFY = 1; + private static final int PERMISSIONS_REQUEST_POST_NOTIFICATIONS_SUBMIT_SAMPLE = 2; + private static final int PERMISSIONS_REQUEST_POST_NOTIFICATIONS_IMMEDIATE_REMOTE_VERIFY = 3; private static final ExecutorService executor = Executors.newSingleThreadExecutor(); private ActivityAttestationBinding binding; @@ -468,6 +470,9 @@ public void onRequestPermissionsResult(int requestCode, } } else if (requestCode == PERMISSIONS_REQUEST_POST_NOTIFICATIONS_REMOTE_VERIFY) { QRScannerActivityLauncher.launch(new Intent(this, QRScannerActivity.class)); + } else if (requestCode == PERMISSIONS_REQUEST_POST_NOTIFICATIONS_IMMEDIATE_REMOTE_VERIFY) { + RemoteVerifyJob.schedule(this, -1); + snackbar.setText(R.string.remote_verify_now).show(); } else if (requestCode == PERMISSIONS_REQUEST_POST_NOTIFICATIONS_SUBMIT_SAMPLE) { SubmitSampleJob.schedule(this); snackbar.setText(R.string.schedule_submit_sample_success).show(); @@ -502,6 +507,7 @@ public boolean onPrepareOptionsMenu(final Menu menu) { menu.findItem(R.id.action_enable_remote_verify) .setEnabled(isSupportedAuditee && !isRemoteVerifyEnabled); menu.findItem(R.id.action_disable_remote_verify).setEnabled(isRemoteVerifyEnabled); + menu.findItem(R.id.action_remote_verify_now).setEnabled(isRemoteVerifyEnabled); menu.findItem(R.id.action_submit_sample).setEnabled(canSubmitSample && !SubmitSampleJob.isScheduled(this)); return true; @@ -544,7 +550,19 @@ public boolean onOptionsItemSelected(final MenuItem item) { stage = Stage.EnableRemoteVerify; startQrScanner(); return true; - } else if (itemId == R.id.action_disable_remote_verify) { + } + else if (itemId == R.id.action_remote_verify_now) { + if (checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { + requestPermissions(new String[]{Manifest.permission.POST_NOTIFICATIONS}, + PERMISSIONS_REQUEST_POST_NOTIFICATIONS_IMMEDIATE_REMOTE_VERIFY); + } else { + RemoteVerifyJob.schedule(this, -1); + snackbar.setText(R.string.remote_verify_now).show(); + } + return true; + } + + else if (itemId == R.id.action_disable_remote_verify) { new AlertDialog.Builder(this) .setMessage(getString(R.string.action_disable_remote_verify) + "?") .setPositiveButton(R.string.disable, (dialogInterface, i) -> { diff --git a/app/src/main/java/app/attestation/auditor/RemoteVerifyJob.java b/app/src/main/java/app/attestation/auditor/RemoteVerifyJob.java index fc4a66e99..8098955a7 100644 --- a/app/src/main/java/app/attestation/auditor/RemoteVerifyJob.java +++ b/app/src/main/java/app/attestation/auditor/RemoteVerifyJob.java @@ -39,6 +39,8 @@ public class RemoteVerifyJob extends JobService { private static final String TAG = "RemoteVerifyJob"; private static final int PERIODIC_JOB_ID = 0; private static final int FIRST_RUN_JOB_ID = 1; + + private static final int FIRE_ONCE_JOB_ID = 2; static final String DOMAIN = "attestation.app"; private static final String CHALLENGE_URL = "https://" + DOMAIN + "/challenge"; private static final String VERIFY_URL = "https://" + DOMAIN + "/verify"; @@ -76,12 +78,15 @@ static void restore(final Context context) { } static void schedule(final Context context, int interval) { - if (interval < MIN_INTERVAL) { - interval = MIN_INTERVAL; - Log.e(TAG, "invalid interval " + interval + " clamped to MIN_INTERVAL " + MIN_INTERVAL); - } else if (interval > MAX_INTERVAL) { - interval = MAX_INTERVAL; - Log.e(TAG, "invalid interval " + interval + " clamped to MAX_INTERVAL " + MAX_INTERVAL); + boolean scheduleNow = interval == -1; // if interval = -1, the job needs to be scheduled now and only once. + if (!scheduleNow) { + if (interval < MIN_INTERVAL) { + interval = MIN_INTERVAL; + Log.e(TAG, "invalid interval " + interval + " clamped to MIN_INTERVAL " + MIN_INTERVAL); + } else if (interval > MAX_INTERVAL) { + interval = MAX_INTERVAL; + Log.e(TAG, "invalid interval " + interval + " clamped to MAX_INTERVAL " + MAX_INTERVAL); + } } final JobScheduler scheduler = context.getSystemService(JobScheduler.class); final JobInfo jobInfo = scheduler.getPendingJob(PERIODIC_JOB_ID); @@ -91,7 +96,8 @@ static void schedule(final Context context, int interval) { jobInfo.getEstimatedNetworkDownloadBytes() == ESTIMATED_DOWNLOAD_BYTES && jobInfo.getEstimatedNetworkUploadBytes() == ESTIMATED_UPLOAD_BYTES && jobInfo.getIntervalMillis() == intervalMillis && - jobInfo.getFlexMillis() == flexMillis) { + jobInfo.getFlexMillis() == flexMillis && + !scheduleNow) { Log.d(TAG, "job already registered"); return; } @@ -111,11 +117,16 @@ static void schedule(final Context context, int interval) { throw new RuntimeException("job schedule failed"); } } - final JobInfo.Builder builder = new JobInfo.Builder(PERIODIC_JOB_ID, serviceName) - .setPeriodic(intervalMillis, flexMillis) + final JobInfo.Builder builder = scheduleNow ? + new JobInfo.Builder(FIRE_ONCE_JOB_ID, serviceName) + .setPersisted(true) + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) + : new JobInfo.Builder(PERIODIC_JOB_ID, serviceName) .setPersisted(true) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) - .setEstimatedNetworkBytes(ESTIMATED_DOWNLOAD_BYTES, ESTIMATED_UPLOAD_BYTES); + .setEstimatedNetworkBytes(ESTIMATED_DOWNLOAD_BYTES, ESTIMATED_UPLOAD_BYTES) + .setPeriodic(intervalMillis, flexMillis); + if (scheduler.schedule(builder.build()) == JobScheduler.RESULT_FAILURE) { throw new RuntimeException("job schedule failed"); } diff --git a/app/src/main/res/menu/menu_attestation.xml b/app/src/main/res/menu/menu_attestation.xml index 26c7f7bf9..58ee00513 100644 --- a/app/src/main/res/menu/menu_attestation.xml +++ b/app/src/main/res/menu/menu_attestation.xml @@ -14,6 +14,9 @@ + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 30b3a932e..1ba552470 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -20,11 +20,13 @@ Clear Auditor pairings Enable remote verification Disable remote verification + Remote verify now Submit sample data Help Scheduled regular remote verification Disabled remote verification + Scheduled immediate remote verification Scheduled submitting sample data Cleared Auditee pairings Failed to fully clear Auditee pairings