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 = [
"java/res/layout/navigation_popup_item.xml",
"java/res/layout/navigation_sheet.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_layout.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 @@
android:visibility="gone" >
<!-- Search provider logo -->
<org.chromium.chrome.browser.ntp.LogoView
android:id="@+id/search_provider_logo"
android:layout_width="wrap_content"
android:layout_height="@dimen/ntp_logo_height"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="@dimen/ntp_logo_margin_top"
android:layout_marginBottom="23dp" />
<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
android:id="@+id/search_provider_logo"
android:layout_width="wrap_content"
android:layout_height="@dimen/ntp_logo_height"
android:layout_gravity="center_horizontal"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="@dimen/ntp_logo_margin_top"
android:layout_marginBottom="23dp" />
</FrameLayout>
<!-- Search box -->
<include layout="@layout/fake_search_box_layout"/>
......
......@@ -361,6 +361,8 @@
<!-- 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_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 -->
<dimen name="feed_header_menu_max_width">225dp</dimen>
......
......@@ -4,8 +4,12 @@
package org.chromium.chrome.browser.cryptids;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.Callback;
import org.chromium.base.Log;
import org.chromium.chrome.browser.enterprise.util.ManagedBrowserUtils;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
......@@ -13,6 +17,9 @@ import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
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.
*/
......@@ -31,6 +38,12 @@ public class ProbabilisticCryptidRenderer {
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
* factors as well as certain restrictions (managed non-null profile, incognito, or disabled
......@@ -56,6 +69,28 @@ public class ProbabilisticCryptidRenderer {
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 long getLastRenderTimestampMillis() {
long lastRenderTimestamp = SharedPreferencesManager.getInstance().readLong(
......
......@@ -22,6 +22,7 @@ import android.widget.LinearLayout;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.CallbackController;
import org.chromium.base.MathUtils;
import org.chromium.base.TraceEvent;
import org.chromium.base.supplier.Supplier;
......@@ -29,6 +30,7 @@ import org.chromium.chrome.R;
import org.chromium.chrome.browser.compositor.layouts.EmptyOverviewModeObserver;
import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
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.DownloadUtils;
import org.chromium.chrome.browser.explore_sites.ExperimentalExploreSitesSection;
......@@ -79,6 +81,7 @@ public class NewTabPageLayout extends LinearLayout implements TileGroup.Observer
private View mTileGridPlaceholder;
private View mNoSearchLogoSpacer;
private QueryTileSection mQueryTileSection;
private ImageView mCryptidHolder;
@Nullable
private View mExploreSectionView; // View is null if explore flag is disabled.
......@@ -93,6 +96,7 @@ public class NewTabPageLayout extends LinearLayout implements TileGroup.Observer
private TileGroup mTileGroup;
private UiConfig mUiConfig;
private Supplier<Tab> mTabProvider;
private CallbackController mCallbackController = new CallbackController();
/**
* Whether the tiles shown in the layout have finished loading.
......@@ -509,7 +513,27 @@ public class NewTabPageLayout extends LinearLayout implements TileGroup.Observer
mSearchProviderLogoView.showSearchProviderInitialView();
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.updateLogo(logo);
......@@ -866,6 +890,11 @@ public class NewTabPageLayout extends LinearLayout implements TileGroup.Observer
}
private void onDestroy() {
if (mCallbackController != null) {
mCallbackController.destroy();
mCallbackController = null;
}
if (mExploreOfflineCard != null) mExploreOfflineCard.destroy();
VrModuleProvider.unregisterVrModeObserver(this);
// 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