introduce tab IDs

    Tabs are identified by IDs now, instead of their position
    Refactored the save/restore code

Change-Id: I7133d55831201d097dc19ec938a85e7085f36749
diff --git a/src/com/android/browser/ActiveTabsPage.java b/src/com/android/browser/ActiveTabsPage.java
index 52d943f..0feba9a 100644
--- a/src/com/android/browser/ActiveTabsPage.java
+++ b/src/com/android/browser/ActiveTabsPage.java
@@ -83,7 +83,8 @@
     @Override
     public void onItemClick(
             AdapterView<?> parent, View view, int position, long id) {
-        boolean needToAttach = !mController.switchToTab(position);
+        final Tab tab = mTabControl.getTab(position);
+        boolean needToAttach = !mController.switchToTab(tab);
         mController.removeActiveTabsPage(needToAttach);
     }
 
diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java
index 4b72ce3..2a7e8eb 100644
--- a/src/com/android/browser/Controller.java
+++ b/src/com/android/browser/Controller.java
@@ -281,10 +281,10 @@
             || lastActiveDate.after(today));
 
         // Find out if we will restore any state and remember the tab.
-        final int currentTab =
+        final long currentTabId =
                 mTabControl.canRestoreState(icicle, restoreIncognitoTabs);
 
-        if (currentTab == -1) {
+        if (currentTabId == -1) {
             // Not able to restore so we go ahead and clear session cookies.  We
             // must do this before trying to login the user as we don't want to
             // clear any session cookies set during login.
@@ -294,14 +294,14 @@
         GoogleAccountLogin.startLoginIfNeeded(mActivity,
                 new Runnable() {
                     @Override public void run() {
-                        onPreloginFinished(icicle, intent, currentTab, restoreIncognitoTabs);
+                        onPreloginFinished(icicle, intent, currentTabId, restoreIncognitoTabs);
                     }
                 });
     }
 
-    private void onPreloginFinished(Bundle icicle, Intent intent, int currentTab,
+    private void onPreloginFinished(Bundle icicle, Intent intent, long currentTabId,
             boolean restoreIncognitoTabs) {
-        if (currentTab == -1) {
+        if (currentTabId == -1) {
             final Bundle extra = intent.getExtras();
             // Create an initial tab.
             // If the intent is ACTION_VIEW and data is not null, the Browser is
@@ -325,7 +325,7 @@
                 }
             }
         } else {
-            mTabControl.restoreState(icicle, currentTab, restoreIncognitoTabs,
+            mTabControl.restoreState(icicle, currentTabId, restoreIncognitoTabs,
                     mUi.needsRestoreAllTabs());
             mUi.updateTabs(mTabControl.getTabs());
             // TabControl.restoreState() will create a new tab even if
@@ -1711,7 +1711,7 @@
                             Tab desiredTab = mTabControl.getTab(id);
                             if (desiredTab != null &&
                                     desiredTab != mTabControl.getCurrentTab()) {
-                                switchToTab(id);
+                                switchToTab(desiredTab);
                             }
                             break;
                         }
@@ -2144,9 +2144,9 @@
         Tab current = mTabControl.getCurrentTab();
         if (current != null
                 && current.getWebView().copyBackForwardList().getSize() == 0) {
-            Tab parent = current.getParentTab();
+            Tab parent = current.getParent();
             if (parent != null) {
-                switchToTab(mTabControl.getTabIndex(parent));
+                switchToTab(parent);
                 closeTab(current);
             }
         }
@@ -2163,7 +2163,7 @@
         // TODO: analyze why the remove and add are necessary
         mUi.attachTab(appTab);
         if (mTabControl.getCurrentTab() != appTab) {
-            switchToTab(mTabControl.getTabIndex(appTab));
+            switchToTab(appTab);
             loadUrlDataIn(appTab, urlData);
         } else {
             // If the tab was the current tab, we have to attach
@@ -2256,17 +2256,15 @@
     }
 
     /**
-     * @param index Index of the tab to change to, as defined by
-     *              mTabControl.getTabIndex(Tab t).
+     * @param tab the tab to switch to
      * @return boolean True if we successfully switched to a different tab.  If
      *                 the indexth tab is null, or if that tab is the same as
      *                 the current one, return false.
      */
     @Override
-    public boolean switchToTab(int index) {
+    public boolean switchToTab(Tab tab) {
         // hide combo view if open
         removeComboView();
-        Tab tab = mTabControl.getTab(index);
         Tab currentTab = mTabControl.getCurrentTab();
         if (tab == null || tab == currentTab) {
             return false;
@@ -2279,25 +2277,20 @@
     public void closeCurrentTab() {
         // hide combo view if open
         removeComboView();
-        final Tab current = mTabControl.getCurrentTab();
         if (mTabControl.getTabCount() == 1) {
             mActivity.finish();
             return;
         }
-        final Tab parent = current.getParentTab();
-        int indexToShow = -1;
-        if (parent != null) {
-            indexToShow = mTabControl.getTabIndex(parent);
-        } else {
-            final int currentIndex = mTabControl.getCurrentIndex();
-            // Try to move to the tab to the right
-            indexToShow = currentIndex + 1;
-            if (indexToShow > mTabControl.getTabCount() - 1) {
-                // Try to move to the tab to the left
-                indexToShow = currentIndex - 1;
+        final Tab current = mTabControl.getCurrentTab();
+        final int pos = mTabControl.getCurrentPosition();
+        Tab newTab = current.getParent();
+        if (newTab == null) {
+            newTab = mTabControl.getTab(pos + 1);
+            if (newTab == null) {
+                newTab = mTabControl.getTab(pos - 1);
             }
         }
-        if (switchToTab(indexToShow)) {
+        if (switchToTab(newTab)) {
             // Close window
             closeTab(current);
         }
@@ -2311,10 +2304,6 @@
     public void closeTab(Tab tab) {
         // hide combo view if open
         removeComboView();
-        int currentIndex = mTabControl.getCurrentIndex();
-        int removeIndex = mTabControl.getTabIndex(tab);
-        Tab newtab = mTabControl.getTab(currentIndex);
-        setActiveTab(newtab);
         removeTab(tab);
     }
 
@@ -2382,9 +2371,9 @@
         } else {
             // Check to see if we are closing a window that was created by
             // another window. If so, we switch back to that window.
-            Tab parent = current.getParentTab();
+            Tab parent = current.getParent();
             if (parent != null) {
-                switchToTab(mTabControl.getTabIndex(parent));
+                switchToTab(parent);
                 // Now we close the other tab
                 closeTab(current);
             } else {
@@ -2445,17 +2434,18 @@
      * helper method for key handler
      * returns the current tab if it can't advance
      */
-    private int getNextTabIndex() {
-        return Math.min(mTabControl.getTabCount() - 1,
-                mTabControl.getCurrentIndex() + 1);
+    private Tab getNextTab() {
+        return mTabControl.getTab(Math.min(mTabControl.getTabCount() - 1,
+                mTabControl.getCurrentPosition() + 1));
     }
 
     /**
      * helper method for key handler
      * returns the current tab if it can't advance
      */
-    private int getPrevTabIndex() {
-        return  Math.max(0, mTabControl.getCurrentIndex() - 1);
+    private Tab getPrevTab() {
+        return  mTabControl.getTab(Math.max(0,
+                mTabControl.getCurrentPosition() - 1));
     }
 
     /**
@@ -2489,10 +2479,10 @@
                 if (event.isCtrlPressed()) {
                     if (event.isShiftPressed()) {
                         // prev tab
-                        switchToTab(getPrevTabIndex());
+                        switchToTab(getPrevTab());
                     } else {
                         // next tab
-                        switchToTab(getNextTabIndex());
+                        switchToTab(getNextTab());
                     }
                     return true;
                 }
diff --git a/src/com/android/browser/IntentHandler.java b/src/com/android/browser/IntentHandler.java
index 40db29f..8d1b784 100644
--- a/src/com/android/browser/IntentHandler.java
+++ b/src/com/android/browser/IntentHandler.java
@@ -146,7 +146,7 @@
                     && !mActivity.getPackageName().equals(appId)
                     && (flags & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
                 if (activateVoiceSearch) {
-                    Tab appTab = mTabControl.getTabFromId(appId);
+                    Tab appTab = mTabControl.getTabFromAppId(appId);
                     if (appTab != null) {
                         mController.reuseTab(appTab, appId, urlData);
                         return;
@@ -162,7 +162,7 @@
                     Tab appTab = mTabControl.findUnusedTabWithUrl(urlData.mUrl);
                     if (appTab != null) {
                         if (current != appTab) {
-                            mController.switchToTab(mTabControl.getTabIndex(appTab));
+                            mController.switchToTab(appTab);
                         }
                         // Otherwise, we are already viewing the correct tab.
                     } else {
diff --git a/src/com/android/browser/NavScreen.java b/src/com/android/browser/NavScreen.java
index 9f2d4ae..a5090fa 100644
--- a/src/com/android/browser/NavScreen.java
+++ b/src/com/android/browser/NavScreen.java
@@ -206,7 +206,7 @@
                     : R.drawable.ic_forward_disabled_holo_dark);
         }
         if (updateFlipper) {
-            mFlipper.setSelection(mUiController.getTabControl().getTabIndex(tab));
+            mFlipper.setSelection(mUiController.getTabControl().getTabPosition(tab));
         }
     }
 
@@ -249,7 +249,7 @@
 
         if (tab != null) {
             // set tab as the selected in flipper, then hide
-            final int tix = mUi.mTabControl.getTabIndex(tab);
+            final int tix = mUi.mTabControl.getTabPosition(tab);
             post(new Runnable() {
                 public void run() {
                     if (tix != -1) {
diff --git a/src/com/android/browser/PieControl.java b/src/com/android/browser/PieControl.java
index 684cd1a..8bcd972 100644
--- a/src/com/android/browser/PieControl.java
+++ b/src/com/android/browser/PieControl.java
@@ -142,7 +142,7 @@
         mUi.captureTab(mUi.getActiveTab());
         mTabAdapter.setTabs(tabs);
         PieStackView sym = (PieStackView) mShowTabs.getPieView();
-        sym.setCurrent(mUiController.getTabControl().getCurrentIndex());
+        sym.setCurrent(mUiController.getTabControl().getCurrentPosition());
 
     }
 
@@ -281,8 +281,7 @@
             view.setOnClickListener(new OnClickListener() {
                 @Override
                 public void onClick(View v) {
-                    mUiController.switchToTab(mUiController.getTabControl()
-                            .getTabIndex(tab));
+                    mUiController.switchToTab(tab);
                 }
             });
             return view;
diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java
index c217e6e..e1dd1ca 100644
--- a/src/com/android/browser/Tab.java
+++ b/src/com/android/browser/Tab.java
@@ -88,6 +88,9 @@
     Activity mActivity;
     private WebViewController mWebViewController;
 
+    // The tab ID
+    private long mId;
+
     // The Geolocation permissions prompt
     private GeolocationPermissionsPrompt mGeolocationPermissionsPrompt;
     // Main WebView wrapper
@@ -104,10 +107,10 @@
     private Bundle mSavedState;
     // Parent Tab. This is the Tab that created this Tab, or null if the Tab was
     // created by the UI
-    private Tab mParentTab;
+    private Tab mParent;
     // Tab that constructed by this Tab. This is used when this Tab is
     // destroyed, it clears all mParentTab values in the children.
-    private Vector<Tab> mChildTabs;
+    private Vector<Tab> mChildren;
     // If true, the tab is in the foreground of the current activity.
     private boolean mInForeground;
     // If true, the tab is in page loading state (after onPageStarted,
@@ -181,17 +184,11 @@
     private PageState mCurrentState;
 
     // Used for saving and restoring each Tab
-    // TODO: Figure out who uses what and where
-    //       Some of these aren't use in this class, and some are only used in
-    //       restoring state but not saving it - FIX THIS
-    static final String WEBVIEW = "webview";
-    static final String NUMTABS = "numTabs";
-    static final String CURRTAB = "currentTab";
+    static final String ID = "ID";
     static final String CURRURL = "currentUrl";
     static final String CURRTITLE = "currentTitle";
     static final String PARENTTAB = "parentTab";
     static final String APPID = "appid";
-    static final String ORIGINALURL = "originalUrl";
     static final String INCOGNITO = "privateBrowsingEnabled";
     static final String SCREENSHOT = "screenshot";
 
@@ -935,18 +932,16 @@
         @Override
         public void onRequestFocus(WebView view) {
             if (!mInForeground) {
-                mWebViewController.switchToTab(mWebViewController.getTabControl().getTabIndex(
-                        Tab.this));
+                mWebViewController.switchToTab(Tab.this);
             }
         }
 
         @Override
         public void onCloseWindow(WebView window) {
-            if (mParentTab != null) {
+            if (mParent != null) {
                 // JavaScript can only close popup window.
                 if (mInForeground) {
-                    mWebViewController.switchToTab(mWebViewController.getTabControl()
-                            .getTabIndex(mParentTab));
+                    mWebViewController.switchToTab(mParent);
                 }
                 mWebViewController.closeTab(Tab.this);
             }
@@ -1324,6 +1319,14 @@
         setWebView(w);
     }
 
+    public void setId(long id) {
+        mId = id;
+    }
+
+    public long getId() {
+        return mId;
+    }
+
     /**
      * Sets the WebView for this tab, correctly removing the old WebView from
      * the container view.
@@ -1374,14 +1377,14 @@
      */
     void removeFromTree() {
         // detach the children
-        if (mChildTabs != null) {
-            for(Tab t : mChildTabs) {
-                t.setParentTab(null);
+        if (mChildren != null) {
+            for(Tab t : mChildren) {
+                t.setParent(null);
             }
         }
         // remove itself from the parent list
-        if (mParentTab != null) {
-            mParentTab.mChildTabs.remove(this);
+        if (mParent != null) {
+            mParent.mChildren.remove(this);
         }
     }
 
@@ -1433,37 +1436,45 @@
     /**
      * Set the parent tab of this tab.
      */
-    void setParentTab(Tab parent) {
-        mParentTab = parent;
+    void setParent(Tab parent) {
+        mParent = parent;
         // This tab may have been freed due to low memory. If that is the case,
-        // the parent tab index is already saved. If we are changing that index
+        // the parent tab id is already saved. If we are changing that id
         // (most likely due to removing the parent tab) we must update the
-        // parent tab index in the saved Bundle.
+        // parent tab id in the saved Bundle.
         if (mSavedState != null) {
             if (parent == null) {
                 mSavedState.remove(PARENTTAB);
             } else {
-                mSavedState.putInt(PARENTTAB, mWebViewController.getTabControl()
-                        .getTabIndex(parent));
+                mSavedState.putLong(PARENTTAB, parent.getId());
             }
         }
     }
 
     /**
+     * If this Tab was created through another Tab, then this method returns
+     * that Tab.
+     * @return the Tab parent or null
+     */
+    public Tab getParent() {
+        return mParent;
+    }
+
+    /**
      * When a Tab is created through the content of another Tab, then we
      * associate the Tabs.
      * @param child the Tab that was created from this Tab
      */
     void addChildTab(Tab child) {
-        if (mChildTabs == null) {
-            mChildTabs = new Vector<Tab>();
+        if (mChildren == null) {
+            mChildren = new Vector<Tab>();
         }
-        mChildTabs.add(child);
-        child.setParentTab(this);
+        mChildren.add(child);
+        child.setParent(this);
     }
 
-    Vector<Tab> getChildTabs() {
-        return mChildTabs;
+    Vector<Tab> getChildren() {
+        return mChildren;
     }
 
     void resume() {
@@ -1651,15 +1662,6 @@
         return mErrorConsole;
     }
 
-    /**
-     * If this Tab was created through another Tab, then this method returns
-     * that Tab.
-     * @return the Tab parent or null
-     */
-    public Tab getParentTab() {
-        return mParentTab;
-    }
-
     private void setLockIconType(LockIcon icon) {
         mCurrentState.mLockIcon = icon;
         mWebViewController.onUpdatedLockIcon(this);
@@ -1724,15 +1726,15 @@
         // Store some extra info for displaying the tab in the picker.
         final WebHistoryItem item = list != null ? list.getCurrentItem() : null;
 
+        mSavedState.putLong(ID, mId);
         mSavedState.putString(CURRURL, mCurrentState.mUrl);
         mSavedState.putString(CURRTITLE, mCurrentState.mTitle);
         if (mAppId != null) {
             mSavedState.putString(APPID, mAppId);
         }
         // Remember the parent tab so the relationship can be restored.
-        if (mParentTab != null) {
-            mSavedState.putInt(PARENTTAB, mWebViewController.getTabControl().getTabIndex(
-                    mParentTab));
+        if (mParent != null) {
+            mSavedState.putLong(PARENTTAB, mParent.mId);
         }
         if (mScreenshot != null) {
             mSavedState.putParcelable(SCREENSHOT, mScreenshot);
@@ -1750,6 +1752,7 @@
         // Restore the internal state even if the WebView fails to restore.
         // This will maintain the app id, original url and close-on-exit values.
         mSavedState = null;
+        mId = b.getLong(ID);
         mAppId = b.getString(APPID);
         mScreenshot = b.getParcelable(SCREENSHOT);
 
diff --git a/src/com/android/browser/TabBar.java b/src/com/android/browser/TabBar.java
index 31c0740..a574d26 100644
--- a/src/com/android/browser/TabBar.java
+++ b/src/com/android/browser/TabBar.java
@@ -155,7 +155,7 @@
             TabView tv = buildTabView(tab);
             mTabs.addTab(tv);
         }
-        mTabs.setSelectedTab(mTabControl.getCurrentIndex());
+        mTabs.setSelectedTab(mTabControl.getCurrentPosition());
     }
 
     @Override
@@ -210,11 +210,12 @@
             } else {
                 showUrlBar();
             }
-        } else {
+        } else if (view instanceof TabView) {
+            final Tab tab = ((TabView) view).mTab;
             int ix = mTabs.getChildIndex(view);
             if (ix >= 0) {
                 mTabs.setSelectedTab(ix);
-                mUiController.switchToTab(ix);
+                mUiController.switchToTab(tab);
             }
         }
     }
@@ -601,7 +602,7 @@
     // TabChangeListener implementation
 
     public void onSetActiveTab(Tab tab) {
-        mTabs.setSelectedTab(mTabControl.getTabIndex(tab));
+        mTabs.setSelectedTab(mTabControl.getTabPosition(tab));
         TabView tv = mTabMap.get(tab);
         if (tv != null) {
             tv.setProgress(tv.mTab.getLoadProgress());
diff --git a/src/com/android/browser/TabControl.java b/src/com/android/browser/TabControl.java
index 8be3041..1fe9053 100644
--- a/src/com/android/browser/TabControl.java
+++ b/src/com/android/browser/TabControl.java
@@ -29,6 +29,13 @@
 class TabControl {
     // Log Tag
     private static final String LOGTAG = "TabControl";
+
+    // next Tab ID
+    private static long sNextId = 0;
+
+    private static final String POSITIONS = "positions";
+    private static final String CURRENT = "current";
+
     // Maximum number of tabs.
     private int mMaxTabs;
     // Private array of WebViews that are used as tabs.
@@ -54,6 +61,10 @@
         mTabQueue = new ArrayList<Tab>(mMaxTabs);
     }
 
+    static long getNextId() {
+        return sNextId++;
+    }
+
     File getThumbnailDir() {
         return mThumbnailDir;
     }
@@ -104,13 +115,13 @@
     }
 
     /**
-     * Return the tab at the specified index.
-     * @return The Tab for the specified index or null if the tab does not
+     * Return the tab at the specified position.
+     * @return The Tab for the specified position or null if the tab does not
      *         exist.
      */
-    Tab getTab(int index) {
-        if (index >= 0 && index < mTabs.size()) {
-            return mTabs.get(index);
+    Tab getTab(int position) {
+        if (position >= 0 && position < mTabs.size()) {
+            return mTabs.get(position);
         }
         return null;
     }
@@ -124,19 +135,19 @@
     }
 
     /**
-     * Return the current tab index.
-     * @return The current tab index
+     * Return the current tab position.
+     * @return The current tab position
      */
-    int getCurrentIndex() {
+    int getCurrentPosition() {
         return mCurrentTab;
     }
 
     /**
-     * Given a Tab, find it's index
+     * Given a Tab, find it's position
      * @param Tab to find
-     * @return index of Tab or -1 if not found
+     * @return position of Tab or -1 if not found
      */
-    int getTabIndex(Tab tab) {
+    int getTabPosition(Tab tab) {
         if (tab == null) {
             return -1;
         }
@@ -153,7 +164,8 @@
      */
     boolean hasAnyOpenIncognitoTabs() {
         for (Tab tab : mTabs) {
-            if (tab.getWebView() != null && tab.getWebView().isPrivateBrowsingEnabled()) {
+            if (tab.getWebView() != null
+                    && tab.getWebView().isPrivateBrowsingEnabled()) {
                 return true;
             }
         }
@@ -175,6 +187,7 @@
 
         // Create a new tab and add it to the tab list
         Tab t = new Tab(mController, w);
+        t.setId(getNextId());
         mTabs.add(t);
         // Initially put the tab in the background.
         t.putInBackground();
@@ -221,7 +234,7 @@
         } else {
             // If a tab that is earlier in the list gets removed, the current
             // index no longer points to the correct tab.
-            mCurrentTab = getTabIndex(current);
+            mCurrentTab = getTabPosition(current);
         }
 
         // destroy the tab
@@ -229,17 +242,6 @@
         // clear it's references to parent and children
         t.removeFromTree();
 
-        // The tab indices have shifted, update all the saved state so we point
-        // to the correct index.
-        for (Tab tab : mTabs) {
-            Vector<Tab> children = tab.getChildTabs();
-            if (children != null) {
-                for (Tab child : children) {
-                    child.setParentTab(tab);
-                }
-            }
-        }
-
         // Remove it from the queue of viewed tabs.
         mTabQueue.remove(t);
         return true;
@@ -264,61 +266,59 @@
         return mTabs.size();
     }
 
-
     /**
-     * Save the state of all the Tabs.
-     * @param outState The Bundle to save the state to.
+     * save the tab state:
+     * current position
+     * position sorted array of tab ids
+     * for each tab id, save the tab state
+     * @param outState
      */
     void saveState(Bundle outState) {
         final int numTabs = getTabCount();
-        outState.putInt(Tab.NUMTABS, numTabs);
-        final int index = getCurrentIndex();
-        outState.putInt(Tab.CURRTAB, (index >= 0 && index < numTabs) ? index : 0);
-        for (int i = 0; i < numTabs; i++) {
-            final Tab t = getTab(i);
-            if (t.saveState()) {
-                outState.putBundle(Tab.WEBVIEW + i, t.getSavedState());
+        long[] ids = new long[numTabs];
+        int i = 0;
+        for (Tab tab : mTabs) {
+            ids[i++] = tab.getId();
+            if (tab.saveState()) {
+                outState.putBundle(Long.toString(tab.getId()), tab.getSavedState());
             }
         }
+        outState.putLongArray(POSITIONS, ids);
+        final long cid = getCurrentTab().getId();
+        outState.putLong(CURRENT, cid);
     }
 
     /**
      * Check if the state can be restored.  If the state can be restored, the
-     * current tab index is returned.  This can be passed to restoreState below
+     * current tab id is returned.  This can be passed to restoreState below
      * in order to restore the correct tab.  Otherwise, -1 is returned and the
      * state cannot be restored.
      */
-    int canRestoreState(Bundle inState, boolean restoreIncognitoTabs) {
-        final int numTabs = (inState == null)
-                ? - 1 : inState.getInt(Tab.NUMTABS, -1);
-        if (numTabs == -1) {
+    long canRestoreState(Bundle inState, boolean restoreIncognitoTabs) {
+        final long[] ids = (inState == null) ? null : inState.getLongArray(POSITIONS);
+        if (ids == null) {
             return -1;
         }
-        final int oldCurrentTab = inState.getInt(Tab.CURRTAB, -1);
-
-        // Determine whether the saved current tab can be restored, and if not,
-        // which tab will take its place.
-        int currentTab = -1;
+        final long oldcurrent = inState.getLong(CURRENT);
+        long current = -1;
         if (restoreIncognitoTabs ||
-                !inState.getBundle(Tab.WEBVIEW + oldCurrentTab)
-                .getBoolean(Tab.INCOGNITO)) {
-            currentTab = oldCurrentTab;
+                !inState.getBundle(Long.toString(oldcurrent)).getBoolean(Tab.INCOGNITO)) {
+                current = oldcurrent;
         } else {
-            for (int i = 0; i < numTabs; i++) {
-                if (!inState.getBundle(Tab.WEBVIEW + i)
-                        .getBoolean(Tab.INCOGNITO)) {
-                    currentTab = i;
+            // pick first non incognito tab
+            for (long id : ids) {
+                if (!inState.getBundle(Long.toString(id)).getBoolean(Tab.INCOGNITO)) {
+                    current = id;
                     break;
                 }
             }
         }
-
-        return currentTab;
+        return current;
     }
 
     /**
      * Restore the state of all the tabs.
-     * @param currentTab The tab index to restore.
+     * @param currentId The tab id to restore.
      * @param inState The saved state of all the tabs.
      * @param restoreIncognitoTabs Restoring private browsing tabs
      * @param restoreAll All webviews get restored, not just the current tab
@@ -326,29 +326,29 @@
      * @return True if there were previous tabs that were restored. False if
      *         there was no saved state or restoring the state failed.
      */
-    void restoreState(Bundle inState, int currentTab,
+    void restoreState(Bundle inState, long currentId,
             boolean restoreIncognitoTabs, boolean restoreAll) {
-        if (currentTab == -1) {
+        if (currentId == -1) {
             return;
         }
-
-        // If currentTab is valid, numTabs must be present.
-        final int numTabs = inState.getInt(Tab.NUMTABS, -1);
-
-        // Map saved tab indices to new indices, in case any incognito tabs
-        // need to not be restored.
-        HashMap<Integer, Integer> originalTabIndices = new HashMap<Integer, Integer>();
-        originalTabIndices.put(-1, -1);
-        for (int i = 0; i < numTabs; i++) {
-            Bundle state = inState.getBundle(Tab.WEBVIEW + i);
-
-            if (!restoreIncognitoTabs && state != null && state.getBoolean(Tab.INCOGNITO)) {
-                originalTabIndices.put(i, -1);
-            } else if (i == currentTab || restoreAll) {
+        long[] ids = inState.getLongArray(POSITIONS);
+        long maxId = -Long.MAX_VALUE;
+        HashMap<Long, Tab> tabMap = new HashMap<Long, Tab>();
+        for (long id : ids) {
+            if (id > maxId) {
+                maxId = id;
+            }
+            final String idkey = Long.toString(id);
+            Bundle state = inState.getBundle(idkey);
+            if (!restoreIncognitoTabs && state != null
+                    && state.getBoolean(Tab.INCOGNITO)) {
+                // ignore tab
+            } else if (id == currentId || restoreAll) {
                 Tab t = createNewTab();
+                tabMap.put(id, t);
                 // Me must set the current tab before restoring the state
                 // so that all the client classes are set.
-                if (i == currentTab) {
+                if (id == currentId) {
                     setCurrentTab(t);
                 }
                 if (!t.restoreState(state)) {
@@ -356,11 +356,12 @@
                     t.getWebView().loadUrl(BrowserSettings.getInstance()
                             .getHomePage());
                 }
-                originalTabIndices.put(i, getTabCount() - 1);
             } else {
                 // Create a new tab and don't restore the state yet, add it
                 // to the tab list
                 Tab t = new Tab(mController, null);
+                t.setId(id);
+                tabMap.put(id, t);
                 if (state != null) {
                     t.setSavedState(state);
                     // Need to maintain the app id and original url so we
@@ -370,21 +371,22 @@
                 mTabs.add(t);
                 // added the tab to the front as they are not current
                 mTabQueue.add(0, t);
-                originalTabIndices.put(i, getTabCount() - 1);
             }
-        }
+            // make sure that there is no id overlap between the restored
+            // and new tabs
+            sNextId = maxId + 1;
 
-        // Rebuild the tree of tabs. Do this after all tabs have been
-        // created/restored so that the parent tab exists.
-        for (int i = 0; i < numTabs; i++) {
-            final Bundle b = inState.getBundle(Tab.WEBVIEW + i);
-            final Tab t = getTab(i);
-            if (b != null && t != null) {
-                final Integer parentIndex = originalTabIndices.get(b.getInt(Tab.PARENTTAB, -1));
-                if (parentIndex != -1) {
-                    final Tab parent = getTab(parentIndex);
+        }
+        // restore parent/child relationships
+        for (long id : ids) {
+            final Tab tab = tabMap.get(id);
+            final Bundle b = inState.getBundle(Long.toString(id));
+            if ((b != null) && (tab != null)) {
+                final long parentId = b.getLong(Tab.PARENTTAB, -1);
+                if (parentId != -1) {
+                    final Tab parent = tabMap.get(parentId);
                     if (parent != null) {
-                        parent.addChildTab(t);
+                        parent.addChildTab(tab);
                     }
                 }
             }
@@ -439,7 +441,7 @@
         for (Tab t : mTabQueue) {
             if (t != null && t.getWebView() != null) {
                 openTabCount++;
-                if (t != current && t != current.getParentTab()) {
+                if (t != current && t != current.getParent()) {
                     tabsToGo.add(t);
                 }
             }
@@ -458,9 +460,7 @@
      * @param view The WebView used to find the tab.
      */
     Tab getTabFromView(WebView view) {
-        final int size = getTabCount();
-        for (int i = 0; i < size; i++) {
-            final Tab t = getTab(i);
+        for (Tab t : mTabs) {
             if (t.getSubWebView() == view || t.getWebView() == view) {
                 return t;
             }
@@ -472,13 +472,11 @@
      * Return the tab with the matching application id.
      * @param id The application identifier.
      */
-    Tab getTabFromId(String id) {
+    Tab getTabFromAppId(String id) {
         if (id == null) {
             return null;
         }
-        final int size = getTabCount();
-        for (int i = 0; i < size; i++) {
-            final Tab t = getTab(i);
+        for (Tab t : mTabs) {
             if (id.equals(t.getAppId())) {
                 return t;
             }
@@ -490,9 +488,7 @@
      * Stop loading in all opened WebView including subWindows.
      */
     void stopAllLoading() {
-        final int size = getTabCount();
-        for (int i = 0; i < size; i++) {
-            final Tab t = getTab(i);
+        for (Tab t : mTabs) {
             final WebView webview = t.getWebView();
             if (webview != null) {
                 webview.stopLoading();
@@ -535,10 +531,8 @@
             return t;
         }
         // Now check all the rest.
-        final int size = getTabCount();
-        for (int i = 0; i < size; i++) {
-            t = getTab(i);
-            if (tabMatchesUrl(t, url)) {
+        for (Tab tab : mTabs) {
+            if (tabMatchesUrl(tab, url)) {
                 return t;
             }
         }
diff --git a/src/com/android/browser/UiController.java b/src/com/android/browser/UiController.java
index a2de1d7..4fc37af 100644
--- a/src/com/android/browser/UiController.java
+++ b/src/com/android/browser/UiController.java
@@ -49,7 +49,7 @@
 
     void setActiveTab(Tab tab);
 
-    boolean switchToTab(int tabIndex);
+    boolean switchToTab(Tab tab);
 
     void closeCurrentTab();
 
diff --git a/src/com/android/browser/UrlHandler.java b/src/com/android/browser/UrlHandler.java
index c76eee8..02a080f 100644
--- a/src/com/android/browser/UrlHandler.java
+++ b/src/com/android/browser/UrlHandler.java
@@ -258,7 +258,7 @@
 
         protected void onPostExecute(String result) {
             // Make sure the Tab was not closed while handling the task
-            if (mController.getTabControl().getTabIndex(mTab) != -1) {
+            if (mController.getTabControl().getTabPosition(mTab) != -1) {
                 // If the Activity Manager is not invoked, load the URL directly
                 if (!startActivityForUrl(result)) {
                     if (!handleMenuClick(mTab, result)) {
diff --git a/src/com/android/browser/WebViewController.java b/src/com/android/browser/WebViewController.java
index 6028a97..bf3bdba 100644
--- a/src/com/android/browser/WebViewController.java
+++ b/src/com/android/browser/WebViewController.java
@@ -104,7 +104,7 @@
     Tab openTab(String url, boolean incognito, boolean setActive,
             boolean useCurrent);
 
-    boolean switchToTab(int tabindex);
+    boolean switchToTab(Tab tab);
 
     void closeTab(Tab tab);