Send feedback for some caught contacts app exceptions (1/2)
am: 3a0b483ff7

Change-Id: I314a341e8f3d0cab5c764b1f41f09ed7b99a2b9f
diff --git a/src-bind/com/android/contactsbind/FeedbackHelper.java b/src-bind/com/android/contactsbind/FeedbackHelper.java
index ae87603..efa4791 100644
--- a/src-bind/com/android/contactsbind/FeedbackHelper.java
+++ b/src-bind/com/android/contactsbind/FeedbackHelper.java
@@ -14,10 +14,12 @@
 package com.android.contactsbind;
 
 import android.content.Context;
+import android.util.Log;
 
 public final class FeedbackHelper {
 
-    public static void sendFeedback(Context context, Throwable t, String description) {
+    public static void sendFeedback(Context context, String tag, String description, Throwable t) {
+        Log.e(tag, description == null ? t.getMessage() : description, t);
     }
 
     private FeedbackHelper() {
diff --git a/src/com/android/contacts/ContactSaveService.java b/src/com/android/contacts/ContactSaveService.java
index 1ed36b5..2e98932 100755
--- a/src/com/android/contacts/ContactSaveService.java
+++ b/src/com/android/contacts/ContactSaveService.java
@@ -64,6 +64,8 @@
 import com.android.contacts.common.util.PermissionsUtil;
 import com.android.contacts.compat.PinnedPositionsCompat;
 import com.android.contacts.util.ContactPhotoUtils;
+import com.android.contactsbind.FeedbackHelper;
+
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 
@@ -554,12 +556,12 @@
 
             } catch (RemoteException e) {
                 // Something went wrong, bail without success
-                Log.e(TAG, "Problem persisting user edits", e);
+                FeedbackHelper.sendFeedback(this, TAG, "Problem persisting user edits", e);
                 break;
 
             } catch (IllegalArgumentException e) {
                 // This is thrown by applyBatch on malformed requests
-                Log.e(TAG, "Problem persisting user edits", e);
+                FeedbackHelper.sendFeedback(this, TAG, "Problem persisting user edits", e);
                 showToast(R.string.contactSavedErrorToast);
                 break;
 
@@ -919,7 +921,7 @@
         deliverCallback(callbackIntent);
     }
 
-    private static void addMembersToGroup(ContentResolver resolver, long[] rawContactsToAdd,
+    private void addMembersToGroup(ContentResolver resolver, long[] rawContactsToAdd,
             long groupId) {
         if (rawContactsToAdd == null) {
             return;
@@ -959,14 +961,16 @@
                 }
             } catch (RemoteException e) {
                 // Something went wrong, bail without success
-                Log.e(TAG, "Problem persisting user edits for raw contact ID " +
-                        String.valueOf(rawContactId), e);
+                FeedbackHelper.sendFeedback(this, TAG,
+                        "Problem persisting user edits for raw contact ID " +
+                                String.valueOf(rawContactId), e);
             } catch (OperationApplicationException e) {
                 // The assert could have failed because the contact is already in the group,
                 // just continue to the next contact
-                Log.w(TAG, "Assert failed in adding raw contact ID " +
-                        String.valueOf(rawContactId) + ". Already exists in group " +
-                        String.valueOf(groupId), e);
+                FeedbackHelper.sendFeedback(this, TAG,
+                        "Assert failed in adding raw contact ID " +
+                                String.valueOf(rawContactId) + ". Already exists in group " +
+                                String.valueOf(groupId), e);
             }
         }
     }
@@ -1444,7 +1448,8 @@
             }
             return true;
         } catch (RemoteException | OperationApplicationException e) {
-            Log.e(TAG, "Failed to apply aggregation exception batch", e);
+            FeedbackHelper.sendFeedback(this, TAG,
+                    "Failed to apply aggregation exception batch", e);
             showToast(R.string.contactSavedErrorToast);
             return false;
         }
@@ -1670,7 +1675,7 @@
                 Log.d(TAG, "importFromSim completed successfully");
             }
         } catch (RemoteException|OperationApplicationException e) {
-            Log.e(TAG, "Failed to import contacts from SIM card", e);
+            FeedbackHelper.sendFeedback(this, TAG, "Failed to import contacts from SIM card", e);
             LocalBroadcastManager.getInstance(this).sendBroadcast(result
                     .putExtra(EXTRA_RESULT_CODE, RESULT_FAILURE));
         }
diff --git a/src/com/android/contacts/common/model/account/ExchangeAccountType.java b/src/com/android/contacts/common/model/account/ExchangeAccountType.java
index 8529e9f..4106c6d 100644
--- a/src/com/android/contacts/common/model/account/ExchangeAccountType.java
+++ b/src/com/android/contacts/common/model/account/ExchangeAccountType.java
@@ -34,6 +34,8 @@
 import com.android.contacts.common.R;
 import com.android.contacts.common.model.dataitem.DataKind;
 import com.android.contacts.common.util.CommonDateUtils;
+import com.android.contactsbind.FeedbackHelper;
+
 import com.google.common.collect.Lists;
 
 import java.util.Locale;
@@ -68,7 +70,8 @@
 
             mIsInitialized = true;
         } catch (DefinitionException e) {
-            Log.e(TAG, "Problem building account type", e);
+            // TODO: Change this to fail fast if there are no feedback reports
+            FeedbackHelper.sendFeedback(context, TAG, "Failed to build exchange account type", e);
         }
     }
 
diff --git a/src/com/android/contacts/common/model/account/ExternalAccountType.java b/src/com/android/contacts/common/model/account/ExternalAccountType.java
index e70232b..2f476e6 100644
--- a/src/com/android/contacts/common/model/account/ExternalAccountType.java
+++ b/src/com/android/contacts/common/model/account/ExternalAccountType.java
@@ -35,6 +35,8 @@
 
 import com.android.contacts.common.R;
 import com.android.contacts.common.model.dataitem.DataKind;
+import com.android.contactsbind.FeedbackHelper;
+
 import com.google.common.annotations.VisibleForTesting;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -151,8 +153,7 @@
             }
             error.append(" for external package ");
             error.append(packageName);
-
-            Log.e(TAG, error.toString(), e);
+            FeedbackHelper.sendFeedback(context, TAG, "Failed to build external account type", e);
             return;
         } finally {
             if (parser != null) {
@@ -343,8 +344,8 @@
                     mAccountTypeLabelAttribute = value;
                 } else if (ATTR_ACCOUNT_ICON.equals(attr)) {
                     mAccountTypeIconAttribute = value;
-                } else {
-                    Log.e(TAG, "Unsupported attribute " + attr);
+                } else if (Log.isLoggable(TAG, Log.WARN)) {
+                    Log.w(TAG, "Unsupported attribute " + attr);
                 }
             }
 
@@ -412,7 +413,9 @@
             return -1; // Empty text is okay.
         }
         if (resourceName.charAt(0) != '@') {
-            Log.e(TAG, xmlAttributeName + " must be a resource name beginnig with '@'");
+            if (Log.isLoggable(TAG, Log.WARN)) {
+                Log.w(TAG, xmlAttributeName + " must be a resource name beginnig with '@'");
+            }
             return -1;
         }
         final String name = resourceName.substring(1);
@@ -420,12 +423,16 @@
         try {
              res = context.getPackageManager().getResourcesForApplication(packageName);
         } catch (NameNotFoundException e) {
-            Log.e(TAG, "Unable to load package " + packageName);
+            if (Log.isLoggable(TAG, Log.WARN)) {
+                Log.w(TAG, "Unable to load package " + packageName);
+            }
             return -1;
         }
         final int resId = res.getIdentifier(name, null, packageName);
         if (resId == 0) {
-            Log.e(TAG, "Unable to load " + resourceName + " from package " + packageName);
+            if (Log.isLoggable(TAG, Log.WARN)) {
+                Log.w(TAG, "Unable to load " + resourceName + " from package " + packageName);
+            }
             return -1;
         }
         return resId;
diff --git a/src/com/android/contacts/common/model/account/FallbackAccountType.java b/src/com/android/contacts/common/model/account/FallbackAccountType.java
index 6fd99c4..39f767d 100644
--- a/src/com/android/contacts/common/model/account/FallbackAccountType.java
+++ b/src/com/android/contacts/common/model/account/FallbackAccountType.java
@@ -22,6 +22,7 @@
 
 import com.android.contacts.common.R;
 import com.android.contacts.common.model.dataitem.DataKind;
+import com.android.contactsbind.FeedbackHelper;
 
 public class FallbackAccountType extends BaseAccountType {
     private static final String TAG = "FallbackAccountType";
@@ -54,7 +55,7 @@
 
             mIsInitialized = true;
         } catch (DefinitionException e) {
-            Log.e(TAG, "Problem building account type", e);
+            FeedbackHelper.sendFeedback(context, TAG, "Failed to build fallback account type", e);
         }
     }
 
diff --git a/src/com/android/contacts/common/model/account/GoogleAccountType.java b/src/com/android/contacts/common/model/account/GoogleAccountType.java
index a94bcff..9e089f7 100644
--- a/src/com/android/contacts/common/model/account/GoogleAccountType.java
+++ b/src/com/android/contacts/common/model/account/GoogleAccountType.java
@@ -27,6 +27,8 @@
 import com.android.contacts.common.R;
 import com.android.contacts.common.model.dataitem.DataKind;
 import com.android.contacts.common.util.CommonDateUtils;
+import com.android.contactsbind.FeedbackHelper;
+
 import com.google.common.collect.Lists;
 
 import java.util.List;
@@ -72,7 +74,7 @@
 
             mIsInitialized = true;
         } catch (DefinitionException e) {
-            Log.e(TAG, "Problem building account type", e);
+            FeedbackHelper.sendFeedback(context, TAG, "Failed to build google account type", e);
         }
     }
 
diff --git a/src/com/android/contacts/common/model/account/SamsungAccountType.java b/src/com/android/contacts/common/model/account/SamsungAccountType.java
index c35a5a6..efb4400 100644
--- a/src/com/android/contacts/common/model/account/SamsungAccountType.java
+++ b/src/com/android/contacts/common/model/account/SamsungAccountType.java
@@ -21,6 +21,7 @@
 import com.android.contacts.common.R;
 import com.android.contacts.common.model.dataitem.DataKind;
 import com.android.contacts.common.util.CommonDateUtils;
+import com.android.contactsbind.FeedbackHelper;
 
 import android.content.ContentValues;
 import android.content.Context;
@@ -71,7 +72,7 @@
 
             mIsInitialized = true;
         } catch (DefinitionException e) {
-            Log.e(TAG, "Problem building account type", e);
+            FeedbackHelper.sendFeedback(context, TAG, "Failed to build samsung account type", e);
         }
     }
 
diff --git a/src/com/android/contacts/common/vcard/ExportProcessor.java b/src/com/android/contacts/common/vcard/ExportProcessor.java
index 2aef379..48420da 100644
--- a/src/com/android/contacts/common/vcard/ExportProcessor.java
+++ b/src/com/android/contacts/common/vcard/ExportProcessor.java
@@ -31,6 +31,7 @@
 import android.widget.Toast;
 
 import com.android.contacts.common.R;
+import com.android.contactsbind.FeedbackHelper;
 import com.android.vcard.VCardComposer;
 import com.android.vcard.VCardConfig;
 
@@ -96,11 +97,8 @@
             if (isCancelled()) {
                 doCancelNotification();
             }
-        } catch (OutOfMemoryError e) {
-            Log.e(LOG_TAG, "OutOfMemoryError thrown during import", e);
-            throw e;
-        } catch (RuntimeException e) {
-            Log.e(LOG_TAG, "RuntimeException thrown during export", e);
+        } catch (OutOfMemoryError|RuntimeException e) {
+            FeedbackHelper.sendFeedback(mService, LOG_TAG, "Failed to process vcard export", e);
             throw e;
         } finally {
             synchronized (this) {
diff --git a/src/com/android/contacts/common/vcard/ImportProcessor.java b/src/com/android/contacts/common/vcard/ImportProcessor.java
index 219ec14..36836c6 100644
--- a/src/com/android/contacts/common/vcard/ImportProcessor.java
+++ b/src/com/android/contacts/common/vcard/ImportProcessor.java
@@ -20,6 +20,7 @@
 import android.net.Uri;
 import android.util.Log;
 
+import com.android.contactsbind.FeedbackHelper;
 import com.android.vcard.VCardEntry;
 import com.android.vcard.VCardEntryCommitter;
 import com.android.vcard.VCardEntryConstructor;
@@ -29,7 +30,6 @@
 import com.android.vcard.VCardParser_V21;
 import com.android.vcard.VCardParser_V30;
 import com.android.vcard.exception.VCardException;
-import com.android.vcard.exception.VCardNestedException;
 import com.android.vcard.exception.VCardNotSupportedException;
 import com.android.vcard.exception.VCardVersionException;
 
@@ -106,12 +106,8 @@
             if (isCancelled() && mListener != null) {
                 mListener.onImportCanceled(mImportRequest, mJobId);
             }
-        } catch (OutOfMemoryError e) {
-            Log.e(LOG_TAG, "OutOfMemoryError thrown during import", e);
-            throw e;
-        } catch (RuntimeException e) {
-            Log.e(LOG_TAG, "RuntimeException thrown during import", e);
-            throw e;
+        } catch (OutOfMemoryError|RuntimeException e) {
+            FeedbackHelper.sendFeedback(mService, LOG_TAG, "Vcard import failed", e);
         } finally {
             synchronized (this) {
                 mDone = true;
@@ -243,19 +239,16 @@
 
                 successful = true;
                 break;
-            } catch (IOException e) {
-                Log.e(LOG_TAG, "IOException was emitted: " + e.getMessage());
-            } catch (VCardNestedException e) {
-                // This exception should not be thrown here. We should instead handle it
+            } catch (IOException|VCardNotSupportedException e) {
+                // VCardNestedException (a subclass of VCardNotSupportedException) should
+                // not be thrown here. We should instead handle it
                 // in the preprocessing session in ImportVCardActivity, as we don't try
                 // to detect the type of given vCard here.
                 //
                 // TODO: Handle this case appropriately, which should mean we have to have
                 // code trying to auto-detect the type of given vCard twice (both in
                 // ImportVCardActivity and ImportVCardService).
-                Log.e(LOG_TAG, "Nested Exception is found.");
-            } catch (VCardNotSupportedException e) {
-                Log.e(LOG_TAG, e.toString());
+                FeedbackHelper.sendFeedback(mService, LOG_TAG, "Failed to read vcard", e);
             } catch (VCardVersionException e) {
                 if (i == length - 1) {
                     Log.e(LOG_TAG, "Appropriate version for this vCard is not found.");
diff --git a/src/com/android/contacts/common/vcard/ImportVCardActivity.java b/src/com/android/contacts/common/vcard/ImportVCardActivity.java
index 9da8c0b..93ab944 100644
--- a/src/com/android/contacts/common/vcard/ImportVCardActivity.java
+++ b/src/com/android/contacts/common/vcard/ImportVCardActivity.java
@@ -44,6 +44,7 @@
 import com.android.contacts.common.activity.RequestImportVCardPermissionsActivity;
 import com.android.contacts.common.model.AccountTypeManager;
 import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contactsbind.FeedbackHelper;
 import com.android.vcard.VCardEntryCounter;
 import com.android.vcard.VCardParser;
 import com.android.vcard.VCardParser_V21;
@@ -234,7 +235,8 @@
                     try {
                         requests.add(constructImportRequest(mSource, null, mDisplayName));
                     } catch (VCardException e) {
-                        Log.e(LOG_TAG, "Maybe the file is in wrong format", e);
+                        FeedbackHelper.sendFeedback(ImportVCardActivity.this, LOG_TAG,
+                                "Failed to cache vcard", e);
                         showFailureNotification(R.string.fail_reason_not_supported);
                         return;
                     }
@@ -252,11 +254,13 @@
                         try {
                             request = constructImportRequest(null, sourceUri, sourceDisplayName);
                         } catch (VCardException e) {
-                            Log.e(LOG_TAG, "Maybe the file is in wrong format", e);
+                            FeedbackHelper.sendFeedback(ImportVCardActivity.this, LOG_TAG,
+                                    "Failed to cache vcard", e);
                             showFailureNotification(R.string.fail_reason_not_supported);
                             return;
                         } catch (IOException e) {
-                            Log.e(LOG_TAG, "Unexpected IOException", e);
+                            FeedbackHelper.sendFeedback(ImportVCardActivity.this, LOG_TAG,
+                                    "Failed to cache vcard", e);
                             showFailureNotification(R.string.fail_reason_io_error);
                             return;
                         }
@@ -273,12 +277,14 @@
                     Log.w(LOG_TAG, "Empty import requests. Ignore it.");
                 }
             } catch (OutOfMemoryError e) {
-                Log.e(LOG_TAG, "OutOfMemoryError occured during caching vCard");
+                FeedbackHelper.sendFeedback(ImportVCardActivity.this, LOG_TAG,
+                        "OutOfMemoryError occured during caching vCard", e);
                 System.gc();
                 runOnUiThread(new DialogDisplayer(
                         getString(R.string.fail_reason_low_memory_during_import)));
             } catch (IOException e) {
-                Log.e(LOG_TAG, "IOException during caching vCard", e);
+                FeedbackHelper.sendFeedback(ImportVCardActivity.this, LOG_TAG,
+                        "IOException during caching vCard", e);
                 runOnUiThread(new DialogDisplayer(
                         getString(R.string.fail_reason_io_error)));
             } finally {
@@ -503,12 +509,8 @@
         }
         try {
             copyTo(sourceUri, localFilename);
-        } catch (SecurityException e) {
-            Log.e(LOG_TAG, "SecurityException", e);
-            showFailureNotification(R.string.fail_reason_io_error);
-            return null;
-        } catch (IOException e) {
-            Log.e(LOG_TAG, "IOException during caching vCard", e);
+        } catch (IOException|SecurityException e) {
+            FeedbackHelper.sendFeedback(this, LOG_TAG, "Failed to copy vcard to local file", e);
             showFailureNotification(R.string.fail_reason_io_error);
             return null;
         }
diff --git a/src/com/android/contacts/common/vcard/NfcImportVCardActivity.java b/src/com/android/contacts/common/vcard/NfcImportVCardActivity.java
index 6093405..f2ddcab 100644
--- a/src/com/android/contacts/common/vcard/NfcImportVCardActivity.java
+++ b/src/com/android/contacts/common/vcard/NfcImportVCardActivity.java
@@ -40,6 +40,7 @@
 import com.android.contacts.common.model.AccountTypeManager;
 import com.android.contacts.common.model.account.AccountWithDataSet;
 import com.android.contacts.common.util.ImplicitIntentsUtil;
+import com.android.contactsbind.FeedbackHelper;
 import com.android.vcard.VCardEntry;
 import com.android.vcard.VCardEntryCounter;
 import com.android.vcard.VCardParser;
@@ -125,7 +126,7 @@
                     parser.addInterpreter(detector);
                     parser.parse(is);
                 } catch (VCardVersionException e2) {
-                    Log.e(TAG, "vCard with unsupported version.");
+                    FeedbackHelper.sendFeedback(this, TAG, "vcard with unsupported version", e2);
                     showFailureNotification(R.string.fail_reason_not_supported);
                     return null;
                 }
@@ -136,7 +137,7 @@
                 }
             }
         } catch (IOException e) {
-            Log.e(TAG, "Failed reading vCard data", e);
+            FeedbackHelper.sendFeedback(this, TAG, "Failed to read vcard data", e);
             showFailureNotification(R.string.fail_reason_io_error);
             return null;
         } catch (VCardNestedException e) {
@@ -144,7 +145,7 @@
             // Go through without throwing the Exception, as we may be able to detect the
             // version before it
         } catch (VCardException e) {
-            Log.e(TAG, "Error parsing vCard", e);
+            FeedbackHelper.sendFeedback(this, TAG, "Failed to parse vcard", e);
             showFailureNotification(R.string.fail_reason_not_supported);
             return null;
         }
diff --git a/src/com/android/contacts/common/vcard/ShareVCardActivity.java b/src/com/android/contacts/common/vcard/ShareVCardActivity.java
index 93868aa..26d20d1 100644
--- a/src/com/android/contacts/common/vcard/ShareVCardActivity.java
+++ b/src/com/android/contacts/common/vcard/ShareVCardActivity.java
@@ -22,6 +22,7 @@
 import android.util.Log;
 
 import com.android.contacts.common.R;
+import com.android.contactsbind.FeedbackHelper;
 
 import java.io.File;
 import java.io.IOException;
@@ -50,7 +51,7 @@
         try {
             file.createNewFile();
         } catch (IOException e) {
-            Log.e(LOG_TAG, "Failed to create .vcf file, because: " + e);
+            FeedbackHelper.sendFeedback(this, LOG_TAG, "Failed to create .vcf file", e);
             finish();
             return;
         }