Commit efb88656 authored by Tommy Martino's avatar Tommy Martino Committed by Commit Bot

Cryptids: Injecting view into NTP logo space

This adds a GIF view that will eventually be used for cryptid rendering.

The general approach is:
* The existing logo is wrapped in a FrameLayout with a new ViewStub.
* When we get a callback indicating that no doodle is present, the NTP
  requests a drawable from the PCR and injects it into an ImageView
  inflated from the ViewStub.

Out-of-scope for this CL is to actually populate the GIF image data; I
have been testing locally with a res/raw file read into a byte array.

Change-Id: Ib5deae5322856c9d8e8a68f0fd46cdb2aaadbe79
Bug: 1061949
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2245888Reviewed-by: default avatarTheresa  <twellington@chromium.org>
Reviewed-by: default avatarsebsg <sebsg@chromium.org>
Commit-Queue: Tommy Martino <tmartino@chromium.org>
Cr-Commit-Position: refs/heads/master@{#790226}
parent 339e6581
...@@ -939,6 +939,7 @@ chrome_java_resources = [ ...@@ -939,6 +939,7 @@ chrome_java_resources = [
"java/res/layout/navigation_popup_item.xml", "java/res/layout/navigation_popup_item.xml",
"java/res/layout/navigation_sheet.xml", "java/res/layout/navigation_sheet.xml",
"java/res/layout/navigation_sheet_toolbar.xml", "java/res/layout/navigation_sheet_toolbar.xml",
"java/res/layout/new_tab_page_cryptid_holder.xml",
"java/res/layout/new_tab_page_incognito.xml", "java/res/layout/new_tab_page_incognito.xml",
"java/res/layout/new_tab_page_layout.xml", "java/res/layout/new_tab_page_layout.xml",
"java/res/layout/new_tab_page_offline_card.xml", "java/res/layout/new_tab_page_offline_card.xml",
......
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2020 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. -->
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@null" />
...@@ -16,15 +16,31 @@ ...@@ -16,15 +16,31 @@
android:visibility="gone" > android:visibility="gone" >
<!-- Search provider logo --> <!-- Search provider logo -->
<FrameLayout
android:id="@+id/logo_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ViewStub
android:id="@+id/cryptid_holder"
android:layout="@layout/new_tab_page_cryptid_holder"
android:layout_width="@dimen/cryptid_width_in_logo_wrapper"
android:layout_height="@dimen/cryptid_height_in_logo_wrapper"
android:layout_gravity="bottom|start" />
<org.chromium.chrome.browser.ntp.LogoView <org.chromium.chrome.browser.ntp.LogoView
android:id="@+id/search_provider_logo" android:id="@+id/search_provider_logo"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="@dimen/ntp_logo_height" android:layout_height="@dimen/ntp_logo_height"
android:layout_gravity="center_horizontal"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:layout_marginEnd="16dp" android:layout_marginEnd="16dp"
android:layout_marginTop="@dimen/ntp_logo_margin_top" android:layout_marginTop="@dimen/ntp_logo_margin_top"
android:layout_marginBottom="23dp" /> android:layout_marginBottom="23dp" />
</FrameLayout>
<!-- Search box --> <!-- Search box -->
<include layout="@layout/fake_search_box_layout"/> <include layout="@layout/fake_search_box_layout"/>
......
...@@ -361,6 +361,8 @@ ...@@ -361,6 +361,8 @@
<!-- This is in sp because we want the icon to scale with the TextView it sits alongside. --> <!-- This is in sp because we want the icon to scale with the TextView it sits alongside. -->
<dimen name="md_incognito_ntp_line_spacing">6sp</dimen> <dimen name="md_incognito_ntp_line_spacing">6sp</dimen>
<dimen name="md_incognito_ntp_padding_left">16dp</dimen> <dimen name="md_incognito_ntp_padding_left">16dp</dimen>
<dimen name="cryptid_height_in_logo_wrapper">60dp</dimen>
<dimen name="cryptid_width_in_logo_wrapper">90dp</dimen>
<!-- NTP Feed dimensions --> <!-- NTP Feed dimensions -->
<dimen name="feed_header_menu_max_width">225dp</dimen> <dimen name="feed_header_menu_max_width">225dp</dimen>
......
...@@ -4,8 +4,12 @@ ...@@ -4,8 +4,12 @@
package org.chromium.chrome.browser.cryptids; package org.chromium.chrome.browser.cryptids;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import org.chromium.base.Callback;
import org.chromium.base.Log; import org.chromium.base.Log;
import org.chromium.chrome.browser.enterprise.util.ManagedBrowserUtils; import org.chromium.chrome.browser.enterprise.util.ManagedBrowserUtils;
import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeFeatureList;
...@@ -13,6 +17,9 @@ import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; ...@@ -13,6 +17,9 @@ import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
import org.chromium.chrome.browser.preferences.SharedPreferencesManager; import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.profiles.Profile;
import jp.tomorrowkey.android.gifplayer.BaseGifDrawable;
import jp.tomorrowkey.android.gifplayer.BaseGifImage;
/** /**
* Allows for cryptids to be displayed on the New Tab Page under certain probabilistic conditions. * Allows for cryptids to be displayed on the New Tab Page under certain probabilistic conditions.
*/ */
...@@ -31,6 +38,12 @@ public class ProbabilisticCryptidRenderer { ...@@ -31,6 +38,12 @@ public class ProbabilisticCryptidRenderer {
private static final String TAG = "ProbabilisticCryptid"; private static final String TAG = "ProbabilisticCryptid";
private static ProbabilisticCryptidRenderer sInstance = new ProbabilisticCryptidRenderer();
public static ProbabilisticCryptidRenderer getInstance() {
return sInstance;
}
/** /**
* Determines whether cryptid should be rendered on this NTP instance, based on probability * Determines whether cryptid should be rendered on this NTP instance, based on probability
* factors as well as certain restrictions (managed non-null profile, incognito, or disabled * factors as well as certain restrictions (managed non-null profile, incognito, or disabled
...@@ -56,6 +69,28 @@ public class ProbabilisticCryptidRenderer { ...@@ -56,6 +69,28 @@ public class ProbabilisticCryptidRenderer {
recordRenderEvent(System.currentTimeMillis()); recordRenderEvent(System.currentTimeMillis());
} }
/**
* Creates an ImageView which will render a cryptid, suitable for use in/around the space of the
* logo on the NTP.
* @param layout A callback which will insert this Drawable into an ImageView in the appropriate
* location. The callback should handle null Drawables, which will be passed if a cryptid is
* not available or shouldn't be used.
*/
public void getCryptidForLogo(Profile profile, Callback<Drawable> callback) {
if (!shouldUseCryptidRendering(profile)) {
callback.onResult(null);
return;
}
// TODO(crbug.com/1061949): Fetch an actual image, and have its callback handle the rest of
// the work.
BaseGifImage image = new BaseGifImage("".getBytes(), 0);
BaseGifDrawable drawable = new BaseGifDrawable(image, Bitmap.Config.ARGB_8888);
drawable.setLoopCount(1); // Plays only once/does not loop.
drawable.setAnimateOnLoad(true);
callback.onResult(drawable);
}
// Protected for testing // Protected for testing
protected long getLastRenderTimestampMillis() { protected long getLastRenderTimestampMillis() {
long lastRenderTimestamp = SharedPreferencesManager.getInstance().readLong( long lastRenderTimestamp = SharedPreferencesManager.getInstance().readLong(
......
...@@ -22,6 +22,7 @@ import android.widget.LinearLayout; ...@@ -22,6 +22,7 @@ import android.widget.LinearLayout;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import org.chromium.base.CallbackController;
import org.chromium.base.MathUtils; import org.chromium.base.MathUtils;
import org.chromium.base.TraceEvent; import org.chromium.base.TraceEvent;
import org.chromium.base.supplier.Supplier; import org.chromium.base.supplier.Supplier;
...@@ -29,6 +30,7 @@ import org.chromium.chrome.R; ...@@ -29,6 +30,7 @@ import org.chromium.chrome.R;
import org.chromium.chrome.browser.compositor.layouts.EmptyOverviewModeObserver; import org.chromium.chrome.browser.compositor.layouts.EmptyOverviewModeObserver;
import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior; import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
import org.chromium.chrome.browser.compositor.layouts.content.InvalidationAwareThumbnailProvider; import org.chromium.chrome.browser.compositor.layouts.content.InvalidationAwareThumbnailProvider;
import org.chromium.chrome.browser.cryptids.ProbabilisticCryptidRenderer;
import org.chromium.chrome.browser.download.DownloadOpenSource; import org.chromium.chrome.browser.download.DownloadOpenSource;
import org.chromium.chrome.browser.download.DownloadUtils; import org.chromium.chrome.browser.download.DownloadUtils;
import org.chromium.chrome.browser.explore_sites.ExperimentalExploreSitesSection; import org.chromium.chrome.browser.explore_sites.ExperimentalExploreSitesSection;
...@@ -79,6 +81,7 @@ public class NewTabPageLayout extends LinearLayout implements TileGroup.Observer ...@@ -79,6 +81,7 @@ public class NewTabPageLayout extends LinearLayout implements TileGroup.Observer
private View mTileGridPlaceholder; private View mTileGridPlaceholder;
private View mNoSearchLogoSpacer; private View mNoSearchLogoSpacer;
private QueryTileSection mQueryTileSection; private QueryTileSection mQueryTileSection;
private ImageView mCryptidHolder;
@Nullable @Nullable
private View mExploreSectionView; // View is null if explore flag is disabled. private View mExploreSectionView; // View is null if explore flag is disabled.
...@@ -93,6 +96,7 @@ public class NewTabPageLayout extends LinearLayout implements TileGroup.Observer ...@@ -93,6 +96,7 @@ public class NewTabPageLayout extends LinearLayout implements TileGroup.Observer
private TileGroup mTileGroup; private TileGroup mTileGroup;
private UiConfig mUiConfig; private UiConfig mUiConfig;
private Supplier<Tab> mTabProvider; private Supplier<Tab> mTabProvider;
private CallbackController mCallbackController = new CallbackController();
/** /**
* Whether the tiles shown in the layout have finished loading. * Whether the tiles shown in the layout have finished loading.
...@@ -509,7 +513,27 @@ public class NewTabPageLayout extends LinearLayout implements TileGroup.Observer ...@@ -509,7 +513,27 @@ public class NewTabPageLayout extends LinearLayout implements TileGroup.Observer
mSearchProviderLogoView.showSearchProviderInitialView(); mSearchProviderLogoView.showSearchProviderInitialView();
mLogoDelegate.getSearchProviderLogo((logo, fromCache) -> { mLogoDelegate.getSearchProviderLogo((logo, fromCache) -> {
if (logo == null && fromCache) return; if (logo == null) {
if (mSearchProviderIsGoogle) {
// We received a null logo and the provider is Google; this means there's no
// doodle.
ProbabilisticCryptidRenderer renderer =
ProbabilisticCryptidRenderer.getInstance();
renderer.getCryptidForLogo(Profile.getLastUsedRegularProfile(),
mCallbackController.makeCancelable((drawable) -> {
if (drawable == null || mCryptidHolder != null) {
return;
}
ViewStub stub = findViewById(R.id.logo_holder)
.findViewById(R.id.cryptid_holder);
ImageView view = (ImageView) stub.inflate();
view.setImageDrawable(drawable);
mCryptidHolder = view;
}));
}
if (fromCache) return;
}
mSearchProviderLogoView.setDelegate(mLogoDelegate); mSearchProviderLogoView.setDelegate(mLogoDelegate);
mSearchProviderLogoView.updateLogo(logo); mSearchProviderLogoView.updateLogo(logo);
...@@ -866,6 +890,11 @@ public class NewTabPageLayout extends LinearLayout implements TileGroup.Observer ...@@ -866,6 +890,11 @@ public class NewTabPageLayout extends LinearLayout implements TileGroup.Observer
} }
private void onDestroy() { private void onDestroy() {
if (mCallbackController != null) {
mCallbackController.destroy();
mCallbackController = null;
}
if (mExploreOfflineCard != null) mExploreOfflineCard.destroy(); if (mExploreOfflineCard != null) mExploreOfflineCard.destroy();
VrModuleProvider.unregisterVrModeObserver(this); VrModuleProvider.unregisterVrModeObserver(this);
// Need to null-check compositor view holder and layout manager since they might've // Need to null-check compositor view holder and layout manager since they might've
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment