Merge changes Icc92997c,I70c032fd,Ibafdaf5f,Ifd2efcc9,Iba5609ac

* changes:
  Fixing transcription crashes caused by job stoppage
  Strip trace info for release build.
  Load VVM config override before loading anything else
  Fix bubble crash when dismiss audio route selector dialog.
  Ignore read missed calls and voicemails for notification
diff --git a/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java b/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java
index 43e03e9..c749b65 100644
--- a/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java
+++ b/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java
@@ -298,7 +298,13 @@
             "no READ_CALL_LOG permission, returning null for calls lookup.");
         return null;
       }
-      final String selection = String.format("%s = 1 AND %s = ?", Calls.NEW, Calls.TYPE);
+      // A call is "new" when:
+      // NEW is 1. usually set when a new row is inserted
+      // TYPE matches the query type.
+      // IS_READ is not 1. A call might be backed up and restored, so it will be "new" to the
+      //   call log, but the user has already read it on another device.
+      final String selection =
+          String.format("%s = 1 AND %s = ? AND %s IS NOT 1", Calls.NEW, Calls.TYPE, Calls.IS_READ);
       final String[] selectionArgs = new String[] {Integer.toString(type)};
       try (Cursor cursor =
           mContentResolver.query(
diff --git a/java/com/android/dialer/logging/dialer_impression.proto b/java/com/android/dialer/logging/dialer_impression.proto
index ef249c2..94af6c3 100644
--- a/java/com/android/dialer/logging/dialer_impression.proto
+++ b/java/com/android/dialer/logging/dialer_impression.proto
@@ -530,5 +530,9 @@
     IN_CALL_DIALPAD_NUMBER_BUTTON_PRESSED = 1265;
     IN_CALL_DIALPAD_HANG_UP_BUTTON_PRESSED = 1266;
     IN_CALL_DIALPAD_CLOSE_BUTTON_PRESSED = 1267;
+
+    // More voicemail transcription impressions
+    VVM_TRANSCRIPTION_JOB_STOPPED = 1268;
+    VVM_TRANSCRIPTION_TASK_CANCELLED = 1269;
   }
 }
diff --git a/java/com/android/dialer/proguard/proguard_release.flags b/java/com/android/dialer/proguard/proguard_release.flags
index c6bdd49..1429740 100644
--- a/java/com/android/dialer/proguard/proguard_release.flags
+++ b/java/com/android/dialer/proguard/proguard_release.flags
@@ -22,3 +22,9 @@
   static *** v(...);
   static *** isLoggable(...);
 }
+
+# This allows proguard to strip Trace code from release builds.
+-assumenosideeffects class android.os.Trace {
+  static *** beginSection(...);
+  static *** endSection(...);
+}
diff --git a/java/com/android/incallui/AudioRouteSelectorActivity.java b/java/com/android/incallui/AudioRouteSelectorActivity.java
index dfd4d1a..f0ae79b 100644
--- a/java/com/android/incallui/AudioRouteSelectorActivity.java
+++ b/java/com/android/incallui/AudioRouteSelectorActivity.java
@@ -32,7 +32,7 @@
   protected void onCreate(@Nullable Bundle bundle) {
     super.onCreate(bundle);
     AudioRouteSelectorDialogFragment.newInstance(AudioModeProvider.getInstance().getAudioState())
-        .show(getSupportFragmentManager(), null);
+        .show(getSupportFragmentManager(), AudioRouteSelectorDialogFragment.TAG);
   }
 
   @Override
@@ -44,4 +44,20 @@
   public void onAudioRouteSelectorDismiss() {
     finish();
   }
+
+  @Override
+  protected void onPause() {
+    super.onPause();
+    AudioRouteSelectorDialogFragment audioRouteSelectorDialogFragment =
+        (AudioRouteSelectorDialogFragment)
+            getSupportFragmentManager().findFragmentByTag(AudioRouteSelectorDialogFragment.TAG);
+    // If Android back button is pressed, the fragment is dismissed and removed. If home button is
+    // pressed, we have to manually dismiss the fragment here. The fragment is also removed when
+    // dismissed.
+    if (audioRouteSelectorDialogFragment != null) {
+      audioRouteSelectorDialogFragment.dismiss();
+    }
+    // We don't expect the activity to resume
+    finish();
+  }
 }
diff --git a/java/com/android/incallui/audioroute/AudioRouteSelectorDialogFragment.java b/java/com/android/incallui/audioroute/AudioRouteSelectorDialogFragment.java
index c7a9d63..860d2d2 100644
--- a/java/com/android/incallui/audioroute/AudioRouteSelectorDialogFragment.java
+++ b/java/com/android/incallui/audioroute/AudioRouteSelectorDialogFragment.java
@@ -37,6 +37,7 @@
 /** Shows picker for audio routes */
 public class AudioRouteSelectorDialogFragment extends BottomSheetDialogFragment {
 
+  public static final String TAG = "AudioRouteSelectorDialogFragment";
   private static final String ARG_AUDIO_STATE = "audio_state";
 
   /** Called when an audio route is picked */
diff --git a/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java b/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java
index 700e1cb..90303f5 100644
--- a/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java
+++ b/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java
@@ -50,6 +50,8 @@
  * that may clutter CarrierConfigManager too much.
  *
  * <p>The current hidden configs are: {@link #getSslPort()} {@link #getDisabledCapabilities()}
+ *
+ * <p>TODO(twyen): refactor this to an interface.
  */
 @TargetApi(VERSION_CODES.O)
 public class OmtpVvmCarrierConfigHelper {
@@ -112,19 +114,19 @@
       return;
     }
 
-    mCarrierConfig = getCarrierConfig(telephonyManager);
-    mTelephonyConfig =
-        new TelephonyVvmConfigManager(context).getConfig(telephonyManager.getSimOperator());
-
-    mVvmType = getVvmType();
-    mProtocol = VisualVoicemailProtocolFactory.create(mContext.getResources(), mVvmType);
-
     if (ConfigOverrideFragment.isOverridden(context)) {
       mOverrideConfig = ConfigOverrideFragment.getConfig(context);
       VvmLog.w(TAG, "Config override is activated: " + mOverrideConfig);
     } else {
       mOverrideConfig = null;
     }
+
+    mCarrierConfig = getCarrierConfig(telephonyManager);
+    mTelephonyConfig =
+        new TelephonyVvmConfigManager(context).getConfig(telephonyManager.getSimOperator());
+
+    mVvmType = getVvmType();
+    mProtocol = VisualVoicemailProtocolFactory.create(mContext.getResources(), mVvmType);
   }
 
   @VisibleForTesting
@@ -187,7 +189,11 @@
   @Nullable
   public Set<String> getCarrierVvmPackageNames() {
     Assert.checkArgument(isValid());
-    Set<String> names = getCarrierVvmPackageNames(mCarrierConfig);
+    Set<String> names = getCarrierVvmPackageNames(mOverrideConfig);
+    if (names != null) {
+      return names;
+    }
+    names = getCarrierVvmPackageNames(mCarrierConfig);
     if (names != null) {
       return names;
     }
@@ -278,7 +284,12 @@
   @Nullable
   public Set<String> getDisabledCapabilities() {
     Assert.checkArgument(isValid());
-    Set<String> disabledCapabilities = getDisabledCapabilities(mCarrierConfig);
+    Set<String> disabledCapabilities;
+    disabledCapabilities = getDisabledCapabilities(mOverrideConfig);
+    if (disabledCapabilities != null) {
+      return disabledCapabilities;
+    }
+    disabledCapabilities = getDisabledCapabilities(mCarrierConfig);
     if (disabledCapabilities != null) {
       return disabledCapabilities;
     }
diff --git a/java/com/android/voicemail/impl/configui/ConfigOverrideFragment.java b/java/com/android/voicemail/impl/configui/ConfigOverrideFragment.java
index 1624ce5..caf33df 100644
--- a/java/com/android/voicemail/impl/configui/ConfigOverrideFragment.java
+++ b/java/com/android/voicemail/impl/configui/ConfigOverrideFragment.java
@@ -49,7 +49,8 @@
    * Any preference with key that starts with this prefix will be written to the dialer carrier
    * config.
    */
-  @VisibleForTesting static final String CONFIG_OVERRIDE_KEY_PREFIX = "vvm_config_override_key_";
+  @VisibleForTesting
+  public static final String CONFIG_OVERRIDE_KEY_PREFIX = "vvm_config_override_key_";
 
   @Override
   public void onCreate(@Nullable Bundle savedInstanceState) {
diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionService.java b/java/com/android/voicemail/impl/transcribe/TranscriptionService.java
index 2ca16fb..b733928 100644
--- a/java/com/android/voicemail/impl/transcribe/TranscriptionService.java
+++ b/java/com/android/voicemail/impl/transcribe/TranscriptionService.java
@@ -49,6 +49,8 @@
   private JobParameters jobParameters;
   private TranscriptionClientFactory clientFactory;
   private TranscriptionConfigProvider configProvider;
+  private TranscriptionTask activeTask;
+  private boolean stopped;
 
   /** Callback used by a task to indicate it has finished processing its work item */
   interface JobCallback {
@@ -134,8 +136,14 @@
   @MainThread
   public boolean onStopJob(JobParameters params) {
     Assert.isMainThread();
-    LogUtil.enterBlock("TranscriptionService.onStopJob");
-    cleanup();
+    LogUtil.i("TranscriptionService.onStopJob", "params: " + params);
+    stopped = true;
+    Logger.get(this).logImpression(DialerImpression.Type.VVM_TRANSCRIPTION_JOB_STOPPED);
+    if (activeTask != null) {
+      LogUtil.i("TranscriptionService.onStopJob", "cancelling active task");
+      activeTask.cancel();
+      Logger.get(this).logImpression(DialerImpression.Type.VVM_TRANSCRIPTION_TASK_CANCELLED);
+    }
     return true;
   }
 
@@ -161,15 +169,20 @@
   @MainThread
   private boolean checkForWork() {
     Assert.isMainThread();
+    if (stopped) {
+      LogUtil.i("TranscriptionService.checkForWork", "stopped");
+      return false;
+    }
     JobWorkItem workItem = jobParameters.dequeueWork();
     if (workItem != null) {
-      TranscriptionTask task =
+      Assert.checkState(activeTask == null);
+      activeTask =
           configProvider.shouldUseSyncApi()
               ? new TranscriptionTaskSync(
                   this, new Callback(), workItem, getClientFactory(), configProvider)
               : new TranscriptionTaskAsync(
                   this, new Callback(), workItem, getClientFactory(), configProvider);
-      getExecutorService().execute(task);
+      getExecutorService().execute(activeTask);
       return true;
     } else {
       return false;
@@ -196,8 +209,13 @@
     public void onWorkCompleted(JobWorkItem completedWorkItem) {
       Assert.isMainThread();
       LogUtil.i("TranscriptionService.Callback.onWorkCompleted", completedWorkItem.toString());
-      jobParameters.completeWork(completedWorkItem);
-      checkForWork();
+      activeTask = null;
+      if (stopped) {
+        LogUtil.i("TranscriptionService.Callback.onWorkCompleted", "stopped");
+      } else {
+        jobParameters.completeWork(completedWorkItem);
+        checkForWork();
+      }
     }
   }
 
diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionTask.java b/java/com/android/voicemail/impl/transcribe/TranscriptionTask.java
index fbab076..60b97da 100644
--- a/java/com/android/voicemail/impl/transcribe/TranscriptionTask.java
+++ b/java/com/android/voicemail/impl/transcribe/TranscriptionTask.java
@@ -19,8 +19,10 @@
 import android.app.job.JobWorkItem;
 import android.content.Context;
 import android.net.Uri;
+import android.support.annotation.MainThread;
 import android.text.TextUtils;
 import android.util.Pair;
+import com.android.dialer.common.Assert;
 import com.android.dialer.common.concurrent.ThreadUtil;
 import com.android.dialer.compat.android.provider.VoicemailCompat;
 import com.android.dialer.logging.DialerImpression;
@@ -64,6 +66,7 @@
   protected final TranscriptionConfigProvider configProvider;
   protected ByteString audioData;
   protected AudioFormat encoding;
+  protected volatile boolean cancelled;
 
   static final String AMR_PREFIX = "#!AMR\n";
 
@@ -87,6 +90,13 @@
     databaseHelper = new TranscriptionDbHelper(context, voicemailUri);
   }
 
+  @MainThread
+  void cancel() {
+    Assert.isMainThread();
+    VvmLog.i(TAG, "cancel");
+    cancelled = true;
+  }
+
   @Override
   public void run() {
     VvmLog.i(TAG, "run");
@@ -144,7 +154,11 @@
               .logImpression(DialerImpression.Type.VVM_TRANSCRIPTION_RESPONSE_EXPIRED);
           break;
         default:
-          updateTranscriptionAndState(transcript, VoicemailCompat.TRANSCRIPTION_FAILED);
+          updateTranscriptionAndState(
+              transcript,
+              cancelled
+                  ? VoicemailCompat.TRANSCRIPTION_NOT_STARTED
+                  : VoicemailCompat.TRANSCRIPTION_FAILED);
           Logger.get(context).logImpression(DialerImpression.Type.VVM_TRANSCRIPTION_RESPONSE_EMPTY);
           break;
       }
@@ -155,6 +169,11 @@
     VvmLog.i(TAG, "sendRequest");
     TranscriptionClient client = clientFactory.getClient();
     for (int i = 0; i < configProvider.getMaxTranscriptionRetries(); i++) {
+      if (cancelled) {
+        VvmLog.i(TAG, "sendRequest, cancelled");
+        return null;
+      }
+
       VvmLog.i(TAG, "sendRequest, try: " + (i + 1));
       if (i == 0) {
         Logger.get(context).logImpression(getRequestSentImpression());
@@ -163,7 +182,10 @@
       }
 
       TranscriptionResponse response = request.getResponse(client);
-      if (response.hasRecoverableError()) {
+      if (cancelled) {
+        VvmLog.i(TAG, "sendRequest, cancelled");
+        return null;
+      } else if (response.hasRecoverableError()) {
         Logger.get(context)
             .logImpression(DialerImpression.Type.VVM_TRANSCRIPTION_RESPONSE_RECOVERABLE_ERROR);
         backoff(i);
@@ -187,7 +209,7 @@
     try {
       Thread.sleep(millis);
     } catch (InterruptedException e) {
-      VvmLog.w(TAG, "interrupted");
+      VvmLog.e(TAG, "interrupted", e);
       Thread.currentThread().interrupt();
     }
   }
diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionTaskAsync.java b/java/com/android/voicemail/impl/transcribe/TranscriptionTaskAsync.java
index 3c41aef..930d7f1 100644
--- a/java/com/android/voicemail/impl/transcribe/TranscriptionTaskAsync.java
+++ b/java/com/android/voicemail/impl/transcribe/TranscriptionTaskAsync.java
@@ -62,7 +62,10 @@
         (TranscriptionResponseAsync)
             sendRequest((client) -> client.sendUploadRequest(getUploadRequest()));
 
-    if (uploadResponse == null) {
+    if (cancelled) {
+      VvmLog.i(TAG, "getTranscription, cancelled.");
+      return new Pair<>(null, TranscriptionStatus.FAILED_NO_RETRY);
+    } else if (uploadResponse == null) {
       VvmLog.i(TAG, "getTranscription, failed to upload voicemail.");
       return new Pair<>(null, TranscriptionStatus.FAILED_NO_RETRY);
     } else {
@@ -87,10 +90,17 @@
     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);
+      }
       GetTranscriptResponseAsync response =
           (GetTranscriptResponseAsync)
               sendRequest((client) -> client.sendGetTranscriptRequest(request));
-      if (response == null) {
+      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));