// Copyright 2016 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.infobar;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.StrictMode;
import org.chromium.base.CommandLine;
import org.chromium.base.ThreadUtils;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.UrlConstants;
import org.chromium.chrome.browser.omaha.VersionNumberGetter;
import org.chromium.chrome.browser.preferences.PrefServiceBridge;
import org.chromium.chrome.browser.preferences.datareduction.DataReductionPromoUtils;
import org.chromium.content_public.browser.WebContents;
import org.chromium.net.GURLUtils;
import java.net.HttpURLConnection;
import java.sql.Date;
import java.util.Calendar;
import java.util.TimeZone;
/**
* Generates an infobar to promote the data reduction proxy to non-users of it. The infobar contains
* a message and a button to enable the proxy. The infobar is displayed when it has not been shown
* previously, the page is HTTP pages, and certain milestone restrictions are met. Once the proxy is
* enabled from the infobar a confirmation toast message is shown.
*/
public class DataReductionPromoInfoBar extends ConfirmInfoBar {
private static final String M48_STABLE_RELEASE_DATE = "2016-01-26";
private static final String ENABLE_INFOBAR_SWITCH = "enable-data-reduction-promo-infobar";
private static final int NO_INSTALL_TIME = 0;
private static Bitmap sIcon;
private static String sTitle;
private static String sText;
private static String sPrimaryButtonText;
private static String sSecondaryButtonText;
/**
* Launch the data reduction infobar promo, if it needs to be displayed.
*
* @param context An Android context.
* @param webContents The WebContents of the tab on which the infobar should show.
* @param url The URL of the page on which the infobar should show.
* @param isFragmentNavigation Whether the main frame navigation did not cause changes to the
* document (for example scrolling to a named anchor PopState).
* @param statusCode The HTTP status code of the navigation.
* @return boolean Whether the promo was launched.
*/
public static boolean maybeLaunchPromoInfoBar(Context context,
WebContents webContents, String url, boolean isErrorPage, boolean isFragmentNavigation,
int statusCode) {
ThreadUtils.assertOnUiThread();
if (webContents.isIncognito()) return false;
if (isErrorPage) return false;
if (isFragmentNavigation) return false;
if (statusCode != HttpURLConnection.HTTP_OK) return false;
if (!DataReductionPromoUtils.canShowPromos()) return false;
// Don't show the infobar promo if neither the first run experience or second run promo has
// been shown.
if (!DataReductionPromoUtils.getDisplayedFreOrSecondRunPromo()) return false;
// Don't show the promo if the user opted out on the first run experience promo.
if (DataReductionPromoUtils.getOptedOutOnFrePromo()) return false;
// Don't show the promo if the user has seen this infobar promo before.
if (DataReductionPromoUtils.getDisplayedInfoBarPromo()) return false;
// Only show the promo on HTTP pages.
if (!GURLUtils.getScheme(url).concat("://").equals(UrlConstants.HTTP_SCHEME)) return false;
int currentMilestone = VersionNumberGetter.getMilestoneFromVersionNumber(
PrefServiceBridge.getInstance().getAboutVersionStrings().getApplicationVersion());
String freOrSecondRunVersion =
DataReductionPromoUtils.getDisplayedFreOrSecondRunPromoVersion();
// Temporarily allowing disk access. TODO: Fix. See http://crbug.com/577185
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
try {
Calendar releaseDateOfM48Stable = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
releaseDateOfM48Stable.setTime(Date.valueOf(M48_STABLE_RELEASE_DATE));
long packageInstallTime = getPackageInstallTime(context);
// The boolean pref that stores whether user opted out on the first run experience was
// added in M51. If the last promo was shown before M51, then |freOrSecondRunVersion|
// will be empty. If Chrome was installed after the FRE promo was added in M48 and
// beforeM51,assume the user opted out from the FRE and don't show the infobar.
if (freOrSecondRunVersion.isEmpty()
&& packageInstallTime > releaseDateOfM48Stable.getTimeInMillis()) {
return false;
}
// Only show the promo if the current version is at least two milestones after the last
// promo was displayed or the command line switch is on. If the last promo was shown
// before M51 then |freOrSecondRunVersion| will be empty and it is safe to show the
// infobar promo.
if (!CommandLine.getInstance().hasSwitch(ENABLE_INFOBAR_SWITCH)
&& !freOrSecondRunVersion.isEmpty()
&& currentMilestone < VersionNumberGetter
.getMilestoneFromVersionNumber(freOrSecondRunVersion) + 2) {
return false;
}
DataReductionPromoInfoBar.launch(webContents,
BitmapFactory.decodeResource(context.getResources(), R.mipmap.app_icon),
context.getString(R.string.data_reduction_promo_infobar_title),
context.getString(R.string.data_reduction_promo_infobar_text),
context.getString(R.string.data_reduction_promo_infobar_button),
context.getString(R.string.no_thanks));
return true;
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
}
/**
* Gets the time at which this app was first installed in milliseconds since January 1, 1970
* 00:00:00.0 UTC.
*
* @param context An Android context.
* @return The time at which this app was first installed in milliseconds since the epoch or
* zero if the time cannot be retrieved.
*/
private static long getPackageInstallTime(Context context) {
PackageInfo packageInfo;
try {
packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
} catch (NameNotFoundException e) {
packageInfo = null;
}
return packageInfo == null ? NO_INSTALL_TIME : packageInfo.firstInstallTime;
}
/**
* Launch a data reduction proxy {@link InfoBar} with the specified title and link
* text. Clicking the link will open the specified settings page.
*
* @param webContents The {@link WebContents} in which to open the {@link InfoBar}.
* @param icon Bitmap to use for the {@link InfoBar} icon.
* @param title The title to display in the {@link InfoBar}.
* @param text The text to display in the {@link InfoBar}.
* @param primaryButtonText The text to display on the primary button.
* @param secondaryButtonText The text to display on the secondary button.
*/
private static void launch(WebContents webContents,
Bitmap icon,
String title,
String text,
String primaryButtonText,
String secondaryButtonText) {
sTitle = title;
sText = text;
sPrimaryButtonText = primaryButtonText;
sSecondaryButtonText = secondaryButtonText;
sIcon = icon;
DataReductionPromoInfoBarDelegate.launch(webContents);
DataReductionPromoUtils.saveInfoBarPromoDisplayed();
}
DataReductionPromoInfoBar() {
super(0, sIcon, sTitle, null, sPrimaryButtonText, sSecondaryButtonText);
}
@Override
public void createContent(InfoBarLayout layout) {
super.createContent(layout);
InfoBarControlLayout control = layout.addControlLayout();
control.addDescription(sText);
}
}