DO NOT MERGE Sticky tab rule: Remember the last tab that was used to call

Bug:3082932

Change-Id: Ic1bc7f64f84bbe2a2a8e5918bfdaa24344d67afb
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index e543e61..92ac452 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -138,22 +138,6 @@
 
         </activity-alias>
 
-        <!-- Main launch Intent to open the Contacts app. This will open the app in its last manual
-        state. This is the state that has been explicitly set by the user (e.g. by clicking a tab).
-        States configured via other Intents (e.g. CallLog after Call) are not considered manual
-        state. At the moment, the Intent always goes to the DialtactsActivity, but this might later
-        be changed to also include sub-activities like Edit or View if they were left open -->
-
-        <activity-alias android:name="ContactsLaunchActivity"
-            android:targetActivity="DialtactsActivity"
-        >
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <category android:name="android.intent.category.BROWSABLE" />
-            </intent-filter>
-        </activity-alias>
-
         <!-- An empty activity that presents the DialtactActivity's Favorites tab -->
         <activity-alias android:name="DialtactsFavoritesEntryActivity"
             android:targetActivity="DialtactsActivity"
diff --git a/src/com/android/contacts/CallDetailActivity.java b/src/com/android/contacts/CallDetailActivity.java
index 14f54c9..9f027bb 100644
--- a/src/com/android/contacts/CallDetailActivity.java
+++ b/src/com/android/contacts/CallDetailActivity.java
@@ -126,6 +126,7 @@
                     Intent callIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
                             Uri.fromParts("tel", mNumber, null));
                     startActivity(callIntent);
+                    StickyTabs.saveTab(this, getIntent());
                     return true;
                 }
             }
@@ -240,6 +241,7 @@
                     // to create new contact from this number.
                     if (personUri != null) {
                         Intent viewIntent = new Intent(Intent.ACTION_VIEW, personUri);
+                        StickyTabs.setTab(viewIntent, getIntent());
                         actions.add(new ViewEntry(R.drawable.sym_action_view_contact,
                                 getString(R.string.menu_viewContact), viewIntent));
                     } else {
@@ -362,6 +364,9 @@
         if (view.getTag() instanceof ViewEntry) {
             ViewEntry entry = (ViewEntry) view.getTag();
             if (entry.intent != null) {
+                if (Intent.ACTION_CALL_PRIVILEGED.equals(entry.intent.getAction())) {
+                    StickyTabs.saveTab(this, getIntent());
+                }
                 startActivity(entry.intent);
             }
         }
diff --git a/src/com/android/contacts/ContactsListActivity.java b/src/com/android/contacts/ContactsListActivity.java
index 719bb25..ac6a3a8 100644
--- a/src/com/android/contacts/ContactsListActivity.java
+++ b/src/com/android/contacts/ContactsListActivity.java
@@ -1593,13 +1593,14 @@
         menu.setHeaderTitle(cursor.getString(getSummaryDisplayNameColumnIndex()));
 
         // View contact details
+        final Intent viewContactIntent = new Intent(Intent.ACTION_VIEW, contactUri);
+        StickyTabs.setTab(viewContactIntent, getIntent());
         menu.add(0, MENU_ITEM_VIEW_CONTACT, 0, R.string.menu_viewContact)
-                .setIntent(new Intent(Intent.ACTION_VIEW, contactUri));
+                .setIntent(viewContactIntent);
 
         if (cursor.getInt(SUMMARY_HAS_PHONE_COLUMN_INDEX) != 0) {
             // Calling contact
-            menu.add(0, MENU_ITEM_CALL, 0,
-                    getString(R.string.menu_call));
+            menu.add(0, MENU_ITEM_CALL, 0, getString(R.string.menu_call));
             // Send SMS item
             menu.add(0, MENU_ITEM_SEND_SMS, 0, getString(R.string.menu_sendSMS));
         }
@@ -1846,6 +1847,7 @@
             final Uri uri = getSelectedUri(position);
             if ((mMode & MODE_MASK_PICKER) == 0) {
                 final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+                StickyTabs.setTab(intent, getIntent());
                 startActivityForResult(intent, SUBACTIVITY_VIEW_CONTACT);
             } else if (mMode == MODE_JOIN_CONTACT) {
                 returnPickerResult(null, null, uri, 0);
@@ -2665,12 +2667,13 @@
                 if (phone == null) {
                     // Display dialog to choose a number to call.
                     PhoneDisambigDialog phoneDialog = new PhoneDisambigDialog(
-                            this, phonesCursor, sendSms);
+                            this, phonesCursor, sendSms, StickyTabs.getTab(getIntent()));
                     phoneDialog.show();
                 } else {
                     if (sendSms) {
                         ContactsUtils.initiateSms(this, phone);
                     } else {
+                        StickyTabs.saveTab(this, getIntent());
                         ContactsUtils.initiateCall(this, phone);
                     }
                 }
@@ -3145,6 +3148,7 @@
                     final String lookupKey = cursor.getString(SUMMARY_LOOKUP_KEY_COLUMN_INDEX);
                     QuickContactBadge quickContact = view.getQuickContact();
                     quickContact.assignContactUri(Contacts.getLookupUri(contactId, lookupKey));
+                    quickContact.setSelectedContactsAppTabIndex(StickyTabs.getTab(getIntent()));
                     viewToUse = quickContact;
                 } else {
                     viewToUse = view.getPhotoView();
diff --git a/src/com/android/contacts/DialtactsActivity.java b/src/com/android/contacts/DialtactsActivity.java
index 05adb7c..b742113 100644
--- a/src/com/android/contacts/DialtactsActivity.java
+++ b/src/com/android/contacts/DialtactsActivity.java
@@ -44,10 +44,6 @@
     private static final String FAVORITES_ENTRY_COMPONENT =
             "com.android.contacts.DialtactsFavoritesEntryActivity";
 
-    /** Opens the Contacts app in the state the user has last set it to */
-    private static final String CONTACTS_LAUNCH_ACTIVITY =
-            "com.android.contacts.ContactsLaunchActivity";
-
     private static final int TAB_INDEX_DIALER = 0;
     private static final int TAB_INDEX_CALL_LOG = 1;
     private static final int TAB_INDEX_CONTACTS = 2;
@@ -55,32 +51,19 @@
 
     static final String EXTRA_IGNORE_STATE = "ignore-state";
 
-    /** Name of the dialtacts shared preferences */
-    static final String PREFS_DIALTACTS = "dialtacts";
     /** If true, when handling the contacts intent the favorites tab will be shown instead */
-    static final String PREF_FAVORITES_AS_CONTACTS = "favorites_as_contacts";
-    static final boolean PREF_FAVORITES_AS_CONTACTS_DEFAULT = false;
-
-    /** Last manually selected tab index */
-    private static final String PREF_LAST_MANUALLY_SELECTED_TAB = "last_manually_selected_tab";
-    private static final int PREF_LAST_MANUALLY_SELECTED_TAB_DEFAULT = TAB_INDEX_DIALER;
+    private static final String PREF_FAVORITES_AS_CONTACTS = "favorites_as_contacts";
+    private static final boolean PREF_FAVORITES_AS_CONTACTS_DEFAULT = false;
 
     private TabHost mTabHost;
     private String mFilterText;
     private Uri mDialUri;
 
-    /**
-     * The index of the tab that has last been manually selected (the user clicked on a tab).
-     * This value does not keep track of programmatically set Tabs (e.g. Call Log after a Call)
-     */
-    private int mLastManuallySelectedTab;
-
     @Override
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
         final Intent intent = getIntent();
-        fixIntent(intent);
 
         requestWindowFeature(Window.FEATURE_NO_TITLE);
         setContentView(R.layout.dialer_activity);
@@ -94,11 +77,6 @@
         setupContactsTab();
         setupFavoritesTab();
 
-        // Load the last manually loaded tab
-        final SharedPreferences prefs = getSharedPreferences(PREFS_DIALTACTS, MODE_PRIVATE);
-        mLastManuallySelectedTab = prefs.getInt(PREF_LAST_MANUALLY_SELECTED_TAB,
-                PREF_LAST_MANUALLY_SELECTED_TAB_DEFAULT);
-
         setCurrentTab(intent);
 
         if (intent.getAction().equals(UI.FILTER_CONTACTS_ACTION)
@@ -113,30 +91,19 @@
 
         final int currentTabIndex = mTabHost.getCurrentTab();
         final SharedPreferences.Editor editor =
-                getSharedPreferences(PREFS_DIALTACTS, MODE_PRIVATE).edit();
+                getSharedPreferences(StickyTabs.PREFERENCES_NAME, MODE_PRIVATE).edit();
         if (currentTabIndex == TAB_INDEX_CONTACTS || currentTabIndex == TAB_INDEX_FAVORITES) {
             editor.putBoolean(PREF_FAVORITES_AS_CONTACTS, currentTabIndex == TAB_INDEX_FAVORITES);
         }
-        editor.putInt(PREF_LAST_MANUALLY_SELECTED_TAB, mLastManuallySelectedTab);
 
         editor.apply();
     }
 
-    private void fixIntent(Intent intent) {
-        // This should be cleaned up: the call key used to send an Intent
-        // that just said to go to the recent calls list.  It now sends this
-        // abstract action, but this class hasn't been rewritten to deal with it.
-        if (Intent.ACTION_CALL_BUTTON.equals(intent.getAction())) {
-            intent.setDataAndType(Calls.CONTENT_URI, Calls.CONTENT_TYPE);
-            intent.putExtra("call_key", true);
-            setIntent(intent);
-        }
-    }
-
     private void setupCallLogTab() {
         // Force the class since overriding tab entries doesn't work
         Intent intent = new Intent("com.android.phone.action.RECENT_CALLS");
         intent.setClass(this, RecentCallsListActivity.class);
+        StickyTabs.setTab(intent, TAB_INDEX_CALL_LOG);
 
         mTabHost.addTab(mTabHost.newTabSpec("call_log")
                 .setIndicator(getString(R.string.recentCallsIconLabel),
@@ -147,6 +114,7 @@
     private void setupDialerTab() {
         Intent intent = new Intent("com.android.phone.action.TOUCH_DIALER");
         intent.setClass(this, TwelveKeyDialer.class);
+        StickyTabs.setTab(intent, TAB_INDEX_DIALER);
 
         mTabHost.addTab(mTabHost.newTabSpec("dialer")
                 .setIndicator(getString(R.string.dialerIconLabel),
@@ -157,6 +125,7 @@
     private void setupContactsTab() {
         Intent intent = new Intent(UI.LIST_DEFAULT);
         intent.setClass(this, ContactsListActivity.class);
+        StickyTabs.setTab(intent, TAB_INDEX_CONTACTS);
 
         mTabHost.addTab(mTabHost.newTabSpec("contacts")
                 .setIndicator(getText(R.string.contactsIconLabel),
@@ -167,6 +136,7 @@
     private void setupFavoritesTab() {
         Intent intent = new Intent(UI.LIST_STREQUENT_ACTION);
         intent.setClass(this, ContactsListActivity.class);
+        StickyTabs.setTab(intent, TAB_INDEX_FAVORITES);
 
         mTabHost.addTab(mTabHost.newTabSpec("favorites")
                 .setIndicator(getString(R.string.contactsFavoritesLabel),
@@ -175,43 +145,11 @@
     }
 
     /**
-     * Returns true if the intent is due to hitting the green send key while in a call.
-     *
-     * @param intent the intent that launched this activity
-     * @param recentCallsRequest true if the intent is requesting to view recent calls
-     * @return true if the intent is due to hitting the green send key while in a call
-     */
-    private boolean isSendKeyWhileInCall(final Intent intent, final boolean recentCallsRequest) {
-        // If there is a call in progress go to the call screen
-        if (recentCallsRequest) {
-            final boolean callKey = intent.getBooleanExtra("call_key", false);
-
-            try {
-                ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
-                if (callKey && phone != null && phone.showCallScreen()) {
-                    return true;
-                }
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to handle send while in call", e);
-            }
-        }
-
-        return false;
-    }
-
-    /**
      * Sets the current tab based on the intent's request type
      *
      * @param intent Intent that contains information about which tab should be selected
      */
     private void setCurrentTab(Intent intent) {
-        // If we got here by hitting send and we're in call forward along to the in-call activity
-        final boolean recentCallsRequest = Calls.CONTENT_TYPE.equals(intent.getType());
-        if (isSendKeyWhileInCall(intent, recentCallsRequest)) {
-            finish();
-            return;
-        }
-
         // Dismiss menu provided by any children activities
         Activity activity = getLocalActivityManager().
                 getActivity(mTabHost.getCurrentTabTag());
@@ -223,25 +161,28 @@
         // state and instead reload their state from the parent's intent
         intent.putExtra(EXTRA_IGNORE_STATE, true);
 
-        // Remember the old manually selected tab index so that it can be restored if it is
-        // overwritten by one of the programmatic tab selections
-        final int savedTabIndex = mLastManuallySelectedTab;
-
         // Choose the tab based on the inbound intent
         String componentName = intent.getComponent().getClassName();
         if (getClass().getName().equals(componentName)) {
-            if (recentCallsRequest) {
-                mTabHost.setCurrentTab(TAB_INDEX_CALL_LOG);
-            } else {
+            if (phoneIsInUse()) {
+                // If we are in a call, show the dialer tab (which allows going back to the
+                // call)
                 mTabHost.setCurrentTab(TAB_INDEX_DIALER);
+            } else {
+                // If we are launched from history (long-press home), go back to the last
+                // tab that was used to make a call
+                if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) {
+                    mTabHost.setCurrentTab(StickyTabs.loadTab(this, TAB_INDEX_DIALER));
+                }
             }
         } else if (FAVORITES_ENTRY_COMPONENT.equals(componentName)) {
             mTabHost.setCurrentTab(TAB_INDEX_FAVORITES);
-        } else if (CONTACTS_LAUNCH_ACTIVITY.equals(componentName)) {
-            mTabHost.setCurrentTab(mLastManuallySelectedTab);
         } else {
-            SharedPreferences prefs = getSharedPreferences(PREFS_DIALTACTS, MODE_PRIVATE);
-            boolean favoritesAsContacts = prefs.getBoolean(PREF_FAVORITES_AS_CONTACTS,
+            // Launched as "Contacts" --> Go either to favorites or contacts, whichever is more
+            // recent
+            final SharedPreferences prefs = getSharedPreferences(StickyTabs.PREFERENCES_NAME,
+                    MODE_PRIVATE);
+            final boolean favoritesAsContacts = prefs.getBoolean(PREF_FAVORITES_AS_CONTACTS,
                     PREF_FAVORITES_AS_CONTACTS_DEFAULT);
             if (favoritesAsContacts) {
                 mTabHost.setCurrentTab(TAB_INDEX_FAVORITES);
@@ -250,9 +191,6 @@
             }
         }
 
-        // Restore to the previous manual selection
-        mLastManuallySelectedTab = savedTabIndex;
-
         // Tell the children activities that they should honor their saved states
         // instead of the state from the parent's intent
         intent.putExtra(EXTRA_IGNORE_STATE, false);
@@ -261,7 +199,6 @@
     @Override
     public void onNewIntent(Intent newIntent) {
         setIntent(newIntent);
-        fixIntent(newIntent);
         setCurrentTab(newIntent);
         final String action = newIntent.getAction();
         if (action.equals(UI.FILTER_CONTACTS_ACTION)) {
@@ -358,6 +295,7 @@
     }
 
     /** {@inheritDoc} */
+    @Override
     public void onTabChanged(String tabId) {
         // Because we're using Activities as our tab children, we trigger
         // onWindowFocusChanged() to let them know when they're active.  This may
@@ -367,9 +305,20 @@
         if (activity != null) {
             activity.onWindowFocusChanged(true);
         }
+    }
 
-        // Remember this tab index. This function is also called, if the tab is set automatically
-        // in which case the setter (setCurrentTab) has to set this to its old value afterwards
-        mLastManuallySelectedTab = mTabHost.getCurrentTab();
+    /**
+     * @return true if the phone is "in use", meaning that at least one line
+     *              is active (ie. off hook or ringing or dialing).
+     */
+    private boolean phoneIsInUse() {
+        boolean phoneInUse = false;
+        try {
+            ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
+            if (phone != null) phoneInUse = !phone.isIdle();
+        } catch (RemoteException e) {
+            Log.w(TAG, "phone.isIdle() failed", e);
+        }
+        return phoneInUse;
     }
 }
diff --git a/src/com/android/contacts/PhoneDisambigDialog.java b/src/com/android/contacts/PhoneDisambigDialog.java
index d8cb14e..3e3d534 100644
--- a/src/com/android/contacts/PhoneDisambigDialog.java
+++ b/src/com/android/contacts/PhoneDisambigDialog.java
@@ -55,18 +55,17 @@
     private Context mContext;
     private AlertDialog mDialog;
     private boolean mSendSms;
+    private int mStickyTab;
     private Cursor mPhonesCursor;
     private ListAdapter mPhonesAdapter;
     private ArrayList<PhoneItem> mPhoneItemList;
 
-    public PhoneDisambigDialog(Context context, Cursor phonesCursor) {
-        this(context, phonesCursor, false /*make call*/);
-    }
-
-    public PhoneDisambigDialog(Context context, Cursor phonesCursor, boolean sendSms) {
+    public PhoneDisambigDialog(Context context, Cursor phonesCursor, boolean sendSms,
+            int stickyTab) {
         mContext = context;
         mSendSms = sendSms;
         mPhonesCursor = phonesCursor;
+        mStickyTab = stickyTab;
 
         mPhoneItemList = makePhoneItemsList(phonesCursor);
         Collapser.collapseList(mPhoneItemList);
@@ -118,6 +117,7 @@
             if (mSendSms) {
                 ContactsUtils.initiateSms(mContext, phone);
             } else {
+                StickyTabs.saveTab(mContext, mStickyTab);
                 ContactsUtils.initiateCall(mContext, phone);
             }
         } else {
diff --git a/src/com/android/contacts/RecentCallsListActivity.java b/src/com/android/contacts/RecentCallsListActivity.java
index dad5491..abda325 100644
--- a/src/com/android/contacts/RecentCallsListActivity.java
+++ b/src/com/android/contacts/RecentCallsListActivity.java
@@ -122,9 +122,9 @@
     static final int LABEL_COLUMN_INDEX = 3;
     static final int MATCHED_NUMBER_COLUMN_INDEX = 4;
 
-    private static final int MENU_ITEM_DELETE = 1;
-    private static final int MENU_ITEM_DELETE_ALL = 2;
-    private static final int MENU_ITEM_VIEW_CONTACTS = 3;
+    private static final int MENU_ITEM_DELETE_ALL = 1;
+    private static final int CONTEXT_MENU_ITEM_DELETE = 1;
+    private static final int CONTEXT_MENU_CALL_CONTACT = 2;
 
     private static final int QUERY_TOKEN = 53;
     private static final int UPDATE_TOKEN = 54;
@@ -221,6 +221,7 @@
                 } else {
                     callUri = Uri.fromParts("tel", number, null);
                 }
+                StickyTabs.saveTab(RecentCallsListActivity.this, getIntent());
                 startActivity(new Intent(Intent.ACTION_CALL_PRIVILEGED, callUri));
             }
         }
@@ -1016,14 +1017,16 @@
 
         if (numberUri != null) {
             Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, numberUri);
-            menu.add(0, 0, 0, getResources().getString(R.string.recentCalls_callNumber, number))
+            menu.add(0, CONTEXT_MENU_CALL_CONTACT, 0,
+                    getResources().getString(R.string.recentCalls_callNumber, number))
                     .setIntent(intent);
         }
 
         if (contactInfoPresent) {
-            menu.add(0, 0, 0, R.string.menu_viewContact)
-                    .setIntent(new Intent(Intent.ACTION_VIEW,
-                            ContentUris.withAppendedId(Contacts.CONTENT_URI, info.personId)));
+            Intent intent = new Intent(Intent.ACTION_VIEW,
+                    ContentUris.withAppendedId(Contacts.CONTENT_URI, info.personId));
+            StickyTabs.setTab(intent, getIntent());
+            menu.add(0, 0, 0, R.string.menu_viewContact).setIntent(intent);
         }
 
         if (numberUri != null && !isVoicemail && !isSipNumber) {
@@ -1052,7 +1055,7 @@
             menu.add(0, 0, 0, R.string.recentCalls_addToContact)
                     .setIntent(intent);
         }
-        menu.add(0, MENU_ITEM_DELETE, 0, R.string.recentCalls_removeFromRecentList);
+        menu.add(0, CONTEXT_MENU_ITEM_DELETE, 0, R.string.recentCalls_removeFromRecentList);
     }
 
     @Override
@@ -1086,30 +1089,23 @@
                 showDialog(DIALOG_CONFIRM_DELETE_ALL);
                 return true;
             }
-
-            case MENU_ITEM_VIEW_CONTACTS: {
-                Intent intent = new Intent(Intent.ACTION_VIEW, Contacts.CONTENT_URI);
-                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                startActivity(intent);
-                return true;
-            }
         }
         return super.onOptionsItemSelected(item);
     }
 
     @Override
     public boolean onContextItemSelected(MenuItem item) {
-        // Convert the menu info to the proper type
-        AdapterView.AdapterContextMenuInfo menuInfo;
-        try {
-             menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
-        } catch (ClassCastException e) {
-            Log.e(TAG, "bad menuInfoIn", e);
-            return false;
-        }
-
         switch (item.getItemId()) {
-            case MENU_ITEM_DELETE: {
+            case CONTEXT_MENU_ITEM_DELETE: {
+                // Convert the menu info to the proper type
+                AdapterView.AdapterContextMenuInfo menuInfo;
+                try {
+                     menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
+                } catch (ClassCastException e) {
+                    Log.e(TAG, "bad menuInfoIn", e);
+                    return false;
+                }
+
                 Cursor cursor = (Cursor)mAdapter.getItem(menuInfo.position);
                 int groupSize = 1;
                 if (mAdapter.isGroupHeader(menuInfo.position)) {
@@ -1128,9 +1124,17 @@
 
                 getContentResolver().delete(Calls.CONTENT_URI, Calls._ID + " IN (" + sb + ")",
                         null);
+                return true;
+            }
+            case CONTEXT_MENU_CALL_CONTACT: {
+                StickyTabs.saveTab(this, getIntent());
+                startActivity(item.getIntent());
+                return true;
+            }
+            default: {
+                return super.onContextItemSelected(item);
             }
         }
-        return super.onContextItemSelected(item);
     }
 
     @Override
@@ -1249,6 +1253,7 @@
                 intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
                                     Uri.fromParts("tel", number, null));
             }
+            StickyTabs.saveTab(this, getIntent());
             intent.setFlags(
                     Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
             startActivity(intent);
@@ -1262,6 +1267,7 @@
         } else {
             Intent intent = new Intent(this, CallDetailActivity.class);
             intent.setData(ContentUris.withAppendedId(CallLog.Calls.CONTENT_URI, id));
+            StickyTabs.setTab(intent, getIntent());
             startActivity(intent);
         }
     }
diff --git a/src/com/android/contacts/StickyTabs.java b/src/com/android/contacts/StickyTabs.java
new file mode 100644
index 0000000..4ecc970
--- /dev/null
+++ b/src/com/android/contacts/StickyTabs.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2010 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.contacts;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.provider.ContactsContract.QuickContact;
+import android.util.Log;
+
+/**
+ * Utility class to annotate Intents with extra data required for the Sticky-Tab behavior, which
+ * allows storing the app to go to the last tab that was used to make a call. Also handles saving
+ * and restoring the tab index
+ */
+public final class StickyTabs {
+    private static final String TAG = "StickyTabs";
+    private static final boolean LOGV = false;
+
+    private static final String EXTRA_TAB_INDEX =
+            QuickContact.EXTRA_SELECTED_CONTACTS_APP_TAB_INDEX;
+
+    /**
+     * Name of the shared setting. We are using the same name as in FroYo to prevent
+     * having an orphan here
+     */
+    public static final String PREFERENCES_NAME = "dialtacts";
+
+    /**
+     * Name of the shared setting. We are using the same name as in FroYo to prevent
+     * having an orphan there
+     */
+    private static final String PREF_LAST_PHONECALL_TAB = "last_manually_selected_tab";
+
+    /**
+     * Writes the selected tab to the passed intent
+     * @param intent The intent to modify.
+     * @param tabIndex The tab index to write to the intent
+     * @return Returns the modified intent. Notice that this is not a new instance (the passed-in
+     * intent is modified)
+     */
+    public static Intent setTab(Intent intent, int tabIndex) {
+        if (LOGV) Log.v(TAG, "*********** Setting tab index of intent to " + tabIndex);
+
+        if (tabIndex == -1) {
+            intent.removeExtra(EXTRA_TAB_INDEX);
+        } else {
+            intent.putExtra(EXTRA_TAB_INDEX, tabIndex);
+        }
+        return intent;
+    }
+
+    /**
+     * Writes the selected tab to the passed intent by retrieving it from the originalIntent that
+     * was passed in
+     * @param intent The intent to modify.
+     * @param originalIntent The intent where the tab index should be read from
+     * @return Returns the modified intent. Notice that this is not a new instance (the passed-in
+     * intent is modified)
+     */
+    public static Intent setTab(Intent intent, Intent originalIntent) {
+        return setTab(intent, getTab(originalIntent));
+    }
+
+    /**
+     * Returns the selected tab or -1 if no tab is stored
+     */
+    public static int getTab(Intent intent) {
+        if (intent.getExtras() == null) return -1;
+        return intent.getExtras().getInt(EXTRA_TAB_INDEX, -1);
+    }
+
+    /**
+     * Persists the given tabIndex. If the value is -1, the previously persisted value is not
+     * overriden
+     */
+    public static void saveTab(Context context, int tabIndex) {
+        if (LOGV) Log.v(TAG, "*********** Persisting tab index " + tabIndex);
+        if (tabIndex == -1) return;
+
+        final SharedPreferences.Editor editor =
+            context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE).edit();
+        editor.putInt(PREF_LAST_PHONECALL_TAB, tabIndex);
+        editor.apply();
+    }
+
+    /**
+     * Persists the tab as it is stored in the Intent. If the intent does not have a tab index,
+     * the persisted value is not overriden
+     */
+    public static void saveTab(Context context, Intent intent) {
+        saveTab(context, getTab(intent));
+    }
+
+    /**
+     * Returns the previously persisted tab or defaultValue if nothing is saved
+     */
+    public static int loadTab(Context context, int defaultValue) {
+        final SharedPreferences prefs = context.getSharedPreferences(PREFERENCES_NAME,
+                Context.MODE_PRIVATE);
+        final int result = prefs.getInt(PREF_LAST_PHONECALL_TAB, defaultValue);
+        if (LOGV) Log.v(TAG, "*********** Loaded tab index: " + result);
+        return result;
+    }
+}
diff --git a/src/com/android/contacts/TwelveKeyDialer.java b/src/com/android/contacts/TwelveKeyDialer.java
index 53c59f3..5219d99 100644
--- a/src/com/android/contacts/TwelveKeyDialer.java
+++ b/src/com/android/contacts/TwelveKeyDialer.java
@@ -774,6 +774,7 @@
     }
 
     void callVoicemail() {
+        StickyTabs.saveTab(this, getIntent());
         Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
                 Uri.fromParts("voicemail", EMPTY_NUMBER, null));
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -810,6 +811,7 @@
             intent.setData(Uri.fromParts("tel", number, null));
         }
 
+        StickyTabs.saveTab(this, getIntent());
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         startActivity(intent);
         mDigits.getText().clear();
diff --git a/src/com/android/contacts/ViewContactActivity.java b/src/com/android/contacts/ViewContactActivity.java
index 80214ac..eeb0a0d 100644
--- a/src/com/android/contacts/ViewContactActivity.java
+++ b/src/com/android/contacts/ViewContactActivity.java
@@ -113,6 +113,7 @@
     private static final int REQUEST_EDIT_CONTACT = 2;
 
     public static final int MENU_ITEM_MAKE_DEFAULT = 3;
+    public static final int MENU_ITEM_CALL = 4;
 
     protected Uri mLookupUri;
     private ContentResolver mResolver;
@@ -217,6 +218,7 @@
         mContactHeaderWidget.setExcludeMimes(new String[] {
             Contacts.CONTENT_ITEM_TYPE
         });
+        mContactHeaderWidget.setSelectedContactsAppTabIndex(StickyTabs.getTab(getIntent()));
 
         mHandler = new NotifyingAsyncQueryHandler(this, this);
 
@@ -568,7 +570,7 @@
         ViewEntry entry = ContactEntryAdapter.getEntry(mSections, info.position, SHOW_SEPARATORS);
         menu.setHeaderTitle(R.string.contactOptionsTitle);
         if (entry.mimetype.equals(CommonDataKinds.Phone.CONTENT_ITEM_TYPE)) {
-            menu.add(0, 0, 0, R.string.menu_call).setIntent(entry.intent);
+            menu.add(0, MENU_ITEM_CALL, 0, R.string.menu_call).setIntent(entry.intent);
             menu.add(0, 0, 0, R.string.menu_sendSMS).setIntent(entry.secondaryIntent);
             if (!entry.isPrimary) {
                 menu.add(0, MENU_ITEM_MAKE_DEFAULT, 0, R.string.menu_makeDefaultNumber);
@@ -651,14 +653,18 @@
     public boolean onContextItemSelected(MenuItem item) {
         switch (item.getItemId()) {
             case MENU_ITEM_MAKE_DEFAULT: {
-                if (makeItemDefault(item)) {
-                    return true;
-                }
-                break;
+                makeItemDefault(item);
+                return true;
+            }
+            case MENU_ITEM_CALL: {
+                StickyTabs.saveTab(this, getIntent());
+                startActivity(item.getIntent());
+                return true;
+            }
+            default: {
+                return super.onContextItemSelected(item);
             }
         }
-
-        return super.onContextItemSelected(item);
     }
 
     private boolean makeItemDefault(MenuItem item) {
@@ -786,6 +792,7 @@
                     if (entry != null && entry.intent != null &&
                             entry.intent.getAction() == Intent.ACTION_CALL_PRIVILEGED) {
                         startActivity(entry.intent);
+                        StickyTabs.saveTab(this, getIntent());
                         return true;
                     }
                 } else if (mPrimaryPhoneUri != null) {
@@ -793,6 +800,7 @@
                     final Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
                             mPrimaryPhoneUri);
                     startActivity(intent);
+                    StickyTabs.saveTab(this, getIntent());
                     return true;
                 }
                 return false;
@@ -820,6 +828,9 @@
         if (entry != null) {
             Intent intent = entry.intent;
             if (intent != null) {
+                if (Intent.ACTION_CALL_PRIVILEGED.equals(intent.getAction())) {
+                    StickyTabs.saveTab(this, getIntent());
+                }
                 try {
                     startActivity(intent);
                 } catch (ActivityNotFoundException e) {
diff --git a/src/com/android/contacts/ui/QuickContactActivity.java b/src/com/android/contacts/ui/QuickContactActivity.java
index 7f6e39b..ec8f44d 100644
--- a/src/com/android/contacts/ui/QuickContactActivity.java
+++ b/src/com/android/contacts/ui/QuickContactActivity.java
@@ -16,6 +16,8 @@
 
 package com.android.contacts.ui;
 
+import com.android.contacts.StickyTabs;
+
 import android.app.Activity;
 import android.content.ContentUris;
 import android.content.Intent;
@@ -61,6 +63,7 @@
             if (LOGV) Log.d(TAG, "Preparing window");
             mQuickContact = new QuickContactWindow(this, this);
         }
+        mQuickContact.setLastSelectedContactsAppTab(StickyTabs.getTab(intent));
 
         // Use our local window token for now
         Uri lookupUri = intent.getData();
diff --git a/src/com/android/contacts/ui/QuickContactWindow.java b/src/com/android/contacts/ui/QuickContactWindow.java
index 8662573..9c6e7ac 100644
--- a/src/com/android/contacts/ui/QuickContactWindow.java
+++ b/src/com/android/contacts/ui/QuickContactWindow.java
@@ -20,6 +20,7 @@
 import com.android.contacts.ContactPresenceIconUtil;
 import com.android.contacts.ContactsUtils;
 import com.android.contacts.R;
+import com.android.contacts.StickyTabs;
 import com.android.contacts.model.ContactsSource;
 import com.android.contacts.model.Sources;
 import com.android.contacts.model.ContactsSource.DataKind;
@@ -157,6 +158,9 @@
     private OnDismissListener mDismissListener;
     private ResolveCache mResolveCache;
 
+    /** Last selected tab of the Dialtacs-Activity. This is -1 if not called out of contacts app */
+    private int mLastSelectedContactsAppTab;
+
     private Uri mLookupUri;
     private Rect mAnchor;
 
@@ -322,6 +326,10 @@
         mDismissListener = dismissListener;
     }
 
+    public void setLastSelectedContactsAppTab(int value) {
+        mLastSelectedContactsAppTab = value;
+    }
+
     private View getHeaderView(int mode) {
         View header = null;
         switch (mode) {
@@ -1423,6 +1431,10 @@
             final Action action = (Action)tag;
             final boolean makePrimary = mMakePrimary;
 
+            if (Intent.ACTION_CALL_PRIVILEGED.equals(action.getIntent().getAction())) {
+                StickyTabs.saveTab(mContext, mLastSelectedContactsAppTab);
+            }
+
             try {
                 mContext.startActivity(action.getIntent());
             } catch (ActivityNotFoundException e) {