summaryrefslogtreecommitdiffstats
path: root/mobile/android/base/java/org/mozilla/gecko/Tab.java
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/base/java/org/mozilla/gecko/Tab.java')
-rw-r--r--mobile/android/base/java/org/mozilla/gecko/Tab.java843
1 files changed, 843 insertions, 0 deletions
diff --git a/mobile/android/base/java/org/mozilla/gecko/Tab.java b/mobile/android/base/java/org/mozilla/gecko/Tab.java
new file mode 100644
index 000000000..6010a3dd9
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/Tab.java
@@ -0,0 +1,843 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Future;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.mozilla.gecko.annotation.RobocopTarget;
+import org.mozilla.gecko.db.BrowserDB;
+import org.mozilla.gecko.db.URLMetadata;
+import org.mozilla.gecko.gfx.BitmapUtils;
+import org.mozilla.gecko.icons.IconCallback;
+import org.mozilla.gecko.icons.IconDescriptor;
+import org.mozilla.gecko.icons.IconRequestBuilder;
+import org.mozilla.gecko.icons.IconResponse;
+import org.mozilla.gecko.icons.Icons;
+import org.mozilla.gecko.reader.ReaderModeUtils;
+import org.mozilla.gecko.reader.ReadingListHelper;
+import org.mozilla.gecko.toolbar.BrowserToolbar.TabEditingState;
+import org.mozilla.gecko.util.ThreadUtils;
+import org.mozilla.gecko.widget.SiteLogins;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
+import android.os.Build;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+
+public class Tab {
+ private static final String LOGTAG = "GeckoTab";
+
+ private static Pattern sColorPattern;
+ private final int mId;
+ private final BrowserDB mDB;
+ private long mLastUsed;
+ private String mUrl;
+ private String mBaseDomain;
+ private String mUserRequested; // The original url requested. May be typed by the user or sent by an extneral app for example.
+ private String mTitle;
+ private Bitmap mFavicon;
+ private String mFaviconUrl;
+ private String mApplicationId; // Intended to be null after explicit user action.
+
+ private IconRequestBuilder mIconRequestBuilder;
+ private Future<IconResponse> mRunningIconRequest;
+
+ private boolean mHasFeeds;
+ private boolean mHasOpenSearch;
+ private final SiteIdentity mSiteIdentity;
+ private SiteLogins mSiteLogins;
+ private BitmapDrawable mThumbnail;
+ private final int mParentId;
+ // Indicates the url was loaded from a source external to the app. This will be cleared
+ // when the user explicitly loads a new url (e.g. clicking a link is not explicit).
+ private final boolean mExternal;
+ private boolean mBookmark;
+ private int mFaviconLoadId;
+ private String mContentType;
+ private boolean mHasTouchListeners;
+ private final ArrayList<View> mPluginViews;
+ private int mState;
+ private Bitmap mThumbnailBitmap;
+ private boolean mDesktopMode;
+ private boolean mEnteringReaderMode;
+ private final Context mAppContext;
+ private ErrorType mErrorType = ErrorType.NONE;
+ private volatile int mLoadProgress;
+ private volatile int mRecordingCount;
+ private volatile boolean mIsAudioPlaying;
+ private volatile boolean mIsMediaPlaying;
+ private String mMostRecentHomePanel;
+ private boolean mShouldShowToolbarWithoutAnimationOnFirstSelection;
+
+ /*
+ * Bundle containing restore data for the panel referenced in mMostRecentHomePanel. This can be
+ * e.g. the most recent folder for the bookmarks panel, or any other state that should be
+ * persisted. This is then used e.g. when returning to homepanels via history.
+ */
+ private Bundle mMostRecentHomePanelData;
+
+ private int mHistoryIndex;
+ private int mHistorySize;
+ private boolean mCanDoBack;
+ private boolean mCanDoForward;
+
+ private boolean mIsEditing;
+ private final TabEditingState mEditingState = new TabEditingState();
+
+ // Will be true when tab is loaded from cache while device was offline.
+ private boolean mLoadedFromCache;
+
+ public static final int STATE_DELAYED = 0;
+ public static final int STATE_LOADING = 1;
+ public static final int STATE_SUCCESS = 2;
+ public static final int STATE_ERROR = 3;
+
+ public static final int LOAD_PROGRESS_INIT = 10;
+ public static final int LOAD_PROGRESS_START = 20;
+ public static final int LOAD_PROGRESS_LOCATION_CHANGE = 60;
+ public static final int LOAD_PROGRESS_LOADED = 80;
+ public static final int LOAD_PROGRESS_STOP = 100;
+
+ public enum ErrorType {
+ CERT_ERROR, // Pages with certificate problems
+ BLOCKED, // Pages blocked for phishing or malware warnings
+ NET_ERROR, // All other types of error
+ NONE // Non error pages
+ }
+
+ public Tab(Context context, int id, String url, boolean external, int parentId, String title) {
+ mAppContext = context.getApplicationContext();
+ mDB = BrowserDB.from(context);
+ mId = id;
+ mUrl = url;
+ mBaseDomain = "";
+ mUserRequested = "";
+ mExternal = external;
+ mParentId = parentId;
+ mTitle = title == null ? "" : title;
+ mSiteIdentity = new SiteIdentity();
+ mHistoryIndex = -1;
+ mContentType = "";
+ mPluginViews = new ArrayList<View>();
+ mState = shouldShowProgress(url) ? STATE_LOADING : STATE_SUCCESS;
+ mLoadProgress = LOAD_PROGRESS_INIT;
+ mIconRequestBuilder = Icons.with(mAppContext).pageUrl(mUrl);
+
+ updateBookmark();
+ }
+
+ private ContentResolver getContentResolver() {
+ return mAppContext.getContentResolver();
+ }
+
+ public void onDestroy() {
+ Tabs.getInstance().notifyListeners(this, Tabs.TabEvents.CLOSED);
+ }
+
+ @RobocopTarget
+ public int getId() {
+ return mId;
+ }
+
+ public synchronized void onChange() {
+ mLastUsed = System.currentTimeMillis();
+ }
+
+ public synchronized long getLastUsed() {
+ return mLastUsed;
+ }
+
+ public int getParentId() {
+ return mParentId;
+ }
+
+ // may be null if user-entered query hasn't yet been resolved to a URI
+ public synchronized String getURL() {
+ return mUrl;
+ }
+
+ // mUserRequested should never be null, but it may be an empty string
+ public synchronized String getUserRequested() {
+ return mUserRequested;
+ }
+
+ // mTitle should never be null, but it may be an empty string
+ public synchronized String getTitle() {
+ return mTitle;
+ }
+
+ public String getDisplayTitle() {
+ if (mTitle != null && mTitle.length() > 0) {
+ return mTitle;
+ }
+
+ return mUrl;
+ }
+
+ /**
+ * Returns the base domain of the loaded uri. Note that if the page is
+ * a Reader mode uri, the base domain returned is that of the original uri.
+ */
+ public String getBaseDomain() {
+ return mBaseDomain;
+ }
+
+ public Bitmap getFavicon() {
+ return mFavicon;
+ }
+
+ protected String getApplicationId() {
+ return mApplicationId;
+ }
+
+ protected void setApplicationId(final String applicationId) {
+ mApplicationId = applicationId;
+ }
+
+ public BitmapDrawable getThumbnail() {
+ return mThumbnail;
+ }
+
+ public String getMostRecentHomePanel() {
+ return mMostRecentHomePanel;
+ }
+
+ public Bundle getMostRecentHomePanelData() {
+ return mMostRecentHomePanelData;
+ }
+
+ public void setMostRecentHomePanel(String panelId) {
+ mMostRecentHomePanel = panelId;
+ mMostRecentHomePanelData = null;
+ }
+
+ public void setMostRecentHomePanelData(Bundle data) {
+ mMostRecentHomePanelData = data;
+ }
+
+ public Bitmap getThumbnailBitmap(int width, int height) {
+ if (mThumbnailBitmap != null) {
+ // Bug 787318 - Honeycomb has a bug with bitmap caching, we can't
+ // reuse the bitmap there.
+ boolean honeycomb = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB
+ && Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB_MR2);
+ boolean sizeChange = mThumbnailBitmap.getWidth() != width
+ || mThumbnailBitmap.getHeight() != height;
+ if (honeycomb || sizeChange) {
+ mThumbnailBitmap = null;
+ }
+ }
+
+ if (mThumbnailBitmap == null) {
+ Bitmap.Config config = (GeckoAppShell.getScreenDepth() == 24) ?
+ Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
+ mThumbnailBitmap = Bitmap.createBitmap(width, height, config);
+ }
+
+ return mThumbnailBitmap;
+ }
+
+ public void updateThumbnail(final Bitmap b, final ThumbnailHelper.CachePolicy cachePolicy) {
+ ThreadUtils.postToBackgroundThread(new Runnable() {
+ @Override
+ public void run() {
+ if (b != null) {
+ try {
+ mThumbnail = new BitmapDrawable(mAppContext.getResources(), b);
+ if (mState == Tab.STATE_SUCCESS && cachePolicy == ThumbnailHelper.CachePolicy.STORE) {
+ saveThumbnailToDB(mDB);
+ } else {
+ // If the page failed to load, or requested that we not cache info about it, clear any previous
+ // thumbnails we've stored.
+ clearThumbnailFromDB(mDB);
+ }
+ } catch (OutOfMemoryError oom) {
+ Log.w(LOGTAG, "Unable to create/scale bitmap.", oom);
+ mThumbnail = null;
+ }
+ } else {
+ mThumbnail = null;
+ }
+
+ Tabs.getInstance().notifyListeners(Tab.this, Tabs.TabEvents.THUMBNAIL);
+ }
+ });
+ }
+
+ public synchronized String getFaviconURL() {
+ return mFaviconUrl;
+ }
+
+ public boolean hasFeeds() {
+ return mHasFeeds;
+ }
+
+ public boolean hasOpenSearch() {
+ return mHasOpenSearch;
+ }
+
+ public boolean hasLoadedFromCache() {
+ return mLoadedFromCache;
+ }
+
+ public SiteIdentity getSiteIdentity() {
+ return mSiteIdentity;
+ }
+
+ public void resetSiteIdentity() {
+ if (mSiteIdentity != null) {
+ mSiteIdentity.reset();
+ Tabs.getInstance().notifyListeners(this, Tabs.TabEvents.SECURITY_CHANGE);
+ }
+ }
+
+ public SiteLogins getSiteLogins() {
+ return mSiteLogins;
+ }
+
+ public boolean isBookmark() {
+ return mBookmark;
+ }
+
+ public boolean isExternal() {
+ return mExternal;
+ }
+
+ public synchronized void updateURL(String url) {
+ if (url != null && url.length() > 0) {
+ mUrl = url;
+ }
+ }
+
+ public synchronized void updateUserRequested(String userRequested) {
+ mUserRequested = userRequested;
+ }
+
+ public void setErrorType(String type) {
+ if ("blocked".equals(type))
+ setErrorType(ErrorType.BLOCKED);
+ else if ("certerror".equals(type))
+ setErrorType(ErrorType.CERT_ERROR);
+ else if ("neterror".equals(type))
+ setErrorType(ErrorType.NET_ERROR);
+ else
+ setErrorType(ErrorType.NONE);
+ }
+
+ public void setErrorType(ErrorType type) {
+ mErrorType = type;
+ }
+
+ public void setMetadata(JSONObject metadata) {
+ if (metadata == null) {
+ return;
+ }
+
+ final ContentResolver cr = mAppContext.getContentResolver();
+ final URLMetadata urlMetadata = mDB.getURLMetadata();
+
+ final Map<String, Object> data = urlMetadata.fromJSON(metadata);
+ ThreadUtils.postToBackgroundThread(new Runnable() {
+ @Override
+ public void run() {
+ urlMetadata.save(cr, data);
+ }
+ });
+ }
+
+ public ErrorType getErrorType() {
+ return mErrorType;
+ }
+
+ public void setContentType(String contentType) {
+ mContentType = (contentType == null) ? "" : contentType;
+ }
+
+ public String getContentType() {
+ return mContentType;
+ }
+
+ public int getHistoryIndex() {
+ return mHistoryIndex;
+ }
+
+ public int getHistorySize() {
+ return mHistorySize;
+ }
+
+ public synchronized void updateTitle(String title) {
+ // Keep the title unchanged while entering reader mode.
+ if (mEnteringReaderMode) {
+ return;
+ }
+
+ // If there was a title, but it hasn't changed, do nothing.
+ if (mTitle != null &&
+ TextUtils.equals(mTitle, title)) {
+ return;
+ }
+
+ mTitle = (title == null ? "" : title);
+ Tabs.getInstance().notifyListeners(this, Tabs.TabEvents.TITLE);
+ }
+
+ public void setState(int state) {
+ mState = state;
+
+ if (mState != Tab.STATE_LOADING)
+ mEnteringReaderMode = false;
+ }
+
+ public int getState() {
+ return mState;
+ }
+
+ public void setHasTouchListeners(boolean aValue) {
+ mHasTouchListeners = aValue;
+ }
+
+ public boolean getHasTouchListeners() {
+ return mHasTouchListeners;
+ }
+
+ public synchronized void addFavicon(String faviconURL, int faviconSize, String mimeType) {
+ mIconRequestBuilder
+ .icon(IconDescriptor.createFavicon(faviconURL, faviconSize, mimeType))
+ .deferBuild();
+ }
+
+ public synchronized void addTouchicon(String iconUrl, int faviconSize, String mimeType) {
+ mIconRequestBuilder
+ .icon(IconDescriptor.createTouchicon(iconUrl, faviconSize, mimeType))
+ .deferBuild();
+ }
+
+ public void loadFavicon() {
+ // Static Favicons never change
+ if (AboutPages.isBuiltinIconPage(mUrl) && mFavicon != null) {
+ return;
+ }
+
+ mRunningIconRequest = mIconRequestBuilder
+ .build()
+ .execute(new IconCallback() {
+ @Override
+ public void onIconResponse(IconResponse response) {
+ mFavicon = response.getBitmap();
+
+ Tabs.getInstance().notifyListeners(Tab.this, Tabs.TabEvents.FAVICON);
+ }
+ });
+ }
+
+ public synchronized void clearFavicon() {
+ // Cancel any ongoing favicon load (if we never finished downloading the old favicon before
+ // we changed page).
+ if (mRunningIconRequest != null) {
+ mRunningIconRequest.cancel(true);
+ }
+
+ // Keep the favicon unchanged while entering reader mode
+ if (mEnteringReaderMode)
+ return;
+
+ mFavicon = null;
+ mFaviconUrl = null;
+ }
+
+ public void setHasFeeds(boolean hasFeeds) {
+ mHasFeeds = hasFeeds;
+ }
+
+ public void setHasOpenSearch(boolean hasOpenSearch) {
+ mHasOpenSearch = hasOpenSearch;
+ }
+
+ public void setLoadedFromCache(boolean loadedFromCache) {
+ mLoadedFromCache = loadedFromCache;
+ }
+
+ public void updateIdentityData(JSONObject identityData) {
+ mSiteIdentity.update(identityData);
+ }
+
+ public void setSiteLogins(SiteLogins siteLogins) {
+ mSiteLogins = siteLogins;
+ }
+
+ void updateBookmark() {
+ if (getURL() == null) {
+ return;
+ }
+
+ ThreadUtils.postToBackgroundThread(new Runnable() {
+ @Override
+ public void run() {
+ final String url = getURL();
+ if (url == null) {
+ return;
+ }
+ final String pageUrl = ReaderModeUtils.stripAboutReaderUrl(url);
+
+ mBookmark = mDB.isBookmark(getContentResolver(), pageUrl);
+ Tabs.getInstance().notifyListeners(Tab.this, Tabs.TabEvents.MENU_UPDATED);
+ }
+ });
+ }
+
+ public void addBookmark() {
+ final String url = getURL();
+ if (url == null) {
+ return;
+ }
+
+ final String pageUrl = ReaderModeUtils.stripAboutReaderUrl(getURL());
+
+ ThreadUtils.postToBackgroundThread(new Runnable() {
+ @Override
+ public void run() {
+ mDB.addBookmark(getContentResolver(), mTitle, pageUrl);
+ Tabs.getInstance().notifyListeners(Tab.this, Tabs.TabEvents.BOOKMARK_ADDED);
+ }
+ });
+
+ if (AboutPages.isAboutReader(url)) {
+ ReadingListHelper.cacheReaderItem(pageUrl, mId, mAppContext);
+ }
+ }
+
+ public void removeBookmark() {
+ final String url = getURL();
+ if (url == null) {
+ return;
+ }
+
+ final String pageUrl = ReaderModeUtils.stripAboutReaderUrl(getURL());
+
+ ThreadUtils.postToBackgroundThread(new Runnable() {
+ @Override
+ public void run() {
+ mDB.removeBookmarksWithURL(getContentResolver(), pageUrl);
+ Tabs.getInstance().notifyListeners(Tab.this, Tabs.TabEvents.BOOKMARK_REMOVED);
+ }
+ });
+
+ // We need to ensure we remove readercached items here - we could have switched out of readermode
+ // before unbookmarking, so we don't necessarily have an about:reader URL here.
+ ReadingListHelper.removeCachedReaderItem(pageUrl, mAppContext);
+ }
+
+ public boolean isEnteringReaderMode() {
+ return mEnteringReaderMode;
+ }
+
+ public void doReload(boolean bypassCache) {
+ GeckoAppShell.notifyObservers("Session:Reload", "{\"bypassCache\":" + String.valueOf(bypassCache) + "}");
+ }
+
+ // Our version of nsSHistory::GetCanGoBack
+ public boolean canDoBack() {
+ return mCanDoBack;
+ }
+
+ public boolean doBack() {
+ if (!canDoBack())
+ return false;
+
+ GeckoAppShell.notifyObservers("Session:Back", "");
+ return true;
+ }
+
+ public void doStop() {
+ GeckoAppShell.notifyObservers("Session:Stop", "");
+ }
+
+ // Our version of nsSHistory::GetCanGoForward
+ public boolean canDoForward() {
+ return mCanDoForward;
+ }
+
+ public boolean doForward() {
+ if (!canDoForward())
+ return false;
+
+ GeckoAppShell.notifyObservers("Session:Forward", "");
+ return true;
+ }
+
+ void handleLocationChange(JSONObject message) throws JSONException {
+ final String uri = message.getString("uri");
+ final String oldUrl = getURL();
+ final boolean sameDocument = message.getBoolean("sameDocument");
+ mEnteringReaderMode = ReaderModeUtils.isEnteringReaderMode(oldUrl, uri);
+ mHistoryIndex = message.getInt("historyIndex");
+ mHistorySize = message.getInt("historySize");
+ mCanDoBack = message.getBoolean("canGoBack");
+ mCanDoForward = message.getBoolean("canGoForward");
+
+ if (!TextUtils.equals(oldUrl, uri)) {
+ updateURL(uri);
+ updateBookmark();
+ if (!sameDocument) {
+ // We can unconditionally clear the favicon and title here: we
+ // already filtered both cases in which this was a (pseudo-)
+ // spurious location change, so we're definitely loading a new
+ // page.
+ clearFavicon();
+
+ // Start to build a new request to load a favicon.
+ mIconRequestBuilder = Icons.with(mAppContext)
+ .pageUrl(uri);
+
+ // Load local static Favicons immediately
+ if (AboutPages.isBuiltinIconPage(uri)) {
+ loadFavicon();
+ }
+
+ updateTitle(null);
+ }
+ }
+
+ if (sameDocument) {
+ // We can get a location change event for the same document with an anchor tag
+ // Notify listeners so that buttons like back or forward will update themselves
+ Tabs.getInstance().notifyListeners(this, Tabs.TabEvents.LOCATION_CHANGE, oldUrl);
+ return;
+ }
+
+ setContentType(message.getString("contentType"));
+ updateUserRequested(message.getString("userRequested"));
+ mBaseDomain = message.optString("baseDomain");
+
+ setHasFeeds(false);
+ setHasOpenSearch(false);
+ mSiteIdentity.reset();
+ setSiteLogins(null);
+ setHasTouchListeners(false);
+ setErrorType(ErrorType.NONE);
+ setLoadProgressIfLoading(LOAD_PROGRESS_LOCATION_CHANGE);
+
+ Tabs.getInstance().notifyListeners(this, Tabs.TabEvents.LOCATION_CHANGE, oldUrl);
+ }
+
+ private static boolean shouldShowProgress(final String url) {
+ return !AboutPages.isAboutPage(url);
+ }
+
+ void handleDocumentStart(boolean restoring, String url) {
+ setLoadProgress(LOAD_PROGRESS_START);
+ setState((!restoring && shouldShowProgress(url)) ? STATE_LOADING : STATE_SUCCESS);
+ mSiteIdentity.reset();
+ }
+
+ void handleDocumentStop(boolean success) {
+ setState(success ? STATE_SUCCESS : STATE_ERROR);
+
+ final String oldURL = getURL();
+ final Tab tab = this;
+ tab.setLoadProgress(LOAD_PROGRESS_STOP);
+
+ ThreadUtils.getBackgroundHandler().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ // tab.getURL() may return null
+ if (!TextUtils.equals(oldURL, getURL()))
+ return;
+
+ ThumbnailHelper.getInstance().getAndProcessThumbnailFor(tab);
+ }
+ }, 500);
+ }
+
+ void handleContentLoaded() {
+ setLoadProgressIfLoading(LOAD_PROGRESS_LOADED);
+ }
+
+ protected void saveThumbnailToDB(final BrowserDB db) {
+ final BitmapDrawable thumbnail = mThumbnail;
+ if (thumbnail == null) {
+ return;
+ }
+
+ try {
+ final String url = getURL();
+ if (url == null) {
+ return;
+ }
+
+ db.updateThumbnailForUrl(getContentResolver(), url, thumbnail);
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+
+ public void loadThumbnailFromDB(final BrowserDB db) {
+ try {
+ final String url = getURL();
+ if (url == null) {
+ return;
+ }
+
+ byte[] thumbnail = db.getThumbnailForUrl(getContentResolver(), url);
+ if (thumbnail == null) {
+ return;
+ }
+
+ Bitmap bitmap = BitmapUtils.decodeByteArray(thumbnail);
+ mThumbnail = new BitmapDrawable(mAppContext.getResources(), bitmap);
+
+ Tabs.getInstance().notifyListeners(Tab.this, Tabs.TabEvents.THUMBNAIL);
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+
+ private void clearThumbnailFromDB(final BrowserDB db) {
+ try {
+ final String url = getURL();
+ if (url == null) {
+ return;
+ }
+
+ // Passing in a null thumbnail will delete the stored thumbnail for this url
+ db.updateThumbnailForUrl(getContentResolver(), url, null);
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+
+ public void addPluginView(View view) {
+ mPluginViews.add(view);
+ }
+
+ public void removePluginView(View view) {
+ mPluginViews.remove(view);
+ }
+
+ public View[] getPluginViews() {
+ return mPluginViews.toArray(new View[mPluginViews.size()]);
+ }
+
+ public void setDesktopMode(boolean enabled) {
+ mDesktopMode = enabled;
+ }
+
+ public boolean getDesktopMode() {
+ return mDesktopMode;
+ }
+
+ public boolean isPrivate() {
+ return false;
+ }
+
+ /**
+ * Sets the tab load progress to the given percentage.
+ *
+ * @param progressPercentage Percentage to set progress to (0-100)
+ */
+ void setLoadProgress(int progressPercentage) {
+ mLoadProgress = progressPercentage;
+ }
+
+ /**
+ * Sets the tab load progress to the given percentage only if the tab is
+ * currently loading.
+ *
+ * about:neterror can trigger a STOP before other page load events (bug
+ * 976426), so any post-START events should make sure the page is loading
+ * before updating progress.
+ *
+ * @param progressPercentage Percentage to set progress to (0-100)
+ */
+ void setLoadProgressIfLoading(int progressPercentage) {
+ if (getState() == STATE_LOADING) {
+ setLoadProgress(progressPercentage);
+ }
+ }
+
+ /**
+ * Gets the tab load progress percentage.
+ *
+ * @return Current progress percentage
+ */
+ public int getLoadProgress() {
+ return mLoadProgress;
+ }
+
+ public void setRecording(boolean isRecording) {
+ if (isRecording) {
+ mRecordingCount++;
+ } else {
+ mRecordingCount--;
+ }
+ }
+
+ public boolean isRecording() {
+ return mRecordingCount > 0;
+ }
+
+ /**
+ * The "MediaPlaying" is used for controling media control interface and
+ * means the tab has playing media.
+ *
+ * @param isMediaPlaying the tab has any playing media or not
+ */
+ public void setIsMediaPlaying(boolean isMediaPlaying) {
+ mIsMediaPlaying = isMediaPlaying;
+ }
+
+ public boolean isMediaPlaying() {
+ return mIsMediaPlaying;
+ }
+
+ /**
+ * The "AudioPlaying" is used for showing the tab sound indicator and means
+ * the tab has playing media and the media is audible.
+ *
+ * @param isAudioPlaying the tab has any audible playing media or not
+ */
+ public void setIsAudioPlaying(boolean isAudioPlaying) {
+ mIsAudioPlaying = isAudioPlaying;
+ }
+
+ public boolean isAudioPlaying() {
+ return mIsAudioPlaying;
+ }
+
+ public boolean isEditing() {
+ return mIsEditing;
+ }
+
+ public void setIsEditing(final boolean isEditing) {
+ this.mIsEditing = isEditing;
+ }
+
+ public TabEditingState getEditingState() {
+ return mEditingState;
+ }
+
+ public void setShouldShowToolbarWithoutAnimationOnFirstSelection(final boolean shouldShowWithoutAnimation) {
+ mShouldShowToolbarWithoutAnimationOnFirstSelection = shouldShowWithoutAnimation;
+ }
+
+ public boolean getShouldShowToolbarWithoutAnimationOnFirstSelection() {
+ return mShouldShowToolbarWithoutAnimationOnFirstSelection;
+ }
+}