package acr.browser.lightning.activity; import android.app.Activity; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.support.annotation.Nullable; import android.support.v7.app.AlertDialog; import android.util.Log; import android.webkit.WebView; import com.squareup.otto.Bus; import java.util.ArrayList; import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; import acr.browser.lightning.R; import acr.browser.lightning.constant.Constants; import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.utils.Utils; import acr.browser.lightning.view.LightningView; /** * @author Stefano Pacifici * @date 2015/09/14 */ @Singleton public class TabsManager { private static final String TAG = TabsManager.class.getSimpleName(); private final List mWebViewList = new ArrayList<>(); private LightningView mCurrentTab; @Inject PreferenceManager mPreferenceManager; @Inject Bus mEventBus; @Inject public TabsManager() {} /** * Restores old tabs that were open before the browser * was closed. Handles the intent used to open the browser. * * @param activity the activity needed to create tabs. * @param intent the intent that started the browser activity. * @param incognito whether or not we are in incognito mode. */ public synchronized void restoreTabsAndHandleIntent(final Activity activity, final Intent intent, final boolean incognito) { // If incognito, only create one tab, do not handle intent // in order to protect user privacy if (incognito && mWebViewList.isEmpty()) { newTab(activity, null, true); return; } String url = null; if (intent != null) { url = intent.getDataString(); } mWebViewList.clear(); mCurrentTab = null; if (mPreferenceManager.getRestoreLostTabsEnabled()) { final String mem = mPreferenceManager.getMemoryUrl(); mPreferenceManager.setMemoryUrl(""); String[] array = Utils.getArray(mem); for (String urlString : array) { if (!urlString.isEmpty()) { newTab(activity, urlString, false); } } } if (url != null) { if (url.startsWith(Constants.FILE)) { final String urlToLoad = url; AlertDialog.Builder builder = new AlertDialog.Builder(activity); builder.setCancelable(true) .setTitle(R.string.title_warning) .setMessage(R.string.message_blocked_local) .setNegativeButton(android.R.string.cancel, null) .setPositiveButton(R.string.action_open, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { newTab(activity, urlToLoad, false); } }) .show(); } else { newTab(activity, url, false); } } if (mWebViewList.size() == 0) { newTab(activity, null, false); } } /** * Return the tab at the given position in tabs list, or null if position is not in tabs list * range. * * @param position the index in tabs list * @return the corespondent {@link LightningView}, or null if the index is invalid */ @Nullable public synchronized LightningView getTabAtPosition(final int position) { if (position < 0 || position >= mWebViewList.size()) { return null; } return mWebViewList.get(position); } /** * Try to low memory pressure */ public synchronized void freeMemory() { for (LightningView tab : mWebViewList) { tab.freeMemory(); } } /** * Shutdown the manager */ public synchronized void shutdown() { for (LightningView tab : mWebViewList) { tab.onDestroy(); } mWebViewList.clear(); mCurrentTab = null; } /** * Resume the tabs * * @param context */ public synchronized void resume(final Context context) { for (LightningView tab : mWebViewList) { tab.initializePreferences(context); } } /** * Forward network connection status to the webviews. * * @param isConnected */ public synchronized void notifyConnectionStatus(final boolean isConnected) { for (LightningView tab : mWebViewList) { final WebView webView = tab.getWebView(); if (webView != null) { webView.setNetworkAvailable(isConnected); } } } /** * @return The number of currently opened tabs */ public synchronized int size() { return mWebViewList.size(); } /** * Create and return a new tab. The tab is automatically added to the tabs list. * * @param activity * @param url * @param isIncognito * @return */ public synchronized LightningView newTab(final Activity activity, final String url, final boolean isIncognito) { final LightningView tab = new LightningView(activity, url, isIncognito); mWebViewList.add(tab); return tab; } /** * Remove a tab and return its reference or null if the position is not in tabs range * * @param position The position of the tab to remove */ private synchronized void removeTab(final int position) { if (position >= mWebViewList.size()) { return; } final LightningView tab = mWebViewList.remove(position); if (mCurrentTab == tab) { mCurrentTab = null; } tab.onDestroy(); Log.d(Constants.TAG, tab.toString()); } public synchronized void deleteTab(int position) { final LightningView currentTab = getCurrentTab(); int current = positionOf(currentTab); if (current == position) { if (size() == 1) { mCurrentTab = null; } else if (current < size() - 1) { // There is another tab after this one mCurrentTab = getTabAtPosition(current + 1); } else { mCurrentTab = getTabAtPosition(current - 1); } removeTab(current); } else { removeTab(position); } } /** * Return the position of the given tab. * * @param tab the tab to look for * @return the position of the tab or -1 if the tab is not in the list */ public synchronized int positionOf(final LightningView tab) { return mWebViewList.indexOf(tab); } /** * @return A string representation of the currently opened tabs */ public String tabsString() { final StringBuilder builder = new StringBuilder(mWebViewList.size()); for (LightningView tab : mWebViewList) { final String url = tab.getUrl(); if (!url.isEmpty()) { builder.append(url).append("|$|SEPARATOR|$|"); } } return builder.toString(); } /** * Return the {@link WebView} associated to the current tab, or null if there is no current tab * * @return a {@link WebView} or null */ @Nullable public synchronized WebView getCurrentWebView() { return mCurrentTab != null ? mCurrentTab.getWebView() : null; } /** * TODO We should remove also this, but probably not * * @return */ @Nullable public synchronized LightningView getCurrentTab() { return mCurrentTab; } /** * Switch the current tab to the one at the given position. It returns the selected. After this * call {@link TabsManager#getCurrentTab()} return the same reference returned by this method if * position is valid. * * @return the selected tab or null if position is out of tabs range */ @Nullable public synchronized LightningView switchToTab(final int position) { if (position < 0 || position >= mWebViewList.size()) { Log.e(TAG, "Returning a null LightningView requested for position: " + position); return null; } else { final LightningView tab = mWebViewList.get(position); if (tab != null) { mCurrentTab = tab; } return tab; } } }