summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2017-11-29 20:53:07 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2017-11-29 20:53:07 +0000
commitb500efc0b02591031c349a69235fc26cde991536 (patch)
tree0145604277fbcf00e8bf48b835a5a9d7fb922e40
parent0e029e7f6d270eda757ccd5981ea4c18489fbdd5 (diff)
parentb9ca335dbbc3325643549f6fbf2dac06a5502d26 (diff)
Merge changes Ie04496dc,Ib2998f03,I6cf53e50,Id6eaaad2
* changes: Delete voicemails when disabling visual voicemail Switching to alarms and exponential backoff while polling for transcription result Format number for SIM selection Disable phone number formatting on the dialpad when making domestic call to Argentina mobile numbers.
-rw-r--r--java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java22
-rw-r--r--java/com/android/dialer/dialpadview/DialpadFragment.java211
-rw-r--r--java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java14
-rw-r--r--java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java61
-rw-r--r--java/com/android/dialer/voicemail/settings/res/values/strings.xml7
-rw-r--r--java/com/android/voicemail/impl/AndroidManifest.xml4
-rw-r--r--java/com/android/voicemail/impl/settings/VisualVoicemailSettingsUtil.java34
-rw-r--r--java/com/android/voicemail/impl/transcribe/GetTranscriptReceiver.java233
-rw-r--r--java/com/android/voicemail/impl/transcribe/TranscriptionConfigProvider.java21
-rw-r--r--java/com/android/voicemail/impl/transcribe/TranscriptionRatingHelper.java3
-rw-r--r--java/com/android/voicemail/impl/transcribe/TranscriptionTask.java101
-rw-r--r--java/com/android/voicemail/impl/transcribe/TranscriptionTaskAsync.java71
-rw-r--r--java/com/android/voicemail/impl/transcribe/TranscriptionUtils.java9
-rw-r--r--java/com/android/voicemail/impl/transcribe/grpc/TranscriptionResponse.java5
-rw-r--r--java/com/android/voicemail/impl/transcribe/grpc/TranscriptionResponseAsync.java5
-rw-r--r--java/com/android/voicemail/impl/transcribe/grpc/TranscriptionResponseSync.java5
-rw-r--r--java/com/android/voicemail/impl/utils/VoicemailDatabaseUtil.java10
17 files changed, 683 insertions, 133 deletions
diff --git a/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java b/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java
index e41a75b22..07891a069 100644
--- a/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java
+++ b/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java
@@ -25,11 +25,13 @@ import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
import android.os.ResultReceiver;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
+import android.telephony.SubscriptionInfo;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
@@ -43,7 +45,10 @@ import android.widget.ListAdapter;
import android.widget.TextView;
import com.android.contacts.common.R;
import com.android.contacts.common.compat.PhoneAccountCompat;
-import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
+import com.android.dialer.location.GeoUtil;
+import com.android.dialer.phonenumberutil.PhoneNumberHelper;
+import com.android.dialer.telecom.TelecomUtil;
+import com.google.common.base.Optional;
import java.util.ArrayList;
import java.util.List;
@@ -319,8 +324,9 @@ public class SelectPhoneAccountDialogFragment extends DialogFragment {
} else {
holder.numberTextView.setVisibility(View.VISIBLE);
holder.numberTextView.setText(
- PhoneNumberUtilsCompat.createTtsSpannable(
- account.getAddress().getSchemeSpecificPart()));
+ PhoneNumberHelper.formatNumberForDisplay(
+ account.getAddress().getSchemeSpecificPart(),
+ getCountryIso(getContext(), accountHandle)));
}
holder.imageView.setImageDrawable(
PhoneAccountCompat.createIconDrawable(account, getContext()));
@@ -339,6 +345,16 @@ public class SelectPhoneAccountDialogFragment extends DialogFragment {
return rowView;
}
+ private static String getCountryIso(
+ Context context, @NonNull PhoneAccountHandle phoneAccountHandle) {
+ Optional<SubscriptionInfo> info =
+ TelecomUtil.getSubscriptionInfo(context, phoneAccountHandle);
+ if (!info.isPresent()) {
+ return GeoUtil.getCurrentCountryIso(context);
+ }
+ return info.get().getCountryIso().toUpperCase();
+ }
+
private static final class ViewHolder {
TextView labelTextView;
diff --git a/java/com/android/dialer/dialpadview/DialpadFragment.java b/java/com/android/dialer/dialpadview/DialpadFragment.java
index 4126443bc..69186d87c 100644
--- a/java/com/android/dialer/dialpadview/DialpadFragment.java
+++ b/java/com/android/dialer/dialpadview/DialpadFragment.java
@@ -89,8 +89,11 @@ import com.android.dialer.telecom.TelecomUtil;
import com.android.dialer.util.CallUtil;
import com.android.dialer.util.PermissionsUtil;
import com.android.dialer.widget.FloatingActionButtonController;
+import com.google.common.base.Optional;
import java.util.HashSet;
import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/** Fragment that displays a twelve-key phone dialpad. */
public class DialpadFragment extends Fragment
@@ -129,6 +132,9 @@ public class DialpadFragment extends Fragment
private static final String EXTRA_SEND_EMPTY_FLASH = "com.android.phone.extra.SEND_EMPTY_FLASH";
private static final String PREF_DIGITS_FILLED_BY_INTENT = "pref_digits_filled_by_intent";
+
+ private static Optional<String> currentCountryIsoForTesting = Optional.absent();
+
private final Object mToneGeneratorLock = new Object();
/** Set of dialpad keys that are currently being pressed */
private final HashSet<View> mPressedDialpadKeys = new HashSet<>(12);
@@ -156,7 +162,6 @@ public class DialpadFragment extends Fragment
// determines if we want to playback local DTMF tones.
private boolean mDTMFToneEnabled;
- private String mCurrentCountryIso;
private CallStateReceiver mCallStateReceiver;
private boolean mWasEmptyBeforeTextChange;
/**
@@ -324,8 +329,6 @@ public class DialpadFragment extends Fragment
mFirstLaunch = state == null;
- mCurrentCountryIso = GeoUtil.getCurrentCountryIso(getActivity());
-
mProhibitedPhoneNumberRegexp =
getResources().getString(R.string.config_prohibited_phone_number_regexp);
@@ -377,8 +380,7 @@ public class DialpadFragment extends Fragment
mDigits.addTextChangedListener(this);
mDigits.setElegantTextHeight(false);
- initPhoneNumberFormattingTextWatcherExecutor.executeSerial(
- GeoUtil.getCurrentCountryIso(getActivity()));
+ initPhoneNumberFormattingTextWatcherExecutor.executeSerial(getCurrentCountryIso());
// Check for the presence of the keypad
View oneButton = fragmentView.findViewById(R.id.one);
@@ -422,6 +424,19 @@ public class DialpadFragment extends Fragment
return fragmentView;
}
+ private String getCurrentCountryIso() {
+ if (currentCountryIsoForTesting.isPresent()) {
+ return currentCountryIsoForTesting.get();
+ }
+
+ return GeoUtil.getCurrentCountryIso(getActivity());
+ }
+
+ @VisibleForTesting(otherwise = VisibleForTesting.NONE)
+ public static void setCurrentCountryIsoForTesting(String countryCode) {
+ currentCountryIsoForTesting = Optional.of(countryCode);
+ }
+
private boolean isLayoutReady() {
return mDigits != null;
}
@@ -561,7 +576,7 @@ public class DialpadFragment extends Fragment
/** Sets formatted digits to digits field. */
private void setFormattedDigits(String data, String normalizedNumber) {
- final String formatted = getFormattedDigits(data, normalizedNumber, mCurrentCountryIso);
+ final String formatted = getFormattedDigits(data, normalizedNumber, getCurrentCountryIso());
if (!TextUtils.isEmpty(formatted)) {
Editable digits = mDigits.getText();
digits.replace(0, digits.length(), formatted);
@@ -1717,19 +1732,189 @@ public class DialpadFragment extends Fragment
}
/**
- * Input: the ISO 3166-1 two letters country code of the country the user is in
+ * A worker that helps formatting the phone number as the user types it in.
*
- * <p>Output: PhoneNumberFormattingTextWatcher. Note: It is unusual to return a non-data value
- * from a worker, but it is a limitation in libphonenumber API that the watcher cannot be
- * initialized on the main thread.
+ * <p>Input: the ISO 3166-1 two-letter country code of the country the user is in.
+ *
+ * <p>Output: an instance of {@link DialerPhoneNumberFormattingTextWatcher}. Note: It is unusual
+ * to return a non-data value from a worker. But {@link DialerPhoneNumberFormattingTextWatcher}
+ * depends on libphonenumber API, which cannot be initialized on the main thread.
*/
private static class InitPhoneNumberFormattingTextWatcherWorker
- implements Worker<String, PhoneNumberFormattingTextWatcher> {
+ implements Worker<String, DialerPhoneNumberFormattingTextWatcher> {
@Nullable
@Override
- public PhoneNumberFormattingTextWatcher doInBackground(@Nullable String countryCode) {
- return new PhoneNumberFormattingTextWatcher(countryCode);
+ public DialerPhoneNumberFormattingTextWatcher doInBackground(@Nullable String countryCode) {
+ return new DialerPhoneNumberFormattingTextWatcher(countryCode);
+ }
+ }
+
+ /**
+ * An extension of Android telephony's {@link PhoneNumberFormattingTextWatcher}. This watcher
+ * skips formatting Argentina mobile numbers for domestic calls.
+ *
+ * <p>As of Nov. 28, 2017, the as-you-type-formatting provided by libphonenumber's
+ * AsYouTypeFormatter (which {@link PhoneNumberFormattingTextWatcher} depends on) can't correctly
+ * format Argentina mobile numbers for domestic calls (a bug). We temporarily disable the
+ * formatting for such numbers until libphonenumber is fixed (which will come as early as the next
+ * Android release).
+ */
+ @VisibleForTesting
+ public static class DialerPhoneNumberFormattingTextWatcher
+ extends PhoneNumberFormattingTextWatcher {
+ private static final Pattern AR_DOMESTIC_CALL_MOBILE_NUMBER_PATTERN;
+
+ // This static initialization block builds a pattern for domestic calls to Argentina mobile
+ // numbers:
+ // (1) Local calls: 15 <local number>
+ // (2) Long distance calls: <area code> 15 <local number>
+ // See https://en.wikipedia.org/wiki/Telephone_numbers_in_Argentina for detailed explanations.
+ static {
+ String regex =
+ "0?("
+ + " ("
+ + " 11|"
+ + " 2("
+ + " 2("
+ + " 02?|"
+ + " [13]|"
+ + " 2[13-79]|"
+ + " 4[1-6]|"
+ + " 5[2457]|"
+ + " 6[124-8]|"
+ + " 7[1-4]|"
+ + " 8[13-6]|"
+ + " 9[1267]"
+ + " )|"
+ + " 3("
+ + " 02?|"
+ + " 1[467]|"
+ + " 2[03-6]|"
+ + " 3[13-8]|"
+ + " [49][2-6]|"
+ + " 5[2-8]|"
+ + " [67]"
+ + " )|"
+ + " 4("
+ + " 7[3-578]|"
+ + " 9"
+ + " )|"
+ + " 6("
+ + " [0136]|"
+ + " 2[24-6]|"
+ + " 4[6-8]?|"
+ + " 5[15-8]"
+ + " )|"
+ + " 80|"
+ + " 9("
+ + " 0[1-3]|"
+ + " [19]|"
+ + " 2\\d|"
+ + " 3[1-6]|"
+ + " 4[02568]?|"
+ + " 5[2-4]|"
+ + " 6[2-46]|"
+ + " 72?|"
+ + " 8[23]?"
+ + " )"
+ + " )|"
+ + " 3("
+ + " 3("
+ + " 2[79]|"
+ + " 6|"
+ + " 8[2578]"
+ + " )|"
+ + " 4("
+ + " 0[0-24-9]|"
+ + " [12]|"
+ + " 3[5-8]?|"
+ + " 4[24-7]|"
+ + " 5[4-68]?|"
+ + " 6[02-9]|"
+ + " 7[126]|"
+ + " 8[2379]?|"
+ + " 9[1-36-8]"
+ + " )|"
+ + " 5("
+ + " 1|"
+ + " 2[1245]|"
+ + " 3[237]?|"
+ + " 4[1-46-9]|"
+ + " 6[2-4]|"
+ + " 7[1-6]|"
+ + " 8[2-5]?"
+ + " )|"
+ + " 6[24]|"
+ + " 7("
+ + " [069]|"
+ + " 1[1568]|"
+ + " 2[15]|"
+ + " 3[145]|"
+ + " 4[13]|"
+ + " 5[14-8]|"
+ + " 7[2-57]|"
+ + " 8[126]"
+ + " )|"
+ + " 8("
+ + " [01]|"
+ + " 2[15-7]|"
+ + " 3[2578]?|"
+ + " 4[13-6]|"
+ + " 5[4-8]?|"
+ + " 6[1-357-9]|"
+ + " 7[36-8]?|"
+ + " 8[5-8]?|"
+ + " 9[124]"
+ + " )"
+ + " )"
+ + " )?15"
+ + ").*";
+ AR_DOMESTIC_CALL_MOBILE_NUMBER_PATTERN = Pattern.compile(regex.replaceAll("\\s+", ""));
+ }
+
+ private final String countryCode;
+
+ DialerPhoneNumberFormattingTextWatcher(String countryCode) {
+ super(countryCode);
+ this.countryCode = countryCode;
+ }
+
+ @Override
+ public synchronized void afterTextChanged(Editable s) {
+ super.afterTextChanged(s);
+
+ if (!"AR".equals(countryCode)) {
+ return;
+ }
+
+ String rawNumber = getRawNumber(s);
+
+ // As modifying the input will trigger another call to afterTextChanged(Editable), we must
+ // check whether the input's format has already been removed and return if it has
+ // been to avoid infinite recursion.
+ if (rawNumber.contentEquals(s)) {
+ return;
+ }
+
+ Matcher matcher = AR_DOMESTIC_CALL_MOBILE_NUMBER_PATTERN.matcher(rawNumber);
+ if (matcher.matches()) {
+ s.replace(0, s.length(), rawNumber);
+ PhoneNumberUtils.addTtsSpan(s, 0 /* start */, s.length() /* endExclusive */);
+ }
+ }
+
+ private static String getRawNumber(Editable s) {
+ StringBuilder rawNumberBuilder = new StringBuilder();
+
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+ if (PhoneNumberUtils.isNonSeparator(c)) {
+ rawNumberBuilder.append(c);
+ }
+ }
+
+ return rawNumberBuilder.toString();
}
}
}
diff --git a/java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java b/java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java
index 40a338588..cdc06dead 100644
--- a/java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java
+++ b/java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java
@@ -26,6 +26,8 @@ import android.support.annotation.Nullable;
import android.telecom.PhoneAccountHandle;
import android.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;
+import android.text.BidiFormatter;
+import android.text.TextDirectionHeuristics;
import android.text.TextUtils;
import android.util.SparseIntArray;
import com.android.dialer.common.Assert;
@@ -337,6 +339,18 @@ public class PhoneNumberHelper {
return formattedNumber != null ? formattedNumber : number;
}
+ @Nullable
+ public static CharSequence formatNumberForDisplay(
+ @Nullable String number, @NonNull String countryIso) {
+ if (number == null) {
+ return null;
+ }
+
+ return PhoneNumberUtils.createTtsSpannable(
+ BidiFormatter.getInstance()
+ .unicodeWrap(formatNumber(number, countryIso), TextDirectionHeuristics.LTR));
+ }
+
/**
* Determines if the specified number is actually a URI (i.e. a SIP address) rather than a regular
* PSTN phone number, based on whether or not the number contains an "@" character.
diff --git a/java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java b/java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java
index aaa1e150d..5ae26f5f7 100644
--- a/java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java
+++ b/java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java
@@ -14,6 +14,8 @@
package com.android.dialer.voicemail.settings;
import android.annotation.TargetApi;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
import android.content.Intent;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
@@ -226,16 +228,13 @@ public class VoicemailSettingsFragment extends PreferenceFragment
LogUtil.d(TAG, "onPreferenceChange: \"" + preference + "\" changed to \"" + objValue + "\"");
if (preference.getKey().equals(voicemailVisualVoicemail.getKey())) {
boolean isEnabled = (boolean) objValue;
- voicemailClient.setVoicemailEnabled(getContext(), phoneAccountHandle, isEnabled);
-
- if (isEnabled) {
- Logger.get(getContext()).logImpression(DialerImpression.Type.VVM_USER_ENABLED_IN_SETTINGS);
+ if (!isEnabled) {
+ showDisableConfirmationDialog();
+ // Don't let the preference setting proceed.
+ return false;
} else {
- Logger.get(getContext()).logImpression(DialerImpression.Type.VVM_USER_DISABLED_IN_SETTINGS);
+ updateVoicemailEnabled(true);
}
-
- updateChangePin();
- updateDonateVoicemail();
} else if (preference.getKey().equals(autoArchiveSwitchPreference.getKey())) {
logArchiveToggle((boolean) objValue);
voicemailClient.setVoicemailArchiveEnabled(
@@ -246,10 +245,24 @@ public class VoicemailSettingsFragment extends PreferenceFragment
getContext(), phoneAccountHandle, (boolean) objValue);
}
- // Always let the preference setting proceed.
+ // Let the preference setting proceed.
return true;
}
+ private void updateVoicemailEnabled(boolean isEnabled) {
+ voicemailClient.setVoicemailEnabled(getContext(), phoneAccountHandle, isEnabled);
+ voicemailVisualVoicemail.setChecked(isEnabled);
+
+ if (isEnabled) {
+ Logger.get(getContext()).logImpression(DialerImpression.Type.VVM_USER_ENABLED_IN_SETTINGS);
+ } else {
+ Logger.get(getContext()).logImpression(DialerImpression.Type.VVM_USER_DISABLED_IN_SETTINGS);
+ }
+
+ updateChangePin();
+ updateDonateVoicemail();
+ }
+
private void updateChangePin() {
if (!voicemailClient.isVoicemailEnabled(getContext(), phoneAccountHandle)) {
voicemailChangePinPreference.setSummary(
@@ -305,4 +318,34 @@ public class VoicemailSettingsFragment extends PreferenceFragment
.putExtra(Settings.EXTRA_CHANNEL_ID, channelId)
.putExtra(Settings.EXTRA_APP_PACKAGE, getContext().getPackageName());
}
+
+ private void showDisableConfirmationDialog() {
+ LogUtil.i(TAG, "showDisableConfirmationDialog");
+ AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+ builder.setTitle(R.string.confirm_disable_voicemail_dialog_title);
+ builder.setMessage(R.string.confirm_disable_voicemail_dialog_message);
+ builder.setPositiveButton(
+ R.string.confirm_disable_voicemail_accept_dialog_label,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ LogUtil.i(TAG, "showDisableConfirmationDialog, confirmed");
+ updateVoicemailEnabled(false);
+ dialog.dismiss();
+ }
+ });
+
+ builder.setNegativeButton(
+ android.R.string.cancel,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ LogUtil.i(TAG, "showDisableConfirmationDialog, cancelled");
+ dialog.dismiss();
+ }
+ });
+
+ builder.setCancelable(true);
+ builder.show();
+ }
}
diff --git a/java/com/android/dialer/voicemail/settings/res/values/strings.xml b/java/com/android/dialer/voicemail/settings/res/values/strings.xml
index 4e502b488..10fa459ff 100644
--- a/java/com/android/dialer/voicemail/settings/res/values/strings.xml
+++ b/java/com/android/dialer/voicemail/settings/res/values/strings.xml
@@ -118,4 +118,11 @@
<!-- Summary information for visual voicemail donation setting [CHAR LIMIT=NONE] -->
<string name="voicemail_donate_preference_summary_info">Let Google review your voicemail messages to improve transcription quality</string>
+ <!-- Title for disable visual voicemail confirmation dialog [CHAR LIMIT=40] -->
+ <string name="confirm_disable_voicemail_dialog_title">Turn off visual voicemail</string>
+ <!-- Message explaining the implictions of disabling visual voicemail [CHAR LIMIT=NONE] -->
+ <string name="confirm_disable_voicemail_dialog_message">This will delete any voicemail and Google transcripts stored within this app. Your carrier may keep its own copies.</string>
+ <!-- The label for the confirm-disable-voicemail button [CHAR LIMIT=16] -->
+ <string name="confirm_disable_voicemail_accept_dialog_label">TURN OFF</string>
+
</resources>
diff --git a/java/com/android/voicemail/impl/AndroidManifest.xml b/java/com/android/voicemail/impl/AndroidManifest.xml
index 53636092a..e7ab5818e 100644
--- a/java/com/android/voicemail/impl/AndroidManifest.xml
+++ b/java/com/android/voicemail/impl/AndroidManifest.xml
@@ -138,5 +138,9 @@
android:name="com.android.internal.telephony.CARRIER_VVM_PACKAGE_INSTALLED" />
</intent-filter>
</receiver>
+
+ <receiver android:name="com.android.voicemail.impl.transcribe.GetTranscriptReceiver"
+ android:exported="false">
+ </receiver>
</application>
</manifest>
diff --git a/java/com/android/voicemail/impl/settings/VisualVoicemailSettingsUtil.java b/java/com/android/voicemail/impl/settings/VisualVoicemailSettingsUtil.java
index 61d76194c..e42d56938 100644
--- a/java/com/android/voicemail/impl/settings/VisualVoicemailSettingsUtil.java
+++ b/java/com/android/voicemail/impl/settings/VisualVoicemailSettingsUtil.java
@@ -19,11 +19,14 @@ import android.content.Context;
import android.support.annotation.VisibleForTesting;
import android.telecom.PhoneAccountHandle;
import com.android.dialer.common.Assert;
+import com.android.dialer.common.concurrent.DialerExecutor.Worker;
+import com.android.dialer.common.concurrent.DialerExecutorComponent;
import com.android.voicemail.VoicemailComponent;
import com.android.voicemail.impl.OmtpVvmCarrierConfigHelper;
import com.android.voicemail.impl.VisualVoicemailPreferences;
import com.android.voicemail.impl.VvmLog;
import com.android.voicemail.impl.sync.VvmAccountManager;
+import com.android.voicemail.impl.utils.VoicemailDatabaseUtil;
/** Save whether or not a particular account is enabled in shared to be retrieved later. */
public class VisualVoicemailSettingsUtil {
@@ -45,9 +48,40 @@ public class VisualVoicemailSettingsUtil {
} else {
VvmAccountManager.removeAccount(context, phoneAccount);
config.startDeactivation();
+ // Remove all voicemails from the database
+ DialerExecutorComponent.get(context)
+ .dialerExecutorFactory()
+ .createNonUiTaskBuilder(new VoicemailDeleteWorker(context))
+ .onSuccess(VisualVoicemailSettingsUtil::onSuccess)
+ .onFailure(VisualVoicemailSettingsUtil::onFailure)
+ .build()
+ .executeParallel(null);
}
}
+ private static class VoicemailDeleteWorker implements Worker<Void, Void> {
+ private final Context context;
+
+ VoicemailDeleteWorker(Context context) {
+ this.context = context;
+ }
+
+ @Override
+ public Void doInBackground(Void unused) {
+ int deleted = VoicemailDatabaseUtil.deleteAll(context);
+ VvmLog.i("VisualVoicemailSettingsUtil.doInBackground", "deleted " + deleted + " voicemails");
+ return null;
+ }
+ }
+
+ private static void onSuccess(Void unused) {
+ VvmLog.i("VisualVoicemailSettingsUtil.onSuccess", "delete voicemails");
+ }
+
+ private static void onFailure(Throwable t) {
+ VvmLog.e("VisualVoicemailSettingsUtil.onFailure", "delete voicemails", t);
+ }
+
public static void setArchiveEnabled(
Context context, PhoneAccountHandle phoneAccount, boolean isEnabled) {
Assert.checkArgument(
diff --git a/java/com/android/voicemail/impl/transcribe/GetTranscriptReceiver.java b/java/com/android/voicemail/impl/transcribe/GetTranscriptReceiver.java
new file mode 100644
index 000000000..cc204ff53
--- /dev/null
+++ b/java/com/android/voicemail/impl/transcribe/GetTranscriptReceiver.java
@@ -0,0 +1,233 @@
+/*
+ * 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.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.SystemClock;
+import android.support.annotation.Nullable;
+import android.util.Pair;
+import com.android.dialer.common.Assert;
+import com.android.dialer.common.backoff.ExponentialBaseCalculator;
+import com.android.dialer.common.concurrent.DialerExecutor.Worker;
+import com.android.dialer.common.concurrent.DialerExecutorComponent;
+import com.android.dialer.logging.DialerImpression;
+import com.android.dialer.logging.Logger;
+import com.android.voicemail.impl.VvmLog;
+import com.android.voicemail.impl.transcribe.grpc.GetTranscriptResponseAsync;
+import com.android.voicemail.impl.transcribe.grpc.TranscriptionClient;
+import com.android.voicemail.impl.transcribe.grpc.TranscriptionClientFactory;
+import com.google.internal.communications.voicemailtranscription.v1.GetTranscriptRequest;
+import com.google.internal.communications.voicemailtranscription.v1.TranscriptionStatus;
+
+/**
+ * This class uses the AlarmManager to poll for the result of a voicemail transcription request.
+ * Initially it waits for the estimated transcription time, and if the result is not available then
+ * it polls using an exponential backoff scheme.
+ */
+public class GetTranscriptReceiver extends BroadcastReceiver {
+ private static final String TAG = "GetTranscriptReceiver";
+ static final String EXTRA_IS_INITIAL_ESTIMATED_WAIT = "extra_is_initial_estimated_wait";
+ static final String EXTRA_VOICEMAIL_URI = "extra_voicemail_uri";
+ static final String EXTRA_TRANSCRIPT_ID = "extra_transcript_id";
+ static final String EXTRA_DELAY_MILLIS = "extra_delay_millis";
+ static final String EXTRA_BASE_MULTIPLIER = "extra_base_multiplier";
+ static final String EXTRA_REMAINING_ATTEMPTS = "extra_remaining_attempts";
+
+ // Schedule an initial alarm to begin checking for a voicemail transcription result.
+ static void beginPolling(
+ Context context,
+ Uri voicemailUri,
+ String transcriptId,
+ long estimatedTranscriptionTimeMillis,
+ TranscriptionConfigProvider configProvider) {
+ long initialDelayMillis = configProvider.getInitialGetTranscriptPollDelayMillis();
+ long maxBackoffMillis = configProvider.getMaxGetTranscriptPollTimeMillis();
+ int maxAttempts = configProvider.getMaxGetTranscriptPolls();
+ double baseMultiplier =
+ ExponentialBaseCalculator.findBase(initialDelayMillis, maxBackoffMillis, maxAttempts);
+ Intent intent =
+ makeAlarmIntent(
+ context, voicemailUri, transcriptId, initialDelayMillis, baseMultiplier, maxAttempts);
+ // Add an extra to distinguish this initial estimated transcription wait from subsequent backoff
+ // waits
+ intent.putExtra(EXTRA_IS_INITIAL_ESTIMATED_WAIT, true);
+ VvmLog.i(
+ TAG,
+ String.format(
+ "beginPolling, check in %d millis, for: %s",
+ estimatedTranscriptionTimeMillis, transcriptId));
+ scheduleAlarm(context, estimatedTranscriptionTimeMillis, intent);
+ }
+
+ // Alarm fired, poll for transcription result on a background thread
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String transcriptId = intent.getStringExtra(EXTRA_TRANSCRIPT_ID);
+ VvmLog.i(TAG, "onReceive, for transcript id: " + transcriptId);
+ DialerExecutorComponent.get(context)
+ .dialerExecutorFactory()
+ .createNonUiTaskBuilder(new PollWorker(context))
+ .onSuccess(this::onSuccess)
+ .onFailure(this::onFailure)
+ .build()
+ .executeParallel(intent);
+ }
+
+ private void onSuccess(Void unused) {
+ VvmLog.i(TAG, "onSuccess");
+ }
+
+ private void onFailure(Throwable t) {
+ VvmLog.e(TAG, "onFailure", t);
+ }
+
+ private static void scheduleAlarm(Context context, long delayMillis, Intent intent) {
+ PendingIntent alarmIntent =
+ PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+ AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ alarmMgr.set(
+ AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() + delayMillis,
+ alarmIntent);
+ }
+
+ private static Intent makeAlarmIntent(
+ Context context,
+ Uri voicemailUri,
+ String transcriptId,
+ long delayMillis,
+ double baseMultiplier,
+ int remainingAttempts) {
+ Intent intent = new Intent(context, GetTranscriptReceiver.class);
+ intent.putExtra(EXTRA_VOICEMAIL_URI, voicemailUri);
+ intent.putExtra(EXTRA_TRANSCRIPT_ID, transcriptId);
+ intent.putExtra(EXTRA_DELAY_MILLIS, delayMillis);
+ intent.putExtra(EXTRA_BASE_MULTIPLIER, baseMultiplier);
+ intent.putExtra(EXTRA_REMAINING_ATTEMPTS, remainingAttempts);
+ return intent;
+ }
+
+ private static class PollWorker implements Worker<Intent, Void> {
+ private final Context context;
+
+ PollWorker(Context context) {
+ this.context = context;
+ }
+
+ @Override
+ public Void doInBackground(Intent intent) {
+ String transcriptId = intent.getStringExtra(EXTRA_TRANSCRIPT_ID);
+ VvmLog.i(TAG, "doInBackground, for transcript id: " + transcriptId);
+ Pair<String, TranscriptionStatus> result = pollForTranscription(transcriptId);
+ if (result.first == null && result.second == null) {
+ // No result, try again if possible
+ Intent nextIntent = getNextAlarmIntent(intent);
+ if (nextIntent == null) {
+ VvmLog.i(TAG, "doInBackground, too many failures for: " + transcriptId);
+ result = new Pair<>(null, TranscriptionStatus.FAILED_NO_RETRY);
+ } else {
+ long nextDelayMillis = nextIntent.getLongExtra(EXTRA_DELAY_MILLIS, 0L);
+ VvmLog.i(
+ TAG,
+ String.format(
+ "doInBackground, check again in %d, for: %s", nextDelayMillis, transcriptId));
+ scheduleAlarm(context, nextDelayMillis, nextIntent);
+ return null;
+ }
+ }
+
+ // Got transcript or failed too many times
+ Uri voicemailUri = intent.getParcelableExtra(EXTRA_VOICEMAIL_URI);
+ TranscriptionDbHelper dbHelper = new TranscriptionDbHelper(context, voicemailUri);
+ TranscriptionTask.recordResult(context, result, dbHelper);
+ return null;
+ }
+
+ private Pair<String, TranscriptionStatus> pollForTranscription(String transcriptId) {
+ VvmLog.i(TAG, "pollForTranscription, transcript id: " + transcriptId);
+ GetTranscriptRequest request = getGetTranscriptRequest(transcriptId);
+ TranscriptionClientFactory factory = null;
+ try {
+ factory = getTranscriptionClientFactory(context);
+ TranscriptionClient client = factory.getClient();
+ Logger.get(context).logImpression(DialerImpression.Type.VVM_TRANSCRIPTION_POLL_REQUEST);
+ GetTranscriptResponseAsync response = client.sendGetTranscriptRequest(request);
+ if (response == null) {
+ VvmLog.i(TAG, "pollForTranscription, no transcription result.");
+ return new Pair<>(null, null);
+ } else if (response.isTranscribing()) {
+ VvmLog.i(TAG, "pollForTranscription, transcribing");
+ return new Pair<>(null, null);
+ } else if (response.hasFatalError()) {
+ VvmLog.i(TAG, "pollForTranscription, fail. " + response.getErrorDescription());
+ return new Pair<>(null, response.getTranscriptionStatus());
+ } else {
+ VvmLog.i(TAG, "pollForTranscription, got transcription");
+ return new Pair<>(response.getTranscript(), TranscriptionStatus.SUCCESS);
+ }
+ } finally {
+ if (factory != null) {
+ factory.shutdown();
+ }
+ }
+ }
+
+ private GetTranscriptRequest getGetTranscriptRequest(String transcriptionId) {
+ Assert.checkArgument(transcriptionId != null);
+ return GetTranscriptRequest.newBuilder().setTranscriptionId(transcriptionId).build();
+ }
+
+ private @Nullable Intent getNextAlarmIntent(Intent previous) {
+ int remainingAttempts = previous.getIntExtra(EXTRA_REMAINING_ATTEMPTS, 0);
+ double baseMultiplier = previous.getDoubleExtra(EXTRA_BASE_MULTIPLIER, 0);
+ long nextDelay = previous.getLongExtra(EXTRA_DELAY_MILLIS, 0);
+ if (!previous.getBooleanExtra(EXTRA_IS_INITIAL_ESTIMATED_WAIT, false)) {
+ // After waiting the estimated transcription time, start decrementing the remaining attempts
+ // and incrementing the backoff time delay
+ remainingAttempts--;
+ if (remainingAttempts <= 0) {
+ return null;
+ }
+ nextDelay = (long) (nextDelay * baseMultiplier);
+ }
+ return makeAlarmIntent(
+ context,
+ previous.getParcelableExtra(EXTRA_VOICEMAIL_URI),
+ previous.getStringExtra(EXTRA_TRANSCRIPT_ID),
+ nextDelay,
+ baseMultiplier,
+ remainingAttempts);
+ }
+ }
+
+ private static TranscriptionClientFactory transcriptionClientFactoryForTesting;
+
+ static void setTranscriptionClientFactoryForTesting(TranscriptionClientFactory factory) {
+ transcriptionClientFactoryForTesting = factory;
+ }
+
+ private static TranscriptionClientFactory getTranscriptionClientFactory(Context context) {
+ if (transcriptionClientFactoryForTesting != null) {
+ return transcriptionClientFactoryForTesting;
+ }
+ return new TranscriptionClientFactory(context, new TranscriptionConfigProvider(context));
+ }
+}
diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionConfigProvider.java b/java/com/android/voicemail/impl/transcribe/TranscriptionConfigProvider.java
index 98c8461f5..3d1755b64 100644
--- a/java/com/android/voicemail/impl/transcribe/TranscriptionConfigProvider.java
+++ b/java/com/android/voicemail/impl/transcribe/TranscriptionConfigProvider.java
@@ -18,6 +18,7 @@ package com.android.voicemail.impl.transcribe;
import android.content.Context;
import android.os.Build;
import com.android.dialer.configprovider.ConfigProviderBindings;
+import java.util.concurrent.TimeUnit;
/** Provides configuration values needed to connect to the transcription server. */
public class TranscriptionConfigProvider {
@@ -65,14 +66,24 @@ public class TranscriptionConfigProvider {
.getLong("voicemail_transcription_max_transcription_retries", 2L);
}
- public long getMaxGetTranscriptPolls() {
+ public int getMaxGetTranscriptPolls() {
+ return (int)
+ ConfigProviderBindings.get(context)
+ .getLong("voicemail_transcription_max_get_transcript_polls", 20L);
+ }
+
+ public long getInitialGetTranscriptPollDelayMillis() {
return ConfigProviderBindings.get(context)
- .getLong("voicemail_transcription_max_get_transcript_polls", 20L);
+ .getLong(
+ "voicemail_transcription_get_initial_transcript_poll_delay_millis",
+ TimeUnit.SECONDS.toMillis(1));
}
- public long getGetTranscriptPollIntervalMillis() {
+ public long getMaxGetTranscriptPollTimeMillis() {
return ConfigProviderBindings.get(context)
- .getLong("voicemail_transcription_get_transcript_poll_interval_millis", 1000L);
+ .getLong(
+ "voicemail_transcription_get_max_transcript_poll_time_millis",
+ TimeUnit.MINUTES.toMillis(20));
}
public boolean isVoicemailDonationAvailable() {
@@ -97,6 +108,6 @@ public class TranscriptionConfigProvider {
shouldUseSyncApi(),
getMaxTranscriptionRetries(),
getMaxGetTranscriptPolls(),
- getGetTranscriptPollIntervalMillis());
+ getMaxGetTranscriptPollTimeMillis());
}
}
diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionRatingHelper.java b/java/com/android/voicemail/impl/transcribe/TranscriptionRatingHelper.java
index 1cafacecf..b721ba5b0 100644
--- a/java/com/android/voicemail/impl/transcribe/TranscriptionRatingHelper.java
+++ b/java/com/android/voicemail/impl/transcribe/TranscriptionRatingHelper.java
@@ -85,7 +85,8 @@ public class TranscriptionRatingHelper {
private SendTranscriptionFeedbackRequest getFeedbackRequest() {
ByteString audioData = TranscriptionUtils.getAudioData(context, voicemailUri);
- String voicemailId = TranscriptionUtils.getFingerprintFor(audioData);
+ String salt = voicemailUri.toString();
+ String voicemailId = TranscriptionUtils.getFingerprintFor(audioData, salt);
TranscriptionRating rating =
TranscriptionRating.newBuilder()
.setTranscriptionId(voicemailId)
diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionTask.java b/java/com/android/voicemail/impl/transcribe/TranscriptionTask.java
index 97cf89eef..ca3320f28 100644
--- a/java/com/android/voicemail/impl/transcribe/TranscriptionTask.java
+++ b/java/com/android/voicemail/impl/transcribe/TranscriptionTask.java
@@ -21,7 +21,6 @@ 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;
@@ -56,14 +55,14 @@ import com.google.protobuf.ByteString;
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 Context context;
+ protected final Uri voicemailUri;
protected final PhoneAccountHandle phoneAccountHandle;
- private final TranscriptionDbHelper databaseHelper;
protected final TranscriptionConfigProvider configProvider;
+ protected final TranscriptionDbHelper dbHelper;
protected ByteString audioData;
protected AudioFormat encoding;
protected volatile boolean cancelled;
@@ -86,7 +85,7 @@ public abstract class TranscriptionTask implements Runnable {
this.voicemailUri = TranscriptionService.getVoicemailUri(workItem);
this.phoneAccountHandle = TranscriptionService.getPhoneAccountHandle(workItem);
this.configProvider = configProvider;
- databaseHelper = new TranscriptionDbHelper(context, voicemailUri);
+ dbHelper = new TranscriptionDbHelper(context, voicemailUri);
}
@MainThread
@@ -124,44 +123,7 @@ public abstract class TranscriptionTask implements Runnable {
private void transcribeVoicemail() {
VvmLog.i(TAG, "transcribeVoicemail");
- Pair<String, TranscriptionStatus> pair = getTranscription();
- String transcript = pair.first;
- TranscriptionStatus status = pair.second;
- if (!TextUtils.isEmpty(transcript)) {
- updateTranscriptionAndState(transcript, VoicemailCompat.TRANSCRIPTION_AVAILABLE);
- VvmLog.i(TAG, "transcribeVoicemail, got response");
- Logger.get(context).logImpression(DialerImpression.Type.VVM_TRANSCRIPTION_RESPONSE_SUCCESS);
- } else {
- VvmLog.i(TAG, "transcribeVoicemail, transcription unsuccessful, " + status);
- switch (status) {
- case FAILED_NO_SPEECH_DETECTED:
- updateTranscriptionAndState(
- transcript, VoicemailCompat.TRANSCRIPTION_FAILED_NO_SPEECH_DETECTED);
- Logger.get(context)
- .logImpression(DialerImpression.Type.VVM_TRANSCRIPTION_RESPONSE_NO_SPEECH_DETECTED);
- break;
- case FAILED_LANGUAGE_NOT_SUPPORTED:
- updateTranscriptionAndState(
- transcript, VoicemailCompat.TRANSCRIPTION_FAILED_LANGUAGE_NOT_SUPPORTED);
- Logger.get(context)
- .logImpression(
- DialerImpression.Type.VVM_TRANSCRIPTION_RESPONSE_LANGUAGE_NOT_SUPPORTED);
- break;
- case EXPIRED:
- updateTranscriptionAndState(transcript, VoicemailCompat.TRANSCRIPTION_FAILED);
- Logger.get(context)
- .logImpression(DialerImpression.Type.VVM_TRANSCRIPTION_RESPONSE_EXPIRED);
- break;
- default:
- updateTranscriptionAndState(
- transcript,
- cancelled
- ? VoicemailCompat.TRANSCRIPTION_NOT_STARTED
- : VoicemailCompat.TRANSCRIPTION_FAILED);
- Logger.get(context).logImpression(DialerImpression.Type.VVM_TRANSCRIPTION_RESPONSE_EMPTY);
- break;
- }
- }
+ recordResult(context, getTranscription(), dbHelper, cancelled);
}
protected TranscriptionResponse sendRequest(Request request) {
@@ -213,12 +175,57 @@ public abstract class TranscriptionTask implements Runnable {
}
}
- private void updateTranscriptionAndState(String transcript, int newState) {
- databaseHelper.setTranscriptionAndState(transcript, newState);
+ protected void updateTranscriptionState(int newState) {
+ dbHelper.setTranscriptionState(newState);
+ }
+
+ protected void updateTranscriptionAndState(String transcript, int newState) {
+ dbHelper.setTranscriptionAndState(transcript, newState);
+ }
+
+ static void recordResult(
+ Context context, Pair<String, TranscriptionStatus> result, TranscriptionDbHelper dbHelper) {
+ recordResult(context, result, dbHelper, false);
}
- private void updateTranscriptionState(int newState) {
- databaseHelper.setTranscriptionState(newState);
+ static void recordResult(
+ Context context,
+ Pair<String, TranscriptionStatus> result,
+ TranscriptionDbHelper dbHelper,
+ boolean cancelled) {
+ if (result.first != null) {
+ VvmLog.i(TAG, "recordResult, got transcription");
+ dbHelper.setTranscriptionAndState(result.first, VoicemailCompat.TRANSCRIPTION_AVAILABLE);
+ Logger.get(context).logImpression(DialerImpression.Type.VVM_TRANSCRIPTION_RESPONSE_SUCCESS);
+ } else if (result.second != null) {
+ VvmLog.i(TAG, "recordResult, failed to transcribe, reason: " + result.second);
+ switch (result.second) {
+ case FAILED_NO_SPEECH_DETECTED:
+ dbHelper.setTranscriptionState(VoicemailCompat.TRANSCRIPTION_FAILED_NO_SPEECH_DETECTED);
+ Logger.get(context)
+ .logImpression(DialerImpression.Type.VVM_TRANSCRIPTION_RESPONSE_NO_SPEECH_DETECTED);
+ break;
+ case FAILED_LANGUAGE_NOT_SUPPORTED:
+ dbHelper.setTranscriptionState(
+ VoicemailCompat.TRANSCRIPTION_FAILED_LANGUAGE_NOT_SUPPORTED);
+ Logger.get(context)
+ .logImpression(
+ DialerImpression.Type.VVM_TRANSCRIPTION_RESPONSE_LANGUAGE_NOT_SUPPORTED);
+ break;
+ case EXPIRED:
+ dbHelper.setTranscriptionState(VoicemailCompat.TRANSCRIPTION_FAILED);
+ Logger.get(context)
+ .logImpression(DialerImpression.Type.VVM_TRANSCRIPTION_RESPONSE_EXPIRED);
+ break;
+ default:
+ dbHelper.setTranscriptionState(
+ cancelled
+ ? VoicemailCompat.TRANSCRIPTION_NOT_STARTED
+ : VoicemailCompat.TRANSCRIPTION_FAILED);
+ Logger.get(context).logImpression(DialerImpression.Type.VVM_TRANSCRIPTION_RESPONSE_EMPTY);
+ break;
+ }
+ }
}
private boolean readAndValidateAudioFile() {
diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionTaskAsync.java b/java/com/android/voicemail/impl/transcribe/TranscriptionTaskAsync.java
index 808bf0f87..bb7aa5f38 100644
--- a/java/com/android/voicemail/impl/transcribe/TranscriptionTaskAsync.java
+++ b/java/com/android/voicemail/impl/transcribe/TranscriptionTaskAsync.java
@@ -19,17 +19,13 @@ import android.app.job.JobWorkItem;
import android.content.Context;
import android.support.annotation.VisibleForTesting;
import android.util.Pair;
-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.VvmLog;
import com.android.voicemail.impl.transcribe.TranscriptionService.JobCallback;
-import com.android.voicemail.impl.transcribe.grpc.GetTranscriptResponseAsync;
import com.android.voicemail.impl.transcribe.grpc.TranscriptionClientFactory;
import com.android.voicemail.impl.transcribe.grpc.TranscriptionResponseAsync;
import com.google.internal.communications.voicemailtranscription.v1.DonationPreference;
-import com.google.internal.communications.voicemailtranscription.v1.GetTranscriptRequest;
import com.google.internal.communications.voicemailtranscription.v1.TranscribeVoicemailAsyncRequest;
import com.google.internal.communications.voicemailtranscription.v1.TranscriptionStatus;
@@ -72,9 +68,19 @@ public class TranscriptionTaskAsync extends TranscriptionTask {
} else if (uploadResponse == null) {
VvmLog.i(TAG, "getTranscription, failed to upload voicemail.");
return new Pair<>(null, TranscriptionStatus.FAILED_NO_RETRY);
+ } else if (uploadResponse.getTranscriptionId() == null) {
+ VvmLog.i(TAG, "getTranscription, upload error: " + uploadResponse.status);
+ return new Pair<>(null, TranscriptionStatus.FAILED_NO_RETRY);
} else {
- waitForTranscription(uploadResponse);
- return pollForTranscription(uploadResponse);
+ VvmLog.i(TAG, "getTranscription, begin polling for result.");
+ GetTranscriptReceiver.beginPolling(
+ context,
+ voicemailUri,
+ uploadResponse.getTranscriptionId(),
+ uploadResponse.getEstimatedWaitMillis(),
+ configProvider);
+ // This indicates that the result is not available yet
+ return new Pair<>(null, null);
}
}
@@ -83,45 +89,6 @@ public class TranscriptionTaskAsync extends TranscriptionTask {
return DialerImpression.Type.VVM_TRANSCRIPTION_REQUEST_SENT_ASYNC;
}
- private static void waitForTranscription(TranscriptionResponseAsync uploadResponse) {
- long millis = uploadResponse.getEstimatedWaitMillis();
- VvmLog.i(TAG, "waitForTranscription, " + millis + " millis");
- sleep(millis);
- }
-
- private Pair<String, TranscriptionStatus> pollForTranscription(
- TranscriptionResponseAsync uploadResponse) {
- VvmLog.i(TAG, "pollForTranscription");
- GetTranscriptRequest request = getGetTranscriptRequest(uploadResponse);
- for (int i = 0; i < configProvider.getMaxGetTranscriptPolls(); i++) {
- if (cancelled) {
- VvmLog.i(TAG, "pollForTranscription, cancelled.");
- return new Pair<>(null, TranscriptionStatus.FAILED_NO_RETRY);
- }
- Logger.get(context).logImpression(DialerImpression.Type.VVM_TRANSCRIPTION_POLL_REQUEST);
- GetTranscriptResponseAsync response =
- (GetTranscriptResponseAsync)
- sendRequest((client) -> client.sendGetTranscriptRequest(request));
- if (cancelled) {
- VvmLog.i(TAG, "pollForTranscription, cancelled.");
- return new Pair<>(null, TranscriptionStatus.FAILED_NO_RETRY);
- } else if (response == null) {
- VvmLog.i(TAG, "pollForTranscription, no transcription result.");
- } else if (response.isTranscribing()) {
- VvmLog.i(TAG, "pollForTranscription, poll count: " + (i + 1));
- } else if (response.hasFatalError()) {
- VvmLog.i(TAG, "pollForTranscription, fail. " + response.getErrorDescription());
- return new Pair<>(null, response.getTranscriptionStatus());
- } else {
- VvmLog.i(TAG, "pollForTranscription, got transcription");
- return new Pair<>(response.getTranscript(), TranscriptionStatus.SUCCESS);
- }
- sleep(configProvider.getGetTranscriptPollIntervalMillis());
- }
- VvmLog.i(TAG, "pollForTranscription, timed out.");
- return new Pair<>(null, TranscriptionStatus.FAILED_NO_RETRY);
- }
-
@VisibleForTesting
TranscribeVoicemailAsyncRequest getUploadRequest() {
TranscribeVoicemailAsyncRequest.Builder builder =
@@ -134,7 +101,12 @@ public class TranscriptionTaskAsync extends TranscriptionTask {
// available (because rating donating voicemails requires locally generated voicemail ids).
if (configProvider.useClientGeneratedVoicemailIds()
|| configProvider.isVoicemailDonationAvailable()) {
- builder.setTranscriptionId(TranscriptionUtils.getFingerprintFor(audioData));
+ // The server currently can't handle repeated transcription id's so if we add the Uri to the
+ // fingerprint (which contains the voicemail id) which is different each time a voicemail is
+ // downloaded. If this becomes a problem then it should be possible to change the server
+ // behavior to allow id's to be re-used, a bug
+ String salt = voicemailUri.toString();
+ builder.setTranscriptionId(TranscriptionUtils.getFingerprintFor(audioData, salt));
}
return builder.build();
}
@@ -145,11 +117,4 @@ public class TranscriptionTaskAsync extends TranscriptionTask {
.getVoicemailClient()
.isVoicemailDonationEnabled(context, phoneAccountHandle);
}
-
- private GetTranscriptRequest getGetTranscriptRequest(TranscriptionResponseAsync uploadResponse) {
- Assert.checkArgument(uploadResponse.getTranscriptionId() != null);
- return GetTranscriptRequest.newBuilder()
- .setTranscriptionId(uploadResponse.getTranscriptionId())
- .build();
- }
}
diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionUtils.java b/java/com/android/voicemail/impl/transcribe/TranscriptionUtils.java
index 36b1400be..3bd14731f 100644
--- a/java/com/android/voicemail/impl/transcribe/TranscriptionUtils.java
+++ b/java/com/android/voicemail/impl/transcribe/TranscriptionUtils.java
@@ -18,6 +18,8 @@ package com.android.voicemail.impl.transcribe;
import android.annotation.TargetApi;
import android.content.Context;
import android.net.Uri;
+import android.os.Build.VERSION_CODES;
+import android.support.annotation.Nullable;
import android.util.Base64;
import com.android.dialer.common.Assert;
import com.google.internal.communications.voicemailtranscription.v1.AudioFormat;
@@ -47,11 +49,14 @@ public class TranscriptionUtils {
: AudioFormat.AUDIO_FORMAT_UNSPECIFIED;
}
- @TargetApi(android.os.Build.VERSION_CODES.O)
- static String getFingerprintFor(ByteString data) {
+ @TargetApi(VERSION_CODES.O)
+ static String getFingerprintFor(ByteString data, @Nullable String salt) {
Assert.checkArgument(data != null);
try {
MessageDigest md = MessageDigest.getInstance("MD5");
+ if (salt != null) {
+ md.update(salt.getBytes());
+ }
byte[] md5Bytes = md.digest(data.toByteArray());
return Base64.encodeToString(md5Bytes, Base64.DEFAULT);
} catch (NoSuchAlgorithmException e) {
diff --git a/java/com/android/voicemail/impl/transcribe/grpc/TranscriptionResponse.java b/java/com/android/voicemail/impl/transcribe/grpc/TranscriptionResponse.java
index f0823de32..ae4796dea 100644
--- a/java/com/android/voicemail/impl/transcribe/grpc/TranscriptionResponse.java
+++ b/java/com/android/voicemail/impl/transcribe/grpc/TranscriptionResponse.java
@@ -50,4 +50,9 @@ public abstract class TranscriptionResponse {
return false;
}
+
+ @Override
+ public String toString() {
+ return "status: " + status;
+ }
}
diff --git a/java/com/android/voicemail/impl/transcribe/grpc/TranscriptionResponseAsync.java b/java/com/android/voicemail/impl/transcribe/grpc/TranscriptionResponseAsync.java
index 38b463053..bd5679407 100644
--- a/java/com/android/voicemail/impl/transcribe/grpc/TranscriptionResponseAsync.java
+++ b/java/com/android/voicemail/impl/transcribe/grpc/TranscriptionResponseAsync.java
@@ -50,4 +50,9 @@ public class TranscriptionResponseAsync extends TranscriptionResponse {
}
return 0;
}
+
+ @Override
+ public String toString() {
+ return super.toString() + ", response: " + response;
+ }
}
diff --git a/java/com/android/voicemail/impl/transcribe/grpc/TranscriptionResponseSync.java b/java/com/android/voicemail/impl/transcribe/grpc/TranscriptionResponseSync.java
index d2e2e218c..382bd1a97 100644
--- a/java/com/android/voicemail/impl/transcribe/grpc/TranscriptionResponseSync.java
+++ b/java/com/android/voicemail/impl/transcribe/grpc/TranscriptionResponseSync.java
@@ -40,4 +40,9 @@ public class TranscriptionResponseSync extends TranscriptionResponse {
public @Nullable String getTranscript() {
return (response != null) ? response.getTranscript() : null;
}
+
+ @Override
+ public String toString() {
+ return super.toString() + ", response: " + response;
+ }
}
diff --git a/java/com/android/voicemail/impl/utils/VoicemailDatabaseUtil.java b/java/com/android/voicemail/impl/utils/VoicemailDatabaseUtil.java
index 711d6a8a4..ef5447d32 100644
--- a/java/com/android/voicemail/impl/utils/VoicemailDatabaseUtil.java
+++ b/java/com/android/voicemail/impl/utils/VoicemailDatabaseUtil.java
@@ -57,6 +57,16 @@ public class VoicemailDatabaseUtil {
return voicemails.size();
}
+ /**
+ * Delete all the voicemails whose source_package field matches this package
+ *
+ * @return the number of voicemails deleted
+ */
+ public static int deleteAll(Context context) {
+ ContentResolver contentResolver = context.getContentResolver();
+ return contentResolver.delete(Voicemails.buildSourceUri(context.getPackageName()), null, null);
+ }
+
/** Maps structured {@link Voicemail} to {@link ContentValues} in content provider. */
private static ContentValues getContentValues(Voicemail voicemail) {
ContentValues contentValues = new ContentValues();