diff options
author | Bijan Amirzada <bijana@codeaurora.org> | 2014-03-21 12:12:18 -0700 |
---|---|---|
committer | Bijan Amirzada <bijana@codeaurora.org> | 2014-03-21 15:49:20 -0700 |
commit | 41242f2ff13293612786e7550a934ee13d5f6b50 (patch) | |
tree | e75b2e10dddacf6fe76d45e8546e9d2472c84015 /src/com/android/browser/TabControl.java | |
parent | a9a5a583503419d8794356f1a3e515db05bda8d0 (diff) | |
download | android_packages_apps_Gello-41242f2ff13293612786e7550a934ee13d5f6b50.tar.gz android_packages_apps_Gello-41242f2ff13293612786e7550a934ee13d5f6b50.tar.bz2 android_packages_apps_Gello-41242f2ff13293612786e7550a934ee13d5f6b50.zip |
Change SWE app properties back to stock Android
- Changed project package name from com.android.swe.browser
back to com.android.browser along with code references to
old package name.
- Changes to AndroidManifest making it conform closer to stock
browser manifest.
- Changed app and apk name back to Browser.
Change-Id: I778ee1d1197bd50bd4a4850eef6d1d7f4ef0ad0b
Diffstat (limited to 'src/com/android/browser/TabControl.java')
-rw-r--r-- | src/com/android/browser/TabControl.java | 721 |
1 files changed, 721 insertions, 0 deletions
diff --git a/src/com/android/browser/TabControl.java b/src/com/android/browser/TabControl.java new file mode 100644 index 00000000..66736cbe --- /dev/null +++ b/src/com/android/browser/TabControl.java @@ -0,0 +1,721 @@ +/* + * Copyright (C) 2007 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.browser; + +import android.os.Bundle; +import android.util.Log; + +import com.android.browser.reflect.ReflectHelper; + +import org.codeaurora.swe.WebView; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Vector; + +class TabControl { + // Log Tag + private static final String LOGTAG = "TabControl"; + + // next Tab ID, starting at 1 + private static long sNextId = 1; + + private static final String POSITIONS = "positions"; + private static final String CURRENT = "current"; + + public static interface OnThumbnailUpdatedListener { + void onThumbnailUpdated(Tab t); + } + + // Maximum number of tabs. + private int mMaxTabs; + // Private array of WebViews that are used as tabs. + private ArrayList<Tab> mTabs; + // Queue of most recently viewed tabs. + private ArrayList<Tab> mTabQueue; + // Current position in mTabs. + private int mCurrentTab = -1; + // the main browser controller + private final Controller mController; + + private OnThumbnailUpdatedListener mOnThumbnailUpdatedListener; + + /** + * Construct a new TabControl object + */ + TabControl(Controller controller) { + mController = controller; + mMaxTabs = mController.getMaxTabs(); + mTabs = new ArrayList<Tab>(mMaxTabs); + mTabQueue = new ArrayList<Tab>(mMaxTabs); + } + + synchronized static long getNextId() { + return sNextId++; + } + + /** + * Return the current tab's main WebView. This will always return the main + * WebView for a given tab and not a subwindow. + * @return The current tab's WebView. + */ + WebView getCurrentWebView() { + Tab t = getTab(mCurrentTab); + if (t == null) { + return null; + } + return t.getWebView(); + } + + /** + * Return the current tab's top-level WebView. This can return a subwindow + * if one exists. + * @return The top-level WebView of the current tab. + */ + WebView getCurrentTopWebView() { + Tab t = getTab(mCurrentTab); + if (t == null) { + return null; + } + return t.getTopWindow(); + } + + /** + * Return the current tab's subwindow if it exists. + * @return The subwindow of the current tab or null if it doesn't exist. + */ + WebView getCurrentSubWindow() { + Tab t = getTab(mCurrentTab); + if (t == null) { + return null; + } + return t.getSubWebView(); + } + + /** + * return the list of tabs + */ + List<Tab> getTabs() { + return mTabs; + } + + /** + * 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 position) { + if (position >= 0 && position < mTabs.size()) { + return mTabs.get(position); + } + return null; + } + + /** + * Return the current tab. + * @return The current tab. + */ + Tab getCurrentTab() { + return getTab(mCurrentTab); + } + + /** + * Return the current tab position. + * @return The current tab position + */ + int getCurrentPosition() { + return mCurrentTab; + } + + /** + * Given a Tab, find it's position + * @param Tab to find + * @return position of Tab or -1 if not found + */ + int getTabPosition(Tab tab) { + if (tab == null) { + return -1; + } + return mTabs.indexOf(tab); + } + + boolean canCreateNewTab() { + return mMaxTabs > mTabs.size(); + } + + /** + * Returns true if there are any incognito tabs open. + * @return True when any incognito tabs are open, false otherwise. + */ + boolean hasAnyOpenIncognitoTabs() { + for (Tab tab : mTabs) { + if (tab.getWebView() != null + && tab.getWebView().isPrivateBrowsingEnabled()) { + return true; + } + } + return false; + } + + void addPreloadedTab(Tab tab) { + for (Tab current : mTabs) { + if (current != null && current.getId() == tab.getId()) { + throw new IllegalStateException("Tab with id " + tab.getId() + " already exists: " + + current.toString()); + } + } + mTabs.add(tab); + tab.setController(mController); + mController.onSetWebView(tab, tab.getWebView()); + tab.putInBackground(); + } + + /** + * Create a new tab. + * @return The newly createTab or null if we have reached the maximum + * number of open tabs. + */ + Tab createNewTab(boolean privateBrowsing) { + return createNewTab(null, privateBrowsing); + } + + Tab createNewTab(Bundle state, boolean privateBrowsing) { + int size = mTabs.size(); + // Return false if we have maxed out on tabs + if (!canCreateNewTab()) { + return null; + } + + final WebView w = createNewWebView(privateBrowsing); + + // Create a new tab and add it to the tab list + Tab t = new Tab(mController, w, state); + mTabs.add(t); + // Initially put the tab in the background. + t.putInBackground(); + return t; + } + + /** + * Create a new tab with default values for closeOnExit(false), + * appId(null), url(null), and privateBrowsing(false). + */ + Tab createNewTab() { + return createNewTab(false); + } + + SnapshotTab createSnapshotTab(long snapshotId) { + SnapshotTab t = new SnapshotTab(mController, snapshotId); + mTabs.add(t); + return t; + } + + /** + * Remove the parent child relationships from all tabs. + */ + void removeParentChildRelationShips() { + for (Tab tab : mTabs) { + tab.removeFromTree(); + } + } + + /** + * Remove the tab from the list. If the tab is the current tab shown, the + * last created tab will be shown. + * @param t The tab to be removed. + */ + boolean removeTab(Tab t) { + if (t == null) { + return false; + } + + // Grab the current tab before modifying the list. + Tab current = getCurrentTab(); + + // Remove t from our list of tabs. + mTabs.remove(t); + + // Put the tab in the background only if it is the current one. + if (current == t) { + t.putInBackground(); + mCurrentTab = -1; + } else { + // If a tab that is earlier in the list gets removed, the current + // index no longer points to the correct tab. + mCurrentTab = getTabPosition(current); + } + + // destroy the tab + t.destroy(); + // clear it's references to parent and children + t.removeFromTree(); + + // Remove it from the queue of viewed tabs. + mTabQueue.remove(t); + return true; + } + + /** + * Destroy all the tabs and subwindows + */ + void destroy() { + for (Tab t : mTabs) { + t.destroy(); + } + mTabs.clear(); + mTabQueue.clear(); + } + + /** + * Returns the number of tabs created. + * @return The number of tabs created. + */ + int getTabCount() { + return mTabs.size(); + } + + /** + * save the tab state: + * current position + * position sorted array of tab ids + * for each tab id, save the tab state + * @param outState + * @param saveImages + */ + void saveState(Bundle outState) { + final int numTabs = getTabCount(); + if (numTabs == 0) { + return; + } + long[] ids = new long[numTabs]; + int i = 0; + for (Tab tab : mTabs) { + Bundle tabState = tab.saveState(); + if (tabState != null && tab.getWebView() != null + && tab.getWebView().isPrivateBrowsingEnabled() == false) { + ids[i++] = tab.getId(); + String key = Long.toString(tab.getId()); + if (outState.containsKey(key)) { + // Dump the tab state for debugging purposes + for (Tab dt : mTabs) { + Log.e(LOGTAG, dt.toString()); + } + throw new IllegalStateException( + "Error saving state, duplicate tab ids!"); + } + outState.putBundle(key, tabState); + } else { + ids[i++] = -1; + // Since we won't be restoring the thumbnail, delete it + tab.deleteThumbnail(); + } + } + if (!outState.isEmpty()) { + outState.putLongArray(POSITIONS, ids); + Tab current = getCurrentTab(); + long cid = -1; + if (current != null) { + cid = current.getId(); + } + outState.putLong(CURRENT, cid); + } + } + + /** + * Check if the state can be restored. If the state can be restored, the + * 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. + */ + long canRestoreState(Bundle inState, boolean restoreIncognitoTabs) { + final long[] ids = (inState == null) ? null : inState.getLongArray(POSITIONS); + if (ids == null) { + return -1; + } + final long oldcurrent = inState.getLong(CURRENT); + long current = -1; + if (restoreIncognitoTabs || (hasState(oldcurrent, inState) && !isIncognito(oldcurrent, inState))) { + current = oldcurrent; + } else { + // pick first non incognito tab + for (long id : ids) { + if (hasState(id, inState) && !isIncognito(id, inState)) { + current = id; + break; + } + } + } + return current; + } + + private boolean hasState(long id, Bundle state) { + if (id == -1) return false; + Bundle tab = state.getBundle(Long.toString(id)); + return ((tab != null) && !tab.isEmpty()); + } + + private boolean isIncognito(long id, Bundle state) { + Bundle tabstate = state.getBundle(Long.toString(id)); + if ((tabstate != null) && !tabstate.isEmpty()) { + return tabstate.getBoolean(Tab.INCOGNITO); + } + return false; + } + + /** + * Restore the state of all the tabs. + * @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 + * (this does not override handling of incognito tabs) + */ + void restoreState(Bundle inState, long currentId, + boolean restoreIncognitoTabs, boolean restoreAll) { + if (currentId == -1) { + return; + } + 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 (state == null || state.isEmpty()) { + // Skip tab + continue; + } else if (!restoreIncognitoTabs + && state.getBoolean(Tab.INCOGNITO)) { + // ignore tab + } else if (id == currentId || restoreAll) { + Tab t = createNewTab(state, false); + if (t == null) { + // We could "break" at this point, but we want + // sNextId to be set correctly. + continue; + } + + // add for carrier homepage feature + // If the webview restore successfully, add javascript interface again. + WebView view = t.getWebView(); + if (view != null) { + Object[] params = { new String("persist.env.c.browser.resource"), + new String("default")}; + Class[] type = new Class[] {String.class, String.class}; + String browserRes = (String)ReflectHelper.invokeStaticMethod( + "android.os.SystemProperties","get", + type, params); + if ("ct".equals(browserRes)) { + view.getSettings().setJavaScriptEnabled(true); + if (mController.getActivity() instanceof BrowserActivity) { + view.addJavascriptInterface(mController.getActivity(), + "default_homepage"); + } + } + } + + tabMap.put(id, t); + // Me must set the current tab before restoring the state + // so that all the client classes are set. + if (id == currentId) { + setCurrentTab(t); + } + } else { + // Create a new tab and don't restore the state yet, add it + // to the tab list + Tab t = new Tab(mController, state); + tabMap.put(id, t); + mTabs.add(t); + // added the tab to the front as they are not current + mTabQueue.add(0, t); + } + } + + // make sure that there is no id overlap between the restored + // and new tabs + sNextId = maxId + 1; + + if (mCurrentTab == -1) { + if (getTabCount() > 0) { + setCurrentTab(getTab(0)); + } + } + // 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(tab); + } + } + } + } + } + + /** + * Free the memory in this order, 1) free the background tabs; 2) free the + * WebView cache; + */ + void freeMemory() { + if (getTabCount() == 0) return; + + // free the least frequently used background tabs + Vector<Tab> tabs = getHalfLeastUsedTabs(getCurrentTab()); + if (tabs.size() > 0) { + Log.w(LOGTAG, "Free " + tabs.size() + " tabs in the browser"); + for (Tab t : tabs) { + // store the WebView's state. + t.saveState(); + // destroy the tab + t.destroy(); + } + return; + } + + // free the WebView's unused memory (this includes the cache) + Log.w(LOGTAG, "Free WebView's unused memory and cache"); + WebView view = getCurrentWebView(); + if (view != null) { + view.freeMemory(); + } + } + + private Vector<Tab> getHalfLeastUsedTabs(Tab current) { + Vector<Tab> tabsToGo = new Vector<Tab>(); + + // Don't do anything if we only have 1 tab or if the current tab is + // null. + if (getTabCount() == 1 || current == null) { + return tabsToGo; + } + + if (mTabQueue.size() == 0) { + return tabsToGo; + } + + // Rip through the queue starting at the beginning and tear down half of + // available tabs which are not the current tab or the parent of the + // current tab. + int openTabCount = 0; + for (Tab t : mTabQueue) { + if (t != null && t.getWebView() != null) { + openTabCount++; + if (t != current && t != current.getParent()) { + tabsToGo.add(t); + } + } + } + + openTabCount /= 2; + if (tabsToGo.size() > openTabCount) { + tabsToGo.setSize(openTabCount); + } + + return tabsToGo; + } + + Tab getLeastUsedTab(Tab current) { + if (getTabCount() == 1 || current == null) { + return null; + } + if (mTabQueue.size() == 0) { + return null; + } + // find a tab which is not the current tab or the parent of the + // current tab + for (Tab t : mTabQueue) { + if (t != null && t.getWebView() != null) { + if (t != current && t != current.getParent()) { + return t; + } + } + } + return null; + } + + /** + * Show the tab that contains the given WebView. + * @param view The WebView used to find the tab. + */ + Tab getTabFromView(WebView view) { + for (Tab t : mTabs) { + if (t.getSubWebView() == view || t.getWebView() == view) { + return t; + } + } + return null; + } + + /** + * Return the tab with the matching application id. + * @param id The application identifier. + */ + Tab getTabFromAppId(String id) { + if (id == null) { + return null; + } + for (Tab t : mTabs) { + if (id.equals(t.getAppId())) { + return t; + } + } + return null; + } + + /** + * Stop loading in all opened WebView including subWindows. + */ + void stopAllLoading() { + for (Tab t : mTabs) { + final WebView webview = t.getWebView(); + if (webview != null) { + webview.stopLoading(); + } + final WebView subview = t.getSubWebView(); + if (subview != null) { + subview.stopLoading(); + } + } + } + + // This method checks if a tab matches the given url. + private boolean tabMatchesUrl(Tab t, String url) { + return url.equals(t.getUrl()) || url.equals(t.getOriginalUrl()); + } + + /** + * Return the tab that matches the given url. + * @param url The url to search for. + */ + Tab findTabWithUrl(String url) { + if (url == null) { + return null; + } + // Check the current tab first. + Tab currentTab = getCurrentTab(); + if (currentTab != null && tabMatchesUrl(currentTab, url)) { + return currentTab; + } + // Now check all the rest. + for (Tab tab : mTabs) { + if (tabMatchesUrl(tab, url)) { + return tab; + } + } + return null; + } + + /** + * Recreate the main WebView of the given tab. + */ + void recreateWebView(Tab t) { + final WebView w = t.getWebView(); + if (w != null) { + t.destroy(); + } + // Create a new WebView. If this tab is the current tab, we need to put + // back all the clients so force it to be the current tab. + t.setWebView(createNewWebView(t.isPrivateBrowsingEnabled()), false); + if (getCurrentTab() == t) { + setCurrentTab(t, true); + } + } + + /** + * Creates a new WebView and registers it with the global settings. + */ + private WebView createNewWebView() { + return createNewWebView(false); + } + + /** + * Creates a new WebView and registers it with the global settings. + * @param privateBrowsing When true, enables private browsing in the new + * WebView. + */ + private WebView createNewWebView(boolean privateBrowsing) { + return mController.getWebViewFactory().createWebView(privateBrowsing); + } + + /** + * Put the current tab in the background and set newTab as the current tab. + * @param newTab The new tab. If newTab is null, the current tab is not + * set. + */ + boolean setCurrentTab(Tab newTab) { + return setCurrentTab(newTab, false); + } + + /** + * If force is true, this method skips the check for newTab == current. + */ + private boolean setCurrentTab(Tab newTab, boolean force) { + Tab current = getTab(mCurrentTab); + if (current == newTab && !force) { + return true; + } + if (current != null) { + current.putInBackground(); + mCurrentTab = -1; + } + if (newTab == null) { + return false; + } + + // Move the newTab to the end of the queue + int index = mTabQueue.indexOf(newTab); + if (index != -1) { + mTabQueue.remove(index); + } + mTabQueue.add(newTab); + + // Display the new current tab + mCurrentTab = mTabs.indexOf(newTab); + WebView mainView = newTab.getWebView(); + boolean needRestore = !newTab.isSnapshot() && (mainView == null); + if (needRestore) { + // Same work as in createNewTab() except don't do new Tab() + mainView = createNewWebView(newTab.isPrivateBrowsingEnabled()); + newTab.setWebView(mainView); + } + newTab.putInForeground(); + return true; + } + + public void setOnThumbnailUpdatedListener(OnThumbnailUpdatedListener listener) { + mOnThumbnailUpdatedListener = listener; + for (Tab t : mTabs) { + WebView web = t.getWebView(); + if (web != null) { + web.setPictureListener(listener != null ? t : null); + } + } + } + + public OnThumbnailUpdatedListener getOnThumbnailUpdatedListener() { + return mOnThumbnailUpdatedListener; + } + +} |