Handle saving and communicating selected tab between View/Edit activities.

EditContactActivity now accepts intents with raw_contacts instead of
contacts. In addition it reports back which raw_contact was selected on
exit.

ViewContactActivity now saves and restores which raw_contact was
currently being viewed, and uses the raw_contact reported back from
EditContactActivity. The overall effect is when moving from View->Edit
or Edit->View the selected tab doesn't change.
diff --git a/src/com/android/contacts/BaseContactCardActivity.java b/src/com/android/contacts/BaseContactCardActivity.java
index ef84e69..441aea1 100644
--- a/src/com/android/contacts/BaseContactCardActivity.java
+++ b/src/com/android/contacts/BaseContactCardActivity.java
@@ -72,6 +72,9 @@
     protected static final int TAB_ACCOUNT_NAME_COLUMN_INDEX = 1;
     protected static final int TAB_ACCOUNT_TYPE_COLUMN_INDEX = 2;
 
+    protected static final String SELECTED_RAW_CONTACT_ID_KEY = "selectedRawContact";
+    protected long mSelectedRawContactId;
+
     private static final int TOKEN_TABS = 0;
 
     @Override
@@ -101,6 +104,19 @@
         asyncSetupTabs();
     }
 
+
+    @Override
+    protected void onRestoreInstanceState(Bundle savedInstanceState) {
+        super.onRestoreInstanceState(savedInstanceState);
+        mSelectedRawContactId = savedInstanceState.getLong(SELECTED_RAW_CONTACT_ID_KEY);
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putLong(SELECTED_RAW_CONTACT_ID_KEY, mSelectedRawContactId);
+    }
+
     private void asyncSetupTabs() {
         long contactId = ContentUris.parseId(mUri);
         mHandler.startQueryEntities(TOKEN_TABS, null,
@@ -108,7 +124,7 @@
     }
 
     /**
-     * Return the contactId associated with the tab at an index.
+     * Return the RawContact id associated with the tab at an index.
      *
      * @param index The index of the tab in question.
      * @return The contactId associated with the tab at the specified index.
@@ -117,6 +133,22 @@
         return mTabRawContactIdMap.get(index);
     }
 
+    /**
+     * Return the tab index associated with the RawContact id.
+     *
+     * @param index The index of the tab in question.
+     * @return The contactId associated with the tab at the specified index.
+     */
+    protected int getTabIndexForRawContactId(long rawContactId) {
+        int numTabs = mTabRawContactIdMap.size();
+        for (int i=0; i < numTabs; i++) {
+            if (mTabRawContactIdMap.get(i) == rawContactId) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
     /** {@inheritDoc} */
     public void onQueryEntitiesComplete(int token, Object cookie, EntityIterator iterator) {
         try{
@@ -170,7 +202,8 @@
                     ContactsSource.LEVEL_SUMMARY);
             addTab(rawContactId, createTabIndicatorView(mTabWidget, source));
         }
-        mTabWidget.setCurrentTab(0);
+
+        selectInitialTab();
         mTabWidget.setVisibility(View.VISIBLE);
         mTabWidget.postInvalidate();
     }
@@ -204,6 +237,18 @@
         mTabWidget.removeAllTabs();
     }
 
+    protected void selectInitialTab() {
+        int selectedTabIndex = -1;
+        if (mSelectedRawContactId > 0) {
+            selectedTabIndex = getTabIndexForRawContactId(mSelectedRawContactId);
+        }
+        if (selectedTabIndex >= 0) {
+            mTabWidget.setCurrentTab(selectedTabIndex);
+        } else {
+            selectDefaultTab();
+        }
+    }
+
     /**
      * Makes the default tab selection. This is called after the tabs have been
      * bound for the first time, and whenever a new intent is received. Override
diff --git a/src/com/android/contacts/ContactsUtils.java b/src/com/android/contacts/ContactsUtils.java
index d2a01ca..33bbf1c 100644
--- a/src/com/android/contacts/ContactsUtils.java
+++ b/src/com/android/contacts/ContactsUtils.java
@@ -21,6 +21,8 @@
 
 import java.io.ByteArrayInputStream;
 import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+
 import java.io.InputStream;
 
 import android.net.Uri;
@@ -230,4 +232,22 @@
         intent.putExtra("return-data", true);
         return intent;
     }
+
+    public static long queryForContactId(ContentResolver cr, long rawContactId) {
+        Cursor contactIdCursor = null;
+        long contactId = -1;
+        try {
+            contactIdCursor = cr.query(RawContacts.CONTENT_URI,
+                    new String[] {RawContacts.CONTACT_ID},
+                    RawContacts._ID + "=" + rawContactId, null, null);
+            if (contactIdCursor != null && contactIdCursor.moveToFirst()) {
+                contactId = contactIdCursor.getLong(0);
+            }
+        } finally {
+            if (contactIdCursor != null) {
+                contactIdCursor.close();
+            }
+        }
+        return contactId;
+    }
 }
diff --git a/src/com/android/contacts/ViewContactActivity.java b/src/com/android/contacts/ViewContactActivity.java
index beaea44..2fd22b1 100644
--- a/src/com/android/contacts/ViewContactActivity.java
+++ b/src/com/android/contacts/ViewContactActivity.java
@@ -98,27 +98,29 @@
     private static final String TAG = "ViewContact";
     private static final String SHOW_BARCODE_INTENT = "com.google.zxing.client.android.ENCODE";
 
+    public static final String RAW_CONTACT_ID_EXTRA = "rawContactIdExtra";
+
     private static final boolean SHOW_SEPARATORS = false;
 
     private static final int DIALOG_CONFIRM_DELETE = 1;
 
-    private static final int REQUEST_JOIN_AGGREGATE = 1;
+    private static final int REQUEST_JOIN_CONTACT = 1;
+    private static final int REQUEST_EDIT_CONTACT = 2;
 
-    public static final int MENU_ITEM_DELETE = 1;
-    public static final int MENU_ITEM_MAKE_DEFAULT = 2;
-    public static final int MENU_ITEM_SHOW_BARCODE = 3;
-    public static final int MENU_ITEM_SPLIT_AGGREGATE = 4;
-    public static final int MENU_ITEM_JOIN_AGGREGATE = 5;
-    public static final int MENU_ITEM_OPTIONS = 6;
+    public static final int MENU_ITEM_EDIT = 1;
+    public static final int MENU_ITEM_DELETE = 2;
+    public static final int MENU_ITEM_MAKE_DEFAULT = 3;
+    public static final int MENU_ITEM_SHOW_BARCODE = 4;
+    public static final int MENU_ITEM_SPLIT_AGGREGATE = 5;
+    public static final int MENU_ITEM_JOIN_AGGREGATE = 6;
+    public static final int MENU_ITEM_OPTIONS = 7;
 
     private Uri mUri;
-    private Uri mAggDataUri;
     private ContentResolver mResolver;
     private ViewAdapter mAdapter;
     private int mNumPhoneNumbers = 0;
 
-    private static final long ALL_CONTACTS_ID = -1;
-    private long mRawContactId = ALL_CONTACTS_ID;
+    private static final long ALL_CONTACTS_ID = -100;
 
     /**
      * A list of distinct contact IDs included in the current contact.
@@ -182,7 +184,6 @@
         mTabContentLayout.addView(mListView);
 
         mUri = getIntent().getData();
-        mAggDataUri = Uri.withAppendedPath(mUri, "data");
         mResolver = getContentResolver();
 
         // Build the list of sections. The order they're added to mSections dictates the
@@ -199,7 +200,10 @@
         //TODO Read this value from a preference
         mShowSmsLinksForAllPhones = true;
 
-        mCursor = mResolver.query(mAggDataUri,
+        //Select the all tab to start.
+        mSelectedRawContactId = ALL_CONTACTS_ID;
+
+        mCursor = mResolver.query(Uri.withAppendedPath(mUri, "data"),
                 CONTACT_PROJECTION, null, null, null);
     }
 
@@ -268,7 +272,7 @@
 
     public void onTabSelectionChanged(int tabIndex, boolean clicked) {
         long rawContactId = getTabRawContactId(tabIndex);
-        mRawContactId = rawContactId;
+        mSelectedRawContactId = rawContactId;
         dataChanged();
     }
 
@@ -300,9 +304,8 @@
 
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
-        menu.add(0, 0, 0, R.string.menu_editContact)
+        menu.add(0, MENU_ITEM_EDIT, 0, R.string.menu_editContact)
                 .setIcon(android.R.drawable.ic_menu_edit)
-                .setIntent(new Intent(Intent.ACTION_EDIT, mUri))
                 .setAlphabeticShortcut('e');
         menu.add(0, MENU_ITEM_DELETE, 0, R.string.menu_deleteContact)
                 .setIcon(android.R.drawable.ic_menu_delete);
@@ -381,6 +384,18 @@
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
+            case MENU_ITEM_EDIT: {
+                long rawContactIdToEdit = mSelectedRawContactId;
+                if (rawContactIdToEdit == ALL_CONTACTS_ID) {
+                    // If the "all" tab is selected, edit the next tab.
+                    rawContactIdToEdit = getTabRawContactId(mTabWidget.getCurrentTab() + 1);
+                }
+                Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI,
+                        rawContactIdToEdit);
+                startActivityForResult(new Intent(Intent.ACTION_EDIT, rawContactUri),
+                        REQUEST_EDIT_CONTACT);
+                break;
+            }
             case MENU_ITEM_DELETE: {
                 // Get confirmation
                 showDialog(DIALOG_CONFIRM_DELETE);
@@ -529,14 +544,29 @@
     public void showJoinAggregateActivity() {
         Intent intent = new Intent(ContactsListActivity.JOIN_AGGREGATE);
         intent.putExtra(ContactsListActivity.EXTRA_AGGREGATE_ID, ContentUris.parseId(mUri));
-        startActivityForResult(intent, REQUEST_JOIN_AGGREGATE);
+        startActivityForResult(intent, REQUEST_JOIN_CONTACT);
     }
 
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
-        if (requestCode == REQUEST_JOIN_AGGREGATE && resultCode == RESULT_OK && intent != null) {
-            final long aggregateId = ContentUris.parseId(intent.getData());
-            joinAggregate(aggregateId);
+        switch (requestCode) {
+            case REQUEST_JOIN_CONTACT: {
+                if (resultCode == RESULT_OK && intent != null) {
+                    final long aggregateId = ContentUris.parseId(intent.getData());
+                    joinAggregate(aggregateId);
+                }
+                break;
+            }
+            case REQUEST_EDIT_CONTACT: {
+                if (resultCode == RESULT_OK && intent != null) {
+                    long newInitialSelectedRawContactId = intent.getLongExtra(
+                            RAW_CONTACT_ID_EXTRA, ALL_CONTACTS_ID);
+                    if (newInitialSelectedRawContactId != mSelectedRawContactId) {
+                        mSelectedRawContactId = newInitialSelectedRawContactId;
+                        selectInitialTab();
+                    }
+                }
+            }
         }
     }
 
@@ -700,7 +730,8 @@
                 }
 
                 // This performs the tab filtering
-                if (mRawContactId != entry.contactId && mRawContactId != ALL_CONTACTS_ID) {
+                if (mSelectedRawContactId != entry.contactId
+                        && mSelectedRawContactId != ALL_CONTACTS_ID) {
                     continue;
                 }
 
diff --git a/src/com/android/contacts/ui/EditContactActivity.java b/src/com/android/contacts/ui/EditContactActivity.java
index b87b0c9..a5b1a47 100644
--- a/src/com/android/contacts/ui/EditContactActivity.java
+++ b/src/com/android/contacts/ui/EditContactActivity.java
@@ -20,6 +20,7 @@
 import com.android.contacts.ContactsUtils;
 import com.android.contacts.R;
 import com.android.contacts.ScrollingTabWidget;
+import com.android.contacts.ViewContactActivity;
 import com.android.contacts.model.ContactsSource;
 import com.android.contacts.model.EntityDelta;
 import com.android.contacts.model.HardCodedSources;
@@ -97,6 +98,11 @@
     private static final String KEY_EDIT_STATE = "state";
     private static final String KEY_EDITOR_STATE = "editor";
     private static final String KEY_SELECTED_TAB = "tab";
+    private static final String KEY_SELECTED_TAB_ID = "tabId";
+    private static final String KEY_CONTACT_ID = "contactId";
+
+    private long mSelectedRawContactId = -1;
+    private long mContactId = -1;
 
     private ScrollingTabWidget mTabWidget;
     private ContactHeaderWidget mHeader;
@@ -213,11 +219,14 @@
             final Uri data = intent.getData();
             final String authority = data.getAuthority();
             if (ContactsContract.AUTHORITY.equals(authority)) {
-                final long contactId = ContentUris.parseId(data);
-                selection = RawContacts.CONTACT_ID + "=" + contactId;
-
+                final long rawContactId = ContentUris.parseId(data);
+                target.mSelectedRawContactId = rawContactId;
+                target.mContactId = ContactsUtils.queryForContactId(target.getContentResolver(),
+                        rawContactId);
+                selection = RawContacts.CONTACT_ID + "=" + target.mContactId;
             } else if (Contacts.AUTHORITY.equals(authority)) {
                 final long rawContactId = ContentUris.parseId(data);
+                target.mSelectedRawContactId = rawContactId;
                 selection = RawContacts._ID + "=" + rawContactId;
             }
 
@@ -277,6 +286,8 @@
         outState.putParcelable(KEY_EDIT_STATE, mState);
 //        outState.putSparseParcelableArray(KEY_EDITOR_STATE, buildEditorState());
 //        outState.putInt(KEY_SELECTED_TAB, mTabWidget.getCurrentTab());
+        outState.putLong(KEY_SELECTED_TAB_ID, mSelectedRawContactId);
+        outState.putLong(KEY_CONTACT_ID, mContactId);
 
         super.onSaveInstanceState(outState);
     }
@@ -285,6 +296,8 @@
     protected void onRestoreInstanceState(Bundle savedInstanceState) {
         // Read modifications from instance
         mState = savedInstanceState.<EditState> getParcelable(KEY_EDIT_STATE);
+        mSelectedRawContactId = savedInstanceState.getLong(KEY_SELECTED_TAB_ID);
+        mContactId = savedInstanceState.getLong(KEY_CONTACT_ID);
 
         Log.d(TAG, "onrestoreinstancestate");
 
@@ -306,19 +319,26 @@
      */
     protected void bindTabs() {
         final Sources sources = Sources.getInstance(this);
+        int selectedTab = 0;
 
         mTabWidget.removeAllTabs();
         for (EntityDelta entity : mState) {
-            final String accountType = entity.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
+            ValuesDelta values = entity.getValues();
+            final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
+            final Long rawContactId = values.getAsLong(RawContacts._ID);
             final ContactsSource source = sources.getInflatedSource(accountType,
                     ContactsSource.LEVEL_CONSTRAINTS);
 
+            if (rawContactId != null && rawContactId == mSelectedRawContactId) {
+                selectedTab = mTabWidget.getTabCount();
+            }
+
             final View tabView = BaseContactCardActivity.createTabIndicatorView(mTabWidget, source);
             mTabWidget.addTab(tabView);
         }
         if (mState.size() > 0) {
-            mTabWidget.setCurrentTab(0);
-            this.onTabSelectionChanged(0, false);
+            mTabWidget.setCurrentTab(selectedTab);
+            this.onTabSelectionChanged(selectedTab, false);
         }
     }
 
@@ -333,12 +353,8 @@
         // TODO: fill header bar with newly parsed data for speed
         // TODO: handle legacy case correctly instead of assuming _id
 
-        final Uri uri = this.getIntent().getData();
-
-        try {
-            final long contactId = ContentUris.parseId(uri);
-            mHeader.bindFromContactId(contactId);
-        } catch (NumberFormatException e) {
+        if (mContactId > 0) {
+            mHeader.bindFromContactId(mContactId);
         }
 
 //        mHeader.setDisplayName(displayName, phoneticName);
@@ -355,6 +371,10 @@
         // Find entity and source for selected tab
         final EntityDelta entity = mState.get(tabIndex);
         final String accountType = entity.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
+        Long rawContactId = entity.getValues().getAsLong(RawContacts._ID);
+        if (rawContactId != null) {
+            mSelectedRawContactId = rawContactId;
+        }
 
         final Sources sources = Sources.getInstance(this);
         final ContactsSource source = sources.getInflatedSource(accountType,
@@ -561,6 +581,8 @@
 
         // Persisting finished, or we timed out waiting on it. Either way,
         // finish this activity, the background task will keep running.
+        setResult(RESULT_OK, new Intent().putExtra(ViewContactActivity.RAW_CONTACT_ID_EXTRA,
+                mSelectedRawContactId));
         this.finish();
         return true;
     }