1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.chrome.browser.infobar; 6 7 import android.content.Context; 8 import android.view.View; 9 10 import org.chromium.base.CalledByNative; 11 import org.chromium.base.VisibleForTesting; 12 import org.chromium.chrome.R; 13 14 /** 15 * The base class for all InfoBar classes. 16 * Note that infobars expire by default when a new navigation occurs. 17 * Make sure to use setExpireOnNavigation(false) if you want an infobar to be sticky. 18 */ 19 public abstract class InfoBar implements InfoBarView { 20 private static final String TAG = "InfoBar"; 21 22 /** 23 * Possible labels of all the infobar buttons. 24 * 25 * Make sure this set of values is aligned with the C++ correspondent in 26 * infobar_android.h 27 */ 28 public static final int ACTION_TYPE_NONE = 0; 29 30 // Confirm infobar 31 public static final int ACTION_TYPE_OK = 1; 32 public static final int ACTION_TYPE_CANCEL = 2; 33 34 // Translate infobar 35 public static final int ACTION_TYPE_TRANSLATE = 3; 36 public static final int ACTION_TYPE_TRANSLATE_SHOW_ORIGINAL = 4; 37 38 private final int mIconDrawableId; 39 private final CharSequence mMessage; 40 41 private InfoBarListeners.Dismiss mListener; 42 private ContentWrapperView mContentView; 43 private InfoBarContainer mContainer; 44 private Context mContext; 45 46 private boolean mExpireOnNavigation; 47 private boolean mIsDismissed; 48 private boolean mControlsEnabled; 49 50 // This cannot be private until the swap in place infrastructure is 51 // improved since subclasses need to access a possibly replaced native 52 // pointer. 53 protected long mNativeInfoBarPtr; 54 55 // Used by tests to reference infobars. 56 private final int mId; 57 private static int sIdCounter = 0; 58 private static int generateId() { 59 return sIdCounter++; 60 } 61 62 /** 63 * @param listener Listens to when buttons have been clicked on the InfoBar. 64 * @param iconDrawableId ID of the resource to use for the Icon. If 0, no icon will be shown. 65 * @param message The message to show in the infobar. 66 */ 67 public InfoBar(InfoBarListeners.Dismiss listener, int iconDrawableId, CharSequence message) { 68 mListener = listener; 69 mId = generateId(); 70 mIconDrawableId = iconDrawableId; 71 mMessage = message; 72 mExpireOnNavigation = true; 73 } 74 75 /** 76 * @return The message shown in the infobar, useful for accessibility. 77 */ 78 public CharSequence getMessage() { 79 return mMessage; 80 } 81 82 /** 83 * Stores a pointer to the native-side counterpart of this InfoBar. 84 * @param nativeInfoBarPtr Pointer to the NativeInfoBar. 85 */ 86 protected void setNativeInfoBar(long nativeInfoBarPtr) { 87 if (nativeInfoBarPtr != 0) { 88 // The native code takes care of expiring infobars on navigations. 89 mExpireOnNavigation = false; 90 mNativeInfoBarPtr = nativeInfoBarPtr; 91 } 92 } 93 94 /** 95 * Change the pointer to the native-side counterpart of this InfoBar. Native-side code is 96 * responsible for managing the cleanup of the pointer. 97 * @param newInfoBarPtr Pointer to the NativeInfoBar. 98 */ 99 protected void replaceNativePointer(long newInfoBarPtr) { 100 mNativeInfoBarPtr = newInfoBarPtr; 101 } 102 103 /** 104 * Determine if the infobar should be dismissed when a new page starts loading. Calling 105 * setExpireOnNavigation(true/false) causes this method always to return true/false. 106 * This only applies to java-only infobars. C++ infobars will use the same logic 107 * as other platforms so they are not attempted to be dismissed twice. 108 * It should really be removed once all infobars have a C++ counterpart. 109 */ 110 public final boolean shouldExpire() { 111 return mExpireOnNavigation && mNativeInfoBarPtr == 0; 112 } 113 114 // Sets whether the bar should be dismissed when a navigation occurs. 115 public void setExpireOnNavigation(boolean expireOnNavigation) { 116 mExpireOnNavigation = expireOnNavigation; 117 } 118 119 /** 120 * @return true if this java infobar owns this {@code nativePointer} 121 */ 122 boolean ownsNativeInfoBar(long nativePointer) { 123 return mNativeInfoBarPtr == nativePointer; 124 } 125 126 /** 127 * @return whether or not the InfoBar has been dismissed. 128 */ 129 protected boolean isDismissed() { 130 return mIsDismissed; 131 } 132 133 /** 134 * Sets the Context used when creating the InfoBar. 135 */ 136 protected void setContext(Context context) { 137 mContext = context; 138 } 139 140 /** 141 * @return The Context used to create the InfoBar. This will be null until the InfoBar is added 142 * to the InfoBarContainer, and should never be null afterward. 143 */ 144 protected Context getContext() { 145 return mContext; 146 } 147 148 /** 149 * Creates the View that represents the InfoBar. 150 * @return The View representing the InfoBar. 151 */ 152 protected final View createView() { 153 assert mContext != null; 154 155 InfoBarLayout layout = new InfoBarLayout(mContext, this, mIconDrawableId, mMessage); 156 createContent(layout); 157 return layout; 158 } 159 160 /** 161 * Used to close a java only infobar. 162 */ 163 public void dismissJavaOnlyInfoBar() { 164 assert mNativeInfoBarPtr == 0; 165 if (closeInfoBar() && mListener != null) { 166 mListener.onInfoBarDismissed(this); 167 } 168 } 169 170 /** 171 * @return whether the infobar actually needed closing. 172 */ 173 @CalledByNative 174 public boolean closeInfoBar() { 175 if (!mIsDismissed) { 176 mIsDismissed = true; 177 if (!mContainer.hasBeenDestroyed()) { 178 // If the container was destroyed, it's already been emptied of all its infobars. 179 mContainer.removeInfoBar(this); 180 } 181 return true; 182 } 183 return false; 184 } 185 186 protected ContentWrapperView getContentWrapper(boolean createIfNotFound) { 187 if (mContentView == null && createIfNotFound) { 188 mContentView = new ContentWrapperView(getContext(), this, createView()); 189 mContentView.setFocusable(false); 190 } 191 return mContentView; 192 } 193 194 protected InfoBarContainer getInfoBarContainer() { 195 return mContainer; 196 } 197 198 /** 199 * @return The content view for the info bar. 200 */ 201 @VisibleForTesting 202 public ContentWrapperView getContentWrapper() { 203 return getContentWrapper(true); 204 } 205 206 void setInfoBarContainer(InfoBarContainer container) { 207 mContainer = container; 208 } 209 210 public boolean areControlsEnabled() { 211 return mControlsEnabled; 212 } 213 214 @Override 215 public void setControlsEnabled(boolean state) { 216 mControlsEnabled = state; 217 218 // Disable all buttons on the infobar. 219 if (mContentView != null) { 220 View closeButton = mContentView.findViewById(R.id.infobar_close_button); 221 View primaryButton = mContentView.findViewById(R.id.button_primary); 222 View secondaryButton = mContentView.findViewById(R.id.button_secondary); 223 View tertiaryButton = mContentView.findViewById(R.id.button_tertiary); 224 if (closeButton != null) closeButton.setEnabled(state); 225 if (primaryButton != null) primaryButton.setEnabled(state); 226 if (secondaryButton != null) secondaryButton.setEnabled(state); 227 if (tertiaryButton != null) tertiaryButton.setEnabled(state); 228 } 229 } 230 231 @Override 232 public void onButtonClicked(boolean isPrimaryButton) { 233 } 234 235 @Override 236 public void onLinkClicked() { 237 if (mNativeInfoBarPtr != 0) { 238 nativeOnLinkClicked(mNativeInfoBarPtr); 239 } 240 } 241 242 @Override 243 public void createContent(InfoBarLayout layout) { 244 } 245 246 /** 247 * Returns the id of the tab this infobar is showing into. 248 */ 249 public int getTabId() { 250 return mContainer.getTabId(); 251 } 252 253 @VisibleForTesting 254 public int getId() { 255 return mId; 256 } 257 258 @VisibleForTesting 259 public void setDismissedListener(InfoBarListeners.Dismiss listener) { 260 mListener = listener; 261 } 262 263 protected native void nativeOnLinkClicked(long nativeInfoBarAndroid); 264 protected native void nativeOnButtonClicked( 265 long nativeInfoBarAndroid, int action, String actionValue); 266 protected native void nativeOnCloseButtonClicked(long nativeInfoBarAndroid); 267 } 268