diff --git a/android/brave_java_sources.gni b/android/brave_java_sources.gni index 27b568c2731..2c7bdfd09a8 100644 --- a/android/brave_java_sources.gni +++ b/android/brave_java_sources.gni @@ -46,8 +46,11 @@ brave_java_sources = [ "../../brave/android/java/org/chromium/chrome/browser/ntp/sponsored/NTPImage.java", "../../brave/android/java/org/chromium/chrome/browser/ntp/sponsored/ImageCredit.java", "../../brave/android/java/org/chromium/chrome/browser/ntp/sponsored/SponsoredImageUtil.java", + "../../brave/android/java/org/chromium/chrome/browser/ntp/sponsored/NTPUtil.java", "../../brave/android/java/org/chromium/chrome/browser/ntp/sponsored/SponsoredLogo.java", + "../../brave/android/java/org/chromium/chrome/browser/ntp/sponsored/SponsoredTab.java", "../../brave/android/java/org/chromium/chrome/browser/ntp/sponsored/NewTabListener.java", + "../../brave/android/java/org/chromium/chrome/browser/ntp/sponsored/RewardsBottomSheetDialogFragment.java", "../../brave/android/java/org/chromium/chrome/browser/onboarding/BraveRewardsOnboardingFragment.java", "../../brave/android/java/org/chromium/chrome/browser/onboarding/BraveRewardsService.java", "../../brave/android/java/org/chromium/chrome/browser/onboarding/BraveShieldsOnboardingFragment.java", @@ -112,7 +115,10 @@ brave_java_sources = [ "../../brave/android/java/org/chromium/chrome/browser/util/BraveReferrer.java", "../../brave/android/java/org/chromium/chrome/browser/util/PackageUtils.java", "../../brave/android/java/org/chromium/chrome/browser/util/TabUtils.java", - "../../brave/android/java/org/chromium/chrome/browser/util/ConfigurationUtils.java" + "../../brave/android/java/org/chromium/chrome/browser/util/ConfigurationUtils.java", + "../../brave/android/java/org/chromium/chrome/browser/util/LocaleUtils.java", + "../../brave/android/java/org/chromium/chrome/browser/util/ImageUtils.java", + "../../brave/android/java/org/chromium/chrome/browser/widget/tile/BraveTileWithTextView.java" ] if (brave_rewards_enabled) { diff --git a/android/java/org/chromium/chrome/browser/ntp/BraveNewTabPageLayout.java b/android/java/org/chromium/chrome/browser/ntp/BraveNewTabPageLayout.java index dd96d5bf542..9410b962769 100644 --- a/android/java/org/chromium/chrome/browser/ntp/BraveNewTabPageLayout.java +++ b/android/java/org/chromium/chrome/browser/ntp/BraveNewTabPageLayout.java @@ -5,9 +5,9 @@ package org.chromium.chrome.browser.ntp; +import android.os.Build; import android.content.Context; import android.util.AttributeSet; -import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.content.SharedPreferences; @@ -19,7 +19,7 @@ import org.chromium.base.ContextUtils; import org.chromium.chrome.browser.settings.BackgroundImagesPreferences; public class BraveNewTabPageLayout extends NewTabPageLayout { - private ViewGroup mBraveStatsLayout; + private ViewGroup mBraveStatsView; public BraveNewTabPageLayout(Context context, AttributeSet attrs) { super(context, attrs); @@ -31,27 +31,20 @@ public class BraveNewTabPageLayout extends NewTabPageLayout { // Make brave stats visibile always on NTP. // NewTabPageLayout::setSearchProviderInfo() makes it invisible. // So, explicitly set it as visible. - mBraveStatsLayout.setVisibility(View.VISIBLE); + mBraveStatsView.setVisibility(View.VISIBLE); } @Override protected void onFinishInflate() { super.onFinishInflate(); - insertBraveStatsLayout(); - } - - private void insertBraveStatsLayout() { - mBraveStatsLayout = (ViewGroup) LayoutInflater.from(getContext()) - .inflate(R.layout.brave_stats_layout, this, false); - ViewGroup logo = (ViewGroup) findViewById(R.id.search_provider_logo); - int insertionPoint = indexOfChild(logo) + 1; - addView(mBraveStatsLayout, insertionPoint); + mBraveStatsView = (ViewGroup) findViewById(R.id.brave_stats); } @Override public int getMaxTileRows() { SharedPreferences sharedPreferences = ContextUtils.getAppSharedPreferences(); - if(sharedPreferences.getBoolean(BackgroundImagesPreferences.PREF_SHOW_BACKGROUND_IMAGES, true)) { + if(sharedPreferences.getBoolean(BackgroundImagesPreferences.PREF_SHOW_BACKGROUND_IMAGES, true) + && (Build.VERSION.SDK_INT > Build.VERSION_CODES.M || (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP))) { return 1; } else { return 2; diff --git a/android/java/org/chromium/chrome/browser/ntp/BraveNewTabPageView.java b/android/java/org/chromium/chrome/browser/ntp/BraveNewTabPageView.java index dc34d15e02c..ee47ac0290c 100644 --- a/android/java/org/chromium/chrome/browser/ntp/BraveNewTabPageView.java +++ b/android/java/org/chromium/chrome/browser/ntp/BraveNewTabPageView.java @@ -5,17 +5,97 @@ package org.chromium.chrome.browser.ntp; +import android.os.Bundle; import android.content.Context; import android.util.AttributeSet; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import android.content.SharedPreferences; +import android.graphics.Canvas; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.drawable.BitmapDrawable; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.ViewGroup; +import android.view.View; +import android.view.Gravity; +import android.widget.LinearLayout; +import android.widget.FrameLayout; +import android.widget.Button; +import android.view.ViewTreeObserver; +import java.util.Calendar; +import android.widget.Toast; +import android.content.res.Configuration; +import android.graphics.drawable.GradientDrawable; +import android.graphics.Color; +import android.app.Activity; +import android.os.Build; +import android.graphics.LinearGradient; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.Shader; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.style.ClickableSpan; +import android.text.style.ForegroundColorSpan; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.method.LinkMovementMethod; +import android.text.TextPaint; +import android.content.Intent; +import android.support.annotation.NonNull; +import java.io.File; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import android.net.Uri; +import android.os.Handler; import org.chromium.base.TraceEvent; import org.chromium.chrome.R; +import org.chromium.base.Log; +import org.chromium.base.PathUtils; +import org.chromium.base.ContextUtils; +import org.chromium.base.ApplicationStatus; import org.chromium.chrome.browser.ntp.NewTabPageView; import org.chromium.chrome.browser.preferences.BravePrefServiceBridge; import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.browser.suggestions.tile.TileGroup; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab.TabImpl; +import org.chromium.chrome.browser.tabmodel.TabLaunchType; +import org.chromium.chrome.browser.ui.widget.displaystyle.UiConfig; +import org.chromium.chrome.browser.ui.widget.displaystyle.ViewResizer; +import org.chromium.chrome.browser.util.ViewUtils; +import org.chromium.chrome.browser.settings.BackgroundImagesPreferences; +import org.chromium.chrome.browser.ntp.sponsored.NTPImage; +import org.chromium.chrome.browser.ntp.sponsored.BackgroundImage; +import org.chromium.chrome.browser.ntp.sponsored.SponsoredImage; +import org.chromium.chrome.browser.ntp.sponsored.NewTabListener; +import org.chromium.chrome.browser.ntp.sponsored.SponsoredImageUtil; +import org.chromium.content_public.browser.LoadUrlParams; +import org.chromium.chrome.browser.ntp.sponsored.RewardsBottomSheetDialogFragment; +import org.chromium.chrome.browser.BraveAdsNativeHelper; +import org.chromium.chrome.browser.BraveRewardsPanelPopup; +import org.chromium.chrome.browser.BraveRewardsObserver; +import org.chromium.chrome.browser.BraveRewardsNativeWorker; +import org.chromium.chrome.browser.tab.EmptyTabObserver; +import org.chromium.chrome.browser.tab.TabObserver; +import org.chromium.chrome.browser.tabmodel.TabSelectionType; +import org.chromium.chrome.browser.download.DownloadUtils; +import org.chromium.ui.base.DeviceFormFactor; +import org.chromium.chrome.browser.tabmodel.TabModel; +import org.chromium.chrome.browser.util.LocaleUtils; +import org.chromium.chrome.browser.util.ConfigurationUtils; +import org.chromium.chrome.browser.util.ImageUtils; +import org.chromium.chrome.browser.ntp.sponsored.NTPUtil; +import org.chromium.chrome.browser.ntp.sponsored.SponsoredTab; + +import static org.chromium.chrome.browser.util.ViewUtils.dpToPx; public class BraveNewTabPageView extends NewTabPageView { private static final String TAG = "BraveNewTabPageView"; @@ -24,15 +104,73 @@ public class BraveNewTabPageView extends NewTabPageView { private static final String PREF_ADS_BLOCKED_COUNT = "ads_blocked_count"; private static final String PREF_HTTPS_UPGRADES_COUNT = "https_upgrades_count"; private static final short MILLISECONDS_PER_ITEM = 50; + private static final int BOTTOM_TOOLBAR_HEIGHT = 56; private TextView mAdsBlockedCountTextView; private TextView mHttpsUpgradesCountTextView; + private TextView mEstTimeSavedCountTextView; + private TextView mAdsBlockedTextView; + private TextView mHttpsUpgradesTextView; private TextView mEstTimeSavedTextView; private Profile mProfile; + private TabImpl mTab; + private SponsoredTab sponsoredTab; + + private NewTabPageLayout mNewTabPageLayout; + private SharedPreferences mSharedPreferences; + private BitmapDrawable imageDrawable; + + private boolean isFromBottomSheet; + public BraveNewTabPageView(Context context, AttributeSet attrs) { super(context, attrs); mProfile = Profile.getLastUsedProfile(); + mNewTabPageLayout = getNewTabPageLayout(); + mSharedPreferences = ContextUtils.getAppSharedPreferences(); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M || (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !sponsoredTab.isMoreTabs())) { + NTPImage ntpImage = sponsoredTab.getTabNTPImage(); + if(ntpImage == null) { + sponsoredTab.setNTPImage(SponsoredImageUtil.getBackgroundImage()); + } else if (ntpImage instanceof SponsoredImage) { + String countryCode = LocaleUtils.getCountryCode(); + SponsoredImage sponsoredImage = (SponsoredImage) ntpImage; + File imageFile = new File(PathUtils.getDataDirectory(), countryCode + "_" + sponsoredImage.getImageUrl()); + if(!imageFile.exists()) { + sponsoredTab.setNTPImage(SponsoredImageUtil.getBackgroundImage()); + } + } + checkForNonDistruptiveBanner(ntpImage); + super.onConfigurationChanged(newConfig); + showNTPImage(ntpImage); + } else { + super.onConfigurationChanged(newConfig); + } + } + + @Override + public void initialize(NewTabPageManager manager, Tab tab, TileGroup.Delegate tileGroupDelegate, + boolean searchProviderHasLogo, boolean searchProviderIsGoogle, int scrollPosition, + long constructedTimeNs) { + super.initialize(manager, tab, tileGroupDelegate, + searchProviderHasLogo, searchProviderIsGoogle, scrollPosition, + constructedTimeNs); + + mTab = (TabImpl) tab; + sponsoredTab = mTab.getSponsoredTab(); + + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) { + NTPImage ntpImage = sponsoredTab.getTabNTPImage(); + checkForNonDistruptiveBanner(ntpImage); + showNTPImage(ntpImage); + } else if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.M && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !sponsoredTab.isMoreTabs()) { + mTab.addObserver(mTabObserver); + } + } @Override @@ -42,7 +180,11 @@ public class BraveNewTabPageView extends NewTabPageView { ViewGroup braveStatsView = (ViewGroup) getNewTabPageLayout().findViewById(R.id.brave_stats); mAdsBlockedCountTextView = (TextView) braveStatsView.findViewById(R.id.brave_stats_text_ads_count); mHttpsUpgradesCountTextView = (TextView) braveStatsView.findViewById(R.id.brave_stats_text_https_count); - mEstTimeSavedTextView = (TextView) braveStatsView.findViewById(R.id.brave_stats_text_time_count); + mEstTimeSavedCountTextView = (TextView) braveStatsView.findViewById(R.id.brave_stats_text_time_count); + + mAdsBlockedTextView = (TextView) braveStatsView.findViewById(R.id.brave_stats_text_ads); + mHttpsUpgradesTextView = (TextView) braveStatsView.findViewById(R.id.brave_stats_text_https); + mEstTimeSavedTextView = (TextView) braveStatsView.findViewById(R.id.brave_stats_text_time); } @Override @@ -65,7 +207,16 @@ public class BraveNewTabPageView extends NewTabPageView { mAdsBlockedCountTextView.setText(getBraveStatsStringFormNumber(adsBlockedCount)); mHttpsUpgradesCountTextView.setText(getBraveStatsStringFormNumber(httpsUpgradesCount)); - mEstTimeSavedTextView.setText(getBraveStatsStringFromTime(estimatedMillisecondsSaved / 1000)); + mEstTimeSavedCountTextView.setText(getBraveStatsStringFromTime(estimatedMillisecondsSaved / 1000)); + + if(mSharedPreferences.getBoolean(BackgroundImagesPreferences.PREF_SHOW_BACKGROUND_IMAGES, true) + && (Build.VERSION.SDK_INT > Build.VERSION_CODES.M || (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !sponsoredTab.isMoreTabs()))) { + mAdsBlockedTextView.setTextColor(mNewTabPageLayout.getResources().getColor(android.R.color.white)); + mHttpsUpgradesTextView.setTextColor(mNewTabPageLayout.getResources().getColor(android.R.color.white)); + mEstTimeSavedTextView.setTextColor(mNewTabPageLayout.getResources().getColor(android.R.color.white)); + mEstTimeSavedCountTextView.setTextColor(mNewTabPageLayout.getResources().getColor(android.R.color.white)); + } + TraceEvent.end(TAG + ".updateBraveStats()"); } @@ -127,4 +278,220 @@ public class BraveNewTabPageView extends NewTabPageView { } return result; } + + private void showNTPImage(NTPImage ntpImage) { + NTPUtil.updateOrientedUI(mTab.getActivity(), mNewTabPageLayout); + + if(mSharedPreferences.getBoolean(BackgroundImagesPreferences.PREF_SHOW_BACKGROUND_IMAGES, true) + && (Build.VERSION.SDK_INT > Build.VERSION_CODES.M || (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !sponsoredTab.isMoreTabs()))) { + ViewTreeObserver observer = mNewTabPageLayout.getViewTreeObserver(); + observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + String countryCode = LocaleUtils.getCountryCode(); + + int layoutWidth = mNewTabPageLayout.getMeasuredWidth(); + int layoutHeight = mNewTabPageLayout.getMeasuredHeight(); + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inScaled = false; + options.inJustDecodeBounds = false; + + Bitmap imageBitmap = null; + float imageWidth; + float imageHeight; + float centerPointX; + float centerPointY; + + if (ntpImage instanceof SponsoredImage) { + SponsoredImage sponsoredImage = (SponsoredImage) ntpImage; + File imageFile = new File(PathUtils.getDataDirectory(), countryCode + "_" + sponsoredImage.getImageUrl()); + try { + Uri imageFileUri = Uri.parse("file://"+imageFile.getAbsolutePath()); + InputStream inputStream = mTab.getActivity().getContentResolver().openInputStream(imageFileUri); + imageBitmap = BitmapFactory.decodeStream(inputStream); + imageWidth = imageBitmap.getWidth(); + imageHeight = imageBitmap.getHeight(); + centerPointX = sponsoredImage.getFocalPointX() == 0 ? (imageWidth/2) : sponsoredImage.getFocalPointX(); + centerPointY = sponsoredImage.getFocalPointY() == 0 ? (imageHeight/2) : sponsoredImage.getFocalPointY(); + + if (SponsoredImageUtil.getSponsoredLogo() != null ) { + ImageView sponsoredLogo = (ImageView)mNewTabPageLayout.findViewById(R.id.sponsored_logo); + sponsoredLogo.setVisibility(View.VISIBLE); + File logoFile = new File(PathUtils.getDataDirectory(),countryCode + "_" + SponsoredImageUtil.getSponsoredLogo().getImageUrl()); + Bitmap logoBitmap = BitmapFactory.decodeFile(logoFile.getPath()); + sponsoredLogo.setImageBitmap(logoBitmap); + sponsoredLogo.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (SponsoredImageUtil.getSponsoredLogo().getDestinationUrl() != null) { + NTPUtil.openImageCredit(SponsoredImageUtil.getSponsoredLogo().getDestinationUrl()); + } + } + }); + } + } catch (Exception exc) { + Log.e("NTP", exc.getMessage()); + return; + } + } else { + BackgroundImage backgroundImage = (BackgroundImage) ntpImage; + + ImageView sponsoredLogo = (ImageView)mNewTabPageLayout.findViewById(R.id.sponsored_logo); + sponsoredLogo.setVisibility(View.GONE); + + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) { + Bitmap imageBitmapRes = BitmapFactory.decodeResource(mNewTabPageLayout.getResources(), backgroundImage.getImageDrawable(), options); + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + imageBitmapRes.compress(Bitmap.CompressFormat.JPEG,50,stream); + byte[] byteArray = stream.toByteArray(); + imageBitmap = BitmapFactory.decodeByteArray(byteArray,0,byteArray.length); + imageBitmapRes.recycle(); + } else { + imageBitmap = BitmapFactory.decodeResource(mNewTabPageLayout.getResources(), backgroundImage.getImageDrawable(), options); + } + imageWidth = imageBitmap.getWidth(); + imageHeight = imageBitmap.getHeight(); + centerPointX = backgroundImage.getCenterPoint(); + centerPointY = 0; + + if (backgroundImage.getImageCredit() != null) { + + String imageCreditStr = String.format(mNewTabPageLayout.getResources().getString(R.string.photo_by, backgroundImage.getImageCredit().getName())); + + SpannableStringBuilder spannableString = new SpannableStringBuilder(imageCreditStr); + spannableString.setSpan(new android.text.style.StyleSpan(android.graphics.Typeface.BOLD), ((imageCreditStr.length()-1) - (backgroundImage.getImageCredit().getName().length()-1)), imageCreditStr.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + + TextView creditText = (TextView)mNewTabPageLayout.findViewById(R.id.credit_text); + creditText.setText(spannableString); + creditText.setVisibility(View.VISIBLE); + creditText.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (backgroundImage.getImageCredit() != null) { + NTPUtil.openImageCredit(backgroundImage.getImageCredit().getUrl()); + } + } + }); + } + } + + float centerRatioX = centerPointX / imageWidth; + + float imageWHRatio = imageWidth / imageHeight; + float imageHWRatio = imageHeight / imageWidth; + + int newImageWidth = (int) (layoutHeight * imageWHRatio); + int newImageHeight = layoutHeight; + + if (newImageWidth < layoutWidth) { + // Image is now too small so we need to adjust width and height based on + // This covers landscape and strange tablet sizes. + newImageWidth = layoutWidth; + newImageHeight = (int) (newImageWidth * imageHWRatio); + } + + int newCenterX = (int) (newImageWidth * centerRatioX); + int startX = (int) (newCenterX - (layoutWidth / 2)); + if (newCenterX < layoutWidth / 2) { + // Need to crop starting at 0 to newImageWidth - left aligned image + startX = 0; + } else if (newImageWidth - newCenterX < layoutWidth / 2) { + // Need to crop right side of image - right aligned + startX = newImageWidth - layoutWidth; + } + + int startY = (newImageHeight - layoutHeight)/2; + if (centerPointY > 0) { + float centerRatioY = centerPointY / imageHeight; + newImageWidth = layoutWidth; + newImageHeight = (int) (layoutWidth * imageHWRatio); + + if (newImageHeight < layoutHeight) { + newImageHeight = layoutHeight; + newImageWidth = (int) (newImageHeight * imageWHRatio); + } + + int newCenterY = (int) (newImageHeight * centerRatioY); + startY = (int) (newCenterY - (layoutHeight / 2)); + if (newCenterY < layoutHeight / 2) { + // Need to crop starting at 0 to newImageWidth - left aligned image + startY = 0; + } else if (newImageHeight - newCenterY < layoutHeight / 2) { + // Need to crop right side of image - right aligned + startY = newImageHeight - layoutHeight; + } + } + + imageBitmap = Bitmap.createScaledBitmap(imageBitmap, newImageWidth, newImageHeight, true); + + Bitmap newBitmap = Bitmap.createBitmap(imageBitmap, startX, startY, layoutWidth, (int) layoutHeight); + Bitmap bitmapWithGradient = ImageUtils.addGradient(mTab.getActivity(), newBitmap, dpToPx(mTab.getActivity(),BOTTOM_TOOLBAR_HEIGHT)); + Bitmap offsetBitmap = ImageUtils.topOffset(bitmapWithGradient, dpToPx(mTab.getActivity(),BOTTOM_TOOLBAR_HEIGHT)); + + imageBitmap.recycle(); + newBitmap.recycle(); + bitmapWithGradient.recycle(); + + // Center vertically, and crop to new center + imageDrawable = new BitmapDrawable(mNewTabPageLayout.getResources(), offsetBitmap); + mNewTabPageLayout.setBackground(imageDrawable); + + mNewTabPageLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this); + } + }); + } + } + + private void checkForNonDistruptiveBanner(NTPImage ntpImage) { + int brOption = NTPUtil.checkForNonDistruptiveBanner(ntpImage, sponsoredTab); + if (SponsoredImageUtil.BR_INVALID_OPTION != brOption) { + NTPUtil.showNonDistruptiveBanner(mTab.getActivity(), mNewTabPageLayout, brOption, sponsoredTab, newTabListener); + } + } + + private void checkAndShowNTPImage() { + NTPImage ntpImage = sponsoredTab.getTabNTPImage(); + if(ntpImage == null) { + sponsoredTab.setNTPImage(SponsoredImageUtil.getBackgroundImage()); + } else if (ntpImage instanceof SponsoredImage) { + String countryCode = LocaleUtils.getCountryCode(); + SponsoredImage sponsoredImage = (SponsoredImage) ntpImage; + File imageFile = new File(PathUtils.getDataDirectory(), countryCode + "_" + sponsoredImage.getImageUrl()); + if(!imageFile.exists()) { + sponsoredTab.setNTPImage(SponsoredImageUtil.getBackgroundImage()); + ntpImage = sponsoredTab.getTabNTPImage(); + } + } + checkForNonDistruptiveBanner(ntpImage); + showNTPImage(ntpImage); + } + + private TabObserver mTabObserver = new EmptyTabObserver() { + @Override + public void onInteractabilityChanged(boolean interactable) { + // Force a layout update if the tab is now in the foreground. + if (interactable) { + checkAndShowNTPImage(); + } else { + if(!isFromBottomSheet){ + mNewTabPageLayout.setBackgroundResource(0); + if (imageDrawable != null && imageDrawable.getBitmap() != null && !imageDrawable.getBitmap().isRecycled()) { + imageDrawable.getBitmap().recycle(); + } + } + } + } + }; + + private NewTabListener newTabListener = new NewTabListener() { + @Override + public void updateInteractableFlag(boolean isBottomSheet) { + isFromBottomSheet = isBottomSheet; + } + + @Override + public void updateNTPImage() { + checkAndShowNTPImage(); + } + }; } diff --git a/android/java/org/chromium/chrome/browser/ntp/sponsored/NTPUtil.java b/android/java/org/chromium/chrome/browser/ntp/sponsored/NTPUtil.java new file mode 100644 index 00000000000..708bb66d8b9 --- /dev/null +++ b/android/java/org/chromium/chrome/browser/ntp/sponsored/NTPUtil.java @@ -0,0 +1,269 @@ +/* Copyright (c) 2020 The Brave Authors. All rights reserved. + * 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.chromium.chrome.browser.ntp.sponsored; + +import android.os.Bundle; +import android.content.Context; +import android.content.SharedPreferences; +import android.view.ViewGroup; +import android.view.View; +import android.view.Gravity; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Button; +import android.os.Handler; + +import org.chromium.chrome.R; + +import org.chromium.content_public.browser.LoadUrlParams; + +import org.chromium.base.ContextUtils; +import org.chromium.ui.base.DeviceFormFactor; +import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.browser.ChromeTabbedActivity; +import org.chromium.chrome.browser.BraveAdsNativeHelper; +import org.chromium.chrome.browser.BraveRewardsHelper; +import org.chromium.chrome.browser.settings.BackgroundImagesPreferences; +import org.chromium.chrome.browser.util.ConfigurationUtils; +import org.chromium.chrome.browser.ntp.sponsored.NTPImage; +import org.chromium.chrome.browser.ntp.sponsored.SponsoredImage; +import org.chromium.chrome.browser.ntp.sponsored.SponsoredImageUtil; +import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.ChromeFeatureList; +import org.chromium.chrome.browser.BraveFeatureList; +import org.chromium.chrome.browser.BraveRewardsNativeWorker; +import org.chromium.chrome.browser.BraveRewardsPanelPopup; +import org.chromium.chrome.browser.preferences.BravePrefServiceBridge; + +import static org.chromium.chrome.browser.util.ViewUtils.dpToPx; + +public class NTPUtil { + public static void openImageCredit(String url) { + ChromeTabbedActivity chromeTabbedActivity = BraveRewardsHelper.getChromeTabbedActivity(); + if(chromeTabbedActivity != null) { + LoadUrlParams loadUrlParams = new LoadUrlParams(url); + chromeTabbedActivity.getActivityTab().loadUrl(loadUrlParams); + } + } + + public static void turnOnAds() { + BraveAdsNativeHelper.nativeSetAdsEnabled(Profile.getLastUsedProfile()); + } + + public static void updateOrientedUI(Context context, ViewGroup view) { + SharedPreferences mSharedPreferences = ContextUtils.getAppSharedPreferences(); + + LinearLayout parentLayout= (LinearLayout)view.findViewById(R.id.parent_layout); + ViewGroup mainLayout = view.findViewById(R.id.ntp_main_layout); + ViewGroup imageCreditLayout = view.findViewById(R.id.image_credit_layout); + + ImageView sponsoredLogo = (ImageView)view.findViewById(R.id.sponsored_logo); + FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(dpToPx(context,170), dpToPx(context,170)); + + boolean isTablet = DeviceFormFactor.isNonMultiDisplayContextOnTablet(context); + + if (ConfigurationUtils.isLandscape(context) && mSharedPreferences.getBoolean(BackgroundImagesPreferences.PREF_SHOW_BACKGROUND_IMAGES, true)) { + // In landscape + parentLayout.removeView(mainLayout); + parentLayout.removeView(imageCreditLayout); + + if (isTablet) { + parentLayout.addView(mainLayout); + parentLayout.addView(imageCreditLayout); + + parentLayout.setOrientation(LinearLayout.VERTICAL); + + LinearLayout.LayoutParams mainLayoutLayoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,0); + mainLayoutLayoutParams.weight = 1f; + mainLayout.setLayoutParams(mainLayoutLayoutParams); + + LinearLayout.LayoutParams imageCreditLayoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); + imageCreditLayout.setLayoutParams(imageCreditLayoutParams); + + layoutParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; + sponsoredLogo.setLayoutParams(layoutParams); + + } else { + parentLayout.addView(imageCreditLayout); + parentLayout.addView(mainLayout); + + parentLayout.setOrientation(LinearLayout.HORIZONTAL); + + LinearLayout.LayoutParams mainLayoutLayoutParams = new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT); + mainLayoutLayoutParams.weight = 0.6f; + mainLayout.setLayoutParams(mainLayoutLayoutParams); + + LinearLayout.LayoutParams imageCreditLayoutParams = new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT); + imageCreditLayoutParams.weight = 0.4f; + imageCreditLayout.setLayoutParams(imageCreditLayoutParams); + + layoutParams.setMargins(dpToPx(context,32), 0, 0, 0); + layoutParams.gravity = Gravity.BOTTOM | Gravity.START; + sponsoredLogo.setLayoutParams(layoutParams); + } + } else { + // In portrait + parentLayout.removeView(mainLayout); + parentLayout.removeView(imageCreditLayout); + + parentLayout.addView(mainLayout); + parentLayout.addView(imageCreditLayout); + + parentLayout.setOrientation(LinearLayout.VERTICAL); + + LinearLayout.LayoutParams mainLayoutLayoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,0); + mainLayoutLayoutParams.weight = 1f; + mainLayout.setLayoutParams(mainLayoutLayoutParams); + + LinearLayout.LayoutParams imageCreditLayoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); + imageCreditLayout.setLayoutParams(imageCreditLayoutParams); + + layoutParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; + sponsoredLogo.setLayoutParams(layoutParams); + } + } + + public static int checkForNonDistruptiveBanner(NTPImage ntpImage, SponsoredTab sponsoredTab) { + BraveRewardsNativeWorker mBraveRewardsNativeWorker = BraveRewardsNativeWorker.getInstance(); + if (sponsoredTab.shouldShowBanner()) { + if (BraveRewardsPanelPopup.isBraveRewardsEnabled()) { + if (BraveAdsNativeHelper.nativeIsBraveAdsEnabled(Profile.getLastUsedProfile())) { + if (ntpImage instanceof SponsoredImage) { + return SponsoredImageUtil.BR_ON_ADS_ON; + } + } else if(BraveAdsNativeHelper.nativeIsLocaleValid(Profile.getLastUsedProfile())) { + if (ntpImage instanceof SponsoredImage) { + return SponsoredImageUtil.BR_ON_ADS_OFF ; + } else { + return SponsoredImageUtil.BR_ON_ADS_OFF_BG_IMAGE; + } + } + } else { + if (ntpImage instanceof SponsoredImage && !mBraveRewardsNativeWorker.IsCreateWalletInProcess()) { + return SponsoredImageUtil.BR_OFF; + } + } + } + return SponsoredImageUtil.BR_INVALID_OPTION; + } + + public static void showNonDistruptiveBanner(ChromeActivity chromeActivity, View view, int ntpType, SponsoredTab sponsoredTab, NewTabListener newTabListener) { + ViewGroup nonDistruptiveBannerLayout = (ViewGroup) view.findViewById(R.id.non_distruptive_banner); + nonDistruptiveBannerLayout.setVisibility(View.GONE); + + Handler handler = new Handler(); + handler.postDelayed(new Runnable() { + @Override + public void run() { + BackgroundImagesPreferences.setOnPreferenceValue(BackgroundImagesPreferences.PREF_SHOW_NON_DISTRUPTIVE_BANNER,false); + + boolean isTablet = DeviceFormFactor.isNonMultiDisplayContextOnTablet(chromeActivity); + if(isTablet || (!isTablet && ConfigurationUtils.isLandscape(chromeActivity))) { + FrameLayout.LayoutParams nonDistruptiveBannerLayoutParams = new FrameLayout.LayoutParams(dpToPx(chromeActivity, 400), FrameLayout.LayoutParams.WRAP_CONTENT); + nonDistruptiveBannerLayoutParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; + nonDistruptiveBannerLayout.setLayoutParams(nonDistruptiveBannerLayoutParams); + } else { + FrameLayout.LayoutParams nonDistruptiveBannerLayoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT); + nonDistruptiveBannerLayoutParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; + nonDistruptiveBannerLayout.setLayoutParams(nonDistruptiveBannerLayoutParams); + } + nonDistruptiveBannerLayout.setVisibility(View.VISIBLE); + + TextView bannerHeader = nonDistruptiveBannerLayout.findViewById(R.id.ntp_banner_header); + TextView bannerText = nonDistruptiveBannerLayout.findViewById(R.id.ntp_banner_text); + TextView learnMoreText = nonDistruptiveBannerLayout.findViewById(R.id.ntp_banner_learn_more_text); + Button turnOnAdsButton = nonDistruptiveBannerLayout.findViewById(R.id.btn_turn_on_ads); + ImageView bannerClose = nonDistruptiveBannerLayout.findViewById(R.id.ntp_banner_close); + bannerClose.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + nonDistruptiveBannerLayout.setVisibility(View.GONE); + sponsoredTab.updateBannerPref(); + } + }); + + learnMoreText.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + nonDistruptiveBannerLayout.setVisibility(View.GONE); + + RewardsBottomSheetDialogFragment rewardsBottomSheetDialogFragment = RewardsBottomSheetDialogFragment.newInstance(); + Bundle bundle = new Bundle(); + bundle.putInt(SponsoredImageUtil.NTP_TYPE, ntpType); + rewardsBottomSheetDialogFragment.setArguments(bundle); + rewardsBottomSheetDialogFragment.setNewTabListener(newTabListener); + rewardsBottomSheetDialogFragment.show(chromeActivity.getSupportFragmentManager(), "rewards_bottom_sheet_dialog_fragment"); + rewardsBottomSheetDialogFragment.setCancelable(false); + + sponsoredTab.updateBannerPref(); + } + }); + + turnOnAdsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + NTPUtil.turnOnAds(); + nonDistruptiveBannerLayout.setVisibility(View.GONE); + + sponsoredTab.updateBannerPref(); + } + }); + + switch(ntpType) { + case SponsoredImageUtil.BR_OFF: + bannerText.setText(chromeActivity.getResources().getString(R.string.get_paid_to_see_image)); + learnMoreText.setVisibility(View.VISIBLE); + break; + case SponsoredImageUtil.BR_ON_ADS_OFF: + bannerText.setText(chromeActivity.getResources().getString(R.string.get_paid_to_see_image)); + learnMoreText.setVisibility(View.VISIBLE); + break; + case SponsoredImageUtil.BR_ON_ADS_OFF_BG_IMAGE: + bannerText.setText(chromeActivity.getResources().getString(R.string.you_can_support_creators)); + turnOnAdsButton.setVisibility(View.VISIBLE); + break; + case SponsoredImageUtil.BR_ON_ADS_ON: + bannerText.setText(chromeActivity.getResources().getString(R.string.you_are_getting_paid)); + learnMoreText.setVisibility(View.VISIBLE); + break; + } + } + }, 1500); + } + + public static NTPImage getNTPImage() { + SharedPreferences mSharedPreferences = ContextUtils.getAppSharedPreferences(); + + if (mSharedPreferences.getBoolean(BackgroundImagesPreferences.PREF_SHOW_SPONSORED_IMAGES, true) + && SponsoredImageUtil.getSponsoredImages().size() > 0 + && mSharedPreferences.getInt(BackgroundImagesPreferences.PREF_APP_OPEN_COUNT, 0) == 1 + && SponsoredImageUtil.getTabIndex() == 2 + && BraveAdsNativeHelper.nativeIsLocaleValid(Profile.getLastUsedProfile()) + && !BravePrefServiceBridge.getInstance().getSafetynetCheckFailed() + && ChromeFeatureList.isEnabled(BraveFeatureList.BRAVE_REWARDS)) { + SponsoredImage sponsoredImage = SponsoredImageUtil.getSponsoredImage(); + SponsoredImageUtil.incrementTabIndex(3); + return sponsoredImage; + } + + if (mSharedPreferences.getBoolean(BackgroundImagesPreferences.PREF_SHOW_SPONSORED_IMAGES, true) + && SponsoredImageUtil.getSponsoredImages().size() > 0 + && SponsoredImageUtil.getTabIndex() != 1 + && SponsoredImageUtil.getTabIndex() % 4 == 0 + && BraveAdsNativeHelper.nativeIsLocaleValid(Profile.getLastUsedProfile()) + && !BravePrefServiceBridge.getInstance().getSafetynetCheckFailed() + && ChromeFeatureList.isEnabled(BraveFeatureList.BRAVE_REWARDS)) { + SponsoredImageUtil.incrementTabIndex(1); + return SponsoredImageUtil.getSponsoredImage(); + } else { + SponsoredImageUtil.incrementTabIndex(1); + return SponsoredImageUtil.getBackgroundImage(); + } + } +} \ No newline at end of file diff --git a/android/java/org/chromium/chrome/browser/ntp/sponsored/RewardsBottomSheetDialogFragment.java b/android/java/org/chromium/chrome/browser/ntp/sponsored/RewardsBottomSheetDialogFragment.java new file mode 100644 index 00000000000..e1d85c4512a --- /dev/null +++ b/android/java/org/chromium/chrome/browser/ntp/sponsored/RewardsBottomSheetDialogFragment.java @@ -0,0 +1,321 @@ +/* Copyright (c) 2020 The Brave Authors. All rights reserved. + * 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.chromium.chrome.browser.ntp.sponsored; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.FrameLayout; +import android.widget.TextView; +import android.widget.Button; +import android.content.Intent; +import android.app.Activity; +import android.text.style.ClickableSpan; +import android.text.style.ForegroundColorSpan; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.method.LinkMovementMethod; +import android.text.TextPaint; +import android.content.res.Configuration; + +import android.support.design.widget.BottomSheetDialogFragment; +import android.support.design.widget.BottomSheetDialog; +import android.support.design.widget.BottomSheetBehavior; +import android.view.ViewTreeObserver; + +import org.chromium.content_public.browser.LoadUrlParams; + +import org.chromium.chrome.browser.BraveAdsNativeHelper; +import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.base.ContextUtils; +import org.chromium.base.ApplicationStatus; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab.TabImpl; +import org.chromium.chrome.browser.util.ConfigurationUtils; +import org.chromium.chrome.browser.ChromeTabbedActivity; +import org.chromium.chrome.browser.onboarding.BraveRewardsService; +import org.chromium.chrome.browser.ntp.sponsored.SponsoredImageUtil; +import org.chromium.chrome.browser.settings.BackgroundImagesPreferences; +import org.chromium.chrome.browser.customtabs.CustomTabActivity; +import org.chromium.chrome.browser.BraveRewardsHelper; +import org.chromium.chrome.browser.tabmodel.TabModel; +import org.chromium.ui.base.DeviceFormFactor; +import org.chromium.chrome.R; + +import static org.chromium.chrome.browser.util.ViewUtils.dpToPx; + +public class RewardsBottomSheetDialogFragment extends BottomSheetDialogFragment{ + private static final String BRAVE_TERMS_PAGE = "https://basicattentiontoken.org/user-terms-of-service/"; + private static final String BRAVE_REWARDS_LEARN_MORE = "https://brave.com/faq-rewards"; + + private int ntpType; + private NewTabListener newTabListener; + + public static RewardsBottomSheetDialogFragment newInstance() { + return new RewardsBottomSheetDialogFragment(); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + if (getArguments()!=null) { + ntpType = getArguments().getInt(SponsoredImageUtil.NTP_TYPE,1); + } + return inflater.inflate(R.layout.ntp_bottom_sheet, container,false); + } + + @Override + public void onPause() { + newTabListener.updateInteractableFlag(true); + super.onPause(); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + boolean isTablet = DeviceFormFactor.isNonMultiDisplayContextOnTablet(getActivity()); + if(isTablet || (!isTablet && newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)) { + getDialog().getWindow().setLayout(dpToPx(getActivity(), 400), -1); + } else { + getDialog().getWindow().setLayout(-1, -1); + } + } + + @Override + public void onResume() { + super.onResume(); + + newTabListener.updateInteractableFlag(false); + + boolean isTablet = DeviceFormFactor.isNonMultiDisplayContextOnTablet(getActivity()); + if(isTablet || (!isTablet && ConfigurationUtils.isLandscape(getActivity()))) { + getDialog().getWindow().setLayout(dpToPx(getActivity(), 400), -1); + } else { + getDialog().getWindow().setLayout(-1, -1); + } + } + + public void setNewTabListener(NewTabListener newTabListener) { + this.newTabListener = newTabListener; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + BottomSheetDialog dialog = (BottomSheetDialog) getDialog(); + FrameLayout bottomSheet = (FrameLayout) dialog.findViewById(android.support.design.R.id.design_bottom_sheet); + BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet); + behavior.setState(BottomSheetBehavior.STATE_EXPANDED); + } + }); + + ImageView btnClose = view.findViewById(R.id.ntp_bottom_sheet_close); + btnClose.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + dismiss(); + } + }); + + Button turnOnAdsButton = view.findViewById(R.id.btn_turn_on_ads); + if (turnOnAdsButton != null) { + turnOnAdsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + turnOnAds(); + dismiss(); + } + }); + } + + Button turnOnRewardsButton = view.findViewById(R.id.btn_turn_on_rewards); + if (turnOnRewardsButton != null) { + turnOnRewardsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + turnOnRewards(); + dismiss(); + } + }); + } + + Button learnMoreButton = view.findViewById(R.id.btn_learn_more); + if (learnMoreButton != null) { + learnMoreButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + braveRewardsLearnMore(); + dismiss(); + } + }); + } + + TextView bottomSheetTitleText= view.findViewById(R.id.ntp_bottom_sheet_title); + TextView bottomSheetText= view.findViewById(R.id.ntp_bottom_sheet_text); + + switch (ntpType) { + case SponsoredImageUtil.BR_OFF: + bottomSheetTitleText.setText(getResources().getString(R.string.turn_on_brave_ads_to_claim)); + turnOnRewardsButton.setVisibility(View.VISIBLE); + learnMoreButton.setVisibility(View.VISIBLE); + String brOffText = String.format(getResources().getString(R.string.ntp_tos_text), getResources().getString(R.string.terms_of_service), getResources().getString(R.string.hide_sponsored_images)); + int termsOfServiceIndex = brOffText.indexOf(getResources().getString(R.string.terms_of_service)); + Spanned brOffTextSpanned = BraveRewardsHelper.spannedFromHtmlString(brOffText); + SpannableString brOffTextSS = new SpannableString(brOffTextSpanned.toString()); + + ClickableSpan tosClickableSpan = new ClickableSpan() { + @Override + public void onClick(@NonNull View textView) { + CustomTabActivity.showInfoPage(getActivity(), BRAVE_TERMS_PAGE); + } + @Override + public void updateDrawState(@NonNull TextPaint ds) { + super.updateDrawState(ds); + ds.setUnderlineText(false); + } + }; + + ClickableSpan brOffHideSponsoredImagesClickableSpan = new ClickableSpan() { + @Override + public void onClick(@NonNull View textView) { + hideSponsoredImages(); + dismiss(); + } + @Override + public void updateDrawState(@NonNull TextPaint ds) { + super.updateDrawState(ds); + ds.setUnderlineText(false); + } + }; + + brOffTextSS.setSpan(tosClickableSpan, termsOfServiceIndex, termsOfServiceIndex + getResources().getString(R.string.terms_of_service).length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + brOffTextSS.setSpan(brOffHideSponsoredImagesClickableSpan, (brOffTextSS.length()-1) - getResources().getString(R.string.hide_sponsored_images).length() , brOffTextSS.length()-1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + ForegroundColorSpan brOffForegroundSpan = new ForegroundColorSpan(getResources().getColor(R.color.brave_theme_color)); + ForegroundColorSpan brOffForegroundSpan2 = new ForegroundColorSpan(getResources().getColor(R.color.brave_theme_color)); + brOffTextSS.setSpan(brOffForegroundSpan, termsOfServiceIndex, termsOfServiceIndex + getResources().getString(R.string.terms_of_service).length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + brOffTextSS.setSpan(brOffForegroundSpan2, (brOffTextSS.length()-1) - getResources().getString(R.string.hide_sponsored_images).length() , brOffTextSS.length()-1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + bottomSheetText.setMovementMethod(LinkMovementMethod.getInstance()); + bottomSheetText.setText(brOffTextSS); + break; + case SponsoredImageUtil.BR_ON_ADS_OFF: + bottomSheetTitleText.setText(getResources().getString(R.string.turn_on_brave_ads_to_claim)); + turnOnAdsButton.setVisibility(View.VISIBLE); + String brOnAdsOffText = String.format( getResources().getString(R.string.br_on_ads_on_text2), getResources().getString(R.string.hide_sponsored_images)); + Spanned brOnAdsOffSpanned = BraveRewardsHelper.spannedFromHtmlString(brOnAdsOffText); + SpannableString brOnAdsOffSS = new SpannableString(brOnAdsOffSpanned.toString()); + + ClickableSpan brOnAdsOffHideSponsoredImagesClickableSpan = new ClickableSpan() { + @Override + public void onClick(@NonNull View textView) { + hideSponsoredImages(); + dismiss(); + } + @Override + public void updateDrawState(@NonNull TextPaint ds) { + super.updateDrawState(ds); + ds.setUnderlineText(false); + } + }; + + brOnAdsOffSS.setSpan(brOnAdsOffHideSponsoredImagesClickableSpan, (brOnAdsOffSS.length()-1) - getResources().getString(R.string.hide_sponsored_images).length() , brOnAdsOffSS.length()-1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + ForegroundColorSpan brOnAdsOffForegroundSpan = new ForegroundColorSpan(getResources().getColor(R.color.brave_theme_color)); + brOnAdsOffSS.setSpan(brOnAdsOffForegroundSpan, (brOnAdsOffSS.length()-1) - getResources().getString(R.string.hide_sponsored_images).length() , brOnAdsOffSS.length()-1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + bottomSheetText.setMovementMethod(LinkMovementMethod.getInstance()); + bottomSheetText.setText(brOnAdsOffSS); + break; + case SponsoredImageUtil.BR_ON_ADS_ON: + bottomSheetTitleText.setText(getResources().getString(R.string.you_are_getting_paid)); + String brOnAdsOnText = String.format(getResources().getString(R.string.br_on_ads_on_text), getResources().getString(R.string.learn_more), getResources().getString(R.string.hide_sponsored_images)); + Spanned brOnAdsOnSpanned = BraveRewardsHelper.spannedFromHtmlString(brOnAdsOnText); + SpannableString brOnAdsOnSS = new SpannableString(brOnAdsOnSpanned.toString()); + + ClickableSpan learnMoreClickableSpan = new ClickableSpan() { + @Override + public void onClick(@NonNull View textView) { + braveRewardsLearnMore(); + dismiss(); + } + @Override + public void updateDrawState(@NonNull TextPaint ds) { + super.updateDrawState(ds); + ds.setUnderlineText(false); + } + }; + + ClickableSpan brOnAdsOnHideSponsoredImagesClickableSpan = new ClickableSpan() { + @Override + public void onClick(@NonNull View textView) { + hideSponsoredImages(); + dismiss(); + } + @Override + public void updateDrawState(@NonNull TextPaint ds) { + super.updateDrawState(ds); + ds.setUnderlineText(false); + } + }; + + brOnAdsOnSS.setSpan(learnMoreClickableSpan, 0, getResources().getString(R.string.learn_more).length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + brOnAdsOnSS.setSpan(brOnAdsOnHideSponsoredImagesClickableSpan, (brOnAdsOnSS.length()-1) - getResources().getString(R.string.hide_sponsored_images).length() , brOnAdsOnSS.length()-1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + ForegroundColorSpan brOnAdsOnForegroundSpan = new ForegroundColorSpan(getResources().getColor(R.color.brave_theme_color)); + ForegroundColorSpan brOnAdsOnForegroundSpan2 = new ForegroundColorSpan(getResources().getColor(R.color.brave_theme_color)); + brOnAdsOnSS.setSpan(brOnAdsOnForegroundSpan, 0, getResources().getString(R.string.learn_more).length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + brOnAdsOnSS.setSpan(brOnAdsOnForegroundSpan2, (brOnAdsOnSS.length()-1) - getResources().getString(R.string.hide_sponsored_images).length() , brOnAdsOnSS.length()-1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + bottomSheetText.setMovementMethod(LinkMovementMethod.getInstance()); + bottomSheetText.setText(brOnAdsOnSS); + break; + } + } + + private void hideSponsoredImages() { + BackgroundImagesPreferences.setOnPreferenceValue(BackgroundImagesPreferences.PREF_SHOW_SPONSORED_IMAGES, false); + reloadTab(); + } + + private void turnOnRewards() { + Intent mBraveRewardsServiceIntent = new Intent(ContextUtils.getApplicationContext(), BraveRewardsService.class); + ContextUtils.getApplicationContext().startService(mBraveRewardsServiceIntent); + } + + private void turnOnAds() { + BraveAdsNativeHelper.nativeSetAdsEnabled(Profile.getLastUsedProfile()); + } + + private void reloadTab() { + ChromeTabbedActivity chromeTabbedActivity = BraveRewardsHelper.getChromeTabbedActivity(); + if(chromeTabbedActivity != null) { + TabImpl currentTab = (TabImpl) chromeTabbedActivity.getActivityTab(); + currentTab.getSponsoredTab().setNTPImage(SponsoredImageUtil.getBackgroundImage()); + newTabListener.updateNTPImage(); + } + } + + private void braveRewardsLearnMore() { + ChromeTabbedActivity chromeTabbedActivity = BraveRewardsHelper.getChromeTabbedActivity(); + if(chromeTabbedActivity != null) { + TabModel tabModel = chromeTabbedActivity.getCurrentTabModel(); + LoadUrlParams loadUrlParams = new LoadUrlParams(BRAVE_REWARDS_LEARN_MORE); + chromeTabbedActivity.getActivityTab().loadUrl(loadUrlParams); + } + } +} \ No newline at end of file diff --git a/android/java/org/chromium/chrome/browser/ntp/sponsored/SponsoredImageUtil.java b/android/java/org/chromium/chrome/browser/ntp/sponsored/SponsoredImageUtil.java index a12a999a083..73671c0d1e9 100644 --- a/android/java/org/chromium/chrome/browser/ntp/sponsored/SponsoredImageUtil.java +++ b/android/java/org/chromium/chrome/browser/ntp/sponsored/SponsoredImageUtil.java @@ -15,6 +15,7 @@ public class SponsoredImageUtil { public static final String NTP_TYPE = "ntp_type"; + public static final int BR_INVALID_OPTION = -1; public static final int BR_OFF = 1; public static final int BR_ON_ADS_OFF = 2; public static final int BR_ON_ADS_OFF_BG_IMAGE = 3; diff --git a/android/java/org/chromium/chrome/browser/ntp/sponsored/SponsoredTab.java b/android/java/org/chromium/chrome/browser/ntp/sponsored/SponsoredTab.java new file mode 100644 index 00000000000..567b3f37b77 --- /dev/null +++ b/android/java/org/chromium/chrome/browser/ntp/sponsored/SponsoredTab.java @@ -0,0 +1,79 @@ +/* Copyright (c) 2020 The Brave Authors. All rights reserved. + * 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.chromium.chrome.browser.ntp.sponsored; + +import android.os.Build; +import org.chromium.base.ContextUtils; +import org.chromium.chrome.browser.settings.BackgroundImagesPreferences; +import org.chromium.chrome.browser.ntp.sponsored.NTPImage; +import org.chromium.chrome.browser.ntp.sponsored.NTPUtil; +import org.chromium.chrome.browser.ntp.sponsored.NewTabListener; +import org.chromium.chrome.browser.ntp.sponsored.SponsoredImageUtil; +import org.chromium.chrome.browser.tabmodel.TabModel; +import org.chromium.chrome.browser.ChromeTabbedActivity; +import org.chromium.chrome.browser.BraveRewardsHelper; + +public class SponsoredTab{ + private NTPImage ntpImage; + private int tabIndex; + private boolean mShouldShowBanner; + private boolean isMoreTabs; + private NewTabListener newTabListener; + + public SponsoredTab() { + ChromeTabbedActivity chromeTabbedActivity = BraveRewardsHelper.getChromeTabbedActivity(); + if(chromeTabbedActivity != null) { + TabModel tabModel = chromeTabbedActivity.getCurrentTabModel(); + isMoreTabs = tabModel.getCount() > SponsoredImageUtil.MAX_TABS ? true : false; + } + + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M || (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !isMoreTabs)){ + ntpImage = NTPUtil.getNTPImage(); + tabIndex = SponsoredImageUtil.getTabIndex(); + updateBannerPref(); + } + } + + public NTPImage getTabNTPImage() { + if (ntpImage != null) { + return ntpImage; + } else { + return NTPUtil.getNTPImage(); + } + } + + public void setNTPImage(NTPImage ntpImage) { + this.ntpImage = ntpImage; + } + + public void setNewTabListener(NewTabListener newTabListener) { + this.newTabListener = newTabListener; + } + + public int getTabIndex() { + return tabIndex; + } + + public void setTanIndex(int tabIndex) { + this.tabIndex = tabIndex; + } + + public boolean shouldShowBanner() { + return mShouldShowBanner; + } + + public void updateBannerPref() { + mShouldShowBanner = ContextUtils.getAppSharedPreferences().getBoolean(BackgroundImagesPreferences.PREF_SHOW_NON_DISTRUPTIVE_BANNER, true); + } + + public boolean isMoreTabs() { + return isMoreTabs; + } + + public void setMoreTabs(boolean isMoreTabs) { + this.isMoreTabs = isMoreTabs; + } +} \ No newline at end of file diff --git a/android/java/org/chromium/chrome/browser/settings/developer/BraveQAPreferences.java b/android/java/org/chromium/chrome/browser/settings/developer/BraveQAPreferences.java index ea4e0c0306a..2bc72da972b 100644 --- a/android/java/org/chromium/chrome/browser/settings/developer/BraveQAPreferences.java +++ b/android/java/org/chromium/chrome/browser/settings/developer/BraveQAPreferences.java @@ -41,6 +41,7 @@ public class BraveQAPreferences extends BravePreferenceFragment private static final String PREF_USE_REWARDS_STAGING_SERVER = "use_rewards_staging_server"; private static final String PREF_QA_MAXIMIZE_INITIAL_ADS_NUMBER = "qa_maximize_initial_ads_number"; + private static final String PREF_QA_DEBUG_NTP= "qa_debug_ntp"; private static final String QA_ADS_PER_HOUR = "qa_ads_per_hour"; @@ -49,6 +50,7 @@ public class BraveQAPreferences extends BravePreferenceFragment private ChromeSwitchPreference mIsStagingServer; private ChromeSwitchPreference mMaximizeAdsNumber; + private ChromeSwitchPreference mDebugNTP; @Override public void onCreate(Bundle savedInstanceState) { @@ -66,6 +68,11 @@ public class BraveQAPreferences extends BravePreferenceFragment mMaximizeAdsNumber.setEnabled(mIsStagingServer.isChecked()); mMaximizeAdsNumber.setOnPreferenceChangeListener(this); } + + mDebugNTP = (ChromeSwitchPreference) findPreference(PREF_QA_DEBUG_NTP); + if(mDebugNTP != null) { + mDebugNTP.setOnPreferenceChangeListener(this); + } } @Override @@ -91,10 +98,20 @@ public class BraveQAPreferences extends BravePreferenceFragment BraveRelaunchUtils.askForRelaunch(getActivity()); } else if (PREF_QA_MAXIMIZE_INITIAL_ADS_NUMBER.equals(preference.getKey())) { enableMaximumAdsNumber((boolean) newValue); + } else if (PREF_QA_DEBUG_NTP.equals(preference.getKey())) { + setOnPreferenceValue(preference.getKey(), (boolean)newValue); + BraveRelaunchUtils.askForRelaunch(getActivity()); } return true; } + private void setOnPreferenceValue(String preferenceName, boolean newValue) { + SharedPreferences sharedPreferences = ContextUtils.getAppSharedPreferences(); + SharedPreferences.Editor sharedPreferencesEditor = sharedPreferences.edit(); + sharedPreferencesEditor.putBoolean(preferenceName, newValue); + sharedPreferencesEditor.apply(); + } + private void checkQACode() { LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); diff --git a/android/java/org/chromium/chrome/browser/util/ImageUtils.java b/android/java/org/chromium/chrome/browser/util/ImageUtils.java new file mode 100644 index 00000000000..463ad2f94a0 --- /dev/null +++ b/android/java/org/chromium/chrome/browser/util/ImageUtils.java @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2020 The Brave Authors. All rights reserved. + * 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.chromium.chrome.browser.util; + +import android.content.Context; +import android.graphics.Color; +import android.graphics.Canvas; +import android.graphics.Bitmap; +import android.graphics.LinearGradient; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.Shader; + +import org.chromium.chrome.R; +import org.chromium.chrome.browser.util.ConfigurationUtils; + +import static org.chromium.chrome.browser.util.ViewUtils.dpToPx; + +public class ImageUtils { + public static Bitmap topOffset(Bitmap src, int offsetY) { + Bitmap outputimage = Bitmap.createBitmap(src.getWidth(), src.getHeight() + offsetY, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(outputimage); + canvas.drawBitmap(src, 0, offsetY, null); + return outputimage; + } + + public static Bitmap addGradient(Context context, Bitmap src, int gradientHeight) { + int w = src.getWidth(); + int h = src.getHeight(); + Bitmap result = Bitmap.createBitmap(src,0,0,w,h); + Canvas canvas = new Canvas(result); + + // Top gradient + int height; + + if(ConfigurationUtils.isLandscape(context)) { + height = ((2*h)/3)+ gradientHeight; + } else { + height = (h/3)+ gradientHeight; + } + + Paint topPaint = new Paint(); + LinearGradient topShader = new LinearGradient(0,0,0,height, context.getResources().getColor(R.color.black_alpha_50), Color.TRANSPARENT, Shader.TileMode.CLAMP); + topPaint.setShader(topShader); + topPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN)); + canvas.drawRect(0,0,w,height,topPaint); + + //Bottom gradient + Paint bottomPaint = new Paint(); + LinearGradient bottomShader = new LinearGradient(0,2*(h/3),0,h, Color.TRANSPARENT, context.getResources().getColor(R.color.black_alpha_30), Shader.TileMode.CLAMP); + bottomPaint.setShader(bottomShader); + bottomPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN)); + canvas.drawRect(0,2*(h/3),w,h,bottomPaint); + + return result; + } +} \ No newline at end of file diff --git a/android/java/org/chromium/chrome/browser/util/LocaleUtils.java b/android/java/org/chromium/chrome/browser/util/LocaleUtils.java new file mode 100644 index 00000000000..c67f854cff9 --- /dev/null +++ b/android/java/org/chromium/chrome/browser/util/LocaleUtils.java @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2020 The Brave Authors. All rights reserved. + * 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.chromium.chrome.browser.util; + +import java.util.List; +import java.util.Arrays; +import java.util.Locale; + +public class LocaleUtils { + public static String getCountryCode() { + Locale locale = Locale.getDefault(); + return locale.getCountry(); + } +} \ No newline at end of file diff --git a/android/java/org/chromium/chrome/browser/widget/tile/BraveTileWithTextView.java b/android/java/org/chromium/chrome/browser/widget/tile/BraveTileWithTextView.java new file mode 100644 index 00000000000..be1ee704010 --- /dev/null +++ b/android/java/org/chromium/chrome/browser/widget/tile/BraveTileWithTextView.java @@ -0,0 +1,47 @@ +/* Copyright (c) 2020 The Brave Authors. All rights reserved. + * 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.chromium.chrome.browser.widget.tile; + +import android.os.Build; +import android.content.Context; +import android.util.AttributeSet; +import android.widget.TextView; +import android.content.SharedPreferences; + +import org.chromium.chrome.R; +import org.chromium.base.ContextUtils; +import org.chromium.chrome.browser.ntp.sponsored.SponsoredImageUtil; +import org.chromium.chrome.browser.BraveRewardsHelper; +import org.chromium.chrome.browser.ChromeTabbedActivity; +import org.chromium.chrome.browser.tabmodel.TabModel; +import org.chromium.chrome.browser.settings.BackgroundImagesPreferences; + +public class BraveTileWithTextView extends TileWithTextView { + public BraveTileWithTextView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public void setTitle(String title, int titleLines) { + + super.setTitle(title, titleLines); + + TextView mTitleView = findViewById(R.id.tile_view_title); + + SharedPreferences mSharedPreferences = ContextUtils.getAppSharedPreferences(); + boolean isMoreTabs = false; + ChromeTabbedActivity chromeTabbedActivity = BraveRewardsHelper.getChromeTabbedActivity(); + if(chromeTabbedActivity != null) { + TabModel tabModel = chromeTabbedActivity.getCurrentTabModel(); + isMoreTabs = tabModel.getCount() >= SponsoredImageUtil.MAX_TABS ? true : false; + } + + if(mSharedPreferences.getBoolean(BackgroundImagesPreferences.PREF_SHOW_BACKGROUND_IMAGES, true) + && (Build.VERSION.SDK_INT > Build.VERSION_CODES.M || (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !isMoreTabs))) { + mTitleView.setTextColor(getResources().getColor(android.R.color.white)); + } + } +} \ No newline at end of file diff --git a/android/java/proguard.flags b/android/java/proguard.flags index 7f7c47fd8ae..4440300382d 100644 --- a/android/java/proguard.flags +++ b/android/java/proguard.flags @@ -9,3 +9,5 @@ ; } -keepattributes JavascriptInterface + +-keep class android.support.design.widget.BottomSheetBehavior { *; } diff --git a/android/java/res/drawable-hdpi/coins.png b/android/java/res/drawable-hdpi/coins.png new file mode 100644 index 00000000000..933a0143a28 Binary files /dev/null and b/android/java/res/drawable-hdpi/coins.png differ diff --git a/android/java/res/drawable-mdpi/coins.png b/android/java/res/drawable-mdpi/coins.png new file mode 100644 index 00000000000..6e9ce6a11e0 Binary files /dev/null and b/android/java/res/drawable-mdpi/coins.png differ diff --git a/android/java/res/drawable-xhdpi/coins.png b/android/java/res/drawable-xhdpi/coins.png new file mode 100644 index 00000000000..bfc0eb46b93 Binary files /dev/null and b/android/java/res/drawable-xhdpi/coins.png differ diff --git a/android/java/res/drawable-xxhdpi/coins.png b/android/java/res/drawable-xxhdpi/coins.png new file mode 100644 index 00000000000..0d776aba25d Binary files /dev/null and b/android/java/res/drawable-xxhdpi/coins.png differ diff --git a/android/java/res/drawable-xxxhdpi/coins.png b/android/java/res/drawable-xxxhdpi/coins.png new file mode 100644 index 00000000000..be51d3580f9 Binary files /dev/null and b/android/java/res/drawable-xxxhdpi/coins.png differ diff --git a/android/java/res/drawable/blue_rounded_button.xml b/android/java/res/drawable/blue_rounded_button.xml new file mode 100644 index 00000000000..20d22201141 --- /dev/null +++ b/android/java/res/drawable/blue_rounded_button.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/android/java/res/drawable/image_credit_rounded_shape.xml b/android/java/res/drawable/image_credit_rounded_shape.xml new file mode 100644 index 00000000000..bc93cf1b7ee --- /dev/null +++ b/android/java/res/drawable/image_credit_rounded_shape.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/android/java/res/layout/new_tab_page_layout.xml b/android/java/res/layout/new_tab_page_layout.xml new file mode 100644 index 00000000000..c027e6d869b --- /dev/null +++ b/android/java/res/layout/new_tab_page_layout.xml @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/java/res/layout/ntp_bottom_sheet.xml b/android/java/res/layout/ntp_bottom_sheet.xml new file mode 100644 index 00000000000..1d267593d6b --- /dev/null +++ b/android/java/res/layout/ntp_bottom_sheet.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + +