package com.borqs.browser; import java.nio.ByteBuffer; import java.util.Map; import java.util.Vector; import org.chromium.chrome.browser.ChromeWebContentsDelegateAndroid; import org.chromium.chrome.browser.ContentViewUtil; import org.chromium.chrome.browser.TabBase; import org.chromium.chrome.testshell.TestShellTab; import org.chromium.content.browser.ContentView; import org.chromium.content.browser.ContentViewRenderView; import org.chromium.content.browser.LoadUrlParams; import org.chromium.content.common.CleanupReference; import org.chromium.ui.WindowAndroid; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.net.http.SslError; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.SystemClock; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.webkit.URLUtil; import android.widget.FrameLayout; public class Tab extends TestShellTab { // Log Tag private static final String LOGTAG = "Tab"; private static final boolean LOGD_ENABLED = com.borqs.browser.Browser.LOGD_ENABLED; // Special case the logtag for messages for the Console to make it easier to // filter them and match the logtag used for these messages in older versions // of the browser. private static final String CONSOLE_LOGTAG = "browser"; private static final int MSG_CAPTURE = 42; private static final int CAPTURE_DELAY = 100; private static final int INITIAL_PROGRESS = 5; private static Bitmap sDefaultFavicon; private static Paint sAlphaPaint = new Paint(); //private static ContentView mContentView; static { sAlphaPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); sAlphaPaint.setColor(Color.TRANSPARENT); } public enum SecurityState { // The page's main resource does not use SSL. Note that we use this // state irrespective of the SSL authentication state of sub-resources. SECURITY_STATE_NOT_SECURE, // The page's main resource uses SSL and the certificate is good. The // same is true of all sub-resources. SECURITY_STATE_SECURE, // The page's main resource uses SSL and the certificate is good, but // some sub-resources either do not use SSL or have problems with their // certificates. SECURITY_STATE_MIXED, // The page's main resource uses SSL but there is a problem with its // certificate. SECURITY_STATE_BAD_CERTIFICATE, } // Used for saving and restoring each Tab 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 INCOGNITO = "privateBrowsingEnabled"; static final String USERAGENT = "useragent"; static final String CLOSEFLAG = "closeOnBack"; Context mContext; protected ContentViewController mWebViewController; private WindowAndroid mWindowAndroid; // private int mNativeTabPtr; // The tab ID private long mId = -1; // The Geolocation permissions prompt // private GeolocationPermissionsPrompt mGeolocationPermissionsPrompt; // Main WebView wrapper private View mContainer; // Main WebView private ContentView mMainView; // Subwindow container private View mSubViewContainer; // Subwindow WebView private ContentView mSubView; // Saved bundle for when we are running low on memory. It contains the // information needed to restore the WebView if the user goes back to the // tab. 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 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> 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, // before onPageFinsihed) private boolean mInPageLoad; // The last reported progress of the current page private int mPageLoadProgress; // The time the load started, used to find load page time private long mLoadStartTime; // Application identifier used to find tabs that another application wants // to reuse. private String mAppId; // flag to indicate if tab should be closed on back private boolean mCloseOnBack; // Keep the original url around to avoid killing the old WebView if the url // has not changed. // Error console for the tab private ErrorConsoleView mErrorConsole; // The listener that gets invoked when a download is started from the // mMainView // private final DownloadListener mDownloadListener; // Listener used to know when we move forward or back in the history list. // private final WebBackForwardListClient mWebBackForwardListClient; // private DataController mDataController; // AsyncTask for downloading touch icons // DownloadTouchIcon mTouchIconLoader; private BrowserSettings mSettings; private int mCaptureWidth; private int mCaptureHeight; private Bitmap mCapture; private Handler mHandler; private boolean mUpdateThumbnail; // AsyncTask for downloading touch icons DownloadTouchIcon mTouchIconLoader; // All the state needed for a page protected static class PageState { String mUrl; String mOriginalUrl; String mTitle; SecurityState mSecurityState; // This is non-null only when mSecurityState is SECURITY_STATE_BAD_CERTIFICATE. SslError mSslCertificateError; Bitmap mFavicon; boolean mIsBookmarkedSite; boolean mIncognito; PageState(Context c, boolean incognito) { mIncognito = incognito; if (mIncognito) { mOriginalUrl = mUrl = "browser:incognito"; mTitle = c.getString(R.string.new_incognito_tab); } else { mOriginalUrl = mUrl = ""; mTitle = c.getString(R.string.new_tab); } mSecurityState = SecurityState.SECURITY_STATE_NOT_SECURE; } PageState(Context c, boolean incognito, String url, Bitmap favicon) { mIncognito = incognito; mOriginalUrl = mUrl = url; if (URLUtil.isHttpsUrl(url)) { mSecurityState = SecurityState.SECURITY_STATE_SECURE; } else { mSecurityState = SecurityState.SECURITY_STATE_NOT_SECURE; } mFavicon = favicon; } } // The current/loading page's state protected PageState mCurrentState; private WebContentsClient mWebContentsClient; private CleanupReference mCleanupReference; private ContentViewRenderView mContentViewRenderView; private static synchronized Bitmap getDefaultFavicon(Context context) { if (sDefaultFavicon == null) { sDefaultFavicon = BitmapFactory.decodeResource( context.getResources(), R.drawable.app_web_browser_sm); } return sDefaultFavicon; } // Construct a new tab static Tab createTab(ContentViewController c, WindowAndroid window, Bundle state) { //WindowAndroid w = new WindowAndroid(c.getActivity()); return new Tab(c, window, state); } // Construct a new tab static Tab createTabWithNativeContents(ContentViewController c, int nativeContentes, WindowAndroid window, Bundle state) { //WindowAndroid w = new WindowAndroid(c.getActivity()); return new Tab(c, nativeContentes, window, state); } private Tab(ContentViewController wvcontroller, WindowAndroid window) { this(wvcontroller, 0, window, null); } private Tab(ContentViewController wvcontroller, WindowAndroid window, Bundle state) { super(wvcontroller.getContext(), window); mWebViewController = wvcontroller; mContext = mWebViewController.getContext(); mSettings = BrowserSettings.getInstance(); mDataController = DataController.getInstance(mContext); mCurrentState = new PageState(mContext, false/*TODO*/); mInPageLoad = false; mInForeground = false; //mContentView = v; // init(); initClient(); mCaptureWidth = mContext.getResources().getDimensionPixelSize( R.dimen.tab_thumbnail_width); mCaptureHeight = mContext.getResources().getDimensionPixelSize( R.dimen.tab_thumbnail_height); updateShouldCaptureThumbnails(); restoreState(state); if (getId() == -1) { mId = TabControl.getNextId(); } setContentView(getContentView()); mHandler = new Handler() { @Override public void handleMessage(Message m) { switch (m.what) { case MSG_CAPTURE: capture(); break; } } }; } private Tab(ContentViewController wvcontroller, int nativeContents, WindowAndroid window, Bundle state) { super(wvcontroller.getContext(), nativeContents, window); mWebViewController = wvcontroller; mContext = mWebViewController.getContext(); mSettings = BrowserSettings.getInstance(); // mDataController = DataController.getInstance(mContext); mCurrentState = new PageState(mContext, false/*TODO*/); mInPageLoad = false; mInForeground = false; //mContentView = v; // init(); initClient(); mCaptureWidth = mContext.getResources().getDimensionPixelSize( R.dimen.tab_thumbnail_width); mCaptureHeight = mContext.getResources().getDimensionPixelSize( R.dimen.tab_thumbnail_height); updateShouldCaptureThumbnails(); restoreState(state); if (getId() == -1) { mId = TabControl.getNextId(); } setContentView(getContentView()); mHandler = new Handler() { @Override public void handleMessage(Message m) { switch (m.what) { case MSG_CAPTURE: capture(); break; } } }; } ContentViewRenderView getRenderView() { // Create the renderview. if (mContentViewRenderView == null) { mContentViewRenderView = new ContentViewRenderView(mContext) { @Override protected void onReadyToRender() { int debug = 2; debug ++; //if (mCurrentTab == null) createTab(mStartupUrl); } }; } mContentViewRenderView.setCurrentContentView(this.getWebView()); return mContentViewRenderView; } /** * This is used to get a new ID when the tab has been preloaded, before it is displayed and * added to TabControl. Preloaded tabs can be created before restoreInstanceState, leading * to overlapping IDs between the preloaded and restored tabs. */ public void refreshIdAfterPreload() { mId = TabControl.getNextId(); } /** * Return the main window of this tab. Note: if a tab is freed in the * background, this can return null. It is only guaranteed to be * non-null for the current tab. * @return The main WebView of this tab. */ ContentView getWebView() { //assert mMainView == getContentView(); return mMainView; //return getContentView(); } /* public ContentView getContentView() { return mMainView; }*/ void setViewContainer(View container) { mContainer = container; } View getViewContainer() { return mContainer; } /** * Return the subwindow of this tab or null if there is no subwindow. * @return The subwindow of this tab or null. */ ContentView getSubWebView() { return mSubView; } void setSubWebView(ContentView subView) { mSubView = subView; } View getSubViewContainer() { return mSubViewContainer; } void setSubViewContainer(View subViewContainer) { mSubViewContainer = subViewContainer; } ContentView getTopWindow() { // ww return mMainView; } ContentView getSubContentView() { return null; } /** * @return The application id string */ String getAppId() { return mAppId; } /** * Set the application id string * @param id */ void setAppId(String id) { mAppId = id; } boolean closeOnBack() { return mCloseOnBack; } void setCloseOnBack(boolean close) { mCloseOnBack = close; } String getUrl() { return UrlUtils.filteredUrl(mCurrentState.mUrl); } String getOriginalUrl() { if (mCurrentState.mOriginalUrl == null) { return getUrl(); } return UrlUtils.filteredUrl(mCurrentState.mOriginalUrl); } /** * Get the title of this tab. */ String getTitle() { if (mCurrentState.mTitle == null && mInPageLoad) { return mContext.getString(R.string.title_bar_loading); } return mCurrentState.mTitle; } /** * Get the favicon of this tab. */ Bitmap getFavicon() { if (mCurrentState.mFavicon != null) { return mCurrentState.mFavicon; } return getDefaultFavicon(mContext); } public boolean isBookmarkedSite() { return mCurrentState.mIsBookmarkedSite; } boolean isPrivateBrowsingEnabled() { return false; } public void setController(ContentViewController ctl) { mWebViewController = ctl; updateShouldCaptureThumbnails(); } public long getId() { return mId; } void setWebView(ContentView w) { setContentView(w, true); } void setContentView(ContentView w) { setContentView(w, true); } /** * Sets the WebView for this tab, correctly removing the old WebView from * the container view. */ void setContentView(ContentView w, boolean restore) { if (mMainView == w) { return; } // If the WebView is changing, the page will be reloaded, so any ongoing // Geolocation permission requests are void. /* if (mGeolocationPermissionsPrompt != null) { mGeolocationPermissionsPrompt.hide(); }*/ mWebViewController.onSetContentView(this, w); if (mMainView != null) { // mMainView.setPictureListener(null); if (w != null) { syncCurrentState(w, null); } else { mCurrentState = new PageState(mContext, false); } } // set the new one mMainView = w; // attach the WebViewClient, WebChromeClient and DownloadListener if (mMainView != null) { // mMainView.setWebViewClient(mWebViewClient); // mMainView.setWebChromeClient(mWebChromeClient); // Attach DownloadManager so that downloads can start in an active // or a non-active window. This can happen when going to a site that // does a redirect after a period of time. The user could have // switched to another tab while waiting for the download to start. // mMainView.setDownloadListener(mDownloadListener); // getWebViewClassic().setWebBackForwardListClient(mWebBackForwardListClient); TabControl tc = mWebViewController.getTabControl(); if (tc != null && tc.getOnThumbnailUpdatedListener() != null) { // mMainView.setPictureListener(this); } if (restore && (mSavedState != null)) { // restoreUserAgent(); /* ww WebBackForwardList restoredState = mMainView.restoreState(mSavedState); if (restoredState == null || restoredState.getSize() == 0) { Log.w(LOGTAG, "Failed to restore WebView state!"); loadUrl(mCurrentState.mOriginalUrl, null); }*/ mSavedState = null; } } } /** * Destroy the tab's main WebView and subWindow if any * Overrides super.destroy(). */ public void destroy() { if (mMainView != null) { dismissSubWindow(); // save the WebView to call destroy() after detach it from the tab ContentView webView = mMainView; setWebView(null); // webView.destroy(); } super.destroy(); } /** * Remove the tab from the parent */ void removeFromTree() { // detach the children if (mChildren != null) { for(Tab t : mChildren) { t.setParent(null); } } // remove itself from the parent list if (mParent != null) { mParent.mChildren.remove(this); } // deleteThumbnail(); } public void updateShouldCaptureThumbnails() { /* ww if (mWebViewController.shouldCaptureThumbnails()) { synchronized (Tab.this) { if (mCapture == null) { mCapture = Bitmap.createBitmap(mCaptureWidth, mCaptureHeight, Bitmap.Config.RGB_565); mCapture.eraseColor(Color.WHITE); if (mInForeground) { postCapture(); } } } } else { synchronized (Tab.this) { mCapture = null; deleteThumbnail(); } } */ } /** * Dismiss the subWindow for the tab. */ void dismissSubWindow() { if (mSubView != null) { mWebViewController.endActionMode(); mSubView.destroy(); mSubView = null; mSubViewContainer = null; } } public boolean shouldUpdateThumbnail() { //return false; return mUpdateThumbnail; } /** * Set the parent tab of this tab. */ void setParent(Tab parent) { if (parent == this) { throw new IllegalStateException("Cannot set parent to self!"); } mParent = parent; // This tab may have been freed due to low memory. If that is the case, // 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 id in the saved Bundle. if (mSavedState != null) { if (parent == null) { mSavedState.remove(PARENTTAB); } else { mSavedState.putLong(PARENTTAB, parent.getId()); } } /* ww // Sync the WebView useragent with the parent if (parent != null && mSettings.hasDesktopUseragent(parent.getWebView()) != mSettings.hasDesktopUseragent(getWebView())) { mSettings.toggleDesktopUseragent(getWebView()); } */ if (parent != null && parent.getId() == getId()) { throw new IllegalStateException("Parent has same ID as child!"); } } /** * 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 (mChildren == null) { mChildren = new Vector<Tab>(); } mChildren.add(child); child.setParent(this); } Vector<Tab> getChildren() { return mChildren; } private void setupHwAcceleration(View web) { /* if (web == null) return; BrowserSettings settings = BrowserSettings.getInstance(); if (settings.isHardwareAccelerated()) { web.setLayerType(View.LAYER_TYPE_NONE, null); } else { web.setLayerType(View.LAYER_TYPE_SOFTWARE, null); }*/ } void pause() { if (this.mMainView != null) { mMainView.onActivityPause(); if (mSubView != null) { mSubView.onActivityPause(); } } } void resume() { if (this.mMainView != null) { mMainView.onActivityResume(); if (mSubView != null) { mSubView.onActivityResume(); } } } void putInForeground() { if (mInForeground) { return; } mInForeground = true; resume(); Activity activity = mWebViewController.getActivity(); mMainView.setOnCreateContextMenuListener(activity); if (mSubView != null) { mSubView.setOnCreateContextMenuListener(activity); } // Show the pending error dialog if the queue is not empty /* ww if (mQueuedErrors != null && mQueuedErrors.size() > 0) { showError(mQueuedErrors.getFirst()); } mWebViewController.bookmarkedStatusHasChanged(this);*/ } void putInBackground() { if (!mInForeground) { return; } capture(); mInForeground = false; pause(); mMainView.setOnCreateContextMenuListener(null); if (mSubView != null) { mSubView.setOnCreateContextMenuListener(null); } } boolean inForeground() { return mInForeground; } protected void capture() { } int getLoadProgress() { if (mInPageLoad) { return mPageLoadProgress; } return 100; } /** * @return TRUE if onPageStarted is called while onPageFinished is not * called yet. */ boolean inPageLoad() { return mInPageLoad; } /** * @return The Bundle with the tab's state if it can be saved, otherwise null */ public Bundle saveState() { // If the WebView is null it means we ran low on memory and we already // stored the saved state in mSavedState. if (mMainView == null) { return mSavedState; } if (TextUtils.isEmpty(mCurrentState.mUrl)) { return null; } mSavedState = new Bundle(); /* ww WebBackForwardList savedList = mMainView.saveState(mSavedState); if (savedList == null || savedList.getSize() == 0) { Log.w(LOGTAG, "Failed to save back/forward list for " + mCurrentState.mUrl); } mSavedState.putLong(ID, mId); mSavedState.putString(CURRURL, mCurrentState.mUrl); mSavedState.putString(CURRTITLE, mCurrentState.mTitle); mSavedState.putBoolean(INCOGNITO, mMainView.isPrivateBrowsingEnabled()); if (mAppId != null) { mSavedState.putString(APPID, mAppId); } mSavedState.putBoolean(CLOSEFLAG, mCloseOnBack); // Remember the parent tab so the relationship can be restored. if (mParent != null) { mSavedState.putLong(PARENTTAB, mParent.mId); } mSavedState.putBoolean(USERAGENT, mSettings.hasDesktopUseragent(getWebView()));*/ return mSavedState; } /* * Restore the state of the tab. */ private void restoreState(Bundle b) { mSavedState = b; if (mSavedState == null) { return; } // Restore the internal state even if the WebView fails to restore. // This will maintain the app id, original url and close-on-exit values. mId = b.getLong(ID); mAppId = b.getString(APPID); mCloseOnBack = b.getBoolean(CLOSEFLAG); // restoreUserAgent(); String url = b.getString(CURRURL); String title = b.getString(CURRTITLE); boolean incognito = b.getBoolean(INCOGNITO); mCurrentState = new PageState(mContext, incognito, url, null); mCurrentState.mTitle = title; synchronized (Tab.this) { if (mCapture != null) { // DataController.getInstance(mContext).loadThumbnail(this); } } } public Bitmap getScreenshot() { /* TODO: need a proper scale here. synchronized (Tab.this) { return mCapture; }*/ if (mMainView == null) return null; if (mMainView.getWidth() <= 0 || mMainView.getContentHeight() <= 0) { return null; } return mMainView.getBitmap(mCaptureWidth, mCaptureHeight); } public boolean isSnapshot() { return false; } private void syncCurrentState(ContentView view, String url) { } protected void persistThumbnail() { // DataController.getInstance(mContext).saveThumbnail(this); } protected void deleteThumbnail() { // DataController.getInstance(mContext).deleteThumbnail(this); } public void loadUrl(String url, Map<String, String> headers) { if (mMainView != null) { mPageLoadProgress = INITIAL_PROGRESS; mInPageLoad = true; mCurrentState = new PageState(mContext, false, url, null); mWebViewController.onPageStarted(this, mMainView, null); // ww mMainView.loadUrl(url, headers); LoadUrlParams params = new LoadUrlParams(url); if (headers != null) params.setExtraHeaders(headers); mMainView.loadUrl(params); } } public boolean canGoBack() { return mMainView != null ? mMainView.canGoBack() : false; } public boolean canGoForward() { return mMainView != null ? mMainView.canGoForward() : false; } public void goBack() { if (mMainView != null) { mMainView.goBack(); } } public void goForward() { if (mMainView != null) { mMainView.goForward(); } } /** * Sets the security state, clears the SSL certificate error and informs * the controller. */ private void setSecurityState(SecurityState securityState) { mCurrentState.mSecurityState = securityState; mCurrentState.mSslCertificateError = null; mWebViewController.onUpdatedSecurityState(this); } /** * @return The tab's security state. */ SecurityState getSecurityState() { return mCurrentState.mSecurityState; } // Chrome related. private static final class DestroyRunnable implements Runnable { private final int mNativeTestShellTab; private DestroyRunnable(int nativeTestShellTab) { mNativeTestShellTab = nativeTestShellTab; } @Override public void run() { nativeDestroy(mNativeTestShellTab); } } public class WebContentsClient extends ChromeWebContentsDelegateAndroid { @Override public void onLoadProgressChanged(int newProgress) { mPageLoadProgress = newProgress; if (newProgress == 100) { mInPageLoad = false; } mWebViewController.onProgressChanged(Tab.this); if (mUpdateThumbnail && newProgress == 100) { mUpdateThumbnail = false; } } @Override public void onUpdateUrl(String url) { if (mCurrentState != null) { mCurrentState.mUrl = url; } } @Override public void onLoadStarted() { mInPageLoad = true; mInPageLoad = true; mUpdateThumbnail = true; mPageLoadProgress = INITIAL_PROGRESS; mCurrentState = new PageState(mContext, false, getWebView().getUrl(), null/*TODO*/); mLoadStartTime = SystemClock.uptimeMillis(); // If we start a touch icon load and then load a new page, we don't // want to cancel the current touch icon loader. But, we do want to // create a new one when the touch icon url is known. if (mTouchIconLoader != null) { mTouchIconLoader.mTab = null; mTouchIconLoader = null; } /* // reset the error console if (mErrorConsole != null) { mErrorConsole.clearErrorMessages(); if (mWebViewController.shouldShowErrorConsole()) { mErrorConsole.showConsole(ErrorConsoleView.SHOW_NONE); } } */ // finally update the UI in the activity if it is in the foreground mWebViewController.onPageStarted(Tab.this, Tab.this.getWebView(), null); updateBookmarkedStatus(); } @Override public void onLoadStopped() { mInPageLoad = false; } @Override public void onTitleUpdated() { if (mCurrentState != null) { mCurrentState.mTitle = getWebView().getTitle(); } } @Override public boolean addNewContents(int nativeSourceWebContents, int nativeWebContents, int disposition, Rect initialPosition, boolean userGesture) { return Tab.this.mWebViewController.createTabWitNativeContents(null, Tab.this, true, false, nativeWebContents); // return mTab.onCreateWindow(nativeSourceWebContents, nativeWebContents, disposition, initialPosition, userGesture); } } public void initClient() { // Build the WebContentsDelegate mWebContentsClient = new WebContentsClient(); setWebContentsDelegate(mWebContentsClient); } private DataController mDataController; public void updateBookmarkedStatus() { mDataController.queryBookmarkStatus(getUrl(), mIsBookmarkCallback); } private DataController.OnQueryUrlIsBookmark mIsBookmarkCallback = new DataController.OnQueryUrlIsBookmark() { @Override public void onQueryUrlIsBookmark(String url, boolean isBookmark) { if (mCurrentState.mUrl.equals(url)) { mCurrentState.mIsBookmarkedSite = isBookmark; Tab.this.mWebViewController.bookmarkedStatusHasChanged(Tab.this); } } }; void updateCaptureFromBlob(byte[] blob) { synchronized (Tab.this) { if (mCapture == null) { return; } ByteBuffer buffer = ByteBuffer.wrap(blob); try { mCapture.copyPixelsFromBuffer(buffer); } catch (RuntimeException rex) { Log.e(LOGTAG, "Load capture has mismatched sizes; buffer: " + buffer.capacity() + " blob: " + blob.length + "capture: " + mCapture.getByteCount()); throw rex; } } } /** * Return the tab's error console. Creates the console if createIfNEcessary * is true and we haven't already created the console. * @param createIfNecessary Flag to indicate if the console should be * created if it has not been already. * @return The tab's error console, or null if one has not been created and * createIfNecessary is false. */ ErrorConsoleView getErrorConsole(boolean createIfNecessary) { if (createIfNecessary && mErrorConsole == null) { mErrorConsole = new ErrorConsoleView(mContext); mErrorConsole.setWebView(mMainView); } return mErrorConsole; } }