summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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();