Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Unified Diff: chrome/android/java_staging/src/org/chromium/chrome/browser/webapps/WebappActivity.java

Issue 1141283003: Upstream oodles of Chrome for Android code into Chromium. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: final patch? Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/android/java_staging/src/org/chromium/chrome/browser/webapps/WebappActivity.java
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/webapps/WebappActivity.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/webapps/WebappActivity.java
new file mode 100644
index 0000000000000000000000000000000000000000..a953abf769507c0a57728262e48e8d8b2f2d43b3
--- /dev/null
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/webapps/WebappActivity.java
@@ -0,0 +1,359 @@
+// 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.graphics.Bitmap;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+
+import com.google.android.apps.chrome.R;
+
+import org.chromium.base.ActivityState;
+import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.base.ApplicationStatus;
+import org.chromium.base.VisibleForTesting;
+import org.chromium.chrome.browser.EmptyTabObserver;
+import org.chromium.chrome.browser.ShortcutHelper;
+import org.chromium.chrome.browser.Tab;
+import org.chromium.chrome.browser.TabObserver;
+import org.chromium.chrome.browser.UrlUtilities;
+import org.chromium.chrome.browser.document.DocumentUtils;
+import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
+import org.chromium.chrome.browser.ssl.ConnectionSecurityHelperSecurityLevel;
+import org.chromium.chrome.browser.util.FeatureUtilities;
+import org.chromium.content.browser.ScreenOrientationProvider;
+import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.content_public.browser.WebContentsObserver;
+import org.chromium.net.NetworkChangeNotifier;
+import org.chromium.ui.base.PageTransition;
+
+import java.io.File;
+
+/**
+ * Displays a webapp in a nearly UI-less Chrome (InfoBars still appear).
+ */
+public class WebappActivity extends FullScreenActivity {
+ public static final String WEBAPP_SCHEME = "webapp";
+
+ private static final String TAG = "WebappActivity";
+ private static final long MS_BEFORE_NAVIGATING_BACK_FROM_INTERSTITIAL = 1000;
+
+ private final WebappInfo mWebappInfo;
+ private AsyncTask<Void, Void, Void> mCleanupTask;
+
+ private WebContentsObserver mWebContentsObserver;
+
+ private WebappUrlBar mUrlBar;
+
+ private boolean mIsInitialized;
+ private Integer mBrandColor;
+
+ /**
+ * Construct all the variables that shouldn't change. We do it here both to clarify when the
+ * objects are created and to ensure that they exist throughout the parallelized initialization
+ * of the WebappActivity.
+ */
+ public WebappActivity() {
+ mWebappInfo = WebappInfo.createEmpty();
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ if (intent == null) return;
+ super.onNewIntent(intent);
+
+ WebappInfo newWebappInfo = WebappInfo.create(intent);
+ if (newWebappInfo == null) {
+ Log.e(TAG, "Failed to parse new Intent: " + intent);
+ finish();
+ } else if (!TextUtils.equals(mWebappInfo.id(), newWebappInfo.id())) {
+ mWebappInfo.copy(newWebappInfo);
+ resetSavedInstanceState();
+ if (mIsInitialized) initializeUI(null);
+ }
+ }
+
+ private void initializeUI(Bundle savedInstanceState) {
+ // We do not load URL when restoring from saved instance states.
+ if (savedInstanceState == null && mWebappInfo.isInitialized()) {
+ if (TextUtils.isEmpty(getActivityTab().getUrl())) {
+ getActivityTab().loadUrl(new LoadUrlParams(
+ mWebappInfo.uri().toString(), PageTransition.AUTO_TOPLEVEL));
+ }
+ } else {
+ if (NetworkChangeNotifier.isOnline()) getActivityTab().reloadIgnoringCache();
+ }
+
+ mWebContentsObserver = createWebContentsObserver();
+ getActivityTab().addObserver(createTabObserver());
+ updateTaskDescription();
+ removeWindowBackground();
+ }
+
+ @Override
+ public void preInflationStartup() {
+ WebappInfo info = WebappInfo.create(getIntent());
+ if (info != null) mWebappInfo.copy(info);
+ mCleanupTask = new WebappDirectoryManager(getActivityDirectory(),
+ WEBAPP_SCHEME, FeatureUtilities.isDocumentModeEligible(this));
+
+ ScreenOrientationProvider.lockOrientation((byte) mWebappInfo.orientation(), this);
+ super.preInflationStartup();
+ }
+
+ @Override
+ public void finishNativeInitialization() {
+ if (!mWebappInfo.isInitialized()) finish();
+ super.finishNativeInitialization();
+ initializeUI(getSavedInstanceState());
+ mIsInitialized = true;
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ mWebappInfo.writeToBundle(outState);
+ if (getActivityTab() != null) getActivityTab().saveInstanceState(outState);
+ }
+
+ @Override
+ public void onStartWithNative() {
+ super.onStartWithNative();
+ if (mCleanupTask.getStatus() == AsyncTask.Status.PENDING) mCleanupTask.execute();
+ }
+
+ @Override
+ public void onStopWithNative() {
+ super.onStopWithNative();
+ mCleanupTask.cancel(true);
+ if (getActivityTab() != null) getActivityTab().saveState(getActivityDirectory());
+ if (getFullscreenManager() != null) {
+ getFullscreenManager().setPersistentFullscreenMode(false);
+ }
+ }
+
+ @Override
+ public void onResume() {
+ if (!isFinishing() && getIntent() != null) {
+ // Avoid situations where Android starts two Activities with the same data.
+ DocumentUtils.finishOtherTasksWithData(getIntent().getData(), getTaskId());
+ }
+ super.onResume();
+ }
+ @Override
+ protected int getControlContainerLayoutId() {
+ return R.layout.webapp_control_container;
+ }
+
+ @Override
+ public void postInflationStartup() {
+ super.postInflationStartup();
+ WebappControlContainer controlContainer =
+ (WebappControlContainer) findViewById(R.id.control_container);
+ mUrlBar = (WebappUrlBar) controlContainer.findViewById(R.id.webapp_url_bar);
+ }
+
+ /**
+ * @return Structure containing data about the webapp currently displayed.
+ */
+ WebappInfo getWebappInfo() {
+ return mWebappInfo;
+ }
+
+ private void updateUrlBar() {
+ Tab tab = getActivityTab();
+ if (tab == null || mUrlBar == null) return;
+ mUrlBar.update(tab.getUrl(), tab.getSecurityLevel());
+ }
+
+ private WebContentsObserver createWebContentsObserver() {
+ // TODO: Move to TabObserver eventually.
+ return new WebContentsObserver(getActivityTab().getWebContents()) {
+ @Override
+ public void didNavigateMainFrame(String url, String baseUrl,
+ boolean isNavigationToDifferentPage, boolean isNavigationInPage,
+ int statusCode) {
+ updateUrlBar();
+ }
+
+ @Override
+ public void didAttachInterstitialPage() {
+ updateUrlBar();
+
+ int state = ApplicationStatus.getStateForActivity(WebappActivity.this);
+ if (state == ActivityState.PAUSED || state == ActivityState.STOPPED
+ || state == ActivityState.DESTROYED) {
+ return;
+ }
+
+ // Kick the interstitial navigation to Chrome.
+ Intent intent = new Intent(
+ Intent.ACTION_VIEW, Uri.parse(getActivityTab().getUrl()));
+ intent.setPackage(getPackageName());
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
+
+ // Pretend like the navigation never happened. We delay so that this happens while
+ // the Activity is in the background.
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ getActivityTab().goBack();
+ }
+ }, MS_BEFORE_NAVIGATING_BACK_FROM_INTERSTITIAL);
+ }
+
+ @Override
+ public void didDetachInterstitialPage() {
+ updateUrlBar();
+ }
+ };
+ }
+
+ private boolean isWebappDomain() {
+ return UrlUtilities.sameDomainOrHost(
+ getActivityTab().getUrl(), getWebappInfo().uri().toString(), true);
+ }
+
+ protected TabObserver createTabObserver() {
+ return new EmptyTabObserver() {
+ @Override
+ public void onSSLStateUpdated(Tab tab) {
+ updateUrlBar();
+ }
+
+ @Override
+ public void onDidStartProvisionalLoadForFrame(
+ Tab tab, long frameId, long parentFrameId, boolean isMainFrame,
+ String validatedUrl, boolean isErrorPage, boolean isIframeSrcdoc) {
+ if (isMainFrame) updateUrlBar();
+ }
+
+ @Override
+ public void onDidChangeThemeColor(int color) {
+ if (!isWebappDomain()) return;
+ mBrandColor = color;
+ updateTaskDescription();
+ }
+
+ @Override
+ public void onTitleUpdated(Tab tab) {
+ if (!isWebappDomain()) return;
+ updateTaskDescription();
+ }
+
+ @Override
+ public void onFaviconUpdated(Tab tab) {
+ if (!isWebappDomain()) return;
+ updateTaskDescription();
+ }
+ };
+ }
+
+ private void updateTaskDescription() {
+ String title = mWebappInfo.title() == null
+ ? getActivityTab().getTitle() : mWebappInfo.title();
+ Bitmap icon = mWebappInfo.icon() == null
+ ? getActivityTab().getFavicon() : mWebappInfo.icon();
+ int color = mBrandColor == null
+ ? getResources().getColor(R.color.default_primary_color) : mBrandColor;
+
+ DocumentUtils.updateTaskDescription(this, title, icon, color, mBrandColor == null);
+ }
+
+ /**
+ * Get the active directory by this web app.
+ *
+ * @return The directory used for the current web app.
+ */
+ @Override
+ protected File getActivityDirectory() {
+ return WebappDirectoryManager.getWebappDirectory(mWebappInfo.id());
+ }
+
+ @VisibleForTesting
+ WebappUrlBar getUrlBarForTests() {
+ return mUrlBar;
+ }
+
+ @VisibleForTesting
+ boolean isUrlBarVisible() {
+ return findViewById(R.id.control_container).getVisibility() == View.VISIBLE;
+ }
+
+ @Override
+ protected final ChromeFullscreenManager createFullscreenManager(View controlContainer) {
+ return new ChromeFullscreenManager(this, controlContainer, getTabModelSelector(),
+ getControlContainerHeightResource(), false /* supportsBrowserOverride */);
+ }
+
+ @Override
+ protected int getControlContainerHeightResource() {
+ return R.dimen.webapp_control_container_height;
+ }
+
+ // Implements {@link FullScreenActivityTab.TopControlsVisibilityDelegate}.
+ @Override
+ public boolean shouldShowTopControls(String url, int securityLevel) {
+ boolean visible = false; // do not show top controls when URL is not ready yet.
+ if (!TextUtils.isEmpty(url)) {
+ boolean isSameWebsite =
+ UrlUtilities.sameDomainOrHost(mWebappInfo.uri().toString(), url, true);
+ visible = !isSameWebsite
+ || securityLevel == ConnectionSecurityHelperSecurityLevel.SECURITY_ERROR
+ || securityLevel == ConnectionSecurityHelperSecurityLevel.SECURITY_WARNING;
+ }
+
+ return visible;
+ }
+
+ // We're temporarily disable CS on webapp since there are some issues. (http://crbug.com/471950)
+ // TODO(changwan): re-enable it once the issues are resolved.
+ @Override
+ protected boolean isContextualSearchAllowed() {
+ return false;
+ }
+
+ /**
+ * Launches the URL in its own WebappActivity.
+ * @param context Context to use for launching the webapp.
+ * @param id ID of the webapp.
+ * @param url URL for the webapp.
+ * @param icon Base64 encoded Bitmap representing the webapp.
+ * @param title String to show in Recents.
+ * @param orientation Default orientation for the activity.
+ */
+ public static void launchInstance(Context context, String id, String url, String icon,
+ String title, int orientation) {
+ String activityName = WebappActivity.class.getName();
+ if (!FeatureUtilities.isDocumentModeEligible(context)) {
+ // Specifically assign the app to a particular WebappActivity instance.
+ int activityIndex = ActivityAssigner.instance(context).assign(id);
+ activityName += String.valueOf(activityIndex);
+ }
+
+ // Fire an intent to launch the Webapp in an unmapped Activity.
+ Intent webappIntent = new Intent();
+ webappIntent.setClassName(context, activityName);
+ webappIntent.putExtra(ShortcutHelper.EXTRA_ICON, icon);
+ webappIntent.putExtra(ShortcutHelper.EXTRA_ID, id);
+ webappIntent.putExtra(ShortcutHelper.EXTRA_URL, url);
+ webappIntent.putExtra(ShortcutHelper.EXTRA_TITLE, title);
+ webappIntent.putExtra(ShortcutHelper.EXTRA_ORIENTATION, orientation);
+
+ // On L, firing intents with the exact same data should relaunch a particular Activity.
+ webappIntent.setAction(Intent.ACTION_VIEW);
+ webappIntent.setData(Uri.parse(WEBAPP_SCHEME + "://" + id));
+ webappIntent.setFlags(ApiCompatibilityUtils.getActivityNewDocumentFlag());
+
+ context.startActivity(webappIntent);
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698