/* * 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.support.annotation.MainThread; import android.support.annotation.VisibleForTesting; import android.telecom.PhoneAccountHandle; import android.text.TextUtils; import android.util.Pair; import com.android.dialer.common.Assert; import com.android.dialer.common.concurrent.ThreadUtil; import com.android.dialer.compat.android.provider.VoicemailCompat; import com.android.dialer.logging.DialerImpression; import com.android.dialer.logging.Logger; 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.android.voicemail.impl.transcribe.grpc.TranscriptionResponse; import com.google.internal.communications.voicemailtranscription.v1.AudioFormat; import com.google.internal.communications.voicemailtranscription.v1.TranscriptionStatus; import com.google.protobuf.ByteString; import java.io.IOException; import java.io.InputStream; /** * Background task to get a voicemail transcription and update the database. * *
* 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 or asynchronous 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 **/ public abstract class TranscriptionTask implements Runnable { private static final String TAG = "TranscriptionTask"; protected final Context context; private final JobCallback callback; private final JobWorkItem workItem; private final TranscriptionClientFactory clientFactory; private final Uri voicemailUri; protected final PhoneAccountHandle phoneAccountHandle; private final TranscriptionDbHelper databaseHelper; protected final TranscriptionConfigProvider configProvider; protected ByteString audioData; protected AudioFormat encoding; protected volatile boolean cancelled; static final String AMR_PREFIX = "#!AMR\n"; /** Functional interface for sending requests to the transcription server */ public interface Request { TranscriptionResponse getResponse(TranscriptionClient client); } TranscriptionTask( Context context, JobCallback callback, JobWorkItem workItem, TranscriptionClientFactory clientFactory, TranscriptionConfigProvider configProvider) { this.context = context; this.callback = callback; this.workItem = workItem; this.clientFactory = clientFactory; this.voicemailUri = TranscriptionService.getVoicemailUri(workItem); this.phoneAccountHandle = TranscriptionService.getPhoneAccountHandle(workItem); this.configProvider = configProvider; databaseHelper = new TranscriptionDbHelper(context, voicemailUri); } @MainThread void cancel() { Assert.isMainThread(); VvmLog.i(TAG, "cancel"); cancelled = true; } @Override public void run() { VvmLog.i(TAG, "run"); if (readAndValidateAudioFile()) { updateTranscriptionState(VoicemailCompat.TRANSCRIPTION_IN_PROGRESS); transcribeVoicemail(); } else { if (AudioFormat.AUDIO_FORMAT_UNSPECIFIED.equals(encoding)) { Logger.get(context) .logImpression(DialerImpression.Type.VVM_TRANSCRIPTION_VOICEMAIL_FORMAT_NOT_SUPPORTED); } else { Logger.get(context) .logImpression(DialerImpression.Type.VVM_TRANSCRIPTION_VOICEMAIL_INVALID_DATA); } updateTranscriptionState(VoicemailCompat.TRANSCRIPTION_FAILED); } ThreadUtil.postOnUiThread( () -> { callback.onWorkCompleted(workItem); }); } protected abstract Pair