summaryrefslogtreecommitdiff
path: root/java/com/android/voicemail/impl
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/android/voicemail/impl')
-rw-r--r--java/com/android/voicemail/impl/AndroidManifest.xml5
-rw-r--r--java/com/android/voicemail/impl/OmtpReceiver.java105
-rw-r--r--java/com/android/voicemail/impl/TelephonyManagerStub.java40
-rw-r--r--java/com/android/voicemail/impl/VvmPackageInstallReceiver.java80
-rw-r--r--java/com/android/voicemail/impl/com/google/internal/communications/voicemailtranscription/v1/VoicemailTranscriptionServiceGrpc.java254
-rw-r--r--java/com/android/voicemail/impl/fetch/VoicemailFetchedCallback.java18
-rw-r--r--java/com/android/voicemail/impl/mail/MailTransport.java3
-rw-r--r--java/com/android/voicemail/impl/scheduling/TaskSchedulerService.java400
-rw-r--r--java/com/android/voicemail/impl/transcribe/TranscriptionConfigProvider.java62
-rw-r--r--java/com/android/voicemail/impl/transcribe/TranscriptionDbHelper.java105
-rw-r--r--java/com/android/voicemail/impl/transcribe/TranscriptionService.java203
-rw-r--r--java/com/android/voicemail/impl/transcribe/TranscriptionTask.java191
-rw-r--r--java/com/android/voicemail/impl/transcribe/VoicemailCompat.java59
-rw-r--r--java/com/android/voicemail/impl/transcribe/grpc/TranscriptionClient.java61
-rw-r--r--java/com/android/voicemail/impl/transcribe/grpc/TranscriptionClientFactory.java194
-rw-r--r--java/com/android/voicemail/impl/transcribe/grpc/voicemail_transcription.proto44
16 files changed, 627 insertions, 1197 deletions
diff --git a/java/com/android/voicemail/impl/AndroidManifest.xml b/java/com/android/voicemail/impl/AndroidManifest.xml
index be7dac10d..95e6e8212 100644
--- a/java/com/android/voicemail/impl/AndroidManifest.xml
+++ b/java/com/android/voicemail/impl/AndroidManifest.xml
@@ -97,11 +97,6 @@
android:exported="false"/>
<service
- android:name="com.android.voicemail.impl.transcribe.TranscriptionService"
- 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/OmtpReceiver.java b/java/com/android/voicemail/impl/OmtpReceiver.java
new file mode 100644
index 000000000..9baf95415
--- /dev/null
+++ b/java/com/android/voicemail/impl/OmtpReceiver.java
@@ -0,0 +1,105 @@
+/*
+ * 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;
+
+import android.annotation.TargetApi;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build.VERSION_CODES;
+import android.telecom.PhoneAccountHandle;
+import android.telephony.VisualVoicemailSms;
+import com.android.dialer.common.Assert;
+import com.android.dialer.logging.DialerImpression;
+import com.android.dialer.logging.Logger;
+import com.android.voicemail.VoicemailComponent;
+import com.android.voicemail.impl.settings.VisualVoicemailSettingsUtil;
+import com.android.voicemail.impl.sync.VvmAccountManager;
+
+/** Listens to com.android.phone.vvm.ACTION_TEMP_VISUAL_VOICEMAIL_SERVICE_EVENT */
+@TargetApi(VERSION_CODES.O)
+public class OmtpReceiver extends BroadcastReceiver {
+
+ private static final String TAG = "VvmOmtpReceiver";
+
+ public static final String ACTION_SMS_RECEIVED = "com.android.vociemailomtp.sms.sms_received";
+
+ public static final String EXTRA_VOICEMAIL_SMS = "extra_voicemail_sms";
+
+ private static final String EXTRA_WHAT = "what";
+
+ private static final int MSG_ON_CELL_SERVICE_CONNECTED = 1;
+
+ private static final int MSG_ON_SMS_RECEIVED = 2;
+
+ private static final int MSG_ON_SIM_REMOVED = 3;
+
+ private static final int MSG_TASK_STOPPED = 5;
+
+ private static final String DATA_PHONE_ACCOUNT_HANDLE = "data_phone_account_handle";
+
+ private static final String DATA_SMS = "data_sms";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // ACTION_VISUAL_VOICEMAIL_SERVICE_EVENT is not a protected broadcast pre-O.
+ if (!VoicemailComponent.get(context).getVoicemailClient().isVoicemailModuleEnabled()) {
+ VvmLog.e(TAG, "ACTION_VISUAL_VOICEMAIL_SERVICE_EVENT received when module is disabled");
+ return;
+ }
+
+ int what = intent.getIntExtra(EXTRA_WHAT, -1);
+ PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(DATA_PHONE_ACCOUNT_HANDLE);
+ OmtpVvmCarrierConfigHelper config = new OmtpVvmCarrierConfigHelper(context, phoneAccountHandle);
+ if (!config.isValid()) {
+ VvmLog.i(TAG, "VVM not supported on " + phoneAccountHandle);
+ return;
+ }
+ if (!VisualVoicemailSettingsUtil.isEnabled(context, phoneAccountHandle)
+ && !config.isLegacyModeEnabled()) {
+ VvmLog.i(TAG, "VVM is disabled");
+ return;
+ }
+ switch (what) {
+ case MSG_ON_CELL_SERVICE_CONNECTED:
+ VvmLog.i(TAG, "onCellServiceConnected");
+ Logger.get(context).logImpression(DialerImpression.Type.VVM_UNBUNDLED_EVENT_RECEIVED);
+ ActivationTask.start(context, phoneAccountHandle, null);
+ break;
+ case MSG_ON_SMS_RECEIVED:
+ VvmLog.i(TAG, "onSmsReceived");
+ Logger.get(context).logImpression(DialerImpression.Type.VVM_UNBUNDLED_EVENT_RECEIVED);
+ VisualVoicemailSms sms = intent.getParcelableExtra(DATA_SMS);
+ Intent receivedIntent = new Intent(ACTION_SMS_RECEIVED);
+ receivedIntent.setPackage(context.getPackageName());
+ receivedIntent.putExtra(EXTRA_VOICEMAIL_SMS, sms);
+ context.sendBroadcast(receivedIntent);
+ break;
+ case MSG_ON_SIM_REMOVED:
+ VvmLog.i(TAG, "onSimRemoved");
+ Logger.get(context).logImpression(DialerImpression.Type.VVM_UNBUNDLED_EVENT_RECEIVED);
+ VvmAccountManager.removeAccount(context, phoneAccountHandle);
+ break;
+ case MSG_TASK_STOPPED:
+ VvmLog.i(TAG, "onStopped");
+ Logger.get(context).logImpression(DialerImpression.Type.VVM_UNBUNDLED_EVENT_RECEIVED);
+ break;
+ default:
+ throw Assert.createIllegalStateFailException("unexpected what: " + what);
+ }
+ }
+}
diff --git a/java/com/android/voicemail/impl/TelephonyManagerStub.java b/java/com/android/voicemail/impl/TelephonyManagerStub.java
new file mode 100644
index 000000000..4762e9023
--- /dev/null
+++ b/java/com/android/voicemail/impl/TelephonyManagerStub.java
@@ -0,0 +1,40 @@
+/*
+ * 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;
+
+import android.annotation.TargetApi;
+import android.os.Build.VERSION_CODES;
+
+/**
+ * Temporary stub for public APIs that should be added into telephony manager.
+ *
+ * <p>TODO(b/32637799) remove this.
+ */
+@TargetApi(VERSION_CODES.O)
+public class TelephonyManagerStub {
+
+ public static void showVoicemailNotification(int voicemailCount) {}
+
+ /**
+ * Dismisses the message waiting (voicemail) indicator.
+ *
+ * @param subId the subscription id we should dismiss the notification for.
+ */
+ public static void clearMwiIndicator(int subId) {}
+
+ public static void setShouldCheckVisualVoicemailConfigurationForMwi(int subId, boolean enabled) {}
+}
diff --git a/java/com/android/voicemail/impl/VvmPackageInstallReceiver.java b/java/com/android/voicemail/impl/VvmPackageInstallReceiver.java
new file mode 100644
index 000000000..1e2de6070
--- /dev/null
+++ b/java/com/android/voicemail/impl/VvmPackageInstallReceiver.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2015 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;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+import com.android.voicemail.VoicemailComponent;
+import com.android.voicemail.impl.settings.VisualVoicemailSettingsUtil;
+
+/**
+ * When a new package is installed, check if it matches any of the vvm carrier apps of the currently
+ * enabled dialer VVM sources. The dialer VVM client will be disabled upon carrier VVM app
+ * installation, unless it was explicitly enabled by the user.
+ */
+public class VvmPackageInstallReceiver extends BroadcastReceiver {
+
+ private static final String TAG = "VvmPkgInstallReceiver";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!VoicemailComponent.get(context).getVoicemailClient().isVoicemailModuleEnabled()) {
+ return;
+ }
+
+ if (intent.getData() == null) {
+ return;
+ }
+
+ String packageName = intent.getData().getSchemeSpecificPart();
+ if (packageName == null) {
+ return;
+ }
+
+ // This get called every time an app is installed and will be noisy. Don't log until the app
+ // is identified as a carrier VVM app.
+ for (PhoneAccountHandle phoneAccount :
+ context.getSystemService(TelecomManager.class).getCallCapablePhoneAccounts()) {
+ OmtpVvmCarrierConfigHelper carrierConfigHelper =
+ new OmtpVvmCarrierConfigHelper(context, phoneAccount);
+ if (!carrierConfigHelper.isValid()) {
+ continue;
+ }
+ if (carrierConfigHelper.getCarrierVvmPackageNames() == null) {
+ continue;
+ }
+ if (!carrierConfigHelper.getCarrierVvmPackageNames().contains(packageName)) {
+ continue;
+ }
+
+ VvmLog.i(TAG, "Carrier app installed");
+ if (VisualVoicemailSettingsUtil.isEnabledUserSet(context, phoneAccount)) {
+ // Skip the check if this voicemail source's setting is overridden by the user.
+ VvmLog.i(TAG, "VVM enabled by user, not disabling");
+ continue;
+ }
+
+ // Force deactivate the client. The user can re-enable it in the settings.
+ // There is no need to update the settings for deactivation. At this point, if the
+ // default value is used it should be false because a carrier package is present.
+ VvmLog.i(TAG, "Carrier VVM package installed, disabling system VVM client");
+ VisualVoicemailSettingsUtil.setEnabled(context, phoneAccount, false);
+ }
+ }
+}
diff --git a/java/com/android/voicemail/impl/com/google/internal/communications/voicemailtranscription/v1/VoicemailTranscriptionServiceGrpc.java b/java/com/android/voicemail/impl/com/google/internal/communications/voicemailtranscription/v1/VoicemailTranscriptionServiceGrpc.java
deleted file mode 100644
index 448c69356..000000000
--- a/java/com/android/voicemail/impl/com/google/internal/communications/voicemailtranscription/v1/VoicemailTranscriptionServiceGrpc.java
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * 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.google.internal.communications.voicemailtranscription.v1;
-
-import static io.grpc.stub.ClientCalls.asyncUnaryCall;
-import static io.grpc.stub.ClientCalls.asyncServerStreamingCall;
-import static io.grpc.stub.ClientCalls.asyncClientStreamingCall;
-import static io.grpc.stub.ClientCalls.asyncBidiStreamingCall;
-import static io.grpc.stub.ClientCalls.blockingUnaryCall;
-import static io.grpc.stub.ClientCalls.blockingServerStreamingCall;
-import static io.grpc.stub.ClientCalls.futureUnaryCall;
-import static io.grpc.MethodDescriptor.generateFullMethodName;
-import static io.grpc.stub.ServerCalls.asyncUnaryCall;
-import static io.grpc.stub.ServerCalls.asyncServerStreamingCall;
-import static io.grpc.stub.ServerCalls.asyncClientStreamingCall;
-import static io.grpc.stub.ServerCalls.asyncBidiStreamingCall;
-import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall;
-import static io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall;
-
-/**
- * <pre>
- * RPC service for transcribing voicemails.
- * </pre>
- */
-@javax.annotation.Generated(
- value = "by gRPC proto compiler (version 1.0.3)",
- comments = "Source: voicemail_transcription.proto")
-public class VoicemailTranscriptionServiceGrpc {
-
- private VoicemailTranscriptionServiceGrpc() {}
-
- public static final String SERVICE_NAME = "google.internal.communications.voicemailtranscription.v1.VoicemailTranscriptionService";
-
- // Static method descriptors that strictly reflect the proto.
- @io.grpc.ExperimentalApi("https://github.com/grpc/grpc-java/issues/1901")
- public static final io.grpc.MethodDescriptor<com.google.internal.communications.voicemailtranscription.v1.TranscribeVoicemailRequest,
- com.google.internal.communications.voicemailtranscription.v1.TranscribeVoicemailResponse> METHOD_TRANSCRIBE_VOICEMAIL =
- io.grpc.MethodDescriptor.create(
- io.grpc.MethodDescriptor.MethodType.UNARY,
- generateFullMethodName(
- "google.internal.communications.voicemailtranscription.v1.VoicemailTranscriptionService", "TranscribeVoicemail"),
- io.grpc.protobuf.lite.ProtoLiteUtils.marshaller(com.google.internal.communications.voicemailtranscription.v1.TranscribeVoicemailRequest.getDefaultInstance()),
- io.grpc.protobuf.lite.ProtoLiteUtils.marshaller(com.google.internal.communications.voicemailtranscription.v1.TranscribeVoicemailResponse.getDefaultInstance()));
-
- /**
- * Creates a new async stub that supports all call types for the service
- */
- public static VoicemailTranscriptionServiceStub newStub(io.grpc.Channel channel) {
- return new VoicemailTranscriptionServiceStub(channel);
- }
-
- /**
- * Creates a new blocking-style stub that supports unary and streaming output calls on the service
- */
- public static VoicemailTranscriptionServiceBlockingStub newBlockingStub(
- io.grpc.Channel channel) {
- return new VoicemailTranscriptionServiceBlockingStub(channel);
- }
-
- /**
- * Creates a new ListenableFuture-style stub that supports unary and streaming output calls on the service
- */
- public static VoicemailTranscriptionServiceFutureStub newFutureStub(
- io.grpc.Channel channel) {
- return new VoicemailTranscriptionServiceFutureStub(channel);
- }
-
- /**
- * <pre>
- * RPC service for transcribing voicemails.
- * </pre>
- */
- public static abstract class VoicemailTranscriptionServiceImplBase implements io.grpc.BindableService {
-
- /**
- * <pre>
- * Returns a transcript of the given voicemail.
- * </pre>
- */
- public void transcribeVoicemail(com.google.internal.communications.voicemailtranscription.v1.TranscribeVoicemailRequest request,
- io.grpc.stub.StreamObserver<com.google.internal.communications.voicemailtranscription.v1.TranscribeVoicemailResponse> responseObserver) {
- asyncUnimplementedUnaryCall(METHOD_TRANSCRIBE_VOICEMAIL, responseObserver);
- }
-
- @java.lang.Override public io.grpc.ServerServiceDefinition bindService() {
- return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor())
- .addMethod(
- METHOD_TRANSCRIBE_VOICEMAIL,
- asyncUnaryCall(
- new MethodHandlers<
- com.google.internal.communications.voicemailtranscription.v1.TranscribeVoicemailRequest,
- com.google.internal.communications.voicemailtranscription.v1.TranscribeVoicemailResponse>(
- this, METHODID_TRANSCRIBE_VOICEMAIL)))
- .build();
- }
- }
-
- /**
- * <pre>
- * RPC service for transcribing voicemails.
- * </pre>
- */
- public static final class VoicemailTranscriptionServiceStub extends io.grpc.stub.AbstractStub<VoicemailTranscriptionServiceStub> {
- private VoicemailTranscriptionServiceStub(io.grpc.Channel channel) {
- super(channel);
- }
-
- private VoicemailTranscriptionServiceStub(io.grpc.Channel channel,
- io.grpc.CallOptions callOptions) {
- super(channel, callOptions);
- }
-
- @java.lang.Override
- protected VoicemailTranscriptionServiceStub build(io.grpc.Channel channel,
- io.grpc.CallOptions callOptions) {
- return new VoicemailTranscriptionServiceStub(channel, callOptions);
- }
-
- /**
- * <pre>
- * Returns a transcript of the given voicemail.
- * </pre>
- */
- public void transcribeVoicemail(com.google.internal.communications.voicemailtranscription.v1.TranscribeVoicemailRequest request,
- io.grpc.stub.StreamObserver<com.google.internal.communications.voicemailtranscription.v1.TranscribeVoicemailResponse> responseObserver) {
- asyncUnaryCall(
- getChannel().newCall(METHOD_TRANSCRIBE_VOICEMAIL, getCallOptions()), request, responseObserver);
- }
- }
-
- /**
- * <pre>
- * RPC service for transcribing voicemails.
- * </pre>
- */
- public static final class VoicemailTranscriptionServiceBlockingStub extends io.grpc.stub.AbstractStub<VoicemailTranscriptionServiceBlockingStub> {
- private VoicemailTranscriptionServiceBlockingStub(io.grpc.Channel channel) {
- super(channel);
- }
-
- private VoicemailTranscriptionServiceBlockingStub(io.grpc.Channel channel,
- io.grpc.CallOptions callOptions) {
- super(channel, callOptions);
- }
-
- @java.lang.Override
- protected VoicemailTranscriptionServiceBlockingStub build(io.grpc.Channel channel,
- io.grpc.CallOptions callOptions) {
- return new VoicemailTranscriptionServiceBlockingStub(channel, callOptions);
- }
-
- /**
- * <pre>
- * Returns a transcript of the given voicemail.
- * </pre>
- */
- public com.google.internal.communications.voicemailtranscription.v1.TranscribeVoicemailResponse transcribeVoicemail(com.google.internal.communications.voicemailtranscription.v1.TranscribeVoicemailRequest request) {
- return blockingUnaryCall(
- getChannel(), METHOD_TRANSCRIBE_VOICEMAIL, getCallOptions(), request);
- }
- }
-
- /**
- * <pre>
- * RPC service for transcribing voicemails.
- * </pre>
- */
- public static final class VoicemailTranscriptionServiceFutureStub extends io.grpc.stub.AbstractStub<VoicemailTranscriptionServiceFutureStub> {
- private VoicemailTranscriptionServiceFutureStub(io.grpc.Channel channel) {
- super(channel);
- }
-
- private VoicemailTranscriptionServiceFutureStub(io.grpc.Channel channel,
- io.grpc.CallOptions callOptions) {
- super(channel, callOptions);
- }
-
- @java.lang.Override
- protected VoicemailTranscriptionServiceFutureStub build(io.grpc.Channel channel,
- io.grpc.CallOptions callOptions) {
- return new VoicemailTranscriptionServiceFutureStub(channel, callOptions);
- }
-
- /**
- * <pre>
- * Returns a transcript of the given voicemail.
- * </pre>
- */
- public com.google.common.util.concurrent.ListenableFuture<com.google.internal.communications.voicemailtranscription.v1.TranscribeVoicemailResponse> transcribeVoicemail(
- com.google.internal.communications.voicemailtranscription.v1.TranscribeVoicemailRequest request) {
- return futureUnaryCall(
- getChannel().newCall(METHOD_TRANSCRIBE_VOICEMAIL, getCallOptions()), request);
- }
- }
-
- private static final int METHODID_TRANSCRIBE_VOICEMAIL = 0;
-
- private static class MethodHandlers<Req, Resp> implements
- io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,
- io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,
- io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,
- io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {
- private final VoicemailTranscriptionServiceImplBase serviceImpl;
- private final int methodId;
-
- public MethodHandlers(VoicemailTranscriptionServiceImplBase serviceImpl, int methodId) {
- this.serviceImpl = serviceImpl;
- this.methodId = methodId;
- }
-
- @java.lang.Override
- @java.lang.SuppressWarnings("unchecked")
- public void invoke(Req request, io.grpc.stub.StreamObserver<Resp> responseObserver) {
- switch (methodId) {
- case METHODID_TRANSCRIBE_VOICEMAIL:
- serviceImpl.transcribeVoicemail((com.google.internal.communications.voicemailtranscription.v1.TranscribeVoicemailRequest) request,
- (io.grpc.stub.StreamObserver<com.google.internal.communications.voicemailtranscription.v1.TranscribeVoicemailResponse>) responseObserver);
- break;
- default:
- throw new AssertionError();
- }
- }
-
- @java.lang.Override
- @java.lang.SuppressWarnings("unchecked")
- public io.grpc.stub.StreamObserver<Req> invoke(
- io.grpc.stub.StreamObserver<Resp> responseObserver) {
- switch (methodId) {
- default:
- throw new AssertionError();
- }
- }
- }
-
- public static io.grpc.ServiceDescriptor getServiceDescriptor() {
- return new io.grpc.ServiceDescriptor(SERVICE_NAME,
- METHOD_TRANSCRIBE_VOICEMAIL);
- }
-
-}
diff --git a/java/com/android/voicemail/impl/fetch/VoicemailFetchedCallback.java b/java/com/android/voicemail/impl/fetch/VoicemailFetchedCallback.java
index d15ce12ef..f386fce0e 100644
--- a/java/com/android/voicemail/impl/fetch/VoicemailFetchedCallback.java
+++ b/java/com/android/voicemail/impl/fetch/VoicemailFetchedCallback.java
@@ -23,12 +23,9 @@ import android.provider.VoicemailContract.Voicemails;
import android.support.annotation.Nullable;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
-import com.android.dialer.common.Assert;
-import com.android.dialer.common.concurrent.ThreadUtil;
import com.android.voicemail.impl.R;
import com.android.voicemail.impl.VvmLog;
import com.android.voicemail.impl.imap.VoicemailPayload;
-import com.android.voicemail.impl.transcribe.TranscriptionService;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.commons.io.IOUtils;
@@ -59,7 +56,6 @@ public class VoicemailFetchedCallback {
* @param voicemailPayload The object containing the content data for the voicemail
*/
public void setVoicemailContent(@Nullable VoicemailPayload voicemailPayload) {
- Assert.isWorkerThread();
if (voicemailPayload == null) {
VvmLog.i(TAG, "Payload not found, message has unsupported format");
ContentValues values = new ContentValues();
@@ -94,23 +90,13 @@ public class VoicemailFetchedCallback {
ContentValues values = new ContentValues();
values.put(Voicemails.MIME_TYPE, voicemailPayload.getMimeType());
values.put(Voicemails.HAS_CONTENT, true);
- if (updateVoicemail(values)) {
- ThreadUtil.postOnUiThread(
- () -> {
- if (!TranscriptionService.transcribeVoicemail(mContext, mUri)) {
- VvmLog.w(TAG, String.format("Failed to schedule transcription for %s", mUri));
- }
- });
- }
+ updateVoicemail(values);
}
- private boolean updateVoicemail(ContentValues values) {
+ private void updateVoicemail(ContentValues values) {
int updatedCount = mContentResolver.update(mUri, values, null, null);
if (updatedCount != 1) {
VvmLog.e(TAG, "Updating voicemail should have updated 1 row, was: " + updatedCount);
- return false;
- } else {
- return true;
}
}
}
diff --git a/java/com/android/voicemail/impl/mail/MailTransport.java b/java/com/android/voicemail/impl/mail/MailTransport.java
index 00339f03d..3df36d544 100644
--- a/java/com/android/voicemail/impl/mail/MailTransport.java
+++ b/java/com/android/voicemail/impl/mail/MailTransport.java
@@ -17,9 +17,7 @@ package com.android.voicemail.impl.mail;
import android.content.Context;
import android.net.Network;
-import android.net.TrafficStats;
import android.support.annotation.VisibleForTesting;
-import com.android.dialer.constants.TrafficStatsTags;
import com.android.voicemail.impl.OmtpEvents;
import com.android.voicemail.impl.imap.ImapHelper;
import com.android.voicemail.impl.mail.store.ImapStore;
@@ -190,7 +188,6 @@ public class MailTransport {
try {
LogUtils.v(TAG, "createSocket: network specified");
- TrafficStats.setThreadStatsTag(TrafficStatsTags.VISUAL_VOICEMAIL_TAG);
return mNetwork.getSocketFactory().createSocket();
} catch (IOException ioe) {
LogUtils.d(TAG, ioe.toString());
diff --git a/java/com/android/voicemail/impl/scheduling/TaskSchedulerService.java b/java/com/android/voicemail/impl/scheduling/TaskSchedulerService.java
new file mode 100644
index 000000000..5ad2447de
--- /dev/null
+++ b/java/com/android/voicemail/impl/scheduling/TaskSchedulerService.java
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2016 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.scheduling;
+
+import android.annotation.TargetApi;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.Build.VERSION_CODES;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.support.annotation.MainThread;
+import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
+import android.support.annotation.WorkerThread;
+import com.android.voicemail.impl.Assert;
+import com.android.voicemail.impl.NeededForTesting;
+import com.android.voicemail.impl.VvmLog;
+import com.android.voicemail.impl.scheduling.TaskQueue.NextTask;
+import java.util.List;
+
+/**
+ * A service to queue and run {@link Task} with the {@link android.app.job.JobScheduler}. A task is
+ * queued using {@link Context#startService(Intent)}. The intent should contain enough information
+ * in {@link Intent#getExtras()} to construct the task (see {@link Tasks#createIntent(Context,
+ * Class)}).
+ *
+ * <p>All tasks are ran in the background with a wakelock being held by the {@link
+ * android.app.job.JobScheduler}, which is between {@link #onStartJob(Job, List)} and {@link
+ * #finishJob()}. The {@link TaskSchedulerJobService} also has a {@link TaskQueue}, but the data is
+ * stored in the {@link android.app.job.JobScheduler} instead of the process memory, so if the
+ * process is killed the queued tasks will be restored. If a new task is added, a new {@link
+ * TaskSchedulerJobService} will be scheduled to run the task. If the job is already scheduled, the
+ * new task will be pushed into the queue of the scheduled job. If the job is already running, the
+ * job will be queued in process memory.
+ *
+ * <p>Only one task will be ran at a time, and same task cannot exist in the queue at the same time.
+ * Refer to {@link TaskQueue} for queuing and execution order.
+ *
+ * <p>If there are still tasks in the queue but none are executable immediately, the service will
+ * enter a "sleep", pushing all remaining task into a new job and end the current job.
+ *
+ * <p>The service will be started when a intent is received, and stopped when there are no more
+ * tasks in the queue.
+ *
+ * <p>{@link android.app.job.JobScheduler} is not used directly due to:
+ *
+ * <ul>
+ * <li>The {@link android.telecom.PhoneAccountHandle} used to differentiate task can not be easily
+ * mapped into an integer for job id
+ * <li>A job cannot be mutated to store information such as retry count.
+ * </ul>
+ */
+@SuppressWarnings("AndroidApiChecker") /* stream() */
+@TargetApi(VERSION_CODES.O)
+public class TaskSchedulerService extends Service {
+
+ interface Job {
+ void finish();
+ }
+
+ private static final String TAG = "VvmTaskScheduler";
+
+ private static final int READY_TOLERANCE_MILLISECONDS = 100;
+
+ /**
+ * Threshold to determine whether to do a short or long sleep when a task is scheduled in the
+ * future.
+ *
+ * <p>A short sleep will continue the job and use {@link Handler#postDelayed(Runnable, long)} to
+ * wait for the next task.
+ *
+ * <p>A long sleep will finish the job and schedule a new one. The exact execution time is
+ * subjected to {@link android.app.job.JobScheduler} battery optimization, and is not exact.
+ */
+ private static final int SHORT_SLEEP_THRESHOLD_MILLISECONDS = 10_000;
+ /**
+ * When there are no more tasks to be run the service should be stopped. But when all tasks has
+ * finished there might still be more tasks in the message queue waiting to be processed,
+ * especially the ones submitted in {@link Task#onCompleted()}. Wait for a while before stopping
+ * the service to make sure there are no pending messages.
+ */
+ private static final int STOP_DELAY_MILLISECONDS = 5_000;
+
+ // The thread to run tasks on
+ private volatile WorkerThreadHandler mWorkerThreadHandler;
+
+ /**
+ * Used by tests to turn task handling into a single threaded process by calling {@link
+ * Handler#handleMessage(Message)} directly
+ */
+ private MessageSender mMessageSender = new MessageSender();
+
+ private MainThreadHandler mMainThreadHandler;
+
+ // Binder given to clients
+ private final IBinder mBinder = new LocalBinder();
+
+ /** Main thread only, access through {@link #getTasks()} */
+ private final TaskQueue mTasks = new TaskQueue();
+
+ private boolean mWorkerThreadIsBusy = false;
+
+ private Job mJob;
+
+ private final Runnable mStopServiceWithDelay =
+ new Runnable() {
+ @MainThread
+ @Override
+ public void run() {
+ VvmLog.i(TAG, "Stopping service");
+ finishJob();
+ stopSelf();
+ }
+ };
+
+ /** Should attempt to run the next task when a task has finished or been added. */
+ private boolean mTaskAutoRunDisabledForTesting = false;
+
+ @VisibleForTesting
+ final class WorkerThreadHandler extends Handler {
+
+ public WorkerThreadHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ @WorkerThread
+ public void handleMessage(Message msg) {
+ Assert.isNotMainThread();
+ Task task = (Task) msg.obj;
+ try {
+ VvmLog.i(TAG, "executing task " + task);
+ task.onExecuteInBackgroundThread();
+ } catch (Throwable throwable) {
+ VvmLog.e(TAG, "Exception while executing task " + task + ":", throwable);
+ }
+
+ Message schedulerMessage = mMainThreadHandler.obtainMessage();
+ schedulerMessage.obj = task;
+ mMessageSender.send(schedulerMessage);
+ }
+ }
+
+ @VisibleForTesting
+ final class MainThreadHandler extends Handler {
+
+ public MainThreadHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ @MainThread
+ public void handleMessage(Message msg) {
+ Assert.isMainThread();
+ Task task = (Task) msg.obj;
+ getTasks().remove(task);
+ task.onCompleted();
+ mWorkerThreadIsBusy = false;
+ maybeRunNextTask();
+ }
+ }
+
+ @Override
+ @MainThread
+ public void onCreate() {
+ super.onCreate();
+ HandlerThread thread = new HandlerThread("VvmTaskSchedulerService");
+ thread.start();
+
+ mWorkerThreadHandler = new WorkerThreadHandler(thread.getLooper());
+ mMainThreadHandler = new MainThreadHandler(Looper.getMainLooper());
+ }
+
+ @Override
+ public void onDestroy() {
+ mWorkerThreadHandler.getLooper().quit();
+ }
+
+ @Override
+ @MainThread
+ public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
+ Assert.isMainThread();
+ if (intent == null) {
+ VvmLog.w(TAG, "null intent received");
+ return START_NOT_STICKY;
+ }
+ Task task = Tasks.createTask(this, intent.getExtras());
+ Assert.isTrue(task != null);
+ addTask(task);
+
+ mMainThreadHandler.removeCallbacks(mStopServiceWithDelay);
+ VvmLog.i(TAG, "task added");
+ if (mJob == null) {
+ scheduleJob(0, true);
+ } else {
+ maybeRunNextTask();
+ }
+ // STICKY means the service will be automatically restarted will the last intent if it is
+ // killed.
+ return START_NOT_STICKY;
+ }
+
+ @MainThread
+ @VisibleForTesting
+ void addTask(Task task) {
+ Assert.isMainThread();
+ getTasks().add(task);
+ }
+
+ @MainThread
+ @VisibleForTesting
+ TaskQueue getTasks() {
+ Assert.isMainThread();
+ return mTasks;
+ }
+
+ @MainThread
+ private void maybeRunNextTask() {
+ Assert.isMainThread();
+ if (mWorkerThreadIsBusy) {
+ return;
+ }
+ if (mTaskAutoRunDisabledForTesting) {
+ // If mTaskAutoRunDisabledForTesting is true, runNextTask() must be explicitly called
+ // to run the next task.
+ return;
+ }
+
+ runNextTask();
+ }
+
+ @VisibleForTesting
+ @MainThread
+ void runNextTask() {
+ Assert.isMainThread();
+ if (getTasks().isEmpty()) {
+ prepareStop();
+ return;
+ }
+ NextTask nextTask = getTasks().getNextTask(READY_TOLERANCE_MILLISECONDS);
+
+ if (nextTask.task != null) {
+ nextTask.task.onBeforeExecute();
+ Message message = mWorkerThreadHandler.obtainMessage();
+ message.obj = nextTask.task;
+ mWorkerThreadIsBusy = true;
+ mMessageSender.send(message);
+ return;
+ }
+ VvmLog.i(TAG, "minimal wait time:" + nextTask.minimalWaitTimeMillis);
+ if (!mTaskAutoRunDisabledForTesting && nextTask.minimalWaitTimeMillis != null) {
+ // No tasks are currently ready. Sleep until the next one should be.
+ // If a new task is added during the sleep the service will wake immediately.
+ sleep(nextTask.minimalWaitTimeMillis);
+ }
+ }
+
+ @MainThread
+ private void sleep(long timeMillis) {
+ VvmLog.i(TAG, "sleep for " + timeMillis + " millis");
+ if (timeMillis < SHORT_SLEEP_THRESHOLD_MILLISECONDS) {
+ mMainThreadHandler.postDelayed(
+ new Runnable() {
+ @Override
+ public void run() {
+ maybeRunNextTask();
+ }
+ },
+ timeMillis);
+ return;
+ }
+ finishJob();
+ mMainThreadHandler.post(() -> scheduleJob(timeMillis, false));
+ }
+
+ private List<Bundle> serializePendingTasks() {
+ return getTasks().toBundles();
+ }
+
+ private void prepareStop() {
+ VvmLog.i(
+ TAG,
+ "no more tasks, stopping service if no task are added in "
+ + STOP_DELAY_MILLISECONDS
+ + " millis");
+ mMainThreadHandler.postDelayed(mStopServiceWithDelay, STOP_DELAY_MILLISECONDS);
+ }
+
+ @NeededForTesting
+ static class MessageSender {
+
+ public void send(Message message) {
+ message.sendToTarget();
+ }
+ }
+
+ @NeededForTesting
+ void setTaskAutoRunDisabledForTest(boolean value) {
+ mTaskAutoRunDisabledForTesting = value;
+ }
+
+ @NeededForTesting
+ void setMessageSenderForTest(MessageSender sender) {
+ mMessageSender = sender;
+ }
+
+ /**
+ * The {@link TaskSchedulerJobService} has started and all queued task should be executed in the
+ * worker thread.
+ */
+ @MainThread
+ public void onStartJob(Job job, List<Bundle> pendingTasks) {
+ VvmLog.i(TAG, "onStartJob");
+ mJob = job;
+ mTasks.fromBundles(this, pendingTasks);
+ maybeRunNextTask();
+ }
+
+ /**
+ * The {@link TaskSchedulerJobService} is being terminated by the system (timeout or network
+ * lost). A new job will be queued to resume all pending tasks. The current unfinished job may be
+ * ran again.
+ */
+ @MainThread
+ public void onStopJob() {
+ VvmLog.e(TAG, "onStopJob");
+ if (isJobRunning()) {
+ finishJob();
+ mMainThreadHandler.post(() -> scheduleJob(0, true));
+ }
+ }
+
+ /**
+ * Serializes all pending tasks and schedule a new {@link TaskSchedulerJobService}.
+ *
+ * @param delayMillis the delay before stating the job, see {@link
+ * android.app.job.JobInfo.Builder#setMinimumLatency(long)}. This must be 0 if {@code
+ * isNewJob} is true.
+ * @param isNewJob a new job will be requested to run immediately, bypassing all requirements.
+ */
+ @MainThread
+ private void scheduleJob(long delayMillis, boolean isNewJob) {
+ Assert.isMainThread();
+ TaskSchedulerJobService.scheduleJob(this, serializePendingTasks(), delayMillis, isNewJob);
+ mTasks.clear();
+ }
+
+ /**
+ * Signals {@link TaskSchedulerJobService} the current session of tasks has finished, and the wake
+ * lock can be released. Note: this only takes effect after the main thread has been returned. If
+ * a new job need to be scheduled, it should be posted on the main thread handler instead of
+ * calling directly.
+ */
+ @MainThread
+ private void finishJob() {
+ Assert.isMainThread();
+ VvmLog.i(TAG, "finishing Job");
+ mJob.finish();
+ mJob = null;
+ }
+
+ @Override
+ @Nullable
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ @NeededForTesting
+ class LocalBinder extends Binder {
+
+ @NeededForTesting
+ public TaskSchedulerService getService() {
+ return TaskSchedulerService.this;
+ }
+ }
+
+ private boolean isJobRunning() {
+ return mJob != null;
+ }
+}
diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionConfigProvider.java b/java/com/android/voicemail/impl/transcribe/TranscriptionConfigProvider.java
deleted file mode 100644
index 17c9be73b..000000000
--- a/java/com/android/voicemail/impl/transcribe/TranscriptionConfigProvider.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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.content.Context;
-import com.android.dialer.common.ConfigProviderBindings;
-
-/** Provides configuration values needed to connect to the transcription server. */
-public class TranscriptionConfigProvider {
- private final Context context;
-
- public TranscriptionConfigProvider(Context context) {
- this.context = context;
- }
-
- public boolean isVoicemailTranscriptionEnabled() {
- return ConfigProviderBindings.get(context).getBoolean("voicemail_transcription_enabled", false);
- }
-
- public String getServerAddress() {
- // Private voicemail transcription service
- return ConfigProviderBindings.get(context)
- .getString(
- "voicemail_transcription_server_address", "voicemailtranscription-pa.googleapis.com");
- }
-
- public String getApiKey() {
- // Android API key restricted to com.google.android.dialer
- return ConfigProviderBindings.get(context)
- .getString(
- "voicemail_transcription_client_api_key", "AIzaSyAXdDnif6B7sBYxU8hzw9qAp3pRPVHs060");
- }
-
- public String getAuthToken() {
- return null;
- }
-
- public boolean shouldUsePlaintext() {
- return ConfigProviderBindings.get(context)
- .getBoolean("voicemail_transcription_server_use_plaintext", false);
- }
-
- @Override
- public String toString() {
- return String.format(
- "{ address: %s, api key: %s, auth token: %s, plaintext: %b }",
- getServerAddress(), getApiKey(), getAuthToken(), shouldUsePlaintext());
- }
-}
diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionDbHelper.java b/java/com/android/voicemail/impl/transcribe/TranscriptionDbHelper.java
deleted file mode 100644
index cbc5cb8a0..000000000
--- a/java/com/android/voicemail/impl/transcribe/TranscriptionDbHelper.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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.annotation.TargetApi;
-import android.content.ContentResolver;
-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.WorkerThread;
-import android.support.v4.os.BuildCompat;
-import android.util.Pair;
-import com.android.dialer.common.Assert;
-import com.android.dialer.common.LogUtil;
-
-/** Helper class for reading and writing transcription data in the database */
-@TargetApi(VERSION_CODES.O)
-public class TranscriptionDbHelper {
- private static final String[] PROJECTION =
- new String[] {
- Voicemails.TRANSCRIPTION, // 0
- VoicemailCompat.TRANSCRIPTION_STATE // 1
- };
-
- public static final int TRANSCRIPTION = 0;
- public static final int TRANSCRIPTION_STATE = 1;
-
- private final ContentResolver contentResolver;
- private final Uri uri;
-
- TranscriptionDbHelper(Context context, Uri uri) {
- Assert.isNotNull(uri);
- this.contentResolver = context.getContentResolver();
- this.uri = uri;
- }
-
- @WorkerThread
- @TargetApi(VERSION_CODES.M) // used for try with resources
- Pair<String, Integer> getTranscriptionAndState() {
- Assert.checkArgument(BuildCompat.isAtLeastO());
- Assert.isWorkerThread();
- try (Cursor cursor = contentResolver.query(uri, PROJECTION, null, null, null)) {
- if (cursor == null) {
- LogUtil.e("TranscriptionDbHelper.getTranscriptionAndState", "query failed.");
- return null;
- }
-
- if (cursor.moveToFirst()) {
- String transcription = cursor.getString(TRANSCRIPTION);
- int transcriptionState = cursor.getInt(TRANSCRIPTION_STATE);
- return new Pair<>(transcription, transcriptionState);
- }
- }
- LogUtil.i("TranscriptionDbHelper.getTranscriptionAndState", "query returned no results");
- return null;
- }
-
- @WorkerThread
- void setTranscriptionState(int transcriptionState) {
- Assert.isWorkerThread();
- LogUtil.i(
- "TranscriptionDbHelper.setTranscriptionState",
- "uri: " + uri + ", state: " + transcriptionState);
- ContentValues values = new ContentValues();
- values.put(VoicemailCompat.TRANSCRIPTION_STATE, transcriptionState);
- updateDatabase(values);
- }
-
- @WorkerThread
- void setTranscriptionAndState(String transcription, int transcriptionState) {
- Assert.isWorkerThread();
- LogUtil.i(
- "TranscriptionDbHelper.setTranscriptionAndState",
- "uri: " + uri + ", state: " + transcriptionState);
- ContentValues values = new ContentValues();
- values.put(Voicemails.TRANSCRIPTION, transcription);
- values.put(VoicemailCompat.TRANSCRIPTION_STATE, transcriptionState);
- updateDatabase(values);
- }
-
- private void updateDatabase(ContentValues values) {
- int updatedCount = contentResolver.update(uri, values, null, null);
- if (updatedCount != 1) {
- LogUtil.e(
- "TranscriptionDbHelper.updateDatabase",
- "Wrong row count, should have updated 1 row, was: " + updatedCount);
- }
- }
-}
diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionService.java b/java/com/android/voicemail/impl/transcribe/TranscriptionService.java
deleted file mode 100644
index 3e80a7f59..000000000
--- a/java/com/android/voicemail/impl/transcribe/TranscriptionService.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * 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.JobParameters;
-import android.app.job.JobScheduler;
-import android.app.job.JobService;
-import android.app.job.JobWorkItem;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.StrictMode;
-import android.support.annotation.MainThread;
-import android.support.annotation.VisibleForTesting;
-import android.support.v4.os.BuildCompat;
-import android.text.TextUtils;
-import com.android.dialer.common.Assert;
-import com.android.dialer.common.LogUtil;
-import com.android.dialer.constants.ScheduledJobIds;
-import com.android.voicemail.impl.transcribe.grpc.TranscriptionClientFactory;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-/**
- * Job scheduler callback for launching voicemail transcription tasks. The transcription tasks will
- * run in the background and will typically last for approximately the length of the voicemail audio
- * (since thats how long the backend transcription service takes to do the transcription).
- */
-public class TranscriptionService extends JobService {
- @VisibleForTesting static final String EXTRA_VOICEMAIL_URI = "extra_voicemail_uri";
-
- private ExecutorService executorService;
- private JobParameters jobParameters;
- private TranscriptionClientFactory clientFactory;
- private TranscriptionConfigProvider configProvider;
- private StrictMode.VmPolicy originalPolicy;
-
- /** Callback used by a task to indicate it has finished processing its work item */
- interface JobCallback {
- void onWorkCompleted(JobWorkItem completedWorkItem);
- }
-
- // Schedule a task to transcribe the indicated voicemail, return true if transcription task was
- // scheduled.
- public static boolean transcribeVoicemail(Context context, Uri voicemailUri) {
- Assert.isMainThread();
- if (BuildCompat.isAtLeastO()) {
- LogUtil.i("TranscriptionService.transcribeVoicemail", "scheduling transcription");
- 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);
- 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");
- return false;
- }
- }
-
- // Cancel all transcription tasks
- public static void cancelTranscriptions(Context context) {
- Assert.isMainThread();
- LogUtil.enterBlock("TranscriptionService.cancelTranscriptions");
- JobScheduler scheduler = context.getSystemService(JobScheduler.class);
- scheduler.cancel(ScheduledJobIds.VVM_TRANSCRIPTION_JOB);
- }
-
- public TranscriptionService() {
- Assert.isMainThread();
- }
-
- @VisibleForTesting
- TranscriptionService(
- ExecutorService executorService,
- TranscriptionClientFactory clientFactory,
- TranscriptionConfigProvider configProvider) {
- this.executorService = executorService;
- this.clientFactory = clientFactory;
- this.configProvider = configProvider;
- }
-
- @Override
- public boolean onStartJob(JobParameters params) {
- Assert.isMainThread();
- LogUtil.enterBlock("TranscriptionService.onStartJob");
- if (!getConfigProvider().isVoicemailTranscriptionEnabled()) {
- LogUtil.i("TranscriptionService.onStartJob", "transcription not enabled, exiting.");
- return false;
- } else if (TextUtils.isEmpty(getConfigProvider().getServerAddress())) {
- LogUtil.i("TranscriptionService.onStartJob", "transcription server not configured, exiting.");
- return false;
- } else {
- LogUtil.i(
- "TranscriptionService.onStartJob",
- "transcription server address: " + configProvider.getServerAddress());
- originalPolicy = StrictMode.getVmPolicy();
- StrictMode.enableDefaults();
- jobParameters = params;
- return checkForWork();
- }
- }
-
- @Override
- public boolean onStopJob(JobParameters params) {
- Assert.isMainThread();
- LogUtil.enterBlock("TranscriptionService.onStopJob");
- cleanup();
- return true;
- }
-
- @Override
- public void onDestroy() {
- Assert.isMainThread();
- LogUtil.enterBlock("TranscriptionService.onDestroy");
- cleanup();
- }
-
- private void cleanup() {
- if (clientFactory != null) {
- clientFactory.shutdown();
- clientFactory = null;
- }
- if (executorService != null) {
- executorService.shutdownNow();
- executorService = null;
- }
- if (originalPolicy != null) {
- StrictMode.setVmPolicy(originalPolicy);
- originalPolicy = null;
- }
- }
-
- @MainThread
- private boolean checkForWork() {
- Assert.isMainThread();
- JobWorkItem workItem = jobParameters.dequeueWork();
- if (workItem != null) {
- getExecutorService()
- .execute(new TranscriptionTask(this, new Callback(), workItem, getClientFactory()));
- return true;
- } else {
- return false;
- }
- }
-
- private ExecutorService getExecutorService() {
- if (executorService == null) {
- // The common use case is transcribing a single voicemail so just use a single thread executor
- // The reason we're not using DialerExecutor here is because the transcription task can be
- // very long running (ie. multiple minutes).
- executorService = Executors.newSingleThreadExecutor();
- }
- return executorService;
- }
-
- private class Callback implements JobCallback {
- @Override
- public void onWorkCompleted(JobWorkItem completedWorkItem) {
- Assert.isMainThread();
- LogUtil.i("TranscriptionService.Callback.onWorkCompleted", completedWorkItem.toString());
- jobParameters.completeWork(completedWorkItem);
- checkForWork();
- }
- }
-
- private static JobWorkItem makeWorkItem(Uri voicemailUri) {
- Intent intent = new Intent();
- intent.putExtra(EXTRA_VOICEMAIL_URI, voicemailUri);
- return new JobWorkItem(intent);
- }
-
- private TranscriptionConfigProvider getConfigProvider() {
- if (configProvider == null) {
- configProvider = new TranscriptionConfigProvider(this);
- }
- return configProvider;
- }
-
- private TranscriptionClientFactory getClientFactory() {
- if (clientFactory == null) {
- clientFactory = new TranscriptionClientFactory(this, getConfigProvider());
- }
- return clientFactory;
- }
-}
diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionTask.java b/java/com/android/voicemail/impl/transcribe/TranscriptionTask.java
deleted file mode 100644
index 0fbc33ad5..000000000
--- a/java/com/android/voicemail/impl/transcribe/TranscriptionTask.java
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * 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.annotation.TargetApi;
-import android.app.job.JobWorkItem;
-import android.content.Context;
-import android.net.Uri;
-import android.text.TextUtils;
-import com.android.dialer.common.concurrent.ThreadUtil;
-import com.android.voicemail.impl.VvmLog;
-import com.android.voicemail.impl.transcribe.TranscriptionService.JobCallback;
-import com.android.voicemail.impl.transcribe.grpc.TranscriptionClient;
-import com.android.voicemail.impl.transcribe.grpc.TranscriptionClientFactory;
-import com.google.internal.communications.voicemailtranscription.v1.AudioFormat;
-import com.google.internal.communications.voicemailtranscription.v1.TranscribeVoicemailRequest;
-import com.google.protobuf.ByteString;
-import io.grpc.Status;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * Background task to get a voicemail transcription and update the database.
- *
- * <pre>
- * This task performs the following steps:
- * 1. Update the transcription-state in the database to 'in-progress'
- * 2. Create grpc client and transcription request
- * 3. Make synchronous grpc transcription request to backend server
- * 3a. On response
- * Update the database with transcription (if successful) and new transcription-state
- * 3b. On network error
- * If retry-count < max then increment retry-count and retry the request
- * Otherwise update the transcription-state in the database to 'transcription-failed'
- * 4. Notify the callback that the work item is complete
- * </pre>
- */
-public class TranscriptionTask implements Runnable {
- private static final String TAG = "TranscriptionTask";
-
- private final Context context;
- private final JobCallback callback;
- private final JobWorkItem workItem;
- private final TranscriptionClientFactory clientFactory;
- private final Uri voicemailUri;
- private final TranscriptionDbHelper databaseHelper;
- private ByteString audioData;
- private AudioFormat encoding;
-
- private static final int MAX_RETRIES = 2;
- static final String AMR_PREFIX = "#!AMR\n";
-
- public TranscriptionTask(
- Context context,
- JobCallback callback,
- JobWorkItem workItem,
- TranscriptionClientFactory clientFactory) {
- this.context = context;
- this.callback = callback;
- this.workItem = workItem;
- this.clientFactory = clientFactory;
- this.voicemailUri = getVoicemailUri(workItem);
- databaseHelper = new TranscriptionDbHelper(context, voicemailUri);
- }
-
- @Override
- public void run() {
- VvmLog.i(TAG, "run");
- if (readAndValidateAudioFile()) {
- updateTranscriptionState(VoicemailCompat.TRANSCRIPTION_IN_PROGRESS);
- transcribeVoicemail();
- } else {
- updateTranscriptionState(VoicemailCompat.TRANSCRIPTION_FAILED);
- }
- ThreadUtil.postOnUiThread(
- () -> {
- callback.onWorkCompleted(workItem);
- });
- }
-
- private void transcribeVoicemail() {
- VvmLog.i(TAG, "transcribeVoicemail");
- TranscribeVoicemailRequest request = makeRequest();
- TranscriptionClient client = clientFactory.getClient();
- String transcript = null;
- for (int i = 0; transcript == null && i < MAX_RETRIES; i++) {
- VvmLog.i(TAG, "transcribeVoicemail, try: " + (i + 1));
- TranscriptionClient.TranscriptionResponseWrapper responseWrapper =
- client.transcribeVoicemail(request);
- if (responseWrapper.status != null) {
- VvmLog.i(TAG, "transcribeVoicemail, status: " + responseWrapper.status.getCode());
- if (shouldRetryRequest(responseWrapper.status)) {
- backoff(i);
- } else {
- break;
- }
- } else if (responseWrapper.response != null) {
- if (!TextUtils.isEmpty(responseWrapper.response.getTranscript())) {
- VvmLog.i(TAG, "transcribeVoicemail, got response");
- transcript = responseWrapper.response.getTranscript();
- } else {
- VvmLog.i(TAG, "transcribeVoicemail, empty transcription");
- }
- } else {
- VvmLog.w(TAG, "transcribeVoicemail, no response");
- }
- }
-
- int newState =
- (transcript == null)
- ? VoicemailCompat.TRANSCRIPTION_FAILED
- : VoicemailCompat.TRANSCRIPTION_AVAILABLE;
- updateTranscriptionAndState(transcript, newState);
- }
-
- private static boolean shouldRetryRequest(Status status) {
- return status.getCode() == Status.Code.UNAVAILABLE;
- }
-
- private static void backoff(int retryCount) {
- VvmLog.i(TAG, "backoff, count: " + retryCount);
- try {
- long millis = (1 << retryCount) * 1000;
- Thread.sleep(millis);
- } catch (InterruptedException e) {
- VvmLog.w(TAG, "interrupted");
- Thread.currentThread().interrupt();
- }
- }
-
- private void updateTranscriptionAndState(String transcript, int newState) {
- databaseHelper.setTranscriptionAndState(transcript, newState);
- }
-
- private void updateTranscriptionState(int newState) {
- databaseHelper.setTranscriptionState(newState);
- }
-
- private TranscribeVoicemailRequest makeRequest() {
- return TranscribeVoicemailRequest.newBuilder()
- .setVoicemailData(audioData)
- .setAudioFormat(encoding)
- .build();
- }
-
- // Uses try-with-resource
- @TargetApi(android.os.Build.VERSION_CODES.M)
- private boolean readAndValidateAudioFile() {
- if (voicemailUri == null) {
- VvmLog.i(TAG, "Transcriber.readAndValidateAudioFile, file not found.");
- return false;
- } else {
- VvmLog.i(TAG, "Transcriber.readAndValidateAudioFile, reading: " + voicemailUri);
- }
-
- try (InputStream in = context.getContentResolver().openInputStream(voicemailUri)) {
- audioData = ByteString.readFrom(in);
- VvmLog.i(TAG, "Transcriber.readAndValidateAudioFile, read " + audioData.size() + " bytes");
- } catch (IOException e) {
- VvmLog.e(TAG, "Transcriber.readAndValidateAudioFile", e);
- return false;
- }
-
- if (audioData.startsWith(ByteString.copyFromUtf8(AMR_PREFIX))) {
- encoding = AudioFormat.AMR_NB_8KHZ;
- } else {
- VvmLog.i(TAG, "Transcriber.readAndValidateAudioFile, unknown encoding");
- encoding = AudioFormat.AUDIO_FORMAT_UNSPECIFIED;
- return false;
- }
-
- return true;
- }
-
- private static Uri getVoicemailUri(JobWorkItem workItem) {
- return workItem.getIntent().getParcelableExtra(TranscriptionService.EXTRA_VOICEMAIL_URI);
- }
-}
diff --git a/java/com/android/voicemail/impl/transcribe/VoicemailCompat.java b/java/com/android/voicemail/impl/transcribe/VoicemailCompat.java
deleted file mode 100644
index c6e30c6de..000000000
--- a/java/com/android/voicemail/impl/transcribe/VoicemailCompat.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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;
-
-/**
- * Provide access to new API constants before they're publicly available
- *
- * <p>Copied from android.provider.VoicemailContract.Voicemails. These should become public in O-MR1
- * and these constants can be removed then.
- */
-public class VoicemailCompat {
-
- /**
- * The state of the voicemail transcription.
- *
- * <p>Possible values: {@link #TRANSCRIPTION_NOT_STARTED}, {@link #TRANSCRIPTION_IN_PROGRESS},
- * {@link #TRANSCRIPTION_FAILED}, {@link #TRANSCRIPTION_AVAILABLE}.
- *
- * <p>Type: INTEGER
- */
- public static final String TRANSCRIPTION_STATE = "transcription_state";
-
- /**
- * Value of {@link #TRANSCRIPTION_STATE} when the voicemail transcription has not yet been
- * attempted.
- */
- public static final int TRANSCRIPTION_NOT_STARTED = 0;
-
- /**
- * Value of {@link #TRANSCRIPTION_STATE} when the voicemail transcription has begun but is not yet
- * complete.
- */
- public static final int TRANSCRIPTION_IN_PROGRESS = 1;
-
- /**
- * Value of {@link #TRANSCRIPTION_STATE} when the voicemail transcription has been attempted and
- * failed.
- */
- public static final int TRANSCRIPTION_FAILED = 2;
-
- /**
- * Value of {@link #TRANSCRIPTION_STATE} when the voicemail transcription has completed and the
- * result has been stored in the {@link #TRANSCRIPTION} column.
- */
- public static final int TRANSCRIPTION_AVAILABLE = 3;
-}
diff --git a/java/com/android/voicemail/impl/transcribe/grpc/TranscriptionClient.java b/java/com/android/voicemail/impl/transcribe/grpc/TranscriptionClient.java
deleted file mode 100644
index 27603d910..000000000
--- a/java/com/android/voicemail/impl/transcribe/grpc/TranscriptionClient.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.grpc;
-
-import android.support.annotation.Nullable;
-import android.support.annotation.WorkerThread;
-import com.android.dialer.common.Assert;
-import com.google.internal.communications.voicemailtranscription.v1.TranscribeVoicemailRequest;
-import com.google.internal.communications.voicemailtranscription.v1.TranscribeVoicemailResponse;
-import com.google.internal.communications.voicemailtranscription.v1.VoicemailTranscriptionServiceGrpc;
-import io.grpc.Status;
-import io.grpc.StatusRuntimeException;
-
-/** Wrapper around Grpc transcription server stub */
-public class TranscriptionClient {
-
- private final VoicemailTranscriptionServiceGrpc.VoicemailTranscriptionServiceBlockingStub stub;
-
- /** Wraps the server response and status objects, either of which may be null. */
- public static class TranscriptionResponseWrapper {
- public final TranscribeVoicemailResponse response;
- public final Status status;
-
- public TranscriptionResponseWrapper(
- @Nullable TranscribeVoicemailResponse response, @Nullable Status status) {
- Assert.checkArgument(!(response == null && status == null));
- this.response = response;
- this.status = status;
- }
- }
-
- TranscriptionClient(
- VoicemailTranscriptionServiceGrpc.VoicemailTranscriptionServiceBlockingStub stub) {
- this.stub = stub;
- }
-
- @WorkerThread
- public TranscriptionResponseWrapper transcribeVoicemail(TranscribeVoicemailRequest request) {
- TranscribeVoicemailResponse response = null;
- Status status = null;
- try {
- response = stub.transcribeVoicemail(request);
- } catch (StatusRuntimeException e) {
- status = e.getStatus();
- }
- return new TranscriptionClient.TranscriptionResponseWrapper(response, status);
- }
-}
diff --git a/java/com/android/voicemail/impl/transcribe/grpc/TranscriptionClientFactory.java b/java/com/android/voicemail/impl/transcribe/grpc/TranscriptionClientFactory.java
deleted file mode 100644
index 6101ed516..000000000
--- a/java/com/android/voicemail/impl/transcribe/grpc/TranscriptionClientFactory.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * 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.grpc;
-
-import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.text.TextUtils;
-import com.android.dialer.common.Assert;
-import com.android.dialer.common.LogUtil;
-import com.android.voicemail.impl.transcribe.TranscriptionConfigProvider;
-import com.google.internal.communications.voicemailtranscription.v1.VoicemailTranscriptionServiceGrpc;
-import io.grpc.CallOptions;
-import io.grpc.Channel;
-import io.grpc.ClientCall;
-import io.grpc.ClientInterceptor;
-import io.grpc.ClientInterceptors;
-import io.grpc.ForwardingClientCall;
-import io.grpc.ManagedChannel;
-import io.grpc.ManagedChannelBuilder;
-import io.grpc.Metadata;
-import io.grpc.MethodDescriptor;
-import io.grpc.okhttp.OkHttpChannelBuilder;
-import java.security.MessageDigest;
-
-/**
- * Factory for creating grpc clients that talk to the transcription server. This allows all clients
- * to share the same channel, which is relatively expensive to create.
- */
-public class TranscriptionClientFactory {
- private static final String DIGEST_ALGORITHM_SHA1 = "SHA1";
- private static final char[] HEX_UPPERCASE = {
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
- };
-
- private final TranscriptionConfigProvider configProvider;
- private final ManagedChannel originalChannel;
- private final String packageName;
- private final String cert;
-
- public TranscriptionClientFactory(Context context, TranscriptionConfigProvider configProvider) {
- this(context, configProvider, getManagedChannel(configProvider));
- }
-
- public TranscriptionClientFactory(
- Context context, TranscriptionConfigProvider configProvider, ManagedChannel managedChannel) {
- this.configProvider = configProvider;
- this.packageName = context.getPackageName();
- this.cert = getCertificateFingerprint(context);
- originalChannel = managedChannel;
- }
-
- public TranscriptionClient getClient() {
- LogUtil.enterBlock("TranscriptionClientFactory.getClient");
- Assert.checkState(!originalChannel.isShutdown());
- Channel channel =
- ClientInterceptors.intercept(
- originalChannel,
- new Interceptor(
- packageName, cert, configProvider.getApiKey(), configProvider.getAuthToken()));
- return new TranscriptionClient(VoicemailTranscriptionServiceGrpc.newBlockingStub(channel));
- }
-
- public void shutdown() {
- LogUtil.enterBlock("TranscriptionClientFactory.shutdown");
- originalChannel.shutdown();
- }
-
- private static ManagedChannel getManagedChannel(TranscriptionConfigProvider configProvider) {
- ManagedChannelBuilder<OkHttpChannelBuilder> builder =
- OkHttpChannelBuilder.forTarget(configProvider.getServerAddress());
- // Only use plaintext for debugging
- if (configProvider.shouldUsePlaintext()) {
- // Just passing 'false' doesnt have the same effect as not setting this field
- builder.usePlaintext(true);
- }
- return builder.build();
- }
-
- private static String getCertificateFingerprint(Context context) {
- try {
- PackageInfo packageInfo =
- context
- .getPackageManager()
- .getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
- if (packageInfo != null
- && packageInfo.signatures != null
- && packageInfo.signatures.length > 0) {
- MessageDigest messageDigest = MessageDigest.getInstance(DIGEST_ALGORITHM_SHA1);
- if (messageDigest == null) {
- LogUtil.w(
- "TranscriptionClientFactory.getCertificateFingerprint", "error getting digest.");
- return null;
- }
- byte[] bytes = messageDigest.digest(packageInfo.signatures[0].toByteArray());
- if (bytes == null) {
- LogUtil.w(
- "TranscriptionClientFactory.getCertificateFingerprint", "empty message digest.");
- return null;
- }
-
- int length = bytes.length;
- StringBuilder out = new StringBuilder(length * 2);
- for (int i = 0; i < length; i++) {
- out.append(HEX_UPPERCASE[(bytes[i] & 0xf0) >>> 4]);
- out.append(HEX_UPPERCASE[bytes[i] & 0x0f]);
- }
- return out.toString();
- } else {
- LogUtil.w(
- "TranscriptionClientFactory.getCertificateFingerprint",
- "failed to get package signature.");
- }
- } catch (Exception e) {
- LogUtil.e(
- "TranscriptionClientFactory.getCertificateFingerprint",
- "error getting certificate fingerprint.",
- e);
- }
-
- return null;
- }
-
- private static final class Interceptor implements ClientInterceptor {
- private final String packageName;
- private final String cert;
- private final String apiKey;
- private final String authToken;
-
- private static final Metadata.Key<String> API_KEY_HEADER =
- Metadata.Key.of("X-Goog-Api-Key", Metadata.ASCII_STRING_MARSHALLER);
- private static final Metadata.Key<String> ANDROID_PACKAGE_HEADER =
- Metadata.Key.of("X-Android-Package", Metadata.ASCII_STRING_MARSHALLER);
- private static final Metadata.Key<String> ANDROID_CERT_HEADER =
- Metadata.Key.of("X-Android-Cert", Metadata.ASCII_STRING_MARSHALLER);
- private static final Metadata.Key<String> AUTHORIZATION_HEADER =
- Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER);
-
- public Interceptor(String packageName, String cert, String apiKey, String authToken) {
- this.packageName = packageName;
- this.cert = cert;
- this.apiKey = apiKey;
- this.authToken = authToken;
- }
-
- @Override
- public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
- MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
- LogUtil.enterBlock(
- "TranscriptionClientFactory.interceptCall, intercepted " + method.getFullMethodName());
- ClientCall<ReqT, RespT> call = next.newCall(method, callOptions);
-
- call =
- new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(call) {
- @Override
- public void start(Listener<RespT> responseListener, Metadata headers) {
- if (!TextUtils.isEmpty(packageName)) {
- LogUtil.i(
- "TranscriptionClientFactory.interceptCall",
- "attaching package name: " + packageName);
- headers.put(ANDROID_PACKAGE_HEADER, packageName);
- }
- if (!TextUtils.isEmpty(cert)) {
- LogUtil.i("TranscriptionClientFactory.interceptCall", "attaching android cert");
- headers.put(ANDROID_CERT_HEADER, cert);
- }
- if (!TextUtils.isEmpty(apiKey)) {
- LogUtil.i("TranscriptionClientFactory.interceptCall", "attaching API Key");
- headers.put(API_KEY_HEADER, apiKey);
- }
- if (!TextUtils.isEmpty(authToken)) {
- LogUtil.i("TranscriptionClientFactory.interceptCall", "attaching auth token");
- headers.put(AUTHORIZATION_HEADER, "Bearer " + authToken);
- }
- super.start(responseListener, headers);
- }
- };
- return call;
- }
- }
-}
diff --git a/java/com/android/voicemail/impl/transcribe/grpc/voicemail_transcription.proto b/java/com/android/voicemail/impl/transcribe/grpc/voicemail_transcription.proto
deleted file mode 100644
index 4b1e19b8a..000000000
--- a/java/com/android/voicemail/impl/transcribe/grpc/voicemail_transcription.proto
+++ /dev/null
@@ -1,44 +0,0 @@
-// LINT.IfChange
-
-syntax = "proto2";
-
-package google.internal.communications.voicemailtranscription.v1;
-
-option java_multiple_files = true;
-option java_package = "com.google.internal.communications.voicemailtranscription.v1";
-option optimize_for = LITE_RUNTIME;
-
-// Enum that specifies supported audio formats.
-enum AudioFormat {
- // Default but invalid value.
- AUDIO_FORMAT_UNSPECIFIED = 0;
-
- // Adaptive Multi-Rate Narrowband, 8kHz sampling frequency.
- // https://en.wikipedia.org/wiki/Adaptive_Multi-Rate_audio_codec
- AMR_NB_8KHZ = 1;
-}
-
-// Request for synchronous voicemail transcription.
-message TranscribeVoicemailRequest {
- // Voicemail audio file containing the raw bytes we receive from the carrier.
- optional bytes voicemail_data = 1;
-
- // Audio format of the voicemail file.
- optional AudioFormat audio_format = 2;
-}
-
-// Response for synchronous voicemail transcription.
-message TranscribeVoicemailResponse {
- // The transcribed text of the voicemail.
- optional string transcript = 1;
-}
-
-// RPC service for transcribing voicemails.
-service VoicemailTranscriptionService {
- // Returns a transcript of the given voicemail.
- rpc TranscribeVoicemail(TranscribeVoicemailRequest)
- returns (TranscribeVoicemailResponse) {}
-}
-
-// LINT.ThenChange(//depot/google3/google/internal/communications/voicemailtranscription/v1/\
-// voicemail_transcription.proto)