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