Index: chrome/android/java_staging/src/org/chromium/chrome/browser/webapps/FullScreenActivityTab.java |
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/webapps/FullScreenActivityTab.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/webapps/FullScreenActivityTab.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b9068a97c49cdadd5c8d7e15707a0414c2172cee |
--- /dev/null |
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/webapps/FullScreenActivityTab.java |
@@ -0,0 +1,341 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+package org.chromium.chrome.browser.webapps; |
+ |
+import android.content.Context; |
+import android.content.Intent; |
+import android.net.Uri; |
+import android.os.Bundle; |
+import android.text.TextUtils; |
+import android.util.Log; |
+import android.view.ContextMenu; |
+import android.view.Menu; |
+ |
+import com.google.android.apps.chrome.R; |
+ |
+import org.chromium.base.annotations.SuppressFBWarnings; |
+import org.chromium.chrome.browser.ChromeActivity; |
+import org.chromium.chrome.browser.IntentHandler; |
+import org.chromium.chrome.browser.ShortcutHelper; |
+import org.chromium.chrome.browser.Tab; |
+import org.chromium.chrome.browser.TabState; |
+import org.chromium.chrome.browser.TabUma.TabCreationState; |
+import org.chromium.chrome.browser.UrlUtilities; |
+import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; |
+import org.chromium.chrome.browser.contextmenu.ContextMenuHelper; |
+import org.chromium.chrome.browser.contextmenu.ContextMenuParams; |
+import org.chromium.chrome.browser.contextmenu.ContextMenuPopulator; |
+import org.chromium.chrome.browser.document.ChromeLauncherActivity; |
+import org.chromium.chrome.browser.tab.ChromeTab; |
+import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType; |
+import org.chromium.chrome.browser.util.StreamUtil; |
+import org.chromium.content_public.browser.LoadUrlParams; |
+import org.chromium.content_public.browser.WebContents; |
+import org.chromium.content_public.browser.WebContentsObserver; |
+import org.chromium.ui.base.Clipboard; |
+import org.chromium.ui.base.PageTransition; |
+import org.chromium.ui.base.WindowAndroid; |
+ |
+import java.io.File; |
+import java.io.FileInputStream; |
+import java.io.FileNotFoundException; |
+import java.io.FileOutputStream; |
+import java.io.IOException; |
+import java.net.URI; |
+ |
+/** |
+ * A tab that will be used for FullScreenActivity. See {@link FullScreenActivity} for more. |
+ */ |
+@SuppressFBWarnings("URF_UNREAD_FIELD") |
+public class FullScreenActivityTab extends ChromeTab { |
+ private static final String TAG = "FullScreenActivityTab"; |
+ |
+ /** |
+ * A delegate to determine top controls visibility. |
+ */ |
+ public interface TopControlsVisibilityDelegate { |
+ /** |
+ * Determines whether top controls should be shown. |
+ * |
+ * @param uri The URI to display. |
+ * @param securityLevel Security level of the Tab. |
+ * @return Whether the URL bar should be visible or not. |
+ */ |
+ boolean shouldShowTopControls(String uri, int securityLevel); |
+ } |
+ |
+ static final String BUNDLE_TAB_ID = "tabId"; |
+ static final String BUNDLE_TAB_URL = "tabUrl"; |
+ |
+ private WebContentsObserver mObserver; |
+ private TopControlsVisibilityDelegate mTopControlsVisibilityDelegate; |
+ |
+ private FullScreenActivityTab(ChromeActivity activity, WindowAndroid window, |
+ TopControlsVisibilityDelegate topControlsVisibilityDelegate) { |
+ super(INVALID_TAB_ID, activity, false, window, TabLaunchType.FROM_MENU_OR_OVERVIEW, |
+ INVALID_TAB_ID, null, null); |
+ initializeFullScreenActivityTab( |
+ activity.getTabContentManager(), false, topControlsVisibilityDelegate); |
+ } |
+ |
+ private FullScreenActivityTab(int id, ChromeActivity activity, WindowAndroid window, |
+ TabState state, TopControlsVisibilityDelegate topControlsVisibilityDelegate) { |
+ super(id, activity, false, window, TabLaunchType.FROM_RESTORE, Tab.INVALID_TAB_ID, |
+ TabCreationState.FROZEN_ON_RESTORE, state); |
+ initializeFullScreenActivityTab( |
+ activity.getTabContentManager(), true, topControlsVisibilityDelegate); |
+ } |
+ |
+ private void initializeFullScreenActivityTab(TabContentManager tabContentManager, |
+ boolean unfreeze, TopControlsVisibilityDelegate topControlsVisibilityDelegate) { |
+ initialize(null, tabContentManager, false); |
+ if (unfreeze) unfreezeContents(); |
+ mObserver = createWebContentsObserver(); |
+ mTopControlsVisibilityDelegate = topControlsVisibilityDelegate; |
+ } |
+ |
+ /** |
+ * Saves the state of the tab out to the {@link Bundle}. |
+ */ |
+ void saveInstanceState(Bundle outState) { |
+ outState.putInt(BUNDLE_TAB_ID, getId()); |
+ outState.putString(BUNDLE_TAB_URL, getUrl()); |
+ } |
+ |
+ /** |
+ * @return WebContentsObserver that watches for changes. |
+ */ |
+ private WebContentsObserver createWebContentsObserver() { |
+ return new WebContentsObserver(getWebContents()) { |
+ @Override |
+ public void didCommitProvisionalLoadForFrame( |
+ long frameId, boolean isMainFrame, String url, int transitionType) { |
+ if (isMainFrame) { |
+ // Notify the renderer to permanently hide the top controls since they do |
+ // not apply to fullscreen content views. |
+ updateTopControlsState(getTopControlsStateConstraints(), |
+ getTopControlsStateConstraints(), true); |
+ } |
+ } |
+ }; |
+ } |
+ |
+ @Override |
+ protected void initContentViewCore(WebContents webContents) { |
+ super.initContentViewCore(webContents); |
+ getContentViewCore().setFullscreenRequiredForOrientationLock(false); |
+ } |
+ |
+ /** |
+ * Loads the given {@code url}. |
+ * @param url URL to load. |
+ */ |
+ public void loadUrl(String url) { |
+ loadUrl(new LoadUrlParams(url, PageTransition.AUTO_TOPLEVEL)); |
+ } |
+ |
+ /** |
+ * Saves the tab data out to a file. |
+ */ |
+ void saveState(File activityDirectory) { |
+ File tabFile = getTabFile(activityDirectory, getId()); |
+ |
+ FileOutputStream foutput = null; |
+ try { |
+ foutput = new FileOutputStream(tabFile); |
+ TabState.saveState(foutput, getState(), false); |
+ } catch (FileNotFoundException exception) { |
+ Log.e(TAG, "Failed to save out tab state.", exception); |
+ } catch (IOException exception) { |
+ Log.e(TAG, "Failed to save out tab state.", exception); |
+ } finally { |
+ StreamUtil.closeQuietly(foutput); |
+ } |
+ } |
+ |
+ /** |
+ * @return {@link File} pointing at the tab state for this Activity. |
+ */ |
+ private static File getTabFile(File activityDirectory, int tabId) { |
+ return new File(activityDirectory, TabState.getTabStateFilename(tabId, false)); |
+ } |
+ |
+ /** |
+ * Creates the {@link FullScreenActivityTab} used by the FullScreenActivity. |
+ * If the {@code savedInstanceState} exists, then the user did not intentionally close the app |
+ * by swiping it away in the recent tasks list. In that case, we try to restore the tab from |
+ * disk. |
+ * @param activity Activity that will own the Tab. |
+ * @param directory Directory associated with the Activity. Null implies tab state isn't saved. |
+ * @param savedInstanceState Bundle saved out when the app was killed by Android. May be null. |
+ * @param topControlsVisibilityDelegate Delegate to determine top controls visibility. |
+ * @return {@link FullScreenActivityTab} for the Activity. |
+ */ |
+ public static FullScreenActivityTab create(ChromeActivity activity, WindowAndroid window, |
+ File directory, Bundle savedInstanceState, |
+ TopControlsVisibilityDelegate topControlsVisibilityDelegate) { |
+ FullScreenActivityTab tab = null; |
+ |
+ int tabId = Tab.INVALID_TAB_ID; |
+ String tabUrl = null; |
+ if (savedInstanceState != null) { |
+ tabId = savedInstanceState.getInt(BUNDLE_TAB_ID, INVALID_TAB_ID); |
+ tabUrl = savedInstanceState.getString(BUNDLE_TAB_URL); |
+ } |
+ |
+ if (tabId != Tab.INVALID_TAB_ID && tabUrl != null && directory != null) { |
+ FileInputStream stream = null; |
+ try { |
+ // Restore the tab. |
+ stream = new FileInputStream(getTabFile(directory, tabId)); |
+ TabState tabState = TabState.readState(stream, false); |
+ tab = new FullScreenActivityTab( |
+ tabId, activity, window, tabState, topControlsVisibilityDelegate); |
+ } catch (FileNotFoundException exception) { |
+ Log.e(TAG, "Failed to restore tab state.", exception); |
+ } catch (IOException exception) { |
+ Log.e(TAG, "Failed to restore tab state.", exception); |
+ } finally { |
+ StreamUtil.closeQuietly(stream); |
+ } |
+ } |
+ |
+ if (tab == null) { |
+ // Create a new tab. |
+ tab = new FullScreenActivityTab(activity, window, topControlsVisibilityDelegate); |
+ } |
+ |
+ return tab; |
+ } |
+ |
+ @Override |
+ protected ContextMenuPopulator createContextMenuPopulator() { |
+ return new ContextMenuPopulator() { |
+ private final Clipboard mClipboard; |
+ |
+ // public ContextMenuPopulator() |
+ { |
+ mClipboard = new Clipboard(getApplicationContext()); |
+ } |
+ |
+ @Override |
+ public boolean shouldShowContextMenu(ContextMenuParams params) { |
+ return params != null && params.isAnchor(); |
+ } |
+ |
+ @Override |
+ public boolean onItemSelected(ContextMenuHelper helper, ContextMenuParams params, |
+ int itemId) { |
+ if (itemId == org.chromium.chrome.R.id.contextmenu_copy_link_address_text) { |
+ String url = params.getUnfilteredLinkUrl(); |
+ mClipboard.setText(url, url); |
+ return true; |
+ } else if (itemId == org.chromium.chrome.R.id.contextmenu_copy_link_text) { |
+ String text = params.getLinkText(); |
+ mClipboard.setText(text, text); |
+ return true; |
+ } else if (itemId == R.id.menu_id_open_in_chrome) { |
+ Intent chromeIntent = |
+ new Intent(Intent.ACTION_VIEW, Uri.parse(params.getLinkUrl())); |
+ chromeIntent.setPackage(getApplicationContext().getPackageName()); |
+ chromeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
+ |
+ boolean activityStarted = false; |
+ if (params.getPageUrl() != null) { |
+ try { |
+ URI pageUri = URI.create(params.getPageUrl()); |
+ if (UrlUtilities.isInternalScheme(pageUri)) { |
+ IntentHandler.startChromeLauncherActivityForTrustedIntent( |
+ chromeIntent, getApplicationContext()); |
+ activityStarted = true; |
+ } |
+ } catch (IllegalArgumentException ex) { |
+ // Ignore the exception for creating the URI and launch the intent |
+ // without the trusted intent extras. |
+ } |
+ } |
+ |
+ if (!activityStarted) { |
+ getApplicationContext().startActivity(chromeIntent); |
+ activityStarted = true; |
+ } |
+ return true; |
+ } |
+ |
+ return false; |
+ } |
+ |
+ @Override |
+ public void buildContextMenu(ContextMenu menu, Context context, |
+ ContextMenuParams params) { |
+ menu.add(Menu.NONE, org.chromium.chrome.R.id.contextmenu_copy_link_address_text, |
+ Menu.NONE, org.chromium.chrome.R.string.contextmenu_copy_link_address); |
+ |
+ String linkText = params.getLinkText(); |
+ if (linkText != null) linkText = linkText.trim(); |
+ |
+ if (!TextUtils.isEmpty(linkText)) { |
+ menu.add(Menu.NONE, org.chromium.chrome.R.id.contextmenu_copy_link_text, |
+ Menu.NONE, org.chromium.chrome.R.string.contextmenu_copy_link_text); |
+ } |
+ |
+ menu.add(Menu.NONE, R.id.menu_id_open_in_chrome, Menu.NONE, |
+ R.string.menu_open_in_chrome); |
+ } |
+ }; |
+ } |
+ |
+ @Override |
+ protected boolean isHidingTopControlsEnabled() { |
+ if (getFullscreenManager() == null) return true; |
+ if (getFullscreenManager().getPersistentFullscreenMode()) return true; |
+ if (mTopControlsVisibilityDelegate == null) return false; |
+ return !mTopControlsVisibilityDelegate.shouldShowTopControls(getUrl(), getSecurityLevel()); |
+ } |
+ |
+ @Override |
+ public boolean isShowingTopControlsEnabled() { |
+ // On webapp activity and embedd content view activity, it's either hiding or showing. |
+ // Users cannot change the visibility state by sliding it in or out. |
+ return !isHidingTopControlsEnabled(); |
+ } |
+ |
+ @Override |
+ protected FullScreenTabWebContentsDelegateAndroid createWebContentsDelegate() { |
+ return new FullScreenTabWebContentsDelegateAndroid(); |
+ } |
+ |
+ /** |
+ * A FullScreenActivityTab is meant to be used for WebappActivities which |
+ * behave slightly differently from tabs. The main difference being that |
+ * it doesn't have a notion of active tab. Thus, some WebContentsDelegate |
+ * method have to be redefined. |
+ */ |
+ public class FullScreenTabWebContentsDelegateAndroid |
+ extends TabChromeWebContentsDelegateAndroidImpl { |
+ @Override |
+ public void activateContents() { |
+ if (!(mActivity instanceof WebappActivity)) return; |
+ |
+ WebappInfo webAppInfo = ((WebappActivity) mActivity).getWebappInfo(); |
+ String url = webAppInfo.uri().toString(); |
+ |
+ Intent intent = new Intent(); |
+ intent.setAction(Intent.ACTION_MAIN); |
+ intent.setPackage(mActivity.getPackageName()); |
+ intent.putExtra(ChromeLauncherActivity.EXTRA_BRING_WEBAPP_TO_FRONT, true); |
+ |
+ intent.putExtra(ShortcutHelper.EXTRA_ICON, webAppInfo.getEncodedIcon()); |
+ intent.putExtra(ShortcutHelper.EXTRA_ID, webAppInfo.id()); |
+ intent.putExtra(ShortcutHelper.EXTRA_URL, url); |
+ intent.putExtra(ShortcutHelper.EXTRA_TITLE, webAppInfo.title()); |
+ intent.putExtra(ShortcutHelper.EXTRA_ORIENTATION, webAppInfo.orientation()); |
+ intent.putExtra(ShortcutHelper.EXTRA_MAC, ShortcutHelper.getEncodedMac(mActivity, url)); |
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
+ |
+ getApplicationContext().startActivity(intent); |
+ } |
+ } |
+} |