blob: a646f1164f10968b85cca8bc8837618525cbb7ee [file] [log] [blame]
// Copyright 2018 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.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import android.support.graphics.drawable.Animatable2Compat;
import android.support.graphics.drawable.AnimatedVectorDrawableCompat;
import android.support.graphics.drawable.VectorDrawableCompat;
import android.support.v4.view.ViewCompat;
import android.view.View;
import android.widget.TextView;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.task.PostTask;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.download.DownloadInfoBarController;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.components.offline_items_collection.ContentId;
import org.chromium.content_public.browser.UiThreadTaskTraits;
/**
* An {@link InfoBar} to provide information about currently running downloads.
*/
public class DownloadProgressInfoBar extends InfoBar {
/**
* Represents the client of this InfoBar. Provides hooks to take actions on various UI events
* associated with the InfoBar.
*/
public interface Client {
/**
* Called when a link is clicked by the user.
* @param itemId The ContentId of the item currently being shown in the InfoBar.
*/
void onLinkClicked(@Nullable ContentId itemId);
/**
* Called when the InfoBar is closed either implicitly or explicitly by the user.
* @param explicitly Whether the InfoBar was closed explicitly by the user from close
* button.
*/
void onInfoBarClosed(boolean explicitly);
}
private final Client mClient;
private AnimatedVectorDrawableCompat mAnimatedDrawable;
private DownloadInfoBarController.DownloadProgressInfoBarData mInfo;
// Indicates whether there is a pending layout update waiting for the currently running
// animation to finish.
private boolean mUpdatePending;
private DownloadProgressInfoBar(
Client client, DownloadInfoBarController.DownloadProgressInfoBarData info) {
super(info.icon, null, null);
mInfo = info;
mClient = client;
}
@Override
protected boolean usesCompactLayout() {
return false;
}
@Override
public void createContent(InfoBarLayout layout) {
setLayoutProperties(layout, mInfo);
}
@Override
public boolean isBottomMostInfoBar() {
return true;
}
@Override
public void onCloseButtonClicked() {
mClient.onInfoBarClosed(true);
super.onCloseButtonClicked();
}
@Override
public void onLinkClicked() {
mClient.onLinkClicked(mInfo.id);
}
/**
* @return The tab associated with this infobar.
*/
public Tab getTab() {
return getNativeInfoBarPtr() == 0 ? null : nativeGetTab(getNativeInfoBarPtr());
}
/**
* Updates the infobar layout with the given data. If the infobar icon is already showing an
* animation, it will wait for the currently animation to finish before showing the new data.
*/
private void setLayoutProperties(
InfoBarLayout layout, DownloadInfoBarController.DownloadProgressInfoBarData info) {
mInfo = info;
if (mAnimatedDrawable != null && mAnimatedDrawable.isRunning()) {
// Wait for the current animation to finish.
mUpdatePending = true;
} else {
updateLayout(layout);
}
}
/**
* Populates the infobar layout with the given information and handles the icon animation. Note
* that the icon can be specified as a static image or an animated image. The animation can be
* specified to be once-only or repeating.
*/
private void updateLayout(InfoBarLayout layout) {
layout.setMessage(mInfo.message);
layout.appendMessageLinkText(mInfo.link);
TextView messageView =
(TextView) layout.getMessageLayout().findViewById(R.id.infobar_message);
messageView.setContentDescription(mInfo.accessibilityMessage);
ViewCompat.setAccessibilityLiveRegion(messageView, View.ACCESSIBILITY_LIVE_REGION_POLITE);
if (!mInfo.hasAnimation) {
if (mInfo.hasVectorDrawable) {
layout.getIcon().setImageDrawable(VectorDrawableCompat.create(
layout.getResources(), mInfo.icon, layout.getContext().getTheme()));
} else {
layout.getIcon().setImageResource(mInfo.icon);
}
return;
}
mAnimatedDrawable = AnimatedVectorDrawableCompat.create(getContext(), mInfo.icon);
mAnimatedDrawable.registerAnimationCallback(new Animatable2Compat.AnimationCallback() {
@Override
public void onAnimationEnd(Drawable drawable) {
if (mUpdatePending) {
mUpdatePending = false;
updateLayout(layout);
return;
}
if (mInfo.dontRepeat) return;
restartIconAnimation();
}
});
layout.getIcon().setImageDrawable(mAnimatedDrawable);
mAnimatedDrawable.start();
}
private void restartIconAnimation() {
PostTask.postTask(UiThreadTaskTraits.DEFAULT, () -> {
if (mAnimatedDrawable == null) return;
mAnimatedDrawable.start();
});
}
/**
* Updates an existing {@link DownloadProgressInfoBar} with the new information.
* @param info The information to be updated on the UI.
*/
public void updateInfoBar(DownloadInfoBarController.DownloadProgressInfoBarData info) {
if (getView() == null) return;
mInfo = info;
setLayoutProperties((InfoBarLayout) getView(), info);
}
@Override
public CharSequence getAccessibilityText() {
return null;
}
/**
* Creates and shows the {@link DownloadProgressInfoBar}.
* @param tab The tab that the {@link DownloadProgressInfoBar} should be shown in.
*/
public static void createInfoBar(
Client client, Tab tab, DownloadInfoBarController.DownloadProgressInfoBarData info) {
nativeCreate(client, tab, info);
}
/**
* Closes the {@link DownloadProgressInfoBar}.
*/
public void closeInfoBar() {
mClient.onInfoBarClosed(false);
super.onCloseButtonClicked();
}
@CalledByNative
private static DownloadProgressInfoBar create(
Client client, DownloadInfoBarController.DownloadProgressInfoBarData info) {
return new DownloadProgressInfoBar(client, info);
}
private static native void nativeCreate(
Client client, Tab tab, DownloadInfoBarController.DownloadProgressInfoBarData info);
private native Tab nativeGetTab(long nativeDownloadProgressInfoBar);
}