Refactor VM Settings and add support for voicemail transcription

This CL refactors the existing voicemail settings fragment and adds UI support for voicemail transcription. It mainly deals with the following:
- ensuring that when the VVM toggle is turned off, transcription and donations are gone.
- when transcription is off, donation preference is gone.
- donation is only available when transcription is available and enabled
- as part of the refactor, fixes existing logging bugs
- breaks preferences and its associated methods into helper methods when possible
- groups relevant preferences together when possible

Bug: 74033229
Test: Unit tests
PiperOrigin-RevId: 189418217
Change-Id: I3442cb5752a235cfca643ba55df3fb75171e3fe4
diff --git a/java/com/android/dialer/app/calllog/PhoneCallDetailsHelper.java b/java/com/android/dialer/app/calllog/PhoneCallDetailsHelper.java
index 937f041..b88a959 100644
--- a/java/com/android/dialer/app/calllog/PhoneCallDetailsHelper.java
+++ b/java/com/android/dialer/app/calllog/PhoneCallDetailsHelper.java
@@ -94,6 +94,49 @@
     calendar = Calendar.getInstance();
   }
 
+  static boolean shouldShowVoicemailDonationPromo(
+      Context context, PhoneAccountHandle accountHandle) {
+    VoicemailClient client = VoicemailComponent.get(context).getVoicemailClient();
+    return client.isVoicemailDonationAvailable(context, accountHandle)
+        && !hasSeenVoicemailDonationPromo(context);
+  }
+
+  static boolean hasSeenVoicemailDonationPromo(Context context) {
+    return StorageComponent.get(context.getApplicationContext())
+        .unencryptedSharedPrefs()
+        .getBoolean(PREF_VOICEMAIL_DONATION_PROMO_SHOWN_KEY, false);
+  }
+
+  private static int dpsToPixels(Context context, int dps) {
+    return (int)
+        (TypedValue.applyDimension(
+            TypedValue.COMPLEX_UNIT_DIP, dps, context.getResources().getDisplayMetrics()));
+  }
+
+  private static void recordPromoShown(Context context) {
+    StorageComponent.get(context.getApplicationContext())
+        .unencryptedSharedPrefs()
+        .edit()
+        .putBoolean(PREF_VOICEMAIL_DONATION_PROMO_SHOWN_KEY, true)
+        .apply();
+  }
+
+  /** Returns true if primary name is empty or the data is from Cequint Caller ID. */
+  private static boolean shouldShowLocation(PhoneCallDetails details) {
+    if (TextUtils.isEmpty(details.geocode)) {
+      return false;
+    }
+    // For caller ID provided by Cequint we want to show the geo location.
+    if (details.sourceType == ContactSource.Type.SOURCE_TYPE_CEQUINT_CALLER_ID) {
+      return true;
+    }
+    // Don't bother showing geo location for contacts.
+    if (!TextUtils.isEmpty(details.namePrimary)) {
+      return false;
+    }
+    return true;
+  }
+
   /** Fills the call details views with content. */
   public void setPhoneCallDetails(PhoneCallDetailsViews views, PhoneCallDetails details) {
     // Display up to a given number of icons.
@@ -250,9 +293,10 @@
       return true;
     }
 
-    // Also show the rating option if voicemail transcription is available (but not enabled)
+    // Also show the rating option if voicemail donation is available (but not enabled)
     // and the donation promo has not yet been shown.
-    if (client.isVoicemailDonationAvailable(context) && !hasSeenVoicemailDonationPromo(context)) {
+    if (client.isVoicemailDonationAvailable(context, account)
+        && !hasSeenVoicemailDonationPromo(context)) {
       return true;
     }
 
@@ -263,7 +307,7 @@
       TranscriptionRatingValue ratingValue, PhoneCallDetails details, View ratingView) {
     LogUtil.enterBlock("PhoneCallDetailsHelper.recordTranscriptionRating");
 
-    if (shouldShowVoicemailDonationPromo(context)) {
+    if (shouldShowVoicemailDonationPromo(context, details.accountHandle)) {
       showVoicemailDonationPromo(ratingValue, details, ratingView);
     } else {
       TranscriptionRatingHelper.sendRating(
@@ -275,19 +319,6 @@
     }
   }
 
-  static boolean shouldShowVoicemailDonationPromo(Context context) {
-    VoicemailClient client = VoicemailComponent.get(context).getVoicemailClient();
-    return client.isVoicemailTranscriptionAvailable(context)
-        && client.isVoicemailDonationAvailable(context)
-        && !hasSeenVoicemailDonationPromo(context);
-  }
-
-  static boolean hasSeenVoicemailDonationPromo(Context context) {
-    return StorageComponent.get(context.getApplicationContext())
-        .unencryptedSharedPrefs()
-        .getBoolean(PREF_VOICEMAIL_DONATION_PROMO_SHOWN_KEY, false);
-  }
-
   private void showVoicemailDonationPromo(
       TranscriptionRatingValue ratingValue, PhoneCallDetails details, View ratingView) {
     AlertDialog.Builder builder = new AlertDialog.Builder(context);
@@ -360,20 +391,6 @@
     }
   }
 
-  private static int dpsToPixels(Context context, int dps) {
-    return (int)
-        (TypedValue.applyDimension(
-            TypedValue.COMPLEX_UNIT_DIP, dps, context.getResources().getDisplayMetrics()));
-  }
-
-  private static void recordPromoShown(Context context) {
-    StorageComponent.get(context.getApplicationContext())
-        .unencryptedSharedPrefs()
-        .edit()
-        .putBoolean(PREF_VOICEMAIL_DONATION_PROMO_SHOWN_KEY, true)
-        .apply();
-  }
-
   private SpannableString getVoicemailDonationPromoContent() {
     return new ContentWithLearnMoreSpanner(context)
         .create(
@@ -462,22 +479,6 @@
     return numberFormattedLabel;
   }
 
-  /** Returns true if primary name is empty or the data is from Cequint Caller ID. */
-  private static boolean shouldShowLocation(PhoneCallDetails details) {
-    if (TextUtils.isEmpty(details.geocode)) {
-      return false;
-    }
-    // For caller ID provided by Cequint we want to show the geo location.
-    if (details.sourceType == ContactSource.Type.SOURCE_TYPE_CEQUINT_CALLER_ID) {
-      return true;
-    }
-    // Don't bother showing geo location for contacts.
-    if (!TextUtils.isEmpty(details.namePrimary)) {
-      return false;
-    }
-    return true;
-  }
-
   public void setPhoneTypeLabelForTest(CharSequence phoneTypeLabel) {
     this.phoneTypeLabelForTest = phoneTypeLabel;
   }
diff --git a/java/com/android/dialer/logging/dialer_impression.proto b/java/com/android/dialer/logging/dialer_impression.proto
index c657768..96ca9c6 100644
--- a/java/com/android/dialer/logging/dialer_impression.proto
+++ b/java/com/android/dialer/logging/dialer_impression.proto
@@ -12,7 +12,7 @@
   // Event enums to be used for Impression Logging in Dialer.
   // It's perfectly acceptable for this enum to be large
   // Values should be from 1000 to 100000.
-  // Next Tag: 1361
+  // Next Tag: 1366
   enum Type {
     UNKNOWN_AOSP_EVENT_TYPE = 1000;
 
@@ -372,7 +372,7 @@
     VVM_SETTINGS_VIEWED = 1148;
     VVM_CHANGE_PIN_CLICKED = 1149;
     VVM_CHANGE_PIN_COMPLETED = 1150;
-    VVM_CHANGE_RINGTONE_CLICKED = 1151;
+    VVM_CHANGE_RINGTONE_CLICKED = 1151 [deprecated = true];
     VVM_CHANGE_VIBRATION_CLICKED = 1152;
     VVM_USER_ENABLED_IN_SETTINGS = 1153;
     VVM_USER_DISABLED_IN_SETTINGS = 1154;
@@ -594,14 +594,12 @@
     ASSISTED_DIALING_FEATURE_DISABLED_BY_USER = 1292;
 
     // User reports a same prefix call as spam from call history
-    REPORT_SAME_PREFIX_CALL_AS_SPAM_VIA_CALL_HISTORY =
-        1290
+    REPORT_SAME_PREFIX_CALL_AS_SPAM_VIA_CALL_HISTORY = 1290
 
         ;
 
     // User reports a same prefix call as not spam from call history
-    REPORT_SAME_PREFIX_CALL_AS_NOT_SPAM_VIA_CALL_HISTORY =
-        1291
+    REPORT_SAME_PREFIX_CALL_AS_NOT_SPAM_VIA_CALL_HISTORY = 1291
 
         ;
 
@@ -715,5 +713,11 @@
     SPAM_BLOCKING_DISABLED_THROUGH_SETTING = 1359;
     // Failure happened while modifying spam blocking setting.
     SPAM_BLOCKING_MODIFY_FAILURE_THROUGH_SETTING = 1360;
+
+    VVM_NOTIFICATIONS_SETTING_CLICKED = 1361;
+    VVM_USER_TURNED_TRANSCRIBE_ON_FROM_SETTINGS = 1362;
+    VVM_USER_TURNED_TRANSCRIBE_OFF_FROM_SETTINGS = 1363;
+    VVM_USER_TURNED_DONATION_ON_FROM_SETTINGS = 1364;
+    VVM_USER_TURNED_DONATION_OFF_FROM_SETTINGS = 1365;
   }
 }
diff --git a/java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java b/java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java
index 5ae26f5..b7db28e 100644
--- a/java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java
+++ b/java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java
@@ -51,8 +51,6 @@
 public class VoicemailSettingsFragment extends PreferenceFragment
     implements Preference.OnPreferenceChangeListener, ActivationStateListener {
 
-  private static final String TAG = "VmSettingsActivity";
-
   // Extras copied from com.android.phone.settings.VoicemailSettingsActivity,
   // it does not recognize EXTRA_PHONE_ACCOUNT_HANDLE in O.
   @VisibleForTesting
@@ -63,21 +61,26 @@
   static final String SUB_LABEL_EXTRA =
       "com.android.phone.settings.SubscriptionInfoHelper.SubscriptionLabel";
 
+  private static final String TAG = "VmSettingsActivity";
   @Nullable private PhoneAccountHandle phoneAccountHandle;
 
   private VoicemailClient voicemailClient;
 
+  // Settings that are independent of the carrier configurations
   private Preference voicemailNotificationPreference;
-  private SwitchPreference voicemailVisualVoicemail;
-  private SwitchPreference autoArchiveSwitchPreference;
-  private SwitchPreference donateVoicemailSwitchPreference;
+  private PreferenceScreen advancedSettingsPreference;
+
+  // Settings that are supported by dialer only if the carrier configurations are valid.
+  private SwitchPreference visualVoicemailPreference;
+  private SwitchPreference voicemailAutoArchivePreference;
+  private SwitchPreference transcribeVoicemailPreference;
+  // Voicemail transcription analysis toggle
+  private SwitchPreference donateTranscribedVoicemailPreference;
   private Preference voicemailChangePinPreference;
-  private PreferenceScreen advancedSettings;
 
   @Override
   public void onCreate(Bundle icicle) {
     super.onCreate(icicle);
-
     phoneAccountHandle =
         Assert.isNotNull(getArguments().getParcelable(VoicemailClient.PARAM_PHONE_ACCOUNT_HANDLE));
     voicemailClient = VoicemailComponent.get(getContext()).getVoicemailClient();
@@ -95,10 +98,162 @@
 
     addPreferencesFromResource(R.xml.voicemail_settings);
 
-    PreferenceScreen prefSet = getPreferenceScreen();
+    initializePreferences();
 
+    setupVisualVoicemailPreferences();
+
+    setupNotificationsPreference();
+    setupAdvancedSettingsPreference();
+  }
+
+  private void setupVisualVoicemailPreferences() {
+    if (!voicemailClient.hasCarrierSupport(getContext(), phoneAccountHandle)) {
+      removeAllVisualVoicemailPreferences();
+      return;
+    }
+
+    setupVisualVoicemailPreference();
+
+    setupVisualVoicemailFeaturePreferences();
+
+    setupVoicemailChangePinPreference();
+  }
+
+  private void setupVisualVoicemailFeaturePreferences() {
+    if (!voicemailClient.isVoicemailEnabled(getContext(), phoneAccountHandle)
+        || !voicemailClient.isActivated(getContext(), phoneAccountHandle)) {
+      removeAllTranscriptionPreferences();
+      getPreferenceScreen().removePreference(voicemailAutoArchivePreference);
+      return;
+    }
+    setupAutoArchivePreference();
+    updateTranscriptionPreferences();
+  }
+
+  private void updateTranscriptionPreferences() {
+    if (!VoicemailComponent.get(getContext())
+        .getVoicemailClient()
+        .isVoicemailTranscriptionAvailable(getContext(), phoneAccountHandle)) {
+      removeAllTranscriptionPreferences();
+      return;
+    } else {
+      showTranscriptionEnabledPreference();
+      updateTranscriptionDonationPreference();
+    }
+  }
+
+  private void showTranscriptionEnabledPreference() {
+    transcribeVoicemailPreference.setOnPreferenceChangeListener(this);
+    transcribeVoicemailPreference.setChecked(
+        voicemailClient.isVoicemailTranscriptionEnabled(getContext(), phoneAccountHandle));
+    transcribeVoicemailPreference.setSummary(
+        R.string.voicemail_transcription_preference_summary_info);
+    transcribeVoicemailPreference.setEnabled(true);
+    getPreferenceScreen().addPreference(transcribeVoicemailPreference);
+  }
+
+  private void updateTranscriptionDonationPreference() {
+    if (!VoicemailComponent.get(getContext())
+        .getVoicemailClient()
+        .isVoicemailDonationAvailable(getContext(), phoneAccountHandle)) {
+      getPreferenceScreen().removePreference(donateTranscribedVoicemailPreference);
+    } else {
+      showTranscriptionDonationEnabledPreferences();
+    }
+  }
+
+  private void showTranscriptionDonationEnabledPreferences() {
+    donateTranscribedVoicemailPreference.setOnPreferenceChangeListener(this);
+    donateTranscribedVoicemailPreference.setChecked(
+        voicemailClient.isVoicemailDonationEnabled(getContext(), phoneAccountHandle));
+    donateTranscribedVoicemailPreference.setSummary(
+        R.string.voicemail_donate_preference_summary_info);
+    donateTranscribedVoicemailPreference.setEnabled(true);
+    getPreferenceScreen().addPreference(donateTranscribedVoicemailPreference);
+  }
+
+  private void removeAllTranscriptionPreferences() {
+    getPreferenceScreen().removePreference(transcribeVoicemailPreference);
+    getPreferenceScreen().removePreference(donateTranscribedVoicemailPreference);
+  }
+
+  private void setupAutoArchivePreference() {
+    if (!VoicemailComponent.get(getContext())
+        .getVoicemailClient()
+        .isVoicemailArchiveAvailable(getContext())) {
+      getPreferenceScreen().removePreference(voicemailAutoArchivePreference);
+    } else {
+      voicemailAutoArchivePreference.setOnPreferenceChangeListener(this);
+      voicemailAutoArchivePreference.setChecked(
+          voicemailClient.isVoicemailArchiveEnabled(getContext(), phoneAccountHandle));
+    }
+  }
+
+  private void setupVisualVoicemailPreference() {
+    visualVoicemailPreference.setOnPreferenceChangeListener(this);
+    visualVoicemailPreference.setChecked(
+        voicemailClient.isVoicemailEnabled(getContext(), phoneAccountHandle));
+  }
+
+  private void initializePreferences() {
     voicemailNotificationPreference =
         findPreference(getString(R.string.voicemail_notifications_key));
+
+    advancedSettingsPreference =
+        (PreferenceScreen) findPreference(getString(R.string.voicemail_advanced_settings_key));
+
+    visualVoicemailPreference =
+        (SwitchPreference) findPreference(getString(R.string.voicemail_visual_voicemail_key));
+
+    voicemailAutoArchivePreference =
+        (SwitchPreference)
+            findPreference(getString(R.string.voicemail_visual_voicemail_archive_key));
+
+    transcribeVoicemailPreference =
+        (SwitchPreference)
+            findPreference(getString(R.string.voicemail_visual_voicemail_transcription_key));
+
+    donateTranscribedVoicemailPreference =
+        (SwitchPreference)
+            findPreference(getString(R.string.voicemail_visual_voicemail_donation_key));
+
+    voicemailChangePinPreference = findPreference(getString(R.string.voicemail_change_pin_key));
+  }
+
+  /** Removes vvm settings since the carrier setup is not supported by Dialer */
+  private void removeAllVisualVoicemailPreferences() {
+    PreferenceScreen prefSet = getPreferenceScreen();
+    prefSet.removePreference(visualVoicemailPreference);
+    prefSet.removePreference(voicemailAutoArchivePreference);
+    prefSet.removePreference(transcribeVoicemailPreference);
+    prefSet.removePreference(donateTranscribedVoicemailPreference);
+    prefSet.removePreference(voicemailChangePinPreference);
+  }
+
+  private void setupVoicemailChangePinPreference() {
+    Intent changePinIntent = new Intent(new Intent(getContext(), VoicemailChangePinActivity.class));
+    changePinIntent.putExtra(VoicemailClient.PARAM_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
+
+    voicemailChangePinPreference.setIntent(changePinIntent);
+    voicemailChangePinPreference.setOnPreferenceClickListener(
+        new OnPreferenceClickListener() {
+          @Override
+          public boolean onPreferenceClick(Preference preference) {
+            Logger.get(getContext()).logImpression(DialerImpression.Type.VVM_CHANGE_PIN_CLICKED);
+            // Let the preference handle the click.
+            return false;
+          }
+        });
+    if (VoicemailChangePinActivity.isPinScrambled(getContext(), phoneAccountHandle)) {
+      voicemailChangePinPreference.setTitle(R.string.voicemail_set_pin_preference_title);
+    } else {
+      voicemailChangePinPreference.setTitle(R.string.voicemail_change_pin_preference_title);
+    }
+    updateChangePinPreference();
+  }
+
+  private void setupNotificationsPreference() {
+
     voicemailNotificationPreference.setIntent(getNotificationSettingsIntent());
 
     voicemailNotificationPreference.setOnPreferenceClickListener(
@@ -106,81 +261,14 @@
           @Override
           public boolean onPreferenceClick(Preference preference) {
             Logger.get(getContext())
-                .logImpression(DialerImpression.Type.VVM_CHANGE_RINGTONE_CLICKED);
+                .logImpression(DialerImpression.Type.VVM_NOTIFICATIONS_SETTING_CLICKED);
             // Let the preference handle the click.
             return false;
           }
         });
+  }
 
-    voicemailVisualVoicemail =
-        (SwitchPreference) findPreference(getString(R.string.voicemail_visual_voicemail_key));
-
-    autoArchiveSwitchPreference =
-        (SwitchPreference)
-            findPreference(getString(R.string.voicemail_visual_voicemail_archive_key));
-
-    donateVoicemailSwitchPreference =
-        (SwitchPreference)
-            findPreference(getString(R.string.voicemail_visual_voicemail_donation_key));
-
-    if (!VoicemailComponent.get(getContext())
-        .getVoicemailClient()
-        .isVoicemailArchiveAvailable(getContext())) {
-      getPreferenceScreen().removePreference(autoArchiveSwitchPreference);
-    }
-
-    if (!VoicemailComponent.get(getContext())
-        .getVoicemailClient()
-        .isVoicemailDonationAvailable(getContext())) {
-      getPreferenceScreen().removePreference(donateVoicemailSwitchPreference);
-    }
-
-    voicemailChangePinPreference = findPreference(getString(R.string.voicemail_change_pin_key));
-
-    if (voicemailClient.hasCarrierSupport(getContext(), phoneAccountHandle)) {
-      Assert.isNotNull(phoneAccountHandle);
-      Intent changePinIntent =
-          new Intent(new Intent(getContext(), VoicemailChangePinActivity.class));
-      changePinIntent.putExtra(VoicemailClient.PARAM_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
-
-      voicemailChangePinPreference.setIntent(changePinIntent);
-      voicemailChangePinPreference.setOnPreferenceClickListener(
-          new OnPreferenceClickListener() {
-            @Override
-            public boolean onPreferenceClick(Preference preference) {
-              Logger.get(getContext()).logImpression(DialerImpression.Type.VVM_CHANGE_PIN_CLICKED);
-              // Let the preference handle the click.
-              return false;
-            }
-          });
-      if (VoicemailChangePinActivity.isPinScrambled(getContext(), phoneAccountHandle)) {
-        voicemailChangePinPreference.setTitle(R.string.voicemail_set_pin_preference_title);
-      } else {
-        voicemailChangePinPreference.setTitle(R.string.voicemail_change_pin_preference_title);
-      }
-      updateChangePin();
-
-      voicemailVisualVoicemail.setOnPreferenceChangeListener(this);
-      voicemailVisualVoicemail.setChecked(
-          voicemailClient.isVoicemailEnabled(getContext(), phoneAccountHandle));
-
-      autoArchiveSwitchPreference.setOnPreferenceChangeListener(this);
-      autoArchiveSwitchPreference.setChecked(
-          voicemailClient.isVoicemailArchiveEnabled(getContext(), phoneAccountHandle));
-
-      donateVoicemailSwitchPreference.setOnPreferenceChangeListener(this);
-      donateVoicemailSwitchPreference.setChecked(
-          voicemailClient.isVoicemailDonationEnabled(getContext(), phoneAccountHandle));
-      updateDonateVoicemail();
-    } else {
-      prefSet.removePreference(voicemailVisualVoicemail);
-      prefSet.removePreference(autoArchiveSwitchPreference);
-      prefSet.removePreference(donateVoicemailSwitchPreference);
-      prefSet.removePreference(voicemailChangePinPreference);
-    }
-
-    advancedSettings =
-        (PreferenceScreen) findPreference(getString(R.string.voicemail_advanced_settings_key));
+  private void setupAdvancedSettingsPreference() {
     Intent advancedSettingsIntent = new Intent(TelephonyManager.ACTION_CONFIGURE_VOICEMAIL);
     advancedSettingsIntent.putExtra(TelephonyManager.EXTRA_HIDE_PUBLIC_SETTINGS, true);
     advancedSettingsIntent.putExtra(
@@ -198,8 +286,9 @@
       }
     }
 
-    advancedSettings.setIntent(advancedSettingsIntent);
-    voicemailChangePinPreference.setOnPreferenceClickListener(
+    advancedSettingsPreference.setIntent(advancedSettingsIntent);
+
+    advancedSettingsPreference.setOnPreferenceClickListener(
         new OnPreferenceClickListener() {
           @Override
           public boolean onPreferenceClick(Preference preference) {
@@ -226,7 +315,7 @@
   @Override
   public boolean onPreferenceChange(Preference preference, Object objValue) {
     LogUtil.d(TAG, "onPreferenceChange: \"" + preference + "\" changed to \"" + objValue + "\"");
-    if (preference.getKey().equals(voicemailVisualVoicemail.getKey())) {
+    if (preference.getKey().equals(visualVoicemailPreference.getKey())) {
       boolean isEnabled = (boolean) objValue;
       if (!isEnabled) {
         showDisableConfirmationDialog();
@@ -235,12 +324,17 @@
       } else {
         updateVoicemailEnabled(true);
       }
-    } else if (preference.getKey().equals(autoArchiveSwitchPreference.getKey())) {
+    } else if (preference.getKey().equals(voicemailAutoArchivePreference.getKey())) {
       logArchiveToggle((boolean) objValue);
       voicemailClient.setVoicemailArchiveEnabled(
           getContext(), phoneAccountHandle, (boolean) objValue);
-    } else if (preference.getKey().equals(donateVoicemailSwitchPreference.getKey())) {
-      logArchiveToggle((boolean) objValue);
+    } else if (preference.getKey().equals(transcribeVoicemailPreference.getKey())) {
+      logTranscribeToggle((boolean) objValue);
+      voicemailClient.setVoicemailTranscriptionEnabled(
+          getContext(), phoneAccountHandle, (boolean) objValue);
+      updateTranscriptionDonationPreference();
+    } else if (preference.getKey().equals(donateTranscribedVoicemailPreference.getKey())) {
+      logDonationToggle((boolean) objValue);
       voicemailClient.setVoicemailDonationEnabled(
           getContext(), phoneAccountHandle, (boolean) objValue);
     }
@@ -251,19 +345,19 @@
 
   private void updateVoicemailEnabled(boolean isEnabled) {
     voicemailClient.setVoicemailEnabled(getContext(), phoneAccountHandle, isEnabled);
-    voicemailVisualVoicemail.setChecked(isEnabled);
+    visualVoicemailPreference.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();
+    updateVoicemailSummaryMessage();
+    updateTranscriptionPreferences();
+    updateChangePinPreference();
   }
 
-  private void updateChangePin() {
+  private void updateChangePinPreference() {
     if (!voicemailClient.isVoicemailEnabled(getContext(), phoneAccountHandle)) {
       voicemailChangePinPreference.setSummary(
           R.string.voicemail_change_pin_preference_summary_disable);
@@ -278,21 +372,6 @@
     }
   }
 
-  private void updateDonateVoicemail() {
-    if (!voicemailClient.isVoicemailEnabled(getContext(), phoneAccountHandle)) {
-      donateVoicemailSwitchPreference.setSummary(
-          R.string.voicemail_donate_preference_summary_disable);
-      donateVoicemailSwitchPreference.setEnabled(false);
-    } else if (!voicemailClient.isActivated(getContext(), phoneAccountHandle)) {
-      donateVoicemailSwitchPreference.setSummary(
-          R.string.voicemail_donate_preference_summary_not_activated);
-      donateVoicemailSwitchPreference.setEnabled(false);
-    } else {
-      donateVoicemailSwitchPreference.setSummary(R.string.voicemail_donate_preference_summary_info);
-      donateVoicemailSwitchPreference.setEnabled(true);
-    }
-  }
-
   private void logArchiveToggle(boolean userTurnedOn) {
     if (userTurnedOn) {
       Logger.get(getContext())
@@ -303,11 +382,45 @@
     }
   }
 
+  private void logTranscribeToggle(boolean userTurnedOn) {
+    if (userTurnedOn) {
+      Logger.get(getContext())
+          .logImpression(DialerImpression.Type.VVM_USER_TURNED_TRANSCRIBE_ON_FROM_SETTINGS);
+    } else {
+      Logger.get(getContext())
+          .logImpression(DialerImpression.Type.VVM_USER_TURNED_TRANSCRIBE_OFF_FROM_SETTINGS);
+    }
+  }
+
+  private void logDonationToggle(boolean userTurnedOn) {
+    if (userTurnedOn) {
+      Logger.get(getContext())
+          .logImpression(DialerImpression.Type.VVM_USER_TURNED_TRANSCRIBE_ON_FROM_SETTINGS);
+    } else {
+      Logger.get(getContext())
+          .logImpression(DialerImpression.Type.VVM_USER_TURNED_TRANSCRIBE_OFF_FROM_SETTINGS);
+    }
+  }
+
   @Override
   public void onActivationStateChanged(PhoneAccountHandle phoneAccountHandle, boolean isActivated) {
     if (this.phoneAccountHandle.equals(phoneAccountHandle)) {
-      updateChangePin();
-      updateDonateVoicemail();
+      updateVoicemailSummaryMessage();
+      updateTranscriptionPreferences();
+      updateChangePinPreference();
+    }
+  }
+
+  /**
+   * Shows the activating message while visual voicemail is being activated. This is useful, since
+   * some toggles do not show up, until voicemail is activated e.g transcription and rating.
+   */
+  private void updateVoicemailSummaryMessage() {
+    if (voicemailClient.isVoicemailEnabled(getContext(), phoneAccountHandle)
+        && !voicemailClient.isActivated(getContext(), phoneAccountHandle)) {
+      visualVoicemailPreference.setSummary(R.string.voicemail_activating_summary_info);
+    } else {
+      visualVoicemailPreference.setSummary("");
     }
   }
 
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 1d2c104..db63098 100644
--- a/java/com/android/dialer/voicemail/settings/res/values/strings.xml
+++ b/java/com/android/dialer/voicemail/settings/res/values/strings.xml
@@ -102,19 +102,24 @@
   <!-- The error message to show if the server reported an error while attempting to change the voicemail PIN -->
   <string name="change_pin_system_error">Unable to set PIN</string>
 
+  <string name="voicemail_visual_voicemail_transcription_key" translatable="false">transcribe_voicemails</string>
   <string name="voicemail_visual_voicemail_donation_key" translatable="false">donate_voicemails</string>
 
+  <!-- Title for visual voicemail setting that enables users voicemails to be transcribed by Google.
+       [CHAR LIMIT=40] -->
+  <string name="voicemail_visual_voicemail_transcription_switch_title">
+    Voicemail transcription
+  </string>
   <!-- Title for visual voicemail setting that enables user to donate their voicemails for analysis.
        [CHAR LIMIT=40] -->
   <string name="voicemail_visual_voicemail_donation_switch_title">
     Voicemail transcription analysis
   </string>
-  <!-- Summary information for visual voicemail donation setting when visual voicemail is not enabled
-       [CHAR LIMIT=NONE] -->
-  <string name="voicemail_donate_preference_summary_disable">Visual voicemail must be enabled to donate voicemails</string>
-  <!-- Summary information for visual voicemail donation setting when visual voicemail is not activated
-       [CHAR LIMIT=NONE] -->
-  <string name="voicemail_donate_preference_summary_not_activated">Visual voicemail is not activated yet, please try again later</string>
+  <!-- Summary information while visual voicemail is activating after turning it on [CHAR LIMIT=NONE] -->
+  <string name="voicemail_activating_summary_info">Activating voicemail</string>
+
+  <!-- Summary information for visual voicemail transcription setting [CHAR LIMIT=NONE] -->
+  <string name="voicemail_transcription_preference_summary_info">Get transcripts of your voicemail using Google\'s transcription service</string>
   <!-- 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 accuracy</string>
 
@@ -125,7 +130,7 @@
   <!-- The label for the confirm-disable-voicemail button [CHAR LIMIT=16] -->
   <string name="confirm_disable_voicemail_accept_dialog_label">TURN OFF</string>
 
-  <string translatable="false" name="transcription_learn_more_url">https://support.google.com/phoneapp/answer/2811844?hl=en%26ref_topic=7539039</string>
-  <string translatable="false" name="donation_learn_more_url">https://support.google.com/phoneapp/answer/2811844#voicemail_transcript</string>
+  <string name="transcription_learn_more_url" translatable="false">https://support.google.com/phoneapp/answer/2811844?hl=en%26ref_topic=7539039</string>
+  <string name="donation_learn_more_url" translatable="false">https://support.google.com/phoneapp/answer/2811844#voicemail_transcript</string>
 
 </resources>
diff --git a/java/com/android/dialer/voicemail/settings/res/xml/voicemail_settings.xml b/java/com/android/dialer/voicemail/settings/res/xml/voicemail_settings.xml
index e558985..175a127 100644
--- a/java/com/android/dialer/voicemail/settings/res/xml/voicemail_settings.xml
+++ b/java/com/android/dialer/voicemail/settings/res/xml/voicemail_settings.xml
@@ -31,8 +31,12 @@
     android:title="@string/voicemail_visual_voicemail_auto_archive_switch_title"/>"
 
   <SwitchPreference
+      android:key="@string/voicemail_visual_voicemail_transcription_key"
+      android:dependency="@string/voicemail_visual_voicemail_key"
+      android:title="@string/voicemail_visual_voicemail_transcription_switch_title"/>"
+  <SwitchPreference
     android:key="@string/voicemail_visual_voicemail_donation_key"
-    android:dependency="@string/voicemail_visual_voicemail_key"
+    android:dependency="@string/voicemail_visual_voicemail_transcription_key"
     android:title="@string/voicemail_visual_voicemail_donation_switch_title"/>"
 
   <Preference
diff --git a/java/com/android/voicemail/VoicemailClient.java b/java/com/android/voicemail/VoicemailClient.java
index 1ce7ef7..5b382f1 100644
--- a/java/com/android/voicemail/VoicemailClient.java
+++ b/java/com/android/voicemail/VoicemailClient.java
@@ -30,35 +30,25 @@
 public interface VoicemailClient {
 
   /**
-   * Whether the voicemail module is enabled (OS has support and not disabled by flags, etc.). This
-   * does not mean the carrier has support or user has enabled the feature.
-   */
-  boolean isVoicemailModuleEnabled();
-
-  /**
    * Broadcast to tell the client to upload local database changes to the server. Since the dialer
    * UI and the client are in the same package, the {@link
    * android.content.Intent#ACTION_PROVIDER_CHANGED} will always be a self-change even if the UI is
    * external to the client.
    */
   String ACTION_UPLOAD = "com.android.voicemail.VoicemailClient.ACTION_UPLOAD";
-
   /** Common key for passing {@link PhoneAccountHandle} in bundles. */
   String PARAM_PHONE_ACCOUNT_HANDLE = "phone_account_handle";
-
   /**
    * Broadcast from the client to inform the app to show a legacy voicemail notification. This
    * broadcast is same as {@link TelephonyManager#ACTION_SHOW_VOICEMAIL_NOTIFICATION}.
    */
   String ACTION_SHOW_LEGACY_VOICEMAIL =
       "com.android.voicemail.VoicemailClient.ACTION_SHOW_LEGACY_VOICEMAIL";
-
   /**
    * Boolean extra send with {@link #ACTION_SHOW_LEGACY_VOICEMAIL}, indicating that the notification
    * is sent by legacy mode and should not be suppressed even when VVM is activated
    */
   String EXTRA_IS_LEGACY_MODE = "is_legacy_mode";
-
   /**
    * Secret code to launch the voicemail config activity intended for OEMs and Carriers. {@code
    * *#*#VVMCONFIG#*#*}
@@ -66,6 +56,12 @@
   String VOICEMAIL_SECRET_CODE = "886266344";
 
   /**
+   * Whether the voicemail module is enabled (OS has support and not disabled by flags, etc.). This
+   * does not mean the carrier has support or user has enabled the feature.
+   */
+  boolean isVoicemailModuleEnabled();
+
+  /**
    * Whether visual voicemail is supported by the carrier for the {@code phoneAccountHandle}. This
    * is purely based on the MCCMNC, and a single account might still be disabled by the carrier.
    */
@@ -123,17 +119,23 @@
 
   /**
    * @return if the voicemail transcription feature is available on the current device. This depends
-   *     on whether the server side flag is turned on for the feature, and if the OS meets the
-   *     requirement for this feature.
+   *     on whether the server side flag is turned on for the feature, visual voicemail is activated
+   *     and enabled and if the OS meets the requirement for this feature.
    */
-  boolean isVoicemailTranscriptionAvailable(Context context);
+  boolean isVoicemailTranscriptionAvailable(Context context, PhoneAccountHandle account);
+
+  /** @return if the voicemail transcription setting has been enabled by the user. */
+  boolean isVoicemailTranscriptionEnabled(Context context, PhoneAccountHandle account);
 
   /** @return if the voicemail donation feature is available. */
-  boolean isVoicemailDonationAvailable(Context context);
+  boolean isVoicemailDonationAvailable(Context context, PhoneAccountHandle account);
 
   /** @return if the voicemail donation setting has been enabled by the user. */
   boolean isVoicemailDonationEnabled(Context context, PhoneAccountHandle account);
 
+  void setVoicemailTranscriptionEnabled(
+      Context context, PhoneAccountHandle phoneAccountHandle, boolean enabled);
+
   void setVoicemailDonationEnabled(
       Context context, PhoneAccountHandle phoneAccountHandle, boolean enabled);
 
@@ -162,12 +164,6 @@
   @MainThread
   void onShutdown(@NonNull Context context);
 
-  /** Listener for changes in {@link #isActivated(Context, PhoneAccountHandle)} */
-  interface ActivationStateListener {
-    @MainThread
-    void onActivationStateChanged(PhoneAccountHandle phoneAccountHandle, boolean isActivated);
-  }
-
   @MainThread
   void addActivationStateListener(ActivationStateListener listener);
 
@@ -187,4 +183,10 @@
    */
   @Nullable
   String getCarrierConfigString(Context context, PhoneAccountHandle phoneAccountHandle, String key);
+
+  /** Listener for changes in {@link #isActivated(Context, PhoneAccountHandle)} */
+  interface ActivationStateListener {
+    @MainThread
+    void onActivationStateChanged(PhoneAccountHandle phoneAccountHandle, boolean isActivated);
+  }
 }
diff --git a/java/com/android/voicemail/impl/VoicemailClientImpl.java b/java/com/android/voicemail/impl/VoicemailClientImpl.java
index 993594e..b0881c9 100644
--- a/java/com/android/voicemail/impl/VoicemailClientImpl.java
+++ b/java/com/android/voicemail/impl/VoicemailClientImpl.java
@@ -123,13 +123,28 @@
   }
 
   @Override
-  public boolean isVoicemailTranscriptionAvailable(Context context) {
+  public boolean isVoicemailTranscriptionAvailable(
+      Context context, PhoneAccountHandle phoneAccountHandle) {
     if (!BuildCompat.isAtLeastO()) {
       LogUtil.i(
           "VoicemailClientImpl.isVoicemailTranscriptionAvailable", "not running on O or later");
       return false;
     }
 
+    if (!isVoicemailEnabled(context, phoneAccountHandle)) {
+      LogUtil.i(
+          "VoicemailClientImpl.isVoicemailTranscriptionAvailable",
+          "visual voicemail is not enabled");
+      return false;
+    }
+
+    if (!isActivated(context, phoneAccountHandle)) {
+      LogUtil.i(
+          "VoicemailClientImpl.isVoicemailTranscriptionAvailable",
+          "visual voicemail is not activated");
+      return false;
+    }
+
     TranscriptionConfigProvider provider = new TranscriptionConfigProvider(context);
     if (!provider.isVoicemailTranscriptionAvailable()) {
       LogUtil.i(
@@ -141,12 +156,24 @@
   }
 
   @Override
-  public boolean isVoicemailDonationAvailable(Context context) {
-    if (!isVoicemailTranscriptionAvailable(context)) {
+  public boolean isVoicemailTranscriptionEnabled(Context context, PhoneAccountHandle account) {
+    return isVoicemailTranscriptionAvailable(context, account)
+        && VisualVoicemailSettingsUtil.isVoicemailTranscriptionEnabled(context, account);
+  }
+
+  @Override
+  public boolean isVoicemailDonationAvailable(
+      Context context, PhoneAccountHandle phoneAccountHandle) {
+    if (!isVoicemailTranscriptionAvailable(context, phoneAccountHandle)) {
       LogUtil.i("VoicemailClientImpl.isVoicemailDonationAvailable", "transcription not available");
       return false;
     }
 
+    if (!isVoicemailTranscriptionEnabled(context, phoneAccountHandle)) {
+      LogUtil.i("VoicemailClientImpl.isVoicemailDonationAvailable", "transcription not enabled");
+      return false;
+    }
+
     TranscriptionConfigProvider provider = new TranscriptionConfigProvider(context);
     if (!provider.isVoicemailDonationAvailable()) {
       LogUtil.i("VoicemailClientImpl.isVoicemailDonationAvailable", "feature disabled by config");
@@ -158,13 +185,34 @@
 
   @Override
   public boolean isVoicemailDonationEnabled(Context context, PhoneAccountHandle account) {
-    return isVoicemailTranscriptionAvailable(context)
+    return isVoicemailTranscriptionEnabled(context, account)
+        && isVoicemailDonationAvailable(context, account)
         && VisualVoicemailSettingsUtil.isVoicemailDonationEnabled(context, account);
   }
 
   @Override
+  public void setVoicemailTranscriptionEnabled(
+      Context context, PhoneAccountHandle phoneAccountHandle, boolean enabled) {
+    Assert.checkArgument(
+        isVoicemailTranscriptionAvailable(context, phoneAccountHandle),
+        "transcription must be available before enabling/disabling it");
+    VisualVoicemailSettingsUtil.setVoicemailTranscriptionEnabled(
+        context, phoneAccountHandle, enabled);
+  }
+
+  @Override
   public void setVoicemailDonationEnabled(
       Context context, PhoneAccountHandle phoneAccountHandle, boolean enabled) {
+    if (enabled) {
+      Assert.checkArgument(
+          isVoicemailTranscriptionAvailable(context, phoneAccountHandle)
+              && isVoicemailTranscriptionEnabled(context, phoneAccountHandle),
+          "should not be able to enable donation without transcription "
+              + "available(value: %b) and enabled (value:%b) for account:%s",
+          isVoicemailTranscriptionAvailable(context, phoneAccountHandle),
+          isVoicemailTranscriptionEnabled(context, phoneAccountHandle),
+          phoneAccountHandle.toString());
+    }
     VisualVoicemailSettingsUtil.setVoicemailDonationEnabled(context, phoneAccountHandle, enabled);
   }
 
diff --git a/java/com/android/voicemail/impl/settings/VisualVoicemailSettingsUtil.java b/java/com/android/voicemail/impl/settings/VisualVoicemailSettingsUtil.java
index e42d569..3e00698 100644
--- a/java/com/android/voicemail/impl/settings/VisualVoicemailSettingsUtil.java
+++ b/java/com/android/voicemail/impl/settings/VisualVoicemailSettingsUtil.java
@@ -33,6 +33,7 @@
 
   @VisibleForTesting public static final String IS_ENABLED_KEY = "is_enabled";
   private static final String ARCHIVE_ENABLED_KEY = "archive_is_enabled";
+  private static final String TRANSCRIBE_VOICEMAILS_KEY = "transcribe_voicemails";
   private static final String DONATE_VOICEMAILS_KEY = "donate_voicemails";
 
   public static void setEnabled(
@@ -59,21 +60,6 @@
     }
   }
 
-  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");
   }
@@ -92,12 +78,24 @@
         .apply();
   }
 
+  public static void setVoicemailTranscriptionEnabled(
+      Context context, PhoneAccountHandle phoneAccount, boolean isEnabled) {
+    Assert.checkArgument(
+        VoicemailComponent.get(context)
+            .getVoicemailClient()
+            .isVoicemailTranscriptionAvailable(context, phoneAccount));
+    new VisualVoicemailPreferences(context, phoneAccount)
+        .edit()
+        .putBoolean(TRANSCRIBE_VOICEMAILS_KEY, isEnabled)
+        .apply();
+  }
+
   public static void setVoicemailDonationEnabled(
       Context context, PhoneAccountHandle phoneAccount, boolean isEnabled) {
     Assert.checkArgument(
         VoicemailComponent.get(context)
             .getVoicemailClient()
-            .isVoicemailTranscriptionAvailable(context));
+            .isVoicemailTranscriptionAvailable(context, phoneAccount));
     new VisualVoicemailPreferences(context, phoneAccount)
         .edit()
         .putBoolean(DONATE_VOICEMAILS_KEY, isEnabled)
@@ -125,6 +123,14 @@
     return prefs.getBoolean(ARCHIVE_ENABLED_KEY, false);
   }
 
+  public static boolean isVoicemailTranscriptionEnabled(
+      Context context, PhoneAccountHandle phoneAccount) {
+    Assert.isNotNull(phoneAccount);
+
+    VisualVoicemailPreferences prefs = new VisualVoicemailPreferences(context, phoneAccount);
+    return prefs.getBoolean(TRANSCRIBE_VOICEMAILS_KEY, false);
+  }
+
   public static boolean isVoicemailDonationEnabled(
       Context context, PhoneAccountHandle phoneAccount) {
     Assert.isNotNull(phoneAccount);
@@ -146,4 +152,19 @@
     VisualVoicemailPreferences prefs = new VisualVoicemailPreferences(context, phoneAccount);
     return prefs.contains(IS_ENABLED_KEY);
   }
+
+  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;
+    }
+  }
 }
diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionService.java b/java/com/android/voicemail/impl/transcribe/TranscriptionService.java
index c206c08..781e347 100644
--- a/java/com/android/voicemail/impl/transcribe/TranscriptionService.java
+++ b/java/com/android/voicemail/impl/transcribe/TranscriptionService.java
@@ -98,6 +98,10 @@
       return false;
     }
     VoicemailClient client = VoicemailComponent.get(context).getVoicemailClient();
+    if (!client.isVoicemailTranscriptionEnabled(context, account)) {
+      LogUtil.i("TranscriptionService.canTranscribeVoicemail", "transcription is not enabled");
+      return false;
+    }
     if (!client.hasAcceptedTos(context, account)) {
       LogUtil.i("TranscriptionService.canTranscribeVoicemail", "hasn't accepted TOS");
       return false;
diff --git a/java/com/android/voicemail/stub/StubVoicemailClient.java b/java/com/android/voicemail/stub/StubVoicemailClient.java
index 2b02261..0a1d553 100644
--- a/java/com/android/voicemail/stub/StubVoicemailClient.java
+++ b/java/com/android/voicemail/stub/StubVoicemailClient.java
@@ -71,12 +71,18 @@
       Context context, PhoneAccountHandle phoneAccountHandle, boolean value) {}
 
   @Override
-  public boolean isVoicemailTranscriptionAvailable(Context context) {
+  public boolean isVoicemailTranscriptionAvailable(
+      Context context, PhoneAccountHandle phoneAccountHandle) {
     return false;
   }
 
   @Override
-  public boolean isVoicemailDonationAvailable(Context context) {
+  public boolean isVoicemailTranscriptionEnabled(Context context, PhoneAccountHandle account) {
+    return false;
+  }
+
+  @Override
+  public boolean isVoicemailDonationAvailable(Context context, PhoneAccountHandle account) {
     return false;
   }
 
@@ -86,6 +92,10 @@
   }
 
   @Override
+  public void setVoicemailTranscriptionEnabled(
+      Context context, PhoneAccountHandle phoneAccountHandle, boolean enabled) {}
+
+  @Override
   public void setVoicemailDonationEnabled(
       Context context, PhoneAccountHandle phoneAccountHandle, boolean enabled) {}