| // Copyright 2013 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.text.Spannable; |
| import android.text.SpannableString; |
| import android.text.SpannableStringBuilder; |
| import android.text.TextUtils; |
| import android.text.style.ClickableSpan; |
| import android.view.LayoutInflater; |
| import android.view.View; |
| import android.widget.Button; |
| import android.widget.CheckBox; |
| |
| import org.chromium.base.CalledByNative; |
| import org.chromium.chrome.browser.infobar.ContentWrapperView; |
| import org.chromium.chrome.browser.infobar.InfoBar; |
| import org.chromium.chrome.browser.infobar.InfoBarLayout; |
| import org.chromium.chrome.browser.infobar.TwoButtonInfoBar; |
| import org.chromium.content.browser.DeviceUtils; |
| import org.chromium.chrome.R; |
| |
| /** |
| * Java version of the translate infobar |
| */ |
| public class TranslateInfoBar extends TwoButtonInfoBar implements SubPanelListener { |
| private static String LOG_TAG = "TranslateInfoBar"; |
| |
| // Needs to be kept in sync with the Type enum in translate_infobar_delegate.h. |
| public static final int BEFORE_TRANSLATE_INFOBAR = 0; |
| public static final int TRANSLATING_INFOBAR = 1; |
| public static final int AFTER_TRANSLATE_INFOBAR = 2; |
| public static final int TRANSLATE_ERROR_INFOBAR = 3; |
| public static final int MAX_INFOBAR_INDEX = 4; |
| |
| // Defines what subpanel needs to be shown, if any |
| public static final int NO_PANEL = 0; |
| public static final int LANGUAGE_PANEL = 1; |
| public static final int NEVER_PANEL = 2; |
| public static final int ALWAYS_PANEL = 3; |
| public static final int MAX_PANEL_INDEX = 4; |
| |
| private int mInfoBarType; |
| private TranslateOptions mOptions; |
| private int mOptionsPanelViewType; |
| private TranslateSubPanel mSubPanel; |
| private final boolean mShouldShowNeverBar; |
| private final TranslateInfoBarDelegate mTranslateDelegate; |
| |
| public TranslateInfoBar(int nativeInfoBarPtr, TranslateInfoBarDelegate delegate, |
| int infoBarType, int sourceLanguageIndex, int targetLanguageIndex, |
| boolean autoTranslatePair, boolean shouldShowNeverBar, String[] languages) { |
| super(null, BACKGROUND_TYPE_INFO, |
| R.drawable.infobar_translate); |
| mTranslateDelegate = delegate; |
| mOptions = new TranslateOptions(sourceLanguageIndex, targetLanguageIndex, languages, |
| autoTranslatePair); |
| mInfoBarType = infoBarType; |
| mShouldShowNeverBar = shouldShowNeverBar; |
| mOptionsPanelViewType = NO_PANEL; |
| setNativeInfoBar(nativeInfoBarPtr); |
| } |
| |
| @Override |
| public void onCloseButtonClicked() { |
| if (getInfoBarType() == BEFORE_TRANSLATE_INFOBAR && mOptionsPanelViewType == NO_PANEL) { |
| // Make it behave exactly as the Nope Button. |
| onButtonClicked(false); |
| } else { |
| nativeOnCloseButtonClicked(mNativeInfoBarPtr); |
| } |
| } |
| |
| @Override |
| public void onButtonClicked(boolean isPrimaryButton) { |
| if (mSubPanel != null) { |
| mSubPanel.onButtonClicked(isPrimaryButton); |
| return; |
| } |
| |
| int action = actionFor(isPrimaryButton); |
| |
| if (getInfoBarType() == BEFORE_TRANSLATE_INFOBAR && mOptionsPanelViewType == NO_PANEL |
| && action == ACTION_TYPE_CANCEL && needsNeverPanel()) { |
| // "Nope" was clicked and instead of dismissing we need to show |
| // the extra never panel. |
| swapPanel(NEVER_PANEL); |
| } else { |
| onTranslateInfoBarButtonClicked(action); |
| } |
| } |
| |
| /** |
| * Based on the infobar and the button pressed figure out what action needs to happen. |
| */ |
| private int actionFor(boolean isPrimaryButton) { |
| int action = InfoBar.ACTION_TYPE_NONE; |
| int infobarType = getInfoBarType(); |
| switch (infobarType) { |
| case TranslateInfoBar.BEFORE_TRANSLATE_INFOBAR: |
| action = isPrimaryButton |
| ? InfoBar.ACTION_TYPE_TRANSLATE : InfoBar.ACTION_TYPE_CANCEL; |
| break; |
| case TranslateInfoBar.AFTER_TRANSLATE_INFOBAR: |
| if (!isPrimaryButton) { |
| action = InfoBar.ACTION_TYPE_TRANSLATE_SHOW_ORIGINAL; |
| } |
| break; |
| case TranslateInfoBar.TRANSLATE_ERROR_INFOBAR: |
| // retry |
| action = InfoBar.ACTION_TYPE_TRANSLATE; |
| break; |
| default: |
| break; |
| } |
| return action; |
| } |
| |
| @Override |
| public CharSequence getMessageText(Context context) { |
| switch (getInfoBarType()) { |
| case BEFORE_TRANSLATE_INFOBAR: |
| String template = context.getString(R.string.translate_infobar_text); |
| return formatBeforeInfoBarMessage(template, mOptions.sourceLanguage(), |
| mOptions.targetLanguage(), LANGUAGE_PANEL); |
| case AFTER_TRANSLATE_INFOBAR: |
| String translated = context.getString( |
| R.string.translate_infobar_translation_done, mOptions.targetLanguage()); |
| if (needsAlwaysPanel()) { |
| String moreOptions = context.getString( |
| R.string.translate_infobar_translation_more_options); |
| return formatAfterTranslateInfoBarMessage(translated, moreOptions, |
| ALWAYS_PANEL); |
| } else { |
| return translated; |
| } |
| case TRANSLATING_INFOBAR: |
| return context.getString(R.string.translate_infobar_translating, |
| mOptions.targetLanguage()); |
| default: |
| return context.getString(R.string.translate_infobar_error); |
| } |
| } |
| |
| @Override |
| public String getPrimaryButtonText(Context context) { |
| switch (getInfoBarType()) { |
| case BEFORE_TRANSLATE_INFOBAR: |
| return context.getString(R.string.translate_button); |
| case AFTER_TRANSLATE_INFOBAR: |
| if (!needsAlwaysPanel()) { |
| return context.getString(R.string.translate_button_done); |
| } |
| return null; |
| case TRANSLATE_ERROR_INFOBAR: |
| return context.getString(R.string.translate_retry); |
| default: |
| return null; // no inner buttons on the remaining infobars |
| } |
| } |
| |
| @Override |
| public String getSecondaryButtonText(Context context) { |
| switch (getInfoBarType()) { |
| case BEFORE_TRANSLATE_INFOBAR: |
| return context.getString(R.string.translate_nope); |
| case AFTER_TRANSLATE_INFOBAR: |
| if (!needsAlwaysPanel()) { |
| return context.getString(R.string.translate_show_original); |
| } |
| return null; |
| default: |
| return null; |
| } |
| } |
| |
| @Override |
| public void createContent(InfoBarLayout layout) { |
| if (mOptionsPanelViewType == NO_PANEL) { |
| mSubPanel = null; |
| } else { |
| mSubPanel = panelFor(mOptionsPanelViewType); |
| if (mSubPanel != null) { |
| mSubPanel.createContent(getContext(), layout); |
| } |
| return; |
| } |
| |
| if (getInfoBarType() == AFTER_TRANSLATE_INFOBAR && !needsAlwaysPanel()) { |
| // Long always translate version |
| TranslateCheckBox checkBox = new TranslateCheckBox(mOptions, this); |
| checkBox.createContent(getContext(), layout); |
| } |
| |
| super.createContent(layout); |
| } |
| |
| // SubPanelListener implementation |
| @Override |
| public void onPanelClosed(int action) { |
| setControlsEnabled(false); |
| if (mOptionsPanelViewType == LANGUAGE_PANEL) { |
| // Close the sub panel and show the infobar again. |
| mOptionsPanelViewType = NO_PANEL; |
| updateViewForCurrentState(createView()); |
| } else { |
| // Apply options and close the infobar. |
| onTranslateInfoBarButtonClicked(action); |
| } |
| } |
| |
| private void onTranslateInfoBarButtonClicked(int action) { |
| onOptionsChanged(); |
| |
| // We need to re-check if the pointer is null now because applying options (like never |
| // translate this site) can sometimes trigger closing the InfoBar. |
| if (mNativeInfoBarPtr == 0) return; |
| nativeOnButtonClicked(mNativeInfoBarPtr, action, ""); |
| } |
| |
| @Override |
| public void setControlsEnabled(boolean state) { |
| super.setControlsEnabled(state); |
| |
| // Handle the "Always Translate" checkbox. |
| ContentWrapperView wrapper = getContentWrapper(false); |
| if (wrapper != null) { |
| CheckBox checkBox = (CheckBox) wrapper.findViewById(R.id.infobar_extra_check); |
| if (checkBox != null) checkBox.setEnabled(state); |
| } |
| } |
| |
| @Override |
| public void onOptionsChanged() { |
| if (mNativeInfoBarPtr == 0) return; |
| |
| if (mOptions.optionsChanged()) { |
| mTranslateDelegate.applyTranslateOptions(mNativeInfoBarPtr, |
| mOptions.sourceLanguageIndex(), |
| mOptions.targetLanguageIndex(), |
| mOptions.alwaysTranslateLanguageState(), |
| mOptions.neverTranslateLanguageState(), |
| mOptions.neverTranslateDomainState()); |
| } |
| } |
| |
| private boolean needsNeverPanel() { |
| return (getInfoBarType() == TranslateInfoBar.BEFORE_TRANSLATE_INFOBAR |
| && mShouldShowNeverBar); |
| } |
| |
| private boolean needsAlwaysPanel() { |
| return (getInfoBarType() == TranslateInfoBar.AFTER_TRANSLATE_INFOBAR |
| && mOptions.alwaysTranslateLanguageState() && !DeviceUtils.isTablet(getContext())); |
| } |
| |
| /** |
| * @param newPanel id of the new panel to swap in. Use NO_PANEL to |
| * simply remove the current panel. |
| */ |
| private void swapPanel(int newPanel) { |
| assert (newPanel >= NO_PANEL && newPanel < MAX_PANEL_INDEX); |
| mOptionsPanelViewType = newPanel; |
| updateViewForCurrentState(createView()); |
| } |
| |
| /** |
| * @return a panel of the specified {@code type} |
| */ |
| private TranslateSubPanel panelFor(int type) { |
| assert (type >= NO_PANEL && type < MAX_PANEL_INDEX); |
| switch (type) { |
| case LANGUAGE_PANEL: |
| return new TranslateLanguagePanel(this, mOptions); |
| case NEVER_PANEL: |
| return new TranslateNeverPanel(this, mOptions); |
| case ALWAYS_PANEL: |
| return new TranslateAlwaysPanel(this, mOptions); |
| default: |
| return null; |
| } |
| } |
| |
| /** |
| * Swaps out the current view in the ContentViewWrapper. |
| */ |
| private void updateViewForCurrentState(View replacement) { |
| setControlsEnabled(false); |
| getInfoBarContainer().swapInfoBarViews(this, replacement); |
| } |
| |
| /** |
| * @return a formatted message with links to {@code panelId}. |
| */ |
| private CharSequence formatBeforeInfoBarMessage(String template, String sourceLanguage, |
| String targetLanguage, final int panelId) { |
| |
| SpannableString formattedSourceLanguage = new SpannableString(sourceLanguage); |
| formattedSourceLanguage.setSpan(new ClickableSpan() { |
| @Override |
| public void onClick(View view) { |
| swapPanel(panelId); |
| } |
| }, 0, sourceLanguage.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
| |
| SpannableString formattedTargetLanguage = new SpannableString(targetLanguage); |
| formattedTargetLanguage.setSpan(new ClickableSpan() { |
| @Override |
| public void onClick(View view) { |
| swapPanel(panelId); |
| } |
| }, 0, targetLanguage.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
| |
| return TextUtils.expandTemplate(template, formattedSourceLanguage, formattedTargetLanguage); |
| } |
| |
| /** |
| * @return a formatted message with a link to {@code panelId} |
| */ |
| private CharSequence formatAfterTranslateInfoBarMessage(String statement, String linkText, |
| final int panelId) { |
| SpannableStringBuilder result = new SpannableStringBuilder(); |
| result.append(statement).append(" "); |
| SpannableString formattedChange = new SpannableString(linkText); |
| formattedChange.setSpan(new ClickableSpan() { |
| @Override |
| public void onClick(View view) { |
| swapPanel(panelId); |
| } |
| }, 0, linkText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
| result.append(formattedChange); |
| return result; |
| } |
| |
| int getInfoBarType() { |
| return mInfoBarType; |
| } |
| |
| void changeInfoBarTypeAndNativePointer(int infoBarType, int newNativePointer) { |
| if (infoBarType >= 0 && infoBarType < MAX_INFOBAR_INDEX) { |
| mInfoBarType = infoBarType; |
| replaceNativePointer(newNativePointer); |
| updateViewForCurrentState(createView()); |
| } else { |
| assert false : "Trying to change the InfoBar to a type that is invalid."; |
| } |
| } |
| } |