am b76f86d1: Fix inserting photos into unwriteable contacts

* commit 'b76f86d1a416522bac1f88ec4aa9a574ac58cfb1':
  Fix inserting photos into unwriteable contacts
diff --git a/src/com/android/contacts/activities/AttachPhotoActivity.java b/src/com/android/contacts/activities/AttachPhotoActivity.java
index 4c4d4dc..3196f87 100644
--- a/src/com/android/contacts/activities/AttachPhotoActivity.java
+++ b/src/com/android/contacts/activities/AttachPhotoActivity.java
@@ -16,20 +16,22 @@
 
 package com.android.contacts.activities;
 
+import android.app.Activity;
 import android.content.ActivityNotFoundException;
 import android.content.ContentResolver;
+import android.content.ContentValues;
 import android.content.Intent;
 import android.content.Loader;
 import android.content.Loader.OnLoadCompleteListener;
-import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 import android.net.Uri;
 import android.os.Bundle;
 import android.provider.ContactsContract.CommonDataKinds.Photo;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.DisplayPhoto;
+import android.provider.ContactsContract.Intents;
+import android.provider.ContactsContract.RawContacts;
 import android.util.Log;
 import android.widget.Toast;
 
@@ -44,9 +46,10 @@
 import com.android.contacts.common.ContactsUtils;
 import com.android.contacts.common.model.account.AccountType;
 import com.android.contacts.common.model.ValuesDelta;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.editor.ContactEditorUtils;
 import com.android.contacts.util.ContactPhotoUtils;
 
-import java.io.File;
 import java.io.FileNotFoundException;
 
 /**
@@ -60,6 +63,7 @@
 
     private static final int REQUEST_PICK_CONTACT = 1;
     private static final int REQUEST_CROP_PHOTO = 2;
+    private static final int REQUEST_PICK_DEFAULT_ACCOUNT_FOR_NEW_CONTACT = 3;
 
     private static final String KEY_CONTACT_URI = "contact_uri";
     private static final String KEY_TEMP_PHOTO_URI = "temp_photo_uri";
@@ -130,7 +134,24 @@
 
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent result) {
-        if (requestCode == REQUEST_PICK_CONTACT) {
+        if (requestCode == REQUEST_PICK_DEFAULT_ACCOUNT_FOR_NEW_CONTACT) {
+            // Bail if the account selector was not successful.
+            if (resultCode != Activity.RESULT_OK) {
+                Log.w(TAG, "account selector was not successful");
+                finish();
+                return;
+            }
+            // If there's an account specified, use it.
+            if (result != null) {
+                AccountWithDataSet account = result.getParcelableExtra(Intents.Insert.ACCOUNT);
+                if (account != null) {
+                    createNewRawContact(account);
+                    return;
+                }
+            }
+            // If there isn't an account specified, then the user opted to keep the contact local.
+            createNewRawContact(null);
+        } else if (requestCode == REQUEST_PICK_CONTACT) {
             if (resultCode != RESULT_OK) {
                 finish();
                 return;
@@ -225,10 +246,17 @@
         RawContactDeltaList deltaList = contact.createRawContactDeltaList();
         RawContactDelta raw = deltaList.getFirstWritableRawContact(this);
         if (raw == null) {
-            Log.w(TAG, "no writable raw-contact found");
+            // We can't directly insert this photo since no raw contacts exist in the contact.
+            selectAccountAndCreateContact();
             return;
         }
 
+        saveToContact(contact, deltaList, raw);
+    }
+
+    private void saveToContact(Contact contact, RawContactDeltaList deltaList,
+            RawContactDelta raw) {
+
         // Create a scaled, compressed bitmap to add to the entity-delta list.
         final int size = ContactsUtils.getThumbnailSize(this);
         Bitmap bitmap;
@@ -236,10 +264,12 @@
             bitmap = ContactPhotoUtils.getBitmapFromUri(this, mCroppedPhotoUri);
         } catch (FileNotFoundException e) {
             Log.w(TAG, "Could not find bitmap");
+            finish();
             return;
         }
         if (bitmap == null) {
             Log.w(TAG, "Could not decode bitmap");
+            finish();
             return;
         }
 
@@ -247,8 +277,10 @@
         final byte[] compressed = ContactPhotoUtils.compressBitmap(scaled);
         if (compressed == null) {
             Log.w(TAG, "could not create scaled and compressed Bitmap");
+            finish();
             return;
         }
+
         // Add compressed bitmap to entity-delta... this allows us to save to
         // a new contact; otherwise the entity-delta-list would be empty, and
         // the ContactSaveService would not create the new contact, and the
@@ -258,6 +290,7 @@
                 RawContactModifier.ensureKindExists(raw, account, Photo.CONTENT_ITEM_TYPE);
         if (values == null) {
             Log.w(TAG, "cannot attach photo to this account type");
+            finish();
             return;
         }
         values.setPhoto(compressed);
@@ -270,10 +303,52 @@
                 "", 0,
                 contact.isUserProfile(),
                 null, null,
-                raw.getRawContactId(),
+                raw.getRawContactId() != null ? raw.getRawContactId() : -1,
                 mCroppedPhotoUri
-                );
+        );
         startService(intent);
         finish();
     }
+
+    private void selectAccountAndCreateContact() {
+        // If there is no default account or the accounts have changed such that we need to
+        // prompt the user again, then launch the account prompt.
+        final ContactEditorUtils editorUtils = ContactEditorUtils.getInstance(this);
+        if (editorUtils.shouldShowAccountChangedNotification()) {
+            Intent intent = new Intent(this, ContactEditorAccountsChangedActivity.class);
+            startActivityForResult(intent, REQUEST_PICK_DEFAULT_ACCOUNT_FOR_NEW_CONTACT);
+        } else {
+            // Otherwise, there should be a default account. Then either create a local contact
+            // (if default account is null) or create a contact with the specified account.
+            AccountWithDataSet defaultAccount = editorUtils.getDefaultAccount();
+            if (defaultAccount == null) {
+                createNewRawContact(null);
+            } else {
+                createNewRawContact(defaultAccount);
+            }
+        }
+    }
+
+    /**
+     * Create a new writeable raw contact to store mCroppedPhotoUri.
+     */
+    private void createNewRawContact(final AccountWithDataSet account) {
+        // Reload the contact from URI instead of trying to pull the contact from a member variable,
+        // since this function can be called after the activity stops and resumes.
+        loadContact(mContactUri, new Listener() {
+            @Override
+            public void onContactLoaded(Contact contactToSave) {
+                final RawContactDeltaList deltaList = contactToSave.createRawContactDeltaList();
+                final ContentValues after = new ContentValues();
+                after.put(RawContacts.ACCOUNT_TYPE, account != null ? account.type : null);
+                after.put(RawContacts.ACCOUNT_NAME, account != null ? account.name : null);
+                after.put(RawContacts.DATA_SET, account != null ? account.dataSet : null);
+
+                final RawContactDelta newRawContactDelta
+                        = new RawContactDelta(ValuesDelta.fromAfter(after));
+                deltaList.add(newRawContactDelta);
+                saveToContact(contactToSave, deltaList, newRawContactDelta);
+            }
+        });
+    }
 }