Show the editor in full-screen for Edit and New.

Change-Id: I1f02d979db141d2b08b82aac85fa2deb39c5fbec
diff --git a/res/layout-xlarge/contact_editor_activity.xml b/res/layout-xlarge/contact_editor_activity.xml
index e3d36a7..09bc8de 100644
--- a/res/layout-xlarge/contact_editor_activity.xml
+++ b/res/layout-xlarge/contact_editor_activity.xml
@@ -15,31 +15,16 @@
 -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="600dip"
+    android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical">
+    android:orientation="vertical"
+    android:paddingLeft="30dip"
+    android:paddingRight="30dip"
+    >
 
     <fragment class="com.android.contacts.views.editor.ContactEditorFragment"
             android:id="@+id/contact_editor_fragment"
             android:layout_width="match_parent"
             android:layout_height="0px"
             android:layout_weight="1" />
-
-    <LinearLayout
-        android:layout_width="wrap_content"
-        android:layout_height="50dip"
-        android:orientation="horizontal"
-        android:gravity="center_horizontal">
-
-        <Button
-            android:id="@+id/done"
-            android:layout_width="150dip"
-            android:layout_height="match_parent"
-            android:text="@string/menu_done" />
-        <Button
-            android:id="@+id/revert"
-            android:layout_width="150dip"
-            android:layout_height="match_parent"
-            android:text="@string/menu_doNotSave" />
-    </LinearLayout>
 </LinearLayout>
diff --git a/res/layout/contact_editor_activity.xml b/res/layout/contact_editor_activity.xml
index ee4d6ac..e51869b 100644
--- a/res/layout/contact_editor_activity.xml
+++ b/res/layout/contact_editor_activity.xml
@@ -22,4 +22,21 @@
             android:id="@+id/contact_editor_fragment"
             android:layout_width="match_parent"
             android:layout_height="match_parent" />
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="50dip"
+        android:orientation="horizontal"
+        android:gravity="center_horizontal">
+
+        <Button
+            android:id="@+id/done"
+            android:layout_width="150dip"
+            android:layout_height="match_parent"
+            android:text="@string/menu_done" />
+        <Button
+            android:id="@+id/revert"
+            android:layout_width="150dip"
+            android:layout_height="match_parent"
+            android:text="@string/menu_doNotSave" />
+    </LinearLayout>
 </FrameLayout>
diff --git a/res/values-xlarge/styles.xml b/res/values-xlarge/styles.xml
index 9d354819..9281e66 100644
--- a/res/values-xlarge/styles.xml
+++ b/res/values-xlarge/styles.xml
@@ -30,7 +30,7 @@
     <style name="ContactDetailActivityTheme" parent="@android:Theme.Dialog">
         <item name="android:windowContentOverlay">@null</item>
     </style>
-    <style name="ContactEditorActivityTheme" parent="@android:Theme.Dialog">
+    <style name="ContactEditorActivityTheme" parent="@android:Theme.Light.Holo">
         <item name="android:windowContentOverlay">@null</item>
     </style>
 </resources>
diff --git a/src/com/android/contacts/activities/ContactBrowserActivity.java b/src/com/android/contacts/activities/ContactBrowserActivity.java
index 09009b4..9cc86db 100644
--- a/src/com/android/contacts/activities/ContactBrowserActivity.java
+++ b/src/com/android/contacts/activities/ContactBrowserActivity.java
@@ -341,18 +341,6 @@
         setupContactDetailFragment(mListFragment.getSelectedContactUri());
     }
 
-    @Override
-    protected void onStop() {
-        super.onStop();
-        Log.d(TAG, "onStop");
-
-        // If anything was left unsaved, save it now but keep the editor open.
-        // Don't do this if we are only rotating the screen
-        if (mEditorFragment != null && !isChangingConfigurations()) {
-            mEditorFragment.save(false);
-        }
-    }
-
     /**
      * Creates the list fragment for the specified mode.
      */
@@ -495,7 +483,7 @@
 
         @Override
         public void onEditRequested(Uri contactLookupUri) {
-            setupContactEditorFragment(contactLookupUri);
+            startActivity(new Intent(Intent.ACTION_EDIT, contactLookupUri));
         }
 
         @Override
diff --git a/src/com/android/contacts/activities/ContactDetailActivity.java b/src/com/android/contacts/activities/ContactDetailActivity.java
index 58c5312..b07ee36 100644
--- a/src/com/android/contacts/activities/ContactDetailActivity.java
+++ b/src/com/android/contacts/activities/ContactDetailActivity.java
@@ -110,8 +110,8 @@
         }
 
         @Override
-        public void onEditRequested(Uri lookupUri) {
-            startActivity(new Intent(Intent.ACTION_EDIT, lookupUri));
+        public void onEditRequested(Uri contactLookupUri) {
+            startActivity(new Intent(Intent.ACTION_EDIT, contactLookupUri));
         }
 
         @Override
diff --git a/src/com/android/contacts/activities/ContactEditorActivity.java b/src/com/android/contacts/activities/ContactEditorActivity.java
index 85aa82e..18ce7fa 100644
--- a/src/com/android/contacts/activities/ContactEditorActivity.java
+++ b/src/com/android/contacts/activities/ContactEditorActivity.java
@@ -93,6 +93,11 @@
         }
     }
 
+    @Override
+    public void onBackPressed() {
+        mFragment.save(true);
+    }
+
     private ContactDeletionInteraction getContactDeletionInteraction() {
         if (mContactDeletionInteraction == null) {
             mContactDeletionInteraction = new ContactDeletionInteraction();
diff --git a/src/com/android/contacts/views/editor/ContactEditorFragment.java b/src/com/android/contacts/views/editor/ContactEditorFragment.java
index 55ec604..a744d0f 100644
--- a/src/com/android/contacts/views/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/views/editor/ContactEditorFragment.java
@@ -47,6 +47,7 @@
 import android.app.Fragment;
 import android.app.LoaderManager;
 import android.app.LoaderManager.LoaderCallbacks;
+import android.app.ProgressDialog;
 import android.content.ActivityNotFoundException;
 import android.content.ContentProviderOperation;
 import android.content.ContentProviderOperation.Builder;
@@ -95,6 +96,7 @@
 import android.widget.Toast;
 
 import java.io.File;
+import java.lang.ref.WeakReference;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -144,6 +146,29 @@
         public static final int JOIN = 3;
     }
 
+    private interface Status {
+        /**
+         * The loader is fetching data
+         */
+        public static final int LOADING = 0;
+
+        /**
+         * Not currently busy. We are waiting for the user to enter data
+         */
+        public static final int EDITING = 1;
+
+        /**
+         * The data is currently being saved. This is used to prevent more auto-saves (they shouldn't
+         * overlap)
+         */
+        public static final int SAVING = 2;
+
+        /**
+         * Prevents any more savings (this is used if Save/Close or Revert was executed by the user)
+         */
+        public static final int CLOSING = 3;
+    }
+
     private static final int REQUEST_CODE_JOIN = 0;
     private static final int REQUEST_CODE_CAMERA_WITH_DATA = 1;
     private static final int REQUEST_CODE_PHOTO_PICKED_WITH_DATA = 2;
@@ -188,6 +213,8 @@
 
     private long mLoaderStartTime;
 
+    private int mStatus;
+
     private AggregationSuggestionEngine mAggregationSuggestionEngine;
 
     public ContactEditorFragment() {
@@ -205,6 +232,10 @@
         if (mAggregationSuggestionEngine != null) {
             mAggregationSuggestionEngine.quit();
         }
+        // If anything was left unsaved, save it now but keep the editor open.
+        if (!getActivity().isChangingConfigurations() && mStatus == Status.EDITING) {
+            save(false);
+        }
     }
 
     @Override
@@ -215,6 +246,11 @@
 
         setHasOptionsMenu(true);
 
+        // If we are in an orientation change, we already have mState (it was loaded by onCreate)
+        if (mState != null) {
+            bindEditors();
+        }
+
         return view;
     }
 
@@ -222,15 +258,23 @@
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
 
-        if (Intent.ACTION_EDIT.equals(mAction)) {
-            if (mListener != null) mListener.setTitleTo(R.string.editContact_title_edit);
-            getLoaderManager().initLoader(LOADER_DATA, null, mDataLoaderListener);
-        } else if (Intent.ACTION_INSERT.equals(mAction)) {
-            if (mListener != null) mListener.setTitleTo(R.string.editContact_title_insert);
+        Log.d(TAG, "onActivityCreated(" + savedInstanceState + ")");
 
-            doAddAction();
-        } else throw new IllegalArgumentException("Unknown Action String " + mAction +
-                ". Only support " + Intent.ACTION_EDIT + " or " + Intent.ACTION_INSERT);
+        // Handle initial actions only when existing state missing
+        final boolean hasIncomingState = savedInstanceState != null &&
+                savedInstanceState.containsKey(KEY_EDIT_STATE);
+
+        if (!hasIncomingState) {
+            if (Intent.ACTION_EDIT.equals(mAction)) {
+                if (mListener != null) mListener.setTitleTo(R.string.editContact_title_edit);
+                getLoaderManager().initLoader(LOADER_DATA, null, mDataLoaderListener);
+            } else if (Intent.ACTION_INSERT.equals(mAction)) {
+                if (mListener != null) mListener.setTitleTo(R.string.editContact_title_insert);
+
+                doAddAction();
+            } else throw new IllegalArgumentException("Unknown Action String " + mAction +
+                    ". Only support " + Intent.ACTION_EDIT + " or " + Intent.ACTION_INSERT);
+        }
     }
 
     public void load(String action, Uri lookupUri, String mimeType, Bundle intentExtras) {
@@ -259,7 +303,7 @@
             // If savedState is non-null, onRestoreInstanceState() will restore the generator.
             mViewIdGenerator = new ViewIdGenerator();
         } else {
-            // Read modifications from instance
+            // Read state from savedState. No loading involved here
             mState = savedState.<EntityDeltaList> getParcelable(KEY_EDIT_STATE);
             mRawContactIdRequestingPhoto = savedState.getLong(
                     KEY_RAW_CONTACT_ID_REQUESTING_PHOTO);
@@ -270,6 +314,7 @@
             }
             mQuerySelection = savedState.getString(KEY_QUERY_SELECTION);
             mContactIdForJoin = savedState.getLong(KEY_CONTACT_ID_FOR_JOIN);
+            mStatus = Status.EDITING;
         }
     }
 
@@ -280,9 +325,10 @@
             return;
         }
 
-        ArrayList<Entity> entities = data.getEntities();
-        StringBuilder sb = new StringBuilder(RawContacts._ID + " IN(");
-        int count = entities.size();
+        // Build Filter mQuerySelection
+        final ArrayList<Entity> entities = data.getEntities();
+        final StringBuilder sb = new StringBuilder(RawContacts._ID + " IN(");
+        final int count = entities.size();
         for (int i = 0; i < count; i++) {
             if (i > 0) {
                 sb.append(',');
@@ -293,14 +339,11 @@
         mQuerySelection = sb.toString();
         mState = EntityDeltaList.fromIterator(entities.iterator());
 
-
-        // TODO: Merge in Intent parameters can only be done on the first load.
-        // The behaviour for subsequent loads is probably broken, so fix this
+        // Merge in Extras from Intent
         final boolean hasExtras = mIntentExtras != null && mIntentExtras.size() > 0;
         final boolean hasState = mState.size() > 0;
         if (hasExtras && hasState) {
             // Find source defining the first RawContact found
-            // TODO: Test this. Can we actually always use the first RawContact. This seems wrong
             final EntityDelta state = mState.get(0);
             final String accountType = state.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
             final Sources sources = Sources.getInstance(mContext);
@@ -434,7 +477,9 @@
         mContent.setVisibility(View.VISIBLE);
 
         // Refresh Action Bar as the visibility of the join command
-        getActivity().invalidateOptionsMenu();
+        // Activity can be null if we have been detached from the Activity
+        final Activity activity = getActivity();
+        if (activity != null) activity.invalidateOptionsMenu();
     }
 
     @Override
@@ -602,8 +647,7 @@
             return false;
         }
 
-        // TODO: Status still needed?
-        //mStatus = STATUS_SAVING;
+        mStatus = Status.SAVING;
         final PersistTask task = new PersistTask(this, saveMode);
         task.execute(mState);
 
@@ -619,6 +663,8 @@
     }
 
     private boolean doRevertAction() {
+        // When this Fragment is closed we don't want it to auto-save
+        mStatus = Status.CLOSING;
         if (mListener != null) mListener.onReverted();
 
         return true;
@@ -655,6 +701,8 @@
                     resultCode = Activity.RESULT_CANCELED;
                     resultIntent = null;
                 }
+                // It is already saved, so prevent that it is saved again
+                mStatus = Status.CLOSING;
                 if (mListener != null) mListener.onSaveFinished(resultCode, resultIntent);
                 break;
             case SaveMode.RELOAD:
@@ -663,6 +711,7 @@
                     // If it already was an EDIT, we are changing to the new Uri now
                     mState = null;
                     load(Intent.ACTION_EDIT, contactLookupUri, mMimeType, null);
+                    mStatus = Status.LOADING;
                     getLoaderManager().restartLoader(LOADER_DATA, null, mDataLoaderListener);
                 }
                 break;
@@ -672,13 +721,14 @@
                 } else {
                     Log.d(TAG, "No listener registered, can not call onSplitFinished");
                 }
+                mStatus = Status.EDITING;
                 break;
 
             case SaveMode.JOIN:
-                //mStatus = STATUS_EDITING;
                 if (success) {
                     showJoinAggregateActivity(contactLookupUri);
                 }
+                mStatus = Status.EDITING;
                 break;
         }
     }
@@ -1284,6 +1334,8 @@
 
         private final Context mContext;
 
+        private WeakReference<ProgressDialog> mProgress;
+
         private int mSaveMode;
         private Uri mContactLookupUri = null;
 
@@ -1296,6 +1348,9 @@
         /** {@inheritDoc} */
         @Override
         protected void onPreExecute(ContactEditorFragment target) {
+            mProgress = new WeakReference<ProgressDialog>(ProgressDialog.show(target.getActivity(),
+                    null, target.getActivity().getText(R.string.savingContact)));
+
             // Before starting this task, start an empty service to protect our
             // process from being reclaimed by the system.
             mContext.startService(new Intent(mContext, EmptyService.class));
@@ -1389,6 +1444,16 @@
                 Toast.makeText(mContext, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show();
             }
 
+            final ProgressDialog progress = mProgress.get();
+            if (progress != null && progress.isShowing()) {
+                try {
+                    progress.dismiss();
+                } catch (Exception e) {
+                    // this can happen if our view has already been closed. this can safely be
+                    // ignored
+                }
+            }
+
             // Stop the service that was protecting us
             mContext.stopService(new Intent(mContext, EmptyService.class));
 
@@ -1485,6 +1550,7 @@
                 return;
             }
 
+            mStatus = Status.EDITING;
             final long setDataStartTime = SystemClock.elapsedRealtime();
             setData(data);
             final long setDataEndTime = SystemClock.elapsedRealtime();