Log visual voicemail to LocalLog

Up to 100 entries of visual voicemail log will be preserved and dumped
into the bug report. The status of the config will also be dumped.

Sample output:
https://paste.googleplex.com/4537194828005376

Fixes: 29517754
Change-Id: I9c460a6544f3b834009667e2eefb863735f82f9a
diff --git a/src/com/android/phone/DumpsysHandler.java b/src/com/android/phone/DumpsysHandler.java
index cf3bde2..d2ae38f 100644
--- a/src/com/android/phone/DumpsysHandler.java
+++ b/src/com/android/phone/DumpsysHandler.java
@@ -1,7 +1,9 @@
 
 package com.android.phone;
 
-import com.android.phone.vvm.omtp.LocalLogHelper;
+import android.content.Context;
+
+import com.android.phone.vvm.omtp.utils.VvmDumpHandler;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -11,8 +13,9 @@
  */
 public class DumpsysHandler {
 
-    public static void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
+    public static void dump(Context context, FileDescriptor fd, PrintWriter writer,
+            String[] args) {
         // Dump OMTP visual voicemail log.
-        LocalLogHelper.dump(fd, writer, args);
+        VvmDumpHandler.dump(context, fd, writer, args);
     }
 }
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index ecefe24..ed014d3 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -3296,7 +3296,7 @@
      * bug report is being generated.
      */
     @Override
-    protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
-        DumpsysHandler.dump(fd, writer, args);
+    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+        DumpsysHandler.dump(mPhone.getContext(), fd, writer, args);
     }
 }
diff --git a/src/com/android/phone/common/mail/internet/MimeUtility.java b/src/com/android/phone/common/mail/internet/MimeUtility.java
index ba5036f..7402a4c 100644
--- a/src/com/android/phone/common/mail/internet/MimeUtility.java
+++ b/src/com/android/phone/common/mail/internet/MimeUtility.java
@@ -19,7 +19,6 @@
 import android.util.Base64;
 import android.util.Base64DataException;
 import android.util.Base64InputStream;
-import android.util.Log;
 
 import com.android.phone.common.mail.Body;
 import com.android.phone.common.mail.BodyPart;
@@ -27,6 +26,7 @@
 import com.android.phone.common.mail.MessagingException;
 import com.android.phone.common.mail.Multipart;
 import com.android.phone.common.mail.Part;
+import com.android.phone.vvm.omtp.VvmLog;
 
 import org.apache.commons.io.IOUtils;
 import org.apache.james.mime4j.codec.EncoderUtil;
@@ -267,14 +267,14 @@
              * If we are not able to process the body there's nothing we can do about it. Return
              * null and let the upper layers handle the missing content.
              */
-            Log.e(LOG_TAG, "Unable to getTextFromPart " + oom.toString());
+            VvmLog.e(LOG_TAG, "Unable to getTextFromPart " + oom.toString());
         }
         catch (Exception e) {
             /*
              * If we are not able to process the body there's nothing we can do about it. Return
              * null and let the upper layers handle the missing content.
              */
-            Log.e(LOG_TAG, "Unable to getTextFromPart " + e.toString());
+            VvmLog.e(LOG_TAG, "Unable to getTextFromPart " + e.toString());
         }
         return null;
     }
diff --git a/src/com/android/phone/common/mail/store/imap/DigestMd5Utils.java b/src/com/android/phone/common/mail/store/imap/DigestMd5Utils.java
index e6376a3..f78dbdf 100644
--- a/src/com/android/phone/common/mail/store/imap/DigestMd5Utils.java
+++ b/src/com/android/phone/common/mail/store/imap/DigestMd5Utils.java
@@ -19,12 +19,12 @@
 import android.annotation.Nullable;
 import android.util.ArrayMap;
 import android.util.Base64;
-import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.phone.common.mail.MailTransport;
 import com.android.phone.common.mail.MessagingException;
 import com.android.phone.common.mail.store.ImapStore;
+import com.android.phone.vvm.omtp.VvmLog;
 
 import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
@@ -244,7 +244,7 @@
                     }
                 }
             } catch (IndexOutOfBoundsException e) {
-                Log.e(TAG, e.toString());
+                VvmLog.e(TAG, e.toString());
                 return null;
             }
             return mResult;
diff --git a/src/com/android/phone/common/mail/store/imap/ImapMemoryLiteral.java b/src/com/android/phone/common/mail/store/imap/ImapMemoryLiteral.java
index aac66c2..4811590 100644
--- a/src/com/android/phone/common/mail/store/imap/ImapMemoryLiteral.java
+++ b/src/com/android/phone/common/mail/store/imap/ImapMemoryLiteral.java
@@ -16,9 +16,8 @@
 
 package com.android.phone.common.mail.store.imap;
 
-import android.util.Log;
-
 import com.android.phone.common.mail.FixedLengthInputStream;
+import com.android.phone.vvm.omtp.VvmLog;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
@@ -45,7 +44,7 @@
             pos += read;
         }
         if (pos != mData.length) {
-            Log.w(TAG, "");
+            VvmLog.w(TAG, "length mismatch");
         }
     }
 
@@ -60,7 +59,7 @@
         try {
             return new String(mData, "US-ASCII");
         } catch (UnsupportedEncodingException e) {
-            Log.e(TAG, "Unsupported encoding: ", e);
+            VvmLog.e(TAG, "Unsupported encoding: ", e);
         }
         return null;
     }
diff --git a/src/com/android/phone/common/mail/store/imap/ImapResponseParser.java b/src/com/android/phone/common/mail/store/imap/ImapResponseParser.java
index d0413df..a6d2df6 100644
--- a/src/com/android/phone/common/mail/store/imap/ImapResponseParser.java
+++ b/src/com/android/phone/common/mail/store/imap/ImapResponseParser.java
@@ -22,6 +22,7 @@
 import com.android.phone.common.mail.FixedLengthInputStream;
 import com.android.phone.common.mail.MessagingException;
 import com.android.phone.common.mail.PeekableInputStream;
+import com.android.phone.vvm.omtp.VvmLog;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -83,9 +84,7 @@
 
     private static IOException newEOSException() {
         final String message = "End of stream reached";
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, message);
-        }
+        VvmLog.d(TAG, message);
         return new IOException(message);
     }
 
@@ -144,9 +143,6 @@
         ImapResponse response = null;
         try {
             response = parseResponse();
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "<<< " + response.toString());
-            }
         } catch (RuntimeException e) {
             // Parser crash -- log network activities.
             onParseError(e);
@@ -183,7 +179,7 @@
             }
         } catch (IOException ignore) {
         }
-        Log.w(TAG, "Exception detected: " + e.getMessage());
+        VvmLog.w(TAG, "Exception detected: " + e.getMessage());
     }
 
     /**
diff --git a/src/com/android/phone/common/mail/store/imap/ImapSimpleString.java b/src/com/android/phone/common/mail/store/imap/ImapSimpleString.java
index 3d5263b..9d65236 100644
--- a/src/com/android/phone/common/mail/store/imap/ImapSimpleString.java
+++ b/src/com/android/phone/common/mail/store/imap/ImapSimpleString.java
@@ -16,7 +16,7 @@
 
 package com.android.phone.common.mail.store.imap;
 
-import android.util.Log;
+import com.android.phone.vvm.omtp.VvmLog;
 
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
@@ -49,7 +49,7 @@
         try {
             return new ByteArrayInputStream(mString.getBytes("US-ASCII"));
         } catch (UnsupportedEncodingException e) {
-            Log.e(TAG, "Unsupported encoding: ", e);
+            VvmLog.e(TAG, "Unsupported encoding: ", e);
         }
         return null;
     }
diff --git a/src/com/android/phone/common/mail/store/imap/ImapString.java b/src/com/android/phone/common/mail/store/imap/ImapString.java
index a33ba24..dd7133c 100644
--- a/src/com/android/phone/common/mail/store/imap/ImapString.java
+++ b/src/com/android/phone/common/mail/store/imap/ImapString.java
@@ -16,7 +16,7 @@
 
 package com.android.phone.common.mail.store.imap;
 
-import android.util.Log;
+import com.android.phone.vvm.omtp.VvmLog;
 
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
@@ -137,7 +137,7 @@
             mParsedDate = DATE_TIME_FORMAT.parse(getString());
             return true;
         } catch (ParseException e) {
-            Log.w("ImapString", getString() + " can't be parsed as a date.");
+            VvmLog.w("ImapString", getString() + " can't be parsed as a date.");
             return false;
         }
     }
diff --git a/src/com/android/phone/common/mail/utils/LogUtils.java b/src/com/android/phone/common/mail/utils/LogUtils.java
index 711af9b..6bd7be6 100644
--- a/src/com/android/phone/common/mail/utils/LogUtils.java
+++ b/src/com/android/phone/common/mail/utils/LogUtils.java
@@ -20,6 +20,7 @@
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.phone.vvm.omtp.VvmLog;
 
 import java.util.List;
 import java.util.regex.Pattern;
@@ -184,7 +185,7 @@
      */
     public static int v(String tag, String format, Object... args) {
         if (isLoggable(tag, VERBOSE)) {
-            return Log.v(tag, String.format(format, args));
+            return VvmLog.v(tag, String.format(format, args));
         }
         return 0;
     }
@@ -202,7 +203,7 @@
      */
     public static int v(String tag, Throwable tr, String format, Object... args) {
         if (isLoggable(tag, VERBOSE)) {
-            return Log.v(tag, String.format(format, args), tr);
+            return VvmLog.v(tag, String.format(format, args), tr);
         }
         return 0;
     }
@@ -219,7 +220,7 @@
      */
     public static int d(String tag, String format, Object... args) {
         if (isLoggable(tag, DEBUG)) {
-            return Log.d(tag, String.format(format, args));
+            return VvmLog.d(tag, String.format(format, args));
         }
         return 0;
     }
@@ -237,7 +238,7 @@
      */
     public static int d(String tag, Throwable tr, String format, Object... args) {
         if (isLoggable(tag, DEBUG)) {
-            return Log.d(tag, String.format(format, args), tr);
+            return VvmLog.d(tag, String.format(format, args), tr);
         }
         return 0;
     }
@@ -254,7 +255,7 @@
      */
     public static int i(String tag, String format, Object... args) {
         if (isLoggable(tag, INFO)) {
-            return Log.i(tag, String.format(format, args));
+            return VvmLog.i(tag, String.format(format, args));
         }
         return 0;
     }
@@ -272,7 +273,7 @@
      */
     public static int i(String tag, Throwable tr, String format, Object... args) {
         if (isLoggable(tag, INFO)) {
-            return Log.i(tag, String.format(format, args), tr);
+            return VvmLog.i(tag, String.format(format, args), tr);
         }
         return 0;
     }
@@ -289,7 +290,7 @@
      */
     public static int w(String tag, String format, Object... args) {
         if (isLoggable(tag, WARN)) {
-            return Log.w(tag, String.format(format, args));
+            return VvmLog.w(tag, String.format(format, args));
         }
         return 0;
     }
@@ -307,7 +308,7 @@
      */
     public static int w(String tag, Throwable tr, String format, Object... args) {
         if (isLoggable(tag, WARN)) {
-            return Log.w(tag, String.format(format, args), tr);
+            return VvmLog.w(tag, String.format(format, args), tr);
         }
         return 0;
     }
@@ -324,7 +325,7 @@
      */
     public static int e(String tag, String format, Object... args) {
         if (isLoggable(tag, ERROR)) {
-            return Log.e(tag, String.format(format, args));
+            return VvmLog.e(tag, String.format(format, args));
         }
         return 0;
     }
@@ -342,7 +343,7 @@
      */
     public static int e(String tag, Throwable tr, String format, Object... args) {
         if (isLoggable(tag, ERROR)) {
-            return Log.e(tag, String.format(format, args), tr);
+            return VvmLog.e(tag, String.format(format, args), tr);
         }
         return 0;
     }
@@ -362,7 +363,7 @@
      *            additional arguments are ignored.
      */
     public static int wtf(String tag, String format, Object... args) {
-        return Log.wtf(tag, String.format(format, args), new Error());
+        return VvmLog.wtf(tag, String.format(format, args), new Error());
     }
 
     /**
@@ -381,7 +382,7 @@
      *            additional arguments are ignored.
      */
     public static int wtf(String tag, Throwable tr, String format, Object... args) {
-        return Log.wtf(tag, String.format(format, args), tr);
+        return VvmLog.wtf(tag, String.format(format, args), tr);
     }
 
 
diff --git a/src/com/android/phone/vvm/omtp/DefaultOmtpEventHandler.java b/src/com/android/phone/vvm/omtp/DefaultOmtpEventHandler.java
index 6816d4c..806ccd5 100644
--- a/src/com/android/phone/vvm/omtp/DefaultOmtpEventHandler.java
+++ b/src/com/android/phone/vvm/omtp/DefaultOmtpEventHandler.java
@@ -22,7 +22,6 @@
 
 import com.android.phone.VoicemailStatus;
 import com.android.phone.vvm.omtp.OmtpEvents.Type;
-import com.android.services.telephony.Log;
 
 public class DefaultOmtpEventHandler {
 
@@ -43,7 +42,7 @@
                 handleOtherEvent(context, subId, event);
                 break;
             default:
-                Log.wtf(TAG, "invalid event type " + event.getType() + " for " + event);
+                VvmLog.wtf(TAG, "invalid event type " + event.getType() + " for " + event);
         }
     }
 
@@ -57,7 +56,7 @@
                         .apply();
                 break;
             default:
-                Log.wtf(TAG, "invalid configuration event " + event);
+                VvmLog.wtf(TAG, "invalid configuration event " + event);
         }
     }
 
@@ -120,7 +119,7 @@
                 break;
 
             default:
-                Log.wtf(TAG, "invalid data channel event " + event);
+                VvmLog.wtf(TAG, "invalid data channel event " + event);
         }
     }
 
@@ -139,7 +138,7 @@
                         .apply();
                 break;
             default:
-                Log.wtf(TAG, "invalid notification channel event " + event);
+                VvmLog.wtf(TAG, "invalid notification channel event " + event);
         }
     }
 
@@ -154,7 +153,7 @@
                         .apply();
                 break;
             default:
-                Log.wtf(TAG, "invalid other event " + event);
+                VvmLog.wtf(TAG, "invalid other event " + event);
         }
     }
 }
diff --git a/src/com/android/phone/vvm/omtp/LocalLogHelper.java b/src/com/android/phone/vvm/omtp/LocalLogHelper.java
deleted file mode 100644
index 13a55c0..0000000
--- a/src/com/android/phone/vvm/omtp/LocalLogHelper.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2015 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.phone.vvm.omtp;
-
-import android.util.LocalLog;
-
-import com.android.internal.util.IndentingPrintWriter;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * Helper methods for adding to OMTP visual voicemail local logs.
- */
-public class LocalLogHelper {
-
-    private static final int MAX_OMTP_VVM_LOGS = 100;
-
-    private static final LocalLog sLocalLog = new LocalLog(MAX_OMTP_VVM_LOGS);
-
-    public static void log(String tag, String log) {
-        sLocalLog.log(tag + ": " + log);
-    }
-
-    public static void dump(FileDescriptor fd, PrintWriter printwriter, String[] args) {
-        IndentingPrintWriter indentingPrintWriter = new IndentingPrintWriter(printwriter, "  ");
-        indentingPrintWriter.println("OmtpVvm:");
-        indentingPrintWriter.increaseIndent();
-        sLocalLog.dump(fd, indentingPrintWriter, args);
-        indentingPrintWriter.decreaseIndent();
-    }
-}
diff --git a/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java b/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
index dd394b4..02318c6 100644
--- a/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
+++ b/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
@@ -27,7 +27,6 @@
 import android.telephony.VisualVoicemailSmsFilterSettings;
 import android.text.TextUtils;
 import android.util.ArraySet;
-import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.phone.VoicemailStatus;
@@ -327,29 +326,48 @@
     }
 
     public void handleEvent(OmtpEvents event) {
+        VvmLog.i(TAG, "OmtpEvent:" + event);
         if (mProtocol != null) {
             mProtocol.handleEvent(mContext, mSubId, event);
         }
     }
 
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder("OmtpVvmCarrierConfigHelper [");
+        builder.append("subId: ").append(getSubId())
+                .append(", carrierConfig: ").append(mCarrierConfig != null)
+                .append(", telephonyConfig: ").append(mTelephonyConfig != null)
+                .append(", type: ").append(getVvmType())
+                .append(", destinationNumber: ").append(getDestinationNumber())
+                .append(", applicationPort: ").append(getApplicationPort())
+                .append(", sslPort: ").append(getSslPort())
+                .append(", isEnabledByDefault: ").append(isEnabledByDefault())
+                .append(", isCellularDataRequired: ").append(isCellularDataRequired())
+                .append(", isPrefetchEnabled: ").append(isPrefetchEnabled())
+                .append(", isLegacyModeEnabled: ").append(isLegacyModeEnabled())
+                .append("]");
+        return builder.toString();
+    }
+
     @Nullable
     private PersistableBundle getCarrierConfig() {
         if (!SubscriptionManager.isValidSubscriptionId(mSubId)) {
-            Log.w(TAG, "Invalid subscriptionId or subscriptionId not provided in intent.");
+            VvmLog
+                    .w(TAG, "Invalid subscriptionId or subscriptionId not provided in intent.");
             return null;
         }
 
         CarrierConfigManager carrierConfigManager = (CarrierConfigManager)
                 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
         if (carrierConfigManager == null) {
-            Log.w(TAG, "No carrier config service found.");
+            VvmLog.w(TAG, "No carrier config service found.");
             return null;
         }
 
         PersistableBundle config = carrierConfigManager.getConfigForSubId(mSubId);
 
         if (TextUtils.isEmpty(config.getString(CarrierConfigManager.KEY_VVM_TYPE_STRING))) {
-            Log.w(TAG, "Carrier config missing VVM type, ignoring.");
             return null;
         }
         return config;
diff --git a/src/com/android/phone/vvm/omtp/SimChangeReceiver.java b/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
index 323b423..3a6b7d3 100644
--- a/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
+++ b/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
@@ -27,7 +27,6 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
-import android.util.Log;
 
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.PhoneConstants;
@@ -51,13 +50,13 @@
     @Override
     public void onReceive(Context context, Intent intent) {
         if (UserHandle.myUserId() != UserHandle.USER_SYSTEM) {
-            Log.v(TAG, "Received broadcast for user that is not system.");
+            VvmLog.v(TAG, "Received broadcast for user that is not system.");
             return;
         }
 
         final String action = intent.getAction();
         if (action == null) {
-            Log.w(TAG, "Null action for intent.");
+            VvmLog.w(TAG, "Null action for intent.");
             return;
         }
 
@@ -65,7 +64,7 @@
             case TelephonyIntents.ACTION_SIM_STATE_CHANGED:
                 if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(
                         intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE))) {
-                    Log.i(TAG, "Sim removed, removing inactive accounts");
+                    VvmLog.i(TAG, "Sim removed, removing inactive accounts");
                     OmtpVvmSourceManager.getInstance(context).removeInactiveSources();
                 }
                 break;
@@ -74,14 +73,14 @@
                         SubscriptionManager.INVALID_SUBSCRIPTION_ID);
 
                 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
-                    Log.i(TAG, "Received SIM change for invalid subscription id.");
+                    VvmLog.i(TAG, "Received SIM change for invalid subscription id.");
                     return;
                 }
-                Log.d(TAG, "Carrier config changed");
+                VvmLog.d(TAG, "Carrier config changed");
                 if (UserManager.get(context).isUserUnlocked() && !isCryptKeeperMode()) {
                     processSubId(context, subId);
                 } else {
-                    Log.d(TAG, "User locked, activation request delayed until unlock");
+                    VvmLog.d(TAG, "User locked, activation request delayed until unlock");
                     // After the device is unlocked, VvmBootCompletedReceiver will iterate through
                     // all call capable subIds, nothing need to be done here.
                 }
@@ -96,8 +95,8 @@
             PhoneAccountHandle phoneAccount = PhoneAccountHandleConverter.fromSubId(subId);
 
             if (VisualVoicemailSettingsUtil.isVisualVoicemailEnabled(context, phoneAccount)) {
-                Log.i(TAG, "Sim state or carrier config changed: requesting"
-                        + " activation for " + phoneAccount.getId());
+                VvmLog.i(TAG, "Sim state or carrier config changed: requesting"
+                        + " activation for " + subId);
 
                 // Add a phone state listener so that changes to the communication channels
                 // can be recorded.
@@ -107,16 +106,17 @@
             } else {
                 if (carrierConfigHelper.isLegacyModeEnabled()) {
                     // SMS still need to be filtered under legacy mode.
+                    VvmLog.i(TAG, "activating SMS filter for legacy mode");
                     carrierConfigHelper.activateSmsFilter();
                 }
                 // It may be that the source was not registered to begin with but we want
                 // to run through the steps to remove the source just in case.
                 OmtpVvmSourceManager.getInstance(context).removeSource(phoneAccount);
-                Log.v(TAG, "Sim change for disabled account.");
+                VvmLog.v(TAG, "Sim change for disabled account.");
             }
         } else {
             String mccMnc = context.getSystemService(TelephonyManager.class).getSimOperator(subId);
-            Log.d(TAG,
+            VvmLog.d(TAG,
                     "visual voicemail not supported for carrier " + mccMnc + " on subId " + subId);
         }
     }
diff --git a/src/com/android/phone/vvm/omtp/VvmBootCompletedReceiver.java b/src/com/android/phone/vvm/omtp/VvmBootCompletedReceiver.java
index b60c7b6..fe1f4cb 100644
--- a/src/com/android/phone/vvm/omtp/VvmBootCompletedReceiver.java
+++ b/src/com/android/phone/vvm/omtp/VvmBootCompletedReceiver.java
@@ -21,7 +21,6 @@
 import android.content.Intent;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
-import android.util.Log;
 
 import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
 
@@ -46,11 +45,11 @@
             return;
         }
 
-        Log.v(TAG, "processing subId list");
+        VvmLog.v(TAG, "processing subId list");
         for (PhoneAccountHandle handle : TelecomManager.from(context)
                 .getCallCapablePhoneAccounts()) {
             int subId = PhoneAccountHandleConverter.toSubId(handle);
-            Log.v(TAG, "processing subId " + subId);
+            VvmLog.v(TAG, "processing subId " + subId);
             SimChangeReceiver.processSubId(context, subId);
         }
     }
diff --git a/src/com/android/phone/vvm/omtp/VvmLog.java b/src/com/android/phone/vvm/omtp/VvmLog.java
new file mode 100644
index 0000000..82d42af
--- /dev/null
+++ b/src/com/android/phone/vvm/omtp/VvmLog.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2015 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.phone.vvm.omtp;
+
+import android.util.LocalLog;
+import android.util.Log;
+
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Helper methods for adding to OMTP visual voicemail local logs.
+ */
+public class VvmLog {
+
+    private static final int MAX_OMTP_VVM_LOGS = 100;
+
+    private static final LocalLog sLocalLog = new LocalLog(MAX_OMTP_VVM_LOGS);
+
+    public static void log(String tag, String log) {
+        sLocalLog.log(tag + ": " + log);
+    }
+
+    public static void dump(FileDescriptor fd, PrintWriter printwriter, String[] args) {
+        IndentingPrintWriter indentingPrintWriter = new IndentingPrintWriter(printwriter, "  ");
+        indentingPrintWriter.increaseIndent();
+        sLocalLog.dump(fd, indentingPrintWriter, args);
+        indentingPrintWriter.decreaseIndent();
+    }
+
+    public static int e(String tag, String log) {
+        log(tag, log);
+        return Log.e(tag, log);
+    }
+
+    public static int e(String tag, String log, Throwable e) {
+        log(tag, log + " " + e);
+        return Log.e(tag, log, e);
+    }
+
+    public static int w(String tag, String log) {
+        log(tag, log);
+        return Log.w(tag, log);
+    }
+
+    public static int w(String tag, String log, Throwable e) {
+        log(tag, log + " " + e);
+        return Log.w(tag, log, e);
+    }
+
+    public static int i(String tag, String log) {
+        log(tag, log);
+        return Log.i(tag, log);
+    }
+
+    public static int i(String tag, String log, Throwable e) {
+        log(tag, log + " " + e);
+        return Log.i(tag, log, e);
+    }
+
+    public static int d(String tag, String log) {
+        log(tag, log);
+        return Log.d(tag, log);
+    }
+
+    public static int d(String tag, String log, Throwable e) {
+        log(tag, log + " " + e);
+        return Log.d(tag, log, e);
+    }
+
+    public static int v(String tag, String log) {
+        log(tag, log);
+        return Log.v(tag, log);
+    }
+
+    public static int v(String tag, String log, Throwable e) {
+        log(tag, log + " " + e);
+        return Log.v(tag, log, e);
+    }
+
+    public static int wtf(String tag, String log) {
+        log(tag, log);
+        return Log.wtf(tag, log);
+    }
+
+    public static int wtf(String tag, String log, Throwable e) {
+        log(tag, log + " " + e);
+        return Log.wtf(tag, log, e);
+    }
+}
diff --git a/src/com/android/phone/vvm/omtp/VvmPackageInstallReceiver.java b/src/com/android/phone/vvm/omtp/VvmPackageInstallReceiver.java
index 08faba7..8a0495b 100644
--- a/src/com/android/phone/vvm/omtp/VvmPackageInstallReceiver.java
+++ b/src/com/android/phone/vvm/omtp/VvmPackageInstallReceiver.java
@@ -31,6 +31,9 @@
  * enabled dialer vvm sources.
  */
 public class VvmPackageInstallReceiver extends BroadcastReceiver {
+
+    private static final String TAG = "VvmPkgInstallReceiver";
+
     @Override
     public void onReceive(Context context, Intent intent) {
         if (intent.getData() == null) {
@@ -59,6 +62,7 @@
                 // Force deactivate the client. The user can re-enable it in the settings.
                 // There are no need to update the settings for deactivation. At this point, if the
                 // default value is used it should be false because a carrier package is present.
+                VvmLog.i(TAG, "Carrier VVM package installed, disabling system VVM client");
                 OmtpVvmSourceManager.getInstance(context).removeSource(phoneAccount);
                 carrierConfigHelper.startDeactivation();
             }
diff --git a/src/com/android/phone/vvm/omtp/VvmPhoneStateListener.java b/src/com/android/phone/vvm/omtp/VvmPhoneStateListener.java
index 3438de2..64b37c6 100644
--- a/src/com/android/phone/vvm/omtp/VvmPhoneStateListener.java
+++ b/src/com/android/phone/vvm/omtp/VvmPhoneStateListener.java
@@ -20,7 +20,6 @@
 import android.telecom.PhoneAccountHandle;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
-import android.util.Log;
 
 import com.android.phone.PhoneGlobals;
 import com.android.phone.PhoneUtils;
@@ -65,16 +64,16 @@
                     new VoicemailStatusQueryHelper(mContext);
             if (voicemailStatusQueryHelper.isVoicemailSourceConfigured(mPhoneAccount)) {
                 if (!voicemailStatusQueryHelper.isNotificationsChannelActive(mPhoneAccount)) {
-                    Log.v(TAG, "Notifications channel is active for " + mPhoneAccount.getId());
+                    VvmLog
+                            .v(TAG, "Notifications channel is active for " + subId);
                     helper.handleEvent(OmtpEvents.NOTIFICATION_IN_SERVICE);
                     PhoneGlobals.getInstance().clearMwiIndicator(subId);
                 }
             }
 
             if (OmtpVvmSourceManager.getInstance(mContext).isVvmSourceRegistered(mPhoneAccount)) {
-                Log.v(TAG, "Signal returned: requesting resync for " + mPhoneAccount.getId());
-                LocalLogHelper.log(TAG,
-                        "Signal returned: requesting resync for " + mPhoneAccount.getId());
+                VvmLog
+                        .v(TAG, "Signal returned: requesting resync for " + subId);
                 // If the source is already registered, run a full sync in case something was missed
                 // while signal was down.
                 Intent serviceIntent = OmtpVvmSyncService.getSyncIntent(
@@ -82,16 +81,15 @@
                         true /* firstAttempt */);
                 mContext.startService(serviceIntent);
             } else {
-                Log.v(TAG, "Signal returned: reattempting activation for " + mPhoneAccount.getId());
-                LocalLogHelper.log(TAG,
-                        "Signal returned: reattempting activation for " + mPhoneAccount.getId());
+                VvmLog.v(TAG,
+                        "Signal returned: reattempting activation for " + subId);
                 // Otherwise initiate an activation because this means that an OMTP source was
                 // recognized but either the activation text was not successfully sent or a response
                 // was not received.
                 helper.startActivation();
             }
         } else {
-            Log.v(TAG, "Notifications channel is inactive for " + mPhoneAccount.getId());
+            VvmLog.v(TAG, "Notifications channel is inactive for " + subId);
             mContext.stopService(OmtpVvmSyncService.getSyncIntent(
                     mContext, OmtpVvmSyncService.SYNC_FULL_SYNC, mPhoneAccount,
                     true /* firstAttempt */));
diff --git a/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java b/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
index 0095f53..fe3911c 100644
--- a/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
+++ b/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
@@ -30,10 +30,10 @@
 import android.telecom.PhoneAccountHandle;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
-import android.util.Log;
 
 import com.android.phone.PhoneUtils;
 import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
+import com.android.phone.vvm.omtp.VvmLog;
 import com.android.phone.vvm.omtp.imap.ImapHelper;
 import com.android.phone.vvm.omtp.sync.OmtpVvmSourceManager;
 import com.android.phone.vvm.omtp.sync.VvmNetworkRequestCallback;
@@ -45,7 +45,7 @@
 
     private static final String TAG = "FetchVoicemailReceiver";
 
-    final static String[] PROJECTION = new String[] {
+    final static String[] PROJECTION = new String[]{
             Voicemails.SOURCE_DATA,      // 0
             Voicemails.PHONE_ACCOUNT_ID, // 1
             Voicemails.PHONE_ACCOUNT_COMPONENT_NAME, // 2
@@ -74,23 +74,28 @@
     @Override
     public void onReceive(final Context context, Intent intent) {
         if (VoicemailContract.ACTION_FETCH_VOICEMAIL.equals(intent.getAction())) {
+            VvmLog.i(TAG, "ACTION_FETCH_VOICEMAIL received");
             mContext = context;
             mContentResolver = context.getContentResolver();
             mUri = intent.getData();
 
             if (mUri == null) {
-                Log.w(TAG, VoicemailContract.ACTION_FETCH_VOICEMAIL + " intent sent with no data");
+                VvmLog.w(TAG,
+                        VoicemailContract.ACTION_FETCH_VOICEMAIL + " intent sent with no data");
                 return;
             }
 
             if (!context.getPackageName().equals(
                     mUri.getQueryParameter(VoicemailContract.PARAM_KEY_SOURCE_PACKAGE))) {
                 // Ignore if the fetch request is for a voicemail not from this package.
+                VvmLog.e(TAG,
+                        "ACTION_FETCH_VOICEMAIL from foreign pacakge " + context.getPackageName());
                 return;
             }
 
             Cursor cursor = mContentResolver.query(mUri, PROJECTION, null, null, null);
             if (cursor == null) {
+                VvmLog.i(TAG, "ACTION_FETCH_VOICEMAIL query returned null");
                 return;
             }
             try {
@@ -103,7 +108,7 @@
                         accountId = telephonyManager.getSimSerialNumber();
 
                         if (TextUtils.isEmpty(accountId)) {
-                            Log.e(TAG, "Account null and no default sim found.");
+                            VvmLog.e(TAG, "Account null and no default sim found.");
                             return;
                         }
                     }
@@ -114,14 +119,14 @@
                             cursor.getString(PHONE_ACCOUNT_ID));
                     if (!OmtpVvmSourceManager.getInstance(context)
                             .isVvmSourceRegistered(mPhoneAccount)) {
-                        Log.w(TAG, "Account not registered - cannot retrieve message.");
+                        VvmLog.w(TAG, "Account not registered - cannot retrieve message.");
                         return;
                     }
 
                     int subId = PhoneUtils.getSubIdForPhoneAccountHandle(mPhoneAccount);
                     OmtpVvmCarrierConfigHelper carrierConfigHelper =
                             new OmtpVvmCarrierConfigHelper(context, subId);
-
+                    VvmLog.i(TAG, "Requesting network to fetch voicemail");
                     mNetworkCallback = new fetchVoicemailNetworkRequestCallback(context,
                             mPhoneAccount);
                     mNetworkCallback.requestNetwork();
@@ -153,15 +158,17 @@
             public void run() {
                 try {
                     while (mRetryCount > 0) {
+                        VvmLog.i(TAG, "fetching voicemail, retry count=" + mRetryCount);
                         ImapHelper imapHelper = new ImapHelper(mContext, mPhoneAccount, network);
                         if (!imapHelper.isSuccessfullyInitialized()) {
-                            Log.w(TAG, "Can't retrieve Imap credentials.");
+                            VvmLog.w(TAG, "Can't retrieve Imap credentials.");
                             return;
                         }
 
                         boolean success = imapHelper.fetchVoicemailPayload(
                                 new VoicemailFetchedCallback(mContext, mUri), mUid);
                         if (!success && mRetryCount > 0) {
+                            VvmLog.i(TAG, "fetch voicemail failed, retrying");
                             mRetryCount--;
                         } else {
                             return;
diff --git a/src/com/android/phone/vvm/omtp/fetch/VoicemailFetchedCallback.java b/src/com/android/phone/vvm/omtp/fetch/VoicemailFetchedCallback.java
index 3862d54..387ca5a 100644
--- a/src/com/android/phone/vvm/omtp/fetch/VoicemailFetchedCallback.java
+++ b/src/com/android/phone/vvm/omtp/fetch/VoicemailFetchedCallback.java
@@ -20,8 +20,8 @@
 import android.content.Context;
 import android.net.Uri;
 import android.provider.VoicemailContract.Voicemails;
-import android.util.Log;
 
+import com.android.phone.vvm.omtp.VvmLog;
 import com.android.phone.vvm.omtp.imap.VoicemailPayload;
 
 import libcore.io.IoUtils;
@@ -51,7 +51,7 @@
      * @param voicemailPayload The object containing the content data for the voicemail
      */
     public void setVoicemailContent(VoicemailPayload voicemailPayload) {
-        Log.d(TAG, String.format("Writing new voicemail content: %s", mUri));
+        VvmLog.d(TAG, String.format("Writing new voicemail content: %s", mUri));
         OutputStream outputStream = null;
 
         try {
@@ -61,7 +61,7 @@
                 outputStream.write(inputBytes);
             }
         } catch (IOException e) {
-            Log.w(TAG, String.format("File not found for %s", mUri));
+            VvmLog.w(TAG, String.format("File not found for %s", mUri));
             return;
         } finally {
             IoUtils.closeQuietly(outputStream);
@@ -73,7 +73,8 @@
         values.put(Voicemails.HAS_CONTENT, true);
         int updatedCount = mContentResolver.update(mUri, values, null, null);
         if (updatedCount != 1) {
-            Log.e(TAG, "Updating voicemail should have updated 1 row, was: " + updatedCount);
+            VvmLog
+                    .e(TAG, "Updating voicemail should have updated 1 row, was: " + updatedCount);
         }
     }
 }
diff --git a/src/com/android/phone/vvm/omtp/imap/ImapHelper.java b/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
index ce9e9c3..216b6a4 100644
--- a/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
+++ b/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
@@ -25,7 +25,6 @@
 import android.telecom.PhoneAccountHandle;
 import android.telecom.Voicemail;
 import android.util.Base64;
-import android.util.Log;
 
 import com.android.phone.PhoneUtils;
 import com.android.phone.VoicemailStatus;
@@ -50,6 +49,7 @@
 import com.android.phone.vvm.omtp.OmtpConstants.ChangePinResult;
 import com.android.phone.vvm.omtp.OmtpEvents;
 import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
+import com.android.phone.vvm.omtp.VvmLog;
 import com.android.phone.vvm.omtp.fetch.VoicemailFetchedCallback;
 import com.android.phone.vvm.omtp.sync.OmtpVvmSyncService.TranscriptionFetchedCallback;
 
@@ -135,11 +135,11 @@
         return mImapStore != null;
     }
 
-    public boolean isRoaming(){
+    public boolean isRoaming() {
         ConnectivityManager connectivityManager = (ConnectivityManager) mContext.getSystemService(
                 Context.CONNECTIVITY_SERVICE);
         NetworkInfo info = connectivityManager.getNetworkInfo(mNetwork);
-        if(info == null){
+        if (info == null) {
             return false;
         }
         return info.isRoaming();
@@ -153,12 +153,16 @@
         return mImapStore.getConnection();
     }
 
-    /** The caller thread will block until the method returns. */
+    /**
+     * The caller thread will block until the method returns.
+     */
     public boolean markMessagesAsRead(List<Voicemail> voicemails) {
         return setFlags(voicemails, Flag.SEEN);
     }
 
-    /** The caller thread will block until the method returns. */
+    /**
+     * The caller thread will block until the method returns.
+     */
     public boolean markMessagesAsDeleted(List<Voicemail> voicemails) {
         return setFlags(voicemails, Flag.DELETED);
     }
@@ -232,7 +236,7 @@
      * transcription exists.
      */
     private Voicemail getVoicemailFromMessageStructure(
-            MessageStructureWrapper messageStructureWrapper) throws MessagingException{
+            MessageStructureWrapper messageStructureWrapper) throws MessagingException {
         Message messageDetails = messageStructureWrapper.messageStructure;
 
         TranscriptionFetchedListener listener = new TranscriptionFetchedListener();
@@ -240,7 +244,7 @@
             FetchProfile fetchProfile = new FetchProfile();
             fetchProfile.add(messageStructureWrapper.transcriptionBodyPart);
 
-            mFolder.fetch(new Message[] {messageDetails}, fetchProfile, listener);
+            mFolder.fetch(new Message[]{messageDetails}, fetchProfile, listener);
         }
 
         // Found an audio attachment, this is a valid voicemail.
@@ -257,8 +261,8 @@
     }
 
     /**
-     * The "from" field of a visual voicemail IMAP message is the number of the caller who left
-     * the message. Extract this number from the list of "from" addresses.
+     * The "from" field of a visual voicemail IMAP message is the number of the caller who left the
+     * message. Extract this number from the list of "from" addresses.
      *
      * @param fromAddresses A list of addresses that comprise the "from" line.
      * @return The number of the voicemail sender.
@@ -297,7 +301,7 @@
 
         // The IMAP folder fetch method will call "messageRetrieved" on the listener when the
         // message is successfully retrieved.
-        mFolder.fetch(new Message[] {message}, fetchProfile, listener);
+        mFolder.fetch(new Message[]{message}, fetchProfile, listener);
         return listener.getMessageStructure();
     }
 
@@ -341,7 +345,7 @@
         FetchProfile fetchProfile = new FetchProfile();
         fetchProfile.add(FetchProfile.Item.BODY);
 
-        mFolder.fetch(new Message[] {message}, fetchProfile, listener);
+        mFolder.fetch(new Message[]{message}, fetchProfile, listener);
         return listener.getVoicemailPayload();
     }
 
@@ -367,7 +371,7 @@
 
                     // This method is called synchronously so the transcription will be populated
                     // in the listener once the next method is called.
-                    mFolder.fetch(new Message[] {message}, fetchProfile, listener);
+                    mFolder.fetch(new Message[]{message}, fetchProfile, listener);
                     callback.setVoicemailTranscription(listener.getVoicemailTranscription());
                 }
             }
@@ -481,7 +485,7 @@
             return;
         }
         if (quota.occupied == mQuotaOccupied && quota.total == mQuotaTotal) {
-            Log.v(TAG, "Quota hasn't changed");
+            VvmLog.v(TAG, "Quota hasn't changed");
             return;
         }
         mQuotaOccupied = quota.occupied;
@@ -493,17 +497,20 @@
                 .putInt(getSharedPrefsKey(PREF_KEY_QUOTA_OCCUPIED), mQuotaOccupied)
                 .putInt(getSharedPrefsKey(PREF_KEY_QUOTA_TOTAL), mQuotaTotal)
                 .apply();
-        Log.v(TAG, "Quota changed to " + mQuotaOccupied + "/" + mQuotaTotal);
+        VvmLog.v(TAG, "Quota changed to " + mQuotaOccupied + "/" + mQuotaTotal);
     }
+
     /**
-     * A wrapper to hold a message with its header details and the structure for transcriptions
-     * (so they can be fetched in the future).
+     * A wrapper to hold a message with its header details and the structure for transcriptions (so
+     * they can be fetched in the future).
      */
     public class MessageStructureWrapper {
+
         public Message messageStructure;
         public BodyPart transcriptionBodyPart;
 
-        public MessageStructureWrapper() { }
+        public MessageStructureWrapper() {
+        }
     }
 
     /**
@@ -511,6 +518,7 @@
      */
     private final class MessageStructureFetchedListener
             implements ImapFolder.MessageRetrievalListener {
+
         private MessageStructureWrapper mMessageStructure;
 
         public MessageStructureFetchedListener() {
@@ -542,7 +550,6 @@
          * @param message The IMAP message.
          * @return The MessageStructureWrapper object corresponding to an IMAP message and
          * transcription.
-         * @throws MessagingException
          */
         private MessageStructureWrapper getMessageOrNull(Message message)
                 throws MessagingException {
@@ -579,9 +586,12 @@
      * Listener for the message body being fetched.
      */
     private final class MessageBodyFetchedListener implements ImapFolder.MessageRetrievalListener {
+
         private VoicemailPayload mVoicemailPayload;
 
-        /** Returns the fetch voicemail payload. */
+        /**
+         * Returns the fetch voicemail payload.
+         */
         public VoicemailPayload getVoicemailPayload() {
             return mVoicemailPayload;
         }
@@ -602,18 +612,18 @@
         private VoicemailPayload getVoicemailPayloadFromMessage(Message message)
                 throws MessagingException, IOException {
             Multipart multipart = (Multipart) message.getBody();
+            List<String> mimeTypes = new ArrayList<>();
             for (int i = 0; i < multipart.getCount(); ++i) {
                 BodyPart bodyPart = multipart.getBodyPart(i);
                 String bodyPartMimeType = bodyPart.getMimeType().toLowerCase();
-                LogUtils.d(TAG, "bodyPart mime type: " + bodyPartMimeType);
-
+                mimeTypes.add(bodyPartMimeType);
                 if (bodyPartMimeType.startsWith("audio/")) {
                     byte[] bytes = getDataFromBody(bodyPart.getBody());
                     LogUtils.d(TAG, String.format("Fetched %s bytes of data", bytes.length));
                     return new VoicemailPayload(bodyPartMimeType, bytes);
                 }
             }
-            LogUtils.e(TAG, "No audio attachment found on this voicemail");
+            LogUtils.e(TAG, "No audio attachment found on this voicemail, mimeTypes:" + mimeTypes);
             return null;
         }
     }
@@ -623,9 +633,12 @@
      */
     private final class TranscriptionFetchedListener implements
             ImapFolder.MessageRetrievalListener {
+
         private String mVoicemailTranscription;
 
-        /** Returns the fetched voicemail transcription. */
+        /**
+         * Returns the fetched voicemail transcription.
+         */
         public String getVoicemailTranscription() {
             return mVoicemailTranscription;
         }
diff --git a/src/com/android/phone/vvm/omtp/protocol/ProtocolHelper.java b/src/com/android/phone/vvm/omtp/protocol/ProtocolHelper.java
index d265bd0..748fd39 100644
--- a/src/com/android/phone/vvm/omtp/protocol/ProtocolHelper.java
+++ b/src/com/android/phone/vvm/omtp/protocol/ProtocolHelper.java
@@ -18,9 +18,9 @@
 
 import android.telephony.SmsManager;
 import android.text.TextUtils;
-import android.util.Log;
 
 import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
+import com.android.phone.vvm.omtp.VvmLog;
 import com.android.phone.vvm.omtp.sms.OmtpMessageSender;
 
 public class ProtocolHelper {
@@ -33,7 +33,7 @@
         int applicationPort = config.getApplicationPort();
         String destinationNumber = config.getDestinationNumber();
         if (TextUtils.isEmpty(destinationNumber)) {
-            Log.w(TAG, "No destination number for this carrier.");
+            VvmLog.w(TAG, "No destination number for this carrier.");
             return null;
         }
 
diff --git a/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocolFactory.java b/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocolFactory.java
index dbf38c2..5f54a50 100644
--- a/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocolFactory.java
+++ b/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocolFactory.java
@@ -18,7 +18,8 @@
 
 import android.annotation.Nullable;
 import android.telephony.TelephonyManager;
-import android.util.Log;
+
+import com.android.phone.vvm.omtp.VvmLog;
 
 public class VisualVoicemailProtocolFactory {
 
@@ -39,7 +40,7 @@
             case VVM_TYPE_VVM3:
                 return new Vvm3Protocol();
             default:
-                Log.e(TAG, "Unexpected visual voicemail type: " + type);
+                VvmLog.e(TAG, "Unexpected visual voicemail type: " + type);
         }
         return null;
     }
diff --git a/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java b/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
index e62d1cf..6ad143f 100644
--- a/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
+++ b/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
@@ -21,13 +21,13 @@
 import android.os.Bundle;
 import android.telecom.PhoneAccountHandle;
 import android.telephony.SmsManager;
-import android.util.Log;
 
 import com.android.phone.common.mail.MessagingException;
 import com.android.phone.settings.VisualVoicemailSettingsUtil;
 import com.android.phone.settings.VoicemailChangePinDialogPreference;
 import com.android.phone.vvm.omtp.OmtpConstants;
 import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
+import com.android.phone.vvm.omtp.VvmLog;
 import com.android.phone.vvm.omtp.imap.ImapHelper;
 import com.android.phone.vvm.omtp.sms.OmtpMessageSender;
 import com.android.phone.vvm.omtp.sms.StatusMessage;
@@ -58,15 +58,12 @@
 
     private static final int PIN_LENGTH = 6;
 
-    public Vvm3Protocol() {
-        Log.d(TAG, "Vvm3Protocol created");
-    }
-
     @Override
     public void startActivation(OmtpVvmCarrierConfigHelper config) {
         // VVM3 does not support activation SMS.
         // Send a status request which will start the provisioning process if the user is not
         // provisioned.
+        VvmLog.i(TAG, "Activating");
         config.requestStatus();
     }
 
@@ -79,12 +76,12 @@
     @Override
     public void startProvisioning(PhoneAccountHandle phoneAccountHandle,
             OmtpVvmCarrierConfigHelper config, StatusMessage message, Bundle data) {
-        Log.i(TAG, "start vvm3 provisioning");
+        VvmLog.i(TAG, "start vvm3 provisioning");
         if ("U".equals(message.getProvisioningStatus())) {
-            Log.i(TAG, "Provisioning status: Unknown, subscribing");
+            VvmLog.i(TAG, "Provisioning status: Unknown, subscribing");
             new Vvm3Subscriber(phoneAccountHandle, config, data).subscribe();
         } else if ("N".equals(message.getProvisioningStatus())) {
-            Log.i(TAG, "setting up new user");
+            VvmLog.i(TAG, "setting up new user");
             VisualVoicemailSettingsUtil.setVisualVoicemailCredentialsFromStatusMessage(
                     config.getContext(), phoneAccountHandle, message);
             startProvisionNewUser(phoneAccountHandle, config, message);
@@ -132,7 +129,7 @@
         @Override
         public void onAvailable(Network network) {
             super.onAvailable(network);
-            Log.i(TAG, "new user: network available");
+            VvmLog.i(TAG, "new user: network available");
             ImapHelper helper = new ImapHelper(mContext, mPhoneAccount, network);
 
             try {
@@ -148,29 +145,31 @@
                     // English
                     helper.changeVoicemailTuiLanguage(VVM3_VM_LANGUAGE_ENGLISH_STANDARD);
                 }
-                Log.i(TAG, "new user: language set");
+                VvmLog.i(TAG, "new user: language set");
 
                 if (setPin(helper)) {
                     // Only close new user tutorial if the PIN has been changed.
                     helper.closeNewUserTutorial();
-                    Log.i(TAG, "new user: NUT closed");
+                    VvmLog.i(TAG, "new user: NUT closed");
 
                     mConfig.requestStatus();
                 }
             } catch (MessagingException | IOException e) {
-                Log.e(TAG, e.toString());
+                VvmLog.e(TAG, e.toString());
             }
         }
 
         private boolean setPin(ImapHelper helper) throws IOException, MessagingException {
             String defaultPin = getDefaultPin();
             if (defaultPin == null) {
+                VvmLog.i(TAG, "cannot generate default PIN");
                 return false;
             }
 
             if (VoicemailChangePinDialogPreference.getDefaultOldPin(mContext, mPhoneAccount)
                     != null) {
                 // The pin was already set
+                VvmLog.i(TAG, "PIN already set");
                 return true;
             }
             String newPin = generatePin();
@@ -181,7 +180,7 @@
                 // TODO(b/29082418): set CONFIGURATION_STATE to VVM3_CONFIGURATION_PIN_NOT_SET
                 // to prompt the user to set the PIN
             }
-            Log.i(TAG, "new user: PIN set");
+            VvmLog.i(TAG, "new user: PIN set");
             return true;
         }
 
@@ -192,12 +191,12 @@
             try {
                 String number = username.substring(0, username.indexOf('@'));
                 if (number.length() < 4) {
-                    Log.e(TAG, "unable to extract number from IMAP username");
+                    VvmLog.e(TAG, "unable to extract number from IMAP username");
                     return null;
                 }
                 return "1" + number.substring(number.length() - 4);
             } catch (StringIndexOutOfBoundsException e) {
-                Log.e(TAG, "unable to extract number from IMAP username");
+                VvmLog.e(TAG, "unable to extract number from IMAP username");
                 return null;
             }
 
diff --git a/src/com/android/phone/vvm/omtp/protocol/Vvm3Subscriber.java b/src/com/android/phone/vvm/omtp/protocol/Vvm3Subscriber.java
index c314ff5..dc3b969 100644
--- a/src/com/android/phone/vvm/omtp/protocol/Vvm3Subscriber.java
+++ b/src/com/android/phone/vvm/omtp/protocol/Vvm3Subscriber.java
@@ -26,10 +26,10 @@
 import android.text.Spanned;
 import android.text.style.URLSpan;
 import android.util.ArrayMap;
-import android.util.Log;
 
 import com.android.phone.Assert;
 import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
+import com.android.phone.vvm.omtp.VvmLog;
 import com.android.phone.vvm.omtp.sync.VvmNetworkRequestCallback;
 import com.android.volley.AuthFailureError;
 import com.android.volley.Request;
@@ -151,6 +151,7 @@
         Assert.isNotMainThread();
         // Cellular data is required to subscribe.
         // processSubscription() is called after network is available.
+        VvmLog.i(TAG, "Subscribing");
         new Vvm3ProvisioningNetworkRequestCallback(mHelper, mHandle).requestNetwork();
     }
 
@@ -161,7 +162,7 @@
             String subscribeLink = findSubscribeLink(selfProvisionResponse);
             clickSubscribeLink(subscribeLink);
         } catch (ProvisioningException e) {
-            Log.e(TAG, e.toString());
+            VvmLog.e(TAG, e.toString());
         }
     }
 
@@ -169,6 +170,7 @@
      * Get the URL to perform self-provisioning from the voicemail management gateway.
      */
     private String getSelfProvisioningGateway() throws ProvisioningException {
+        VvmLog.i(TAG, "retrieving SPG URL");
         String response = vvm3XmlRequest(OPERATION_GET_SPG_URL);
         return extractText(response, SPG_URL_TAG);
     }
@@ -179,6 +181,8 @@
      * subscription. The cookie from this response and cellular data is required to click the link.
      */
     private String getSelfProvisionResponse(String url) throws ProvisioningException {
+        VvmLog.i(TAG, "Retrieving self provisioning response");
+
         RequestFuture<String> future = RequestFuture.newFuture();
 
         StringRequest stringRequest = new StringRequest(Request.Method.POST, url, future, future) {
@@ -205,6 +209,7 @@
     }
 
     private void clickSubscribeLink(String subscribeLink) throws ProvisioningException {
+        VvmLog.i(TAG, "Clicking subscribe link");
         RequestFuture<String> future = RequestFuture.newFuture();
 
         StringRequest stringRequest = new StringRequest(Request.Method.POST,
@@ -219,10 +224,10 @@
     }
 
     private String vvm3XmlRequest(String operation) throws ProvisioningException {
-        Log.d(TAG, "Sending vvm3XmlRequest for " + operation);
+        VvmLog.d(TAG, "Sending vvm3XmlRequest for " + operation);
         String voicemailManagementGateway = mData.getString(VMG_URL_KEY);
         if (voicemailManagementGateway == null) {
-            Log.e(TAG, "voicemailManagementGateway url unknown");
+            VvmLog.e(TAG, "voicemailManagementGateway url unknown");
             return null;
         }
         String transactionId = createTransactionId();
@@ -285,7 +290,7 @@
         @Override
         public void onAvailable(Network network) {
             super.onAvailable(network);
-            Log.d(TAG, "provisioning: network available");
+            VvmLog.d(TAG, "provisioning: network available");
             mRequestQueue = Volley
                     .newRequestQueue(mContext, new NetworkSpecifiedHurlStack(network));
             processSubscription();
diff --git a/src/com/android/phone/vvm/omtp/sms/LegacyModeSmsHandler.java b/src/com/android/phone/vvm/omtp/sms/LegacyModeSmsHandler.java
index 53422c4..ba5bd70 100644
--- a/src/com/android/phone/vvm/omtp/sms/LegacyModeSmsHandler.java
+++ b/src/com/android/phone/vvm/omtp/sms/LegacyModeSmsHandler.java
@@ -21,12 +21,12 @@
 import android.os.Bundle;
 import android.provider.VoicemailContract;
 import android.telecom.PhoneAccountHandle;
-import android.util.Log;
 
 import com.android.internal.telephony.Phone;
 import com.android.phone.PhoneUtils;
 import com.android.phone.vvm.omtp.OmtpConstants;
 import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
+import com.android.phone.vvm.omtp.VvmLog;
 
 /**
  * Class ot handle voicemail SMS under legacy mode
@@ -38,14 +38,14 @@
     private static final String TAG = "LegacyModeSmsHandler";
 
     public static void handle(Context context, Intent intent, PhoneAccountHandle handle) {
-        Log.v(TAG, "processing VVM SMS on legacy mode");
+        VvmLog.v(TAG, "processing VVM SMS on legacy mode");
         String eventType = intent.getExtras()
                 .getString(VoicemailContract.EXTRA_VOICEMAIL_SMS_PREFIX);
         Bundle data = intent.getExtras().getBundle(VoicemailContract.EXTRA_VOICEMAIL_SMS_FIELDS);
 
         if (eventType.equals(OmtpConstants.SYNC_SMS_PREFIX)) {
             SyncMessage message = new SyncMessage(data);
-            Log.v(TAG, "Received SYNC sms for " + handle.getId() +
+            VvmLog.v(TAG, "Received SYNC sms for " + handle.getId() +
                     " with event " + message.getSyncTriggerEvent());
 
             switch (message.getSyncTriggerEvent()) {
@@ -55,7 +55,7 @@
                     // change.
                     // For some carriers new message count could be set to 0 even if there are still
                     // unread messages, to clear the message waiting indicator.
-                    Log.v(TAG, "updating MWI");
+                    VvmLog.v(TAG, "updating MWI");
                     Phone phone = PhoneUtils.getPhoneForPhoneAccountHandle(handle);
                     // Setting voicemail message count to non-zero will show the telephony voicemail
                     // notification, and zero will clear it.
diff --git a/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java b/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
index 6bb053f..c930a98 100644
--- a/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
+++ b/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
@@ -25,14 +25,13 @@
 import android.provider.VoicemailContract;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.Voicemail;
-import android.util.Log;
 
 import com.android.phone.PhoneGlobals;
 import com.android.phone.settings.VisualVoicemailSettingsUtil;
-import com.android.phone.vvm.omtp.LocalLogHelper;
 import com.android.phone.vvm.omtp.OmtpConstants;
 import com.android.phone.vvm.omtp.OmtpEvents;
 import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
+import com.android.phone.vvm.omtp.VvmLog;
 import com.android.phone.vvm.omtp.sync.OmtpVvmSourceManager;
 import com.android.phone.vvm.omtp.sync.OmtpVvmSyncService;
 import com.android.phone.vvm.omtp.sync.VoicemailsQueryHelper;
@@ -49,7 +48,7 @@
     @Override
     public void onReceive(Context context, Intent intent) {
         if (!UserManager.get(context).isUserUnlocked()) {
-            Log.i(TAG, "Received message on locked device");
+            VvmLog.i(TAG, "Received message on locked device");
             // A full sync will happen after the device is unlocked, so nothing need to be done.
             return;
         }
@@ -59,7 +58,7 @@
         PhoneAccountHandle phone = PhoneAccountHandleConverter.fromSubId(subId);
 
         if (phone == null) {
-            Log.i(TAG, "Received message for null phone account");
+            VvmLog.i(TAG, "Received message for null phone account");
             return;
         }
 
@@ -68,7 +67,7 @@
             if (helper.isLegacyModeEnabled()) {
                 LegacyModeSmsHandler.handle(context, intent, phone);
             } else {
-                Log.i(TAG, "Received vvm message for disabled vvm source.");
+                VvmLog.i(TAG, "Received vvm message for disabled vvm source.");
             }
             return;
         }
@@ -80,23 +79,20 @@
         if (eventType.equals(OmtpConstants.SYNC_SMS_PREFIX)) {
             SyncMessage message = new SyncMessage(data);
 
-            Log.v(TAG, "Received SYNC sms for " + phone.getId() +
-                    " with event " + message.getSyncTriggerEvent());
-            LocalLogHelper.log(TAG, "Received SYNC sms for " + phone.getId() +
+            VvmLog.v(TAG, "Received SYNC sms for " + subId +
                     " with event " + message.getSyncTriggerEvent());
             processSync(phone, message);
         } else if (eventType.equals(OmtpConstants.STATUS_SMS_PREFIX)) {
-            Log.v(TAG, "Received STATUS sms for " + phone.getId());
-            LocalLogHelper.log(TAG, "Received Status sms for " + phone.getId());
+            VvmLog.v(TAG, "Received Status sms for " + subId);
             StatusMessage message = new StatusMessage(data);
             if (message.getProvisioningStatus().equals(OmtpConstants.SUBSCRIBER_READY)) {
                 updateSource(phone, subId, message);
             } else {
-                Log.v(TAG, "Subscriber not ready, start provisioning");
+                VvmLog.v(TAG, "Subscriber not ready, start provisioning");
                 mContext.startService(OmtpProvisioningService.getProvisionIntent(mContext, intent));
             }
         } else {
-            Log.e(TAG, "Unknown prefix: " + eventType);
+            VvmLog.e(TAG, "Unknown prefix: " + eventType);
         }
     }
 
@@ -138,7 +134,8 @@
                 // Not implemented in V1
                 break;
             default:
-               Log.e(TAG, "Unrecognized sync trigger event: " + message.getSyncTriggerEvent());
+                VvmLog.e(TAG,
+                        "Unrecognized sync trigger event: " + message.getSyncTriggerEvent());
                break;
         }
 
@@ -171,7 +168,7 @@
 
             PhoneGlobals.getInstance().clearMwiIndicator(subId);
         } else {
-            Log.e(TAG, "Visual voicemail not available for subscriber.");
+            VvmLog.e(TAG, "Visual voicemail not available for subscriber.");
         }
     }
 }
diff --git a/src/com/android/phone/vvm/omtp/sms/OmtpMessageSender.java b/src/com/android/phone/vvm/omtp/sms/OmtpMessageSender.java
index 356f5e4..9a775f0 100644
--- a/src/com/android/phone/vvm/omtp/sms/OmtpMessageSender.java
+++ b/src/com/android/phone/vvm/omtp/sms/OmtpMessageSender.java
@@ -20,9 +20,10 @@
 import android.telephony.SmsManager;
 
 import com.android.phone.vvm.omtp.OmtpConstants;
-import com.android.services.telephony.Log;
+import com.android.phone.vvm.omtp.VvmLog;
 
 import java.io.UnsupportedEncodingException;
+import java.util.Locale;
 
 /**
  * Send client originated OMTP messages to the OMTP server.
@@ -73,7 +74,8 @@
     protected void sendSms(String text, PendingIntent sentIntent) {
         // If application port is set to 0 then send simple text message, else send data message.
         if (mApplicationPort == 0) {
-            Log.v(TAG, String.format("Sending TEXT sms '%s' to %s", text, mDestinationNumber));
+            VvmLog
+                    .v(TAG, String.format("Sending TEXT sms '%s' to %s", text, mDestinationNumber));
             mSmsManager.sendTextMessageWithSelfPermissions(mDestinationNumber, null, text,
                     sentIntent, null, false);
         } else {
@@ -83,8 +85,9 @@
             } catch (UnsupportedEncodingException e) {
                 throw new IllegalStateException("Failed to encode: " + text);
             }
-            Log.v(TAG, String.format("Sending BINARY sms '%s' to %s:%d", text, mDestinationNumber,
-                    mApplicationPort));
+            VvmLog.v(TAG,
+                    String.format(Locale.US, "Sending BINARY sms '%s' to %s:%d", text,
+                            mDestinationNumber, mApplicationPort));
             mSmsManager.sendDataMessageWithSelfPermissions(mDestinationNumber, null,
                     mApplicationPort, data, sentIntent, null);
         }
diff --git a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncReceiver.java b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncReceiver.java
index 0902b6d..415fc91 100644
--- a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncReceiver.java
+++ b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncReceiver.java
@@ -20,7 +20,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.provider.VoicemailContract;
-import android.util.Log;
+
+import com.android.phone.vvm.omtp.VvmLog;
 
 public class OmtpVvmSyncReceiver extends BroadcastReceiver {
 
@@ -29,7 +30,7 @@
     @Override
     public void onReceive(final Context context, Intent intent) {
         if (VoicemailContract.ACTION_SYNC_VOICEMAIL.equals(intent.getAction())) {
-            Log.v(TAG, "Sync intent received");
+            VvmLog.v(TAG, "Sync intent received");
             Intent syncIntent = OmtpVvmSyncService
                     .getSyncIntent(context, OmtpVvmSyncService.SYNC_FULL_SYNC, null, true);
             intent.putExtra(OmtpVvmSyncService.EXTRA_IS_MANUAL_SYNC, true);
diff --git a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
index c0411ec..74b1f66 100644
--- a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
+++ b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
@@ -27,14 +27,13 @@
 import android.telecom.PhoneAccountHandle;
 import android.telecom.Voicemail;
 import android.text.TextUtils;
-import android.util.Log;
 
 import com.android.phone.PhoneUtils;
 import com.android.phone.VoicemailStatus;
 import com.android.phone.settings.VisualVoicemailSettingsUtil;
-import com.android.phone.vvm.omtp.LocalLogHelper;
 import com.android.phone.vvm.omtp.OmtpEvents;
 import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
+import com.android.phone.vvm.omtp.VvmLog;
 import com.android.phone.vvm.omtp.fetch.VoicemailFetchedCallback;
 import com.android.phone.vvm.omtp.imap.ImapHelper;
 
@@ -169,21 +168,21 @@
     @Override
     protected void onHandleIntent(Intent intent) {
         if (intent == null) {
-            Log.d(TAG, "onHandleIntent: could not handle null intent");
+            VvmLog.d(TAG, "onHandleIntent: could not handle null intent");
             return;
         }
         String action = intent.getAction();
         PhoneAccountHandle phoneAccount = intent.getParcelableExtra(EXTRA_PHONE_ACCOUNT);
-        LocalLogHelper.log(TAG, "Sync requested: " + action +
+        VvmLog.log(TAG, "Sync requested: " + action +
                 " for all accounts: " + String.valueOf(phoneAccount == null));
 
         boolean isManualSync = intent.getBooleanExtra(EXTRA_IS_MANUAL_SYNC, false);
         Voicemail voicemail = intent.getParcelableExtra(EXTRA_VOICEMAIL);
         if (phoneAccount != null) {
-            Log.v(TAG, "Sync requested: " + action + " - for account: " + phoneAccount);
+            VvmLog.v(TAG, "Sync requested: " + action + " - for account: " + phoneAccount);
             setupAndSendRequest(phoneAccount, voicemail, action, isManualSync);
         } else {
-            Log.v(TAG, "Sync requested: " + action + " - for all accounts");
+            VvmLog.v(TAG, "Sync requested: " + action + " - for all accounts");
             OmtpVvmSourceManager vvmSourceManager =
                     OmtpVvmSourceManager.getInstance(this);
             Set<PhoneAccountHandle> sources = vvmSourceManager.getOmtpVvmSources();
@@ -196,7 +195,7 @@
     private void setupAndSendRequest(PhoneAccountHandle phoneAccount, Voicemail voicemail,
             String action, boolean isManualSync) {
         if (!VisualVoicemailSettingsUtil.isVisualVoicemailEnabled(this, phoneAccount)) {
-            Log.v(TAG, "Sync requested for disabled account");
+            VvmLog.v(TAG, "Sync requested for disabled account");
             return;
         }
 
@@ -208,7 +207,7 @@
                     : MINIMUM_MANUAL_SYNC_INTERVAL_MILLIS;
             if (currentTime - lastSyncTime < minimumInterval) {
                 // If it's been less than a minute since the last sync, bail.
-                Log.v(TAG, "Avoiding duplicate full sync: synced recently for "
+                VvmLog.v(TAG, "Avoiding duplicate full sync: synced recently for "
                         + phoneAccount.getId());
 
                 /**
@@ -238,7 +237,7 @@
             while (retryCount > 0) {
                 ImapHelper imapHelper = new ImapHelper(this, phoneAccount, network);
                 if (!imapHelper.isSuccessfullyInitialized()) {
-                    Log.w(TAG, "Can't retrieve Imap credentials.");
+                    VvmLog.w(TAG, "Can't retrieve Imap credentials.");
                     VisualVoicemailSettingsUtil.resetVisualVoicemailRetryInterval(this,
                             phoneAccount);
                     return;
@@ -257,7 +256,7 @@
                 if (VisualVoicemailSettingsUtil.isVisualVoicemailEnabled(this, phoneAccount) &&
                         !success) {
                     retryCount--;
-                    Log.v(TAG, "Retrying " + action);
+                    VvmLog.v(TAG, "Retrying " + action);
                 } else {
                     // Nothing more to do here, just exit.
                     VisualVoicemailSettingsUtil.resetVisualVoicemailRetryInterval(this,
@@ -285,7 +284,7 @@
             downloadSuccess = download(imapHelper, account);
         }
 
-        Log.v(TAG, "upload succeeded: [" + String.valueOf(uploadSuccess)
+        VvmLog.v(TAG, "upload succeeded: [" + String.valueOf(uploadSuccess)
                 + "] download succeeded: [" + String.valueOf(downloadSuccess) + "]");
 
         boolean success = uploadSuccess && downloadSuccess;
@@ -330,9 +329,9 @@
             super.onAvailable(network);
             NetworkInfo info = getConnectivityManager().getNetworkInfo(network);
             if (info == null) {
-                Log.d(TAG, "Network Type: Unknown");
+                VvmLog.d(TAG, "Network Type: Unknown");
             } else {
-                Log.d(TAG, "Network Type: " + info.getTypeName());
+                VvmLog.d(TAG, "Network Type: " + info.getTypeName());
             }
 
             doSync(network, this, mPhoneAccount, mVoicemail, mAction);
@@ -428,7 +427,7 @@
         long retryInterval = VisualVoicemailSettingsUtil.getVisualVoicemailRetryInterval(this,
                 phoneAccount);
 
-        Log.v(TAG, "Retrying " + action + " in " + retryInterval + "ms");
+        VvmLog.v(TAG, "Retrying " + action + " in " + retryInterval + "ms");
 
         AlarmManager alarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
         alarmManager.set(AlarmManager.RTC, System.currentTimeMillis() + retryInterval,
diff --git a/src/com/android/phone/vvm/omtp/sync/VvmNetworkRequestCallback.java b/src/com/android/phone/vvm/omtp/sync/VvmNetworkRequestCallback.java
index 4e09527..11526ce 100644
--- a/src/com/android/phone/vvm/omtp/sync/VvmNetworkRequestCallback.java
+++ b/src/com/android/phone/vvm/omtp/sync/VvmNetworkRequestCallback.java
@@ -24,11 +24,11 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.telecom.PhoneAccountHandle;
-import android.util.Log;
 
 import com.android.phone.PhoneUtils;
 import com.android.phone.vvm.omtp.OmtpEvents;
 import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
+import com.android.phone.vvm.omtp.VvmLog;
 
 /**
  * Base class for network request call backs for visual voicemail syncing with the Imap server. This
@@ -80,11 +80,11 @@
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
 
         if (mCarrierConfigHelper.isCellularDataRequired()) {
-            Log.d(TAG, "Transport type: CELLULAR");
+            VvmLog.d(TAG, "Transport type: CELLULAR");
             builder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                     .setNetworkSpecifier(Integer.toString(mSubId));
         } else {
-            Log.d(TAG, "Transport type: ANY");
+            VvmLog.d(TAG, "Transport type: ANY");
         }
         return builder.build();
     }
@@ -96,7 +96,7 @@
     @Override
     @CallSuper
     public void onLost(Network network) {
-        Log.d(TAG, "onLost");
+        VvmLog.d(TAG, "onLost");
         mResultReceived = true;
         onFailed(NETWORK_REQUEST_FAILED_LOST);
     }
@@ -117,7 +117,7 @@
 
     public void requestNetwork() {
         if (mRequestSent == true) {
-            Log.e(TAG, "requestNetwork() called twice");
+            VvmLog.e(TAG, "requestNetwork() called twice");
             return;
         }
         mRequestSent = true;
@@ -138,7 +138,7 @@
     }
 
     public void releaseNetwork() {
-        Log.d(TAG, "releaseNetwork");
+        VvmLog.d(TAG, "releaseNetwork");
         getConnectivityManager().unregisterNetworkCallback(this);
     }
 
@@ -152,7 +152,7 @@
 
     @CallSuper
     public void onFailed(String reason) {
-        Log.d(TAG, "onFailed: " + reason);
+        VvmLog.d(TAG, "onFailed: " + reason);
         if (mCarrierConfigHelper.isCellularDataRequired()) {
             mCarrierConfigHelper.handleEvent(OmtpEvents.DATA_NO_CONNECTION_CELLULAR_REQUIRED);
         } else {
diff --git a/src/com/android/phone/vvm/omtp/utils/VvmDumpHandler.java b/src/com/android/phone/vvm/omtp/utils/VvmDumpHandler.java
new file mode 100644
index 0000000..227cf42
--- /dev/null
+++ b/src/com/android/phone/vvm/omtp/utils/VvmDumpHandler.java
@@ -0,0 +1,32 @@
+package com.android.phone.vvm.omtp.utils;
+
+import android.content.Context;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
+import com.android.phone.vvm.omtp.VvmLog;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+public class VvmDumpHandler {
+
+    public static void dump(Context context, FileDescriptor fd, PrintWriter writer,
+            String[] args) {
+        IndentingPrintWriter indentedWriter = new IndentingPrintWriter(writer, "  ");
+        indentedWriter.println("******* OmtpVvm *******");
+        indentedWriter.println("======= Configs =======");
+        indentedWriter.increaseIndent();
+        for (PhoneAccountHandle handle : TelecomManager.from(context)
+                .getCallCapablePhoneAccounts()) {
+            int subId = PhoneAccountHandleConverter.toSubId(handle);
+            OmtpVvmCarrierConfigHelper config = new OmtpVvmCarrierConfigHelper(context, subId);
+            indentedWriter.println(config.toString());
+        }
+        indentedWriter.decreaseIndent();
+        indentedWriter.println("======== Logs =========");
+        VvmLog.dump(fd, indentedWriter, args);
+    }
+}