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/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) {}