Refactoring and adding TOS check before transcribing

This cl just adds a check before starting a transcription job
to verify that the user has accepted the appropriate TOS. Its
a rather big cl just because it had to expose some TOS acceptance
details that were previously encapsulated in the VoicemailTosMessageCreator.

Bug: 69267260
Test: manual and unit tests
PiperOrigin-RevId: 176132370
Change-Id: Ic28fb197a07f9df7a9b5f1729c84566cba0890fc
diff --git a/java/com/android/voicemail/VoicemailClient.java b/java/com/android/voicemail/VoicemailClient.java
index db5d745..1ce7ef7 100644
--- a/java/com/android/voicemail/VoicemailClient.java
+++ b/java/com/android/voicemail/VoicemailClient.java
@@ -179,6 +179,8 @@
 
   void onTosAccepted(Context context, PhoneAccountHandle phoneAccountHandle);
 
+  boolean hasAcceptedTos(Context context, PhoneAccountHandle phoneAccountHandle);
+
   /**
    * @return arbitrary carrier configuration String value associate with the indicated key. See
    *     {@code CarrierConfigKeys.java}
diff --git a/java/com/android/voicemail/VoicemailVersionConstants.java b/java/com/android/voicemail/VoicemailVersionConstants.java
new file mode 100644
index 0000000..44ef661
--- /dev/null
+++ b/java/com/android/voicemail/VoicemailVersionConstants.java
@@ -0,0 +1,38 @@
+/*
+ * 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;
+
+/**
+ * Shared preference keys and values relating to the voicemail version that the user has accepted.
+ * Note: these can be carrier dependent.
+ */
+public interface VoicemailVersionConstants {
+  // Preference key to check which version of the Verizon ToS that the user has accepted.
+  String PREF_VVM3_TOS_VERSION_ACCEPTED_KEY = "vvm3_tos_version_accepted";
+
+  // Preference key to check which version of the Google Dialer ToS that the user has accepted.
+  String PREF_DIALER_TOS_VERSION_ACCEPTED_KEY = "dialer_tos_version_accepted";
+
+  // Preference key to check which feature version the user has acknowledged
+  String PREF_DIALER_FEATURE_VERSION_ACKNOWLEDGED_KEY = "dialer_feature_version_acknowledged";
+
+  int CURRENT_VVM3_TOS_VERSION = 2;
+  int CURRENT_DIALER_TOS_VERSION = 1;
+  int LEGACY_VOICEMAIL_FEATURE_VERSION = 1; // original visual voicemail
+  int TRANSCRIPTION_VOICEMAIL_FEATURE_VERSION = 2;
+  int CURRENT_VOICEMAIL_FEATURE_VERSION = TRANSCRIPTION_VOICEMAIL_FEATURE_VERSION;
+}
diff --git a/java/com/android/voicemail/impl/PackageReplacedReceiver.java b/java/com/android/voicemail/impl/PackageReplacedReceiver.java
index 6a7ca4a..bc56286 100644
--- a/java/com/android/voicemail/impl/PackageReplacedReceiver.java
+++ b/java/com/android/voicemail/impl/PackageReplacedReceiver.java
@@ -16,14 +16,27 @@
 
 package com.android.voicemail.impl;
 
+import android.annotation.TargetApi;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.net.Uri;
+import android.preference.PreferenceManager;
+import android.provider.CallLog.Calls;
+import android.provider.VoicemailContract.Voicemails;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
+import com.android.dialer.common.LogUtil;
+import com.android.dialer.common.concurrent.DialerExecutor.Worker;
+import com.android.dialer.common.concurrent.DialerExecutorComponent;
 import com.android.voicemail.VoicemailComponent;
+import com.android.voicemail.VoicemailVersionConstants;
 
-/** Receives MY_PACKAGE_REPLACED to trigger VVM activation. */
+/**
+ * Receives MY_PACKAGE_REPLACED to trigger VVM activation and to check for legacy voicemail users.
+ */
 public class PackageReplacedReceiver extends BroadcastReceiver {
 
   @Override
@@ -39,5 +52,74 @@
         context.getSystemService(TelecomManager.class).getCallCapablePhoneAccounts()) {
       ActivationTask.start(context, phoneAccountHandle, null);
     }
+
+    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+    if (!prefs.contains(VoicemailVersionConstants.PREF_DIALER_FEATURE_VERSION_ACKNOWLEDGED_KEY)) {
+      setVoicemailFeatureVersionAsync(context);
+    }
+  }
+
+  private void setVoicemailFeatureVersionAsync(Context context) {
+    LogUtil.enterBlock("PackageReplacedReceiver.setVoicemailFeatureVersionAsync");
+
+    // Check if user is already using voicemail (ie do they have any voicemails), and set the
+    // acknowledged feature value accordingly.
+    PendingResult pendingResult = goAsync();
+    DialerExecutorComponent.get(context)
+        .dialerExecutorFactory()
+        .createNonUiTaskBuilder(new ExistingVoicemailCheck(context))
+        .onSuccess(
+            output -> {
+              LogUtil.i("PackageReplacedReceiver.setVoicemailFeatureVersionAsync", "success");
+              pendingResult.finish();
+            })
+        .onFailure(
+            throwable -> {
+              LogUtil.i("PackageReplacedReceiver.setVoicemailFeatureVersionAsync", "failure");
+              pendingResult.finish();
+            })
+        .build()
+        .executeParallel(null);
+  }
+
+  private static class ExistingVoicemailCheck implements Worker<Void, Void> {
+    private static final String[] PROJECTION = new String[] {Voicemails._ID};
+
+    private final Context context;
+
+    ExistingVoicemailCheck(Context context) {
+      this.context = context;
+    }
+
+    @TargetApi(android.os.Build.VERSION_CODES.M) // used for try with resources
+    @Override
+    public Void doInBackground(Void arg) throws Throwable {
+      LogUtil.i("PackageReplacedReceiver.ExistingVoicemailCheck.doInBackground", "");
+
+      // Check the database for existing voicemails.
+      boolean hasVoicemails = false;
+      Uri uri = Voicemails.buildSourceUri(context.getPackageName());
+      String whereClause = Calls.TYPE + " = " + Calls.VOICEMAIL_TYPE;
+      try (Cursor cursor =
+          context.getContentResolver().query(uri, PROJECTION, whereClause, null, null)) {
+        if (cursor == null) {
+          LogUtil.e(
+              "PackageReplacedReceiver.ExistingVoicemailCheck.doInBackground",
+              "failed to check for existing voicemails");
+        } else if (cursor.moveToFirst()) {
+          hasVoicemails = true;
+        }
+      }
+
+      LogUtil.i(
+          "PackageReplacedReceiver.ExistingVoicemailCheck.doInBackground",
+          "has voicemails: " + hasVoicemails);
+      int version = hasVoicemails ? VoicemailVersionConstants.LEGACY_VOICEMAIL_FEATURE_VERSION : 0;
+      PreferenceManager.getDefaultSharedPreferences(context)
+          .edit()
+          .putInt(VoicemailVersionConstants.PREF_DIALER_FEATURE_VERSION_ACKNOWLEDGED_KEY, version)
+          .apply();
+      return null;
+    }
   }
 }
diff --git a/java/com/android/voicemail/impl/VoicemailClientImpl.java b/java/com/android/voicemail/impl/VoicemailClientImpl.java
index 3305438..60fc806 100644
--- a/java/com/android/voicemail/impl/VoicemailClientImpl.java
+++ b/java/com/android/voicemail/impl/VoicemailClientImpl.java
@@ -16,8 +16,10 @@
 import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.os.Build.VERSION_CODES;
 import android.os.PersistableBundle;
+import android.preference.PreferenceManager;
 import android.provider.VoicemailContract.Status;
 import android.provider.VoicemailContract.Voicemails;
 import android.support.annotation.MainThread;
@@ -32,6 +34,7 @@
 import com.android.voicemail.PinChanger;
 import com.android.voicemail.VisualVoicemailTypeExtensions;
 import com.android.voicemail.VoicemailClient;
+import com.android.voicemail.VoicemailVersionConstants;
 import com.android.voicemail.impl.configui.VoicemailSecretCodeActivity;
 import com.android.voicemail.impl.settings.VisualVoicemailSettingsUtil;
 import com.android.voicemail.impl.sync.VvmAccountManager;
@@ -292,6 +295,21 @@
   }
 
   @Override
+  public boolean hasAcceptedTos(Context context, PhoneAccountHandle phoneAccountHandle) {
+    SharedPreferences preferences =
+        PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
+    OmtpVvmCarrierConfigHelper helper = new OmtpVvmCarrierConfigHelper(context, phoneAccountHandle);
+    boolean isVvm3 = VisualVoicemailTypeExtensions.VVM_TYPE_VVM3.equals(helper.getVvmType());
+    if (isVvm3) {
+      return preferences.getInt(VoicemailVersionConstants.PREF_VVM3_TOS_VERSION_ACCEPTED_KEY, 0)
+          >= VoicemailVersionConstants.CURRENT_VVM3_TOS_VERSION;
+    } else {
+      return preferences.getInt(VoicemailVersionConstants.PREF_DIALER_TOS_VERSION_ACCEPTED_KEY, 0)
+          >= VoicemailVersionConstants.CURRENT_DIALER_TOS_VERSION;
+    }
+  }
+
+  @Override
   @Nullable
   public String getCarrierConfigString(Context context, PhoneAccountHandle account, String key) {
     OmtpVvmCarrierConfigHelper helper = new OmtpVvmCarrierConfigHelper(context, account);
diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionService.java b/java/com/android/voicemail/impl/transcribe/TranscriptionService.java
index 33c9676..a19ab62 100644
--- a/java/com/android/voicemail/impl/transcribe/TranscriptionService.java
+++ b/java/com/android/voicemail/impl/transcribe/TranscriptionService.java
@@ -69,15 +69,7 @@
   public static boolean scheduleNewVoicemailTranscriptionJob(
       Context context, Uri voicemailUri, PhoneAccountHandle account, boolean highPriority) {
     Assert.isMainThread();
-    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
-      LogUtil.i(
-          "TranscriptionService.scheduleNewVoicemailTranscriptionJob", "not supported by sdk");
-      return false;
-    }
-    if (!carrierAllowsOttTranscription(context, account)) {
-      LogUtil.i(
-          "TranscriptionService.scheduleNewVoicemailTranscriptionJob",
-          "carrier doesn't allow transcription");
+    if (!canTranscribeVoicemail(context, account)) {
       return false;
     }
 
@@ -101,12 +93,24 @@
     return scheduler.enqueue(builder.build(), workItem) == JobScheduler.RESULT_SUCCESS;
   }
 
-  private static boolean carrierAllowsOttTranscription(
-      Context context, PhoneAccountHandle account) {
+  private static boolean canTranscribeVoicemail(Context context, PhoneAccountHandle account) {
+    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
+      LogUtil.i("TranscriptionService.canTranscribeVoicemail", "not supported by sdk");
+      return false;
+    }
     VoicemailClient client = VoicemailComponent.get(context).getVoicemailClient();
-    return Boolean.parseBoolean(
+    if (!client.hasAcceptedTos(context, account)) {
+      LogUtil.i("TranscriptionService.canTranscribeVoicemail", "hasn't accepted TOS");
+      return false;
+    }
+    if (!Boolean.parseBoolean(
         client.getCarrierConfigString(
-            context, account, CarrierConfigKeys.VVM_CARRIER_ALLOWS_OTT_TRANSCRIPTION_STRING));
+            context, account, CarrierConfigKeys.VVM_CARRIER_ALLOWS_OTT_TRANSCRIPTION_STRING))) {
+      LogUtil.i(
+          "TranscriptionService.canTranscribeVoicemail", "carrier doesn't allow transcription");
+      return false;
+    }
+    return true;
   }
 
   // Cancel all transcription tasks
diff --git a/java/com/android/voicemail/stub/StubVoicemailClient.java b/java/com/android/voicemail/stub/StubVoicemailClient.java
index cfbb3ec..3069ea4 100644
--- a/java/com/android/voicemail/stub/StubVoicemailClient.java
+++ b/java/com/android/voicemail/stub/StubVoicemailClient.java
@@ -133,6 +133,11 @@
   public void onTosAccepted(Context context, PhoneAccountHandle account) {}
 
   @Override
+  public boolean hasAcceptedTos(Context context, PhoneAccountHandle phoneAccountHandle) {
+    return false;
+  }
+
+  @Override
   @Nullable
   public String getCarrierConfigString(Context context, PhoneAccountHandle account, String key) {
     return null;