summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormdooley <mdooley@google.com>2017-08-16 13:25:50 -0700
committerEric Erfanian <erfanian@google.com>2017-08-30 15:44:51 +0000
commit0feba780889cb1e67df64a457109fc6134111261 (patch)
tree17b86dc18831c4f58088f0aea29f81c3886b3958
parent780a361bb4416d1b3e34ed8bb3dab213070fcd17 (diff)
Transcribe old voicemails
This cl adds a transcription backfill service to transcribe old voicemails. This service queries the database for any voicemails without a transcription and whose transcription_state column has not been set and schedules a transcription task to update them. This service is only run once, after the user accepts the voicemail TOS and we have an un-metered network connection. Bug: 62423649 Test: manual and updated unit tests PiperOrigin-RevId: 165486104 Change-Id: Ic85c9d728937411638074fec07cf44bb83862acb
-rw-r--r--java/com/android/dialer/app/voicemail/error/VoicemailTosMessageCreator.java1
-rw-r--r--java/com/android/dialer/constants/ScheduledJobIds.java1
-rw-r--r--java/com/android/voicemail/VoicemailClient.java2
-rw-r--r--java/com/android/voicemail/impl/AndroidManifest.xml5
-rw-r--r--java/com/android/voicemail/impl/VoicemailClientImpl.java7
-rw-r--r--java/com/android/voicemail/impl/fetch/VoicemailFetchedCallback.java2
-rw-r--r--java/com/android/voicemail/impl/transcribe/TranscriptionBackfillService.java79
-rw-r--r--java/com/android/voicemail/impl/transcribe/TranscriptionDbHelper.java44
-rw-r--r--java/com/android/voicemail/impl/transcribe/TranscriptionService.java24
-rw-r--r--java/com/android/voicemail/impl/transcribe/TranscriptionTask.java6
-rw-r--r--java/com/android/voicemail/stub/StubVoicemailClient.java3
11 files changed, 156 insertions, 18 deletions
diff --git a/java/com/android/dialer/app/voicemail/error/VoicemailTosMessageCreator.java b/java/com/android/dialer/app/voicemail/error/VoicemailTosMessageCreator.java
index 865d2527a..427d3eda5 100644
--- a/java/com/android/dialer/app/voicemail/error/VoicemailTosMessageCreator.java
+++ b/java/com/android/dialer/app/voicemail/error/VoicemailTosMessageCreator.java
@@ -232,6 +232,7 @@ public class VoicemailTosMessageCreator {
.putInt(DIALER_TOS_VERSION_ACCEPTED_KEY, CURRENT_DIALER_TOS_VERSION)
.apply();
}
+ VoicemailComponent.get(context).getVoicemailClient().onTosAccepted(context);
}
private void logTosCreatedImpression() {
diff --git a/java/com/android/dialer/constants/ScheduledJobIds.java b/java/com/android/dialer/constants/ScheduledJobIds.java
index a54adc757..cf93a464a 100644
--- a/java/com/android/dialer/constants/ScheduledJobIds.java
+++ b/java/com/android/dialer/constants/ScheduledJobIds.java
@@ -33,6 +33,7 @@ public final class ScheduledJobIds {
public static final int VVM_STATUS_CHECK_JOB = 201;
public static final int VVM_DEVICE_PROVISIONED_JOB = 202;
public static final int VVM_TRANSCRIPTION_JOB = 203;
+ public static final int VVM_TRANSCRIPTION_BACKFILL_JOB = 204;
public static final int VOIP_REGISTRATION = 300;
diff --git a/java/com/android/voicemail/VoicemailClient.java b/java/com/android/voicemail/VoicemailClient.java
index 28d2bf0ff..21846a480 100644
--- a/java/com/android/voicemail/VoicemailClient.java
+++ b/java/com/android/voicemail/VoicemailClient.java
@@ -148,4 +148,6 @@ public interface VoicemailClient {
@MainThread
void onShutdown(@NonNull Context context);
+
+ void onTosAccepted(Context context);
}
diff --git a/java/com/android/voicemail/impl/AndroidManifest.xml b/java/com/android/voicemail/impl/AndroidManifest.xml
index 69d9efe64..4cad2247c 100644
--- a/java/com/android/voicemail/impl/AndroidManifest.xml
+++ b/java/com/android/voicemail/impl/AndroidManifest.xml
@@ -97,6 +97,11 @@
android:exported="false"/>
<service
+ android:name="com.android.voicemail.impl.transcribe.TranscriptionBackfillService"
+ android:permission="android.permission.BIND_JOB_SERVICE"
+ android:exported="false"/>
+
+ <service
android:name="com.android.voicemail.impl.OmtpService"
android:permission="android.permission.BIND_VISUAL_VOICEMAIL_SERVICE"
android:exported="true"
diff --git a/java/com/android/voicemail/impl/VoicemailClientImpl.java b/java/com/android/voicemail/impl/VoicemailClientImpl.java
index 1b9890381..9bb14f2dc 100644
--- a/java/com/android/voicemail/impl/VoicemailClientImpl.java
+++ b/java/com/android/voicemail/impl/VoicemailClientImpl.java
@@ -36,6 +36,7 @@ import com.android.voicemail.impl.settings.VisualVoicemailSettingsUtil;
import com.android.voicemail.impl.settings.VoicemailChangePinActivity;
import com.android.voicemail.impl.settings.VoicemailSettingsFragment;
import com.android.voicemail.impl.sync.VvmAccountManager;
+import com.android.voicemail.impl.transcribe.TranscriptionBackfillService;
import java.util.List;
import javax.inject.Inject;
@@ -230,4 +231,10 @@ public class VoicemailClientImpl implements VoicemailClient {
where.append(")");
}
}
+
+ @Override
+ public void onTosAccepted(Context context) {
+ LogUtil.i("VoicemailClientImpl.onTosAccepted", "try backfilling voicemail transcriptions");
+ TranscriptionBackfillService.scheduleTask(context);
+ }
}
diff --git a/java/com/android/voicemail/impl/fetch/VoicemailFetchedCallback.java b/java/com/android/voicemail/impl/fetch/VoicemailFetchedCallback.java
index d15ce12ef..3e825407b 100644
--- a/java/com/android/voicemail/impl/fetch/VoicemailFetchedCallback.java
+++ b/java/com/android/voicemail/impl/fetch/VoicemailFetchedCallback.java
@@ -97,7 +97,7 @@ public class VoicemailFetchedCallback {
if (updateVoicemail(values)) {
ThreadUtil.postOnUiThread(
() -> {
- if (!TranscriptionService.transcribeVoicemail(mContext, mUri)) {
+ if (!TranscriptionService.scheduleNewVoicemailTranscriptionJob(mContext, mUri, true)) {
VvmLog.w(TAG, String.format("Failed to schedule transcription for %s", mUri));
}
});
diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionBackfillService.java b/java/com/android/voicemail/impl/transcribe/TranscriptionBackfillService.java
new file mode 100644
index 000000000..d6e362014
--- /dev/null
+++ b/java/com/android/voicemail/impl/transcribe/TranscriptionBackfillService.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.voicemail.impl.transcribe;
+
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.app.job.JobWorkItem;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.support.v4.app.JobIntentService;
+import android.support.v4.os.BuildCompat;
+import com.android.dialer.common.LogUtil;
+import com.android.dialer.constants.ScheduledJobIds;
+import java.util.List;
+
+/**
+ * JobScheduler service for transcribing old voicemails. This service does a database scan for
+ * un-transcribed voicemails and schedules transcription tasks for them, once we have an un-metered
+ * network connection.
+ */
+public class TranscriptionBackfillService extends JobIntentService {
+
+ /** Schedule a task to scan the database for untranscribed voicemails */
+ public static boolean scheduleTask(Context context) {
+ if (BuildCompat.isAtLeastO()) {
+ LogUtil.enterBlock("TranscriptionBackfillService.transcribeOldVoicemails");
+ ComponentName componentName = new ComponentName(context, TranscriptionBackfillService.class);
+ JobInfo.Builder builder =
+ new JobInfo.Builder(ScheduledJobIds.VVM_TRANSCRIPTION_BACKFILL_JOB, componentName)
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);
+ JobScheduler scheduler = context.getSystemService(JobScheduler.class);
+ return scheduler.enqueue(builder.build(), makeWorkItem()) == JobScheduler.RESULT_SUCCESS;
+ } else {
+ LogUtil.i("TranscriptionBackfillService.transcribeOldVoicemails", "not supported");
+ return false;
+ }
+ }
+
+ private static JobWorkItem makeWorkItem() {
+ Intent intent = new Intent();
+ return new JobWorkItem(intent);
+ }
+
+ @Override
+ protected void onHandleWork(Intent intent) {
+ LogUtil.enterBlock("TranscriptionBackfillService.onHandleWork");
+
+ TranscriptionDbHelper dbHelper = new TranscriptionDbHelper(this);
+ List<Uri> untranscribed = dbHelper.getUntranscribedVoicemails();
+ LogUtil.i(
+ "TranscriptionBackfillService.onHandleWork",
+ "found " + untranscribed.size() + " untranscribed voicemails");
+ // TODO(mdooley): Consider doing the actual transcriptions here instead of scheduling jobs.
+ for (Uri uri : untranscribed) {
+ TranscriptionService.scheduleNewVoicemailTranscriptionJob(this, uri, false);
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ LogUtil.enterBlock("TranscriptionBackfillService.onDestroy");
+ super.onDestroy();
+ }
+}
diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionDbHelper.java b/java/com/android/voicemail/impl/transcribe/TranscriptionDbHelper.java
index cbc5cb8a0..9d3c2e4a7 100644
--- a/java/com/android/voicemail/impl/transcribe/TranscriptionDbHelper.java
+++ b/java/com/android/voicemail/impl/transcribe/TranscriptionDbHelper.java
@@ -17,29 +17,36 @@ package com.android.voicemail.impl.transcribe;
import android.annotation.TargetApi;
import android.content.ContentResolver;
+import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build.VERSION_CODES;
import android.provider.VoicemailContract.Voicemails;
+import android.support.annotation.VisibleForTesting;
import android.support.annotation.WorkerThread;
import android.support.v4.os.BuildCompat;
import android.util.Pair;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
+import java.util.ArrayList;
+import java.util.List;
/** Helper class for reading and writing transcription data in the database */
@TargetApi(VERSION_CODES.O)
public class TranscriptionDbHelper {
- private static final String[] PROJECTION =
+ @VisibleForTesting
+ static final String[] PROJECTION =
new String[] {
- Voicemails.TRANSCRIPTION, // 0
- VoicemailCompat.TRANSCRIPTION_STATE // 1
+ Voicemails._ID, // 0
+ Voicemails.TRANSCRIPTION, // 1
+ VoicemailCompat.TRANSCRIPTION_STATE // 2
};
- public static final int TRANSCRIPTION = 0;
- public static final int TRANSCRIPTION_STATE = 1;
+ static final int ID = 0;
+ static final int TRANSCRIPTION = 1;
+ static final int TRANSCRIPTION_STATE = 2;
private final ContentResolver contentResolver;
private final Uri uri;
@@ -50,10 +57,14 @@ public class TranscriptionDbHelper {
this.uri = uri;
}
+ TranscriptionDbHelper(Context context) {
+ this(context, Voicemails.buildSourceUri(context.getPackageName()));
+ }
+
@WorkerThread
@TargetApi(VERSION_CODES.M) // used for try with resources
Pair<String, Integer> getTranscriptionAndState() {
- Assert.checkArgument(BuildCompat.isAtLeastO());
+ Assert.checkState(BuildCompat.isAtLeastO());
Assert.isWorkerThread();
try (Cursor cursor = contentResolver.query(uri, PROJECTION, null, null, null)) {
if (cursor == null) {
@@ -72,6 +83,27 @@ public class TranscriptionDbHelper {
}
@WorkerThread
+ @TargetApi(VERSION_CODES.M) // used for try with resources
+ List<Uri> getUntranscribedVoicemails() {
+ Assert.checkArgument(BuildCompat.isAtLeastO());
+ Assert.isWorkerThread();
+ List<Uri> untranscribed = new ArrayList<>();
+ String whereClause =
+ Voicemails.TRANSCRIPTION + " is NULL AND " + VoicemailCompat.TRANSCRIPTION_STATE + "=?";
+ String[] whereArgs = {String.valueOf(VoicemailCompat.TRANSCRIPTION_NOT_STARTED)};
+ try (Cursor cursor = contentResolver.query(uri, PROJECTION, whereClause, whereArgs, null)) {
+ if (cursor == null) {
+ LogUtil.e("TranscriptionDbHelper.getUntranscribedVoicemails", "query failed.");
+ } else {
+ while (cursor.moveToNext()) {
+ untranscribed.add(ContentUris.withAppendedId(uri, cursor.getLong(ID)));
+ }
+ }
+ }
+ return untranscribed;
+ }
+
+ @WorkerThread
void setTranscriptionState(int transcriptionState) {
Assert.isWorkerThread();
LogUtil.i(
diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionService.java b/java/com/android/voicemail/impl/transcribe/TranscriptionService.java
index 6933a3a66..85e524302 100644
--- a/java/com/android/voicemail/impl/transcribe/TranscriptionService.java
+++ b/java/com/android/voicemail/impl/transcribe/TranscriptionService.java
@@ -58,22 +58,30 @@ public class TranscriptionService extends JobService {
// Schedule a task to transcribe the indicated voicemail, return true if transcription task was
// scheduled.
- public static boolean transcribeVoicemail(Context context, Uri voicemailUri) {
+ public static boolean scheduleNewVoicemailTranscriptionJob(
+ Context context, Uri voicemailUri, boolean highPriority) {
Assert.isMainThread();
if (BuildCompat.isAtLeastO()) {
- LogUtil.i("TranscriptionService.transcribeVoicemail", "scheduling transcription");
+ LogUtil.i(
+ "TranscriptionService.scheduleNewVoicemailTranscriptionJob", "scheduling transcription");
Logger.get(context).logImpression(DialerImpression.Type.VVM_TRANSCRIPTION_VOICEMAIL_RECEIVED);
ComponentName componentName = new ComponentName(context, TranscriptionService.class);
JobInfo.Builder builder =
- new JobInfo.Builder(ScheduledJobIds.VVM_TRANSCRIPTION_JOB, componentName)
- .setMinimumLatency(0)
- .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
+ new JobInfo.Builder(ScheduledJobIds.VVM_TRANSCRIPTION_JOB, componentName);
+ if (highPriority) {
+ builder
+ .setMinimumLatency(0)
+ .setOverrideDeadline(0)
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
+ } else {
+ builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);
+ }
JobScheduler scheduler = context.getSystemService(JobScheduler.class);
JobWorkItem workItem = makeWorkItem(voicemailUri);
return scheduler.enqueue(builder.build(), workItem) == JobScheduler.RESULT_SUCCESS;
} else {
- LogUtil.i("TranscriptionService.transcribeVoicemail", "not supported");
+ LogUtil.i("TranscriptionService.scheduleNewVoicemailTranscriptionJob", "not supported");
return false;
}
}
@@ -165,6 +173,10 @@ public class TranscriptionService extends JobService {
}
}
+ static Uri getVoicemailUri(JobWorkItem workItem) {
+ return workItem.getIntent().getParcelableExtra(EXTRA_VOICEMAIL_URI);
+ }
+
private ExecutorService getExecutorService() {
if (executorService == null) {
// The common use case is transcribing a single voicemail so just use a single thread executor
diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionTask.java b/java/com/android/voicemail/impl/transcribe/TranscriptionTask.java
index 61a5ee8de..b5f29da00 100644
--- a/java/com/android/voicemail/impl/transcribe/TranscriptionTask.java
+++ b/java/com/android/voicemail/impl/transcribe/TranscriptionTask.java
@@ -81,7 +81,7 @@ public abstract class TranscriptionTask implements Runnable {
this.callback = callback;
this.workItem = workItem;
this.clientFactory = clientFactory;
- this.voicemailUri = getVoicemailUri(workItem);
+ this.voicemailUri = TranscriptionService.getVoicemailUri(workItem);
this.configProvider = configProvider;
databaseHelper = new TranscriptionDbHelper(context, voicemailUri);
}
@@ -222,8 +222,4 @@ public abstract class TranscriptionTask implements Runnable {
return true;
}
-
- private static Uri getVoicemailUri(JobWorkItem workItem) {
- return workItem.getIntent().getParcelableExtra(TranscriptionService.EXTRA_VOICEMAIL_URI);
- }
}
diff --git a/java/com/android/voicemail/stub/StubVoicemailClient.java b/java/com/android/voicemail/stub/StubVoicemailClient.java
index e5d51455c..992950340 100644
--- a/java/com/android/voicemail/stub/StubVoicemailClient.java
+++ b/java/com/android/voicemail/stub/StubVoicemailClient.java
@@ -99,4 +99,7 @@ public final class StubVoicemailClient implements VoicemailClient {
@Override
public void onShutdown(@NonNull Context context) {}
+
+ @Override
+ public void onTosAccepted(Context context) {}
}