mobile/android/base/toolbar/BrowserToolbar.java

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 package org.mozilla.gecko.toolbar;
     8 import java.util.ArrayList;
     9 import java.util.Arrays;
    10 import java.util.EnumSet;
    11 import java.util.List;
    13 import org.json.JSONObject;
    14 import org.mozilla.gecko.BrowserApp;
    15 import org.mozilla.gecko.GeckoAppShell;
    16 import org.mozilla.gecko.GeckoApplication;
    17 import org.mozilla.gecko.GeckoProfile;
    18 import org.mozilla.gecko.LightweightTheme;
    19 import org.mozilla.gecko.R;
    20 import org.mozilla.gecko.Tab;
    21 import org.mozilla.gecko.Tabs;
    22 import org.mozilla.gecko.Telemetry;
    23 import org.mozilla.gecko.TelemetryContract;
    24 import org.mozilla.gecko.animation.PropertyAnimator;
    25 import org.mozilla.gecko.animation.PropertyAnimator.PropertyAnimationListener;
    26 import org.mozilla.gecko.animation.ViewHelper;
    27 import org.mozilla.gecko.menu.GeckoMenu;
    28 import org.mozilla.gecko.menu.MenuPopup;
    29 import org.mozilla.gecko.toolbar.ToolbarDisplayLayout.OnStopListener;
    30 import org.mozilla.gecko.toolbar.ToolbarDisplayLayout.OnTitleChangeListener;
    31 import org.mozilla.gecko.toolbar.ToolbarDisplayLayout.UpdateFlags;
    32 import org.mozilla.gecko.util.Clipboard;
    33 import org.mozilla.gecko.util.GeckoEventListener;
    34 import org.mozilla.gecko.util.HardwareUtils;
    35 import org.mozilla.gecko.util.MenuUtils;
    36 import org.mozilla.gecko.widget.ThemedImageButton;
    37 import org.mozilla.gecko.widget.ThemedImageView;
    38 import org.mozilla.gecko.widget.ThemedRelativeLayout;
    40 import android.content.Context;
    41 import android.content.res.Resources;
    42 import android.graphics.Bitmap;
    43 import android.graphics.drawable.BitmapDrawable;
    44 import android.graphics.drawable.Drawable;
    45 import android.graphics.drawable.StateListDrawable;
    46 import android.os.Build;
    47 import android.text.TextUtils;
    48 import android.util.AttributeSet;
    49 import android.util.Log;
    50 import android.view.ContextMenu;
    51 import android.view.KeyEvent;
    52 import android.view.LayoutInflater;
    53 import android.view.MenuInflater;
    54 import android.view.MotionEvent;
    55 import android.view.View;
    56 import android.view.ViewGroup;
    57 import android.view.animation.AccelerateInterpolator;
    58 import android.view.animation.Interpolator;
    59 import android.view.inputmethod.InputMethodManager;
    60 import android.widget.Button;
    61 import android.widget.ImageButton;
    62 import android.widget.ImageView;
    63 import android.widget.LinearLayout;
    64 import android.widget.PopupWindow;
    65 import android.widget.RelativeLayout;
    67 /**
    68 * {@code BrowserToolbar} is single entry point for users of the toolbar
    69 * subsystem i.e. this should be the only import outside the 'toolbar'
    70 * package.
    71 *
    72 * {@code BrowserToolbar} serves at the single event bus for all
    73 * sub-components in the toolbar. It tracks tab events and gecko messages
    74 * and update the state of its inner components accordingly.
    75 *
    76 * It has two states, display and edit, which are controlled by
    77 * ToolbarEditLayout and ToolbarDisplayLayout. In display state, the toolbar
    78 * displays the current state for the selected tab. In edit state, it shows
    79 * a text entry for searching bookmarks/history. {@code BrowserToolbar}
    80 * provides public API to enter, cancel, and commit the edit state as well
    81 * as a set of listeners to allow {@code BrowserToolbar} users to react
    82 * to state changes accordingly.
    83 */
    84 public class BrowserToolbar extends ThemedRelativeLayout
    85                             implements Tabs.OnTabsChangedListener,
    86                                        GeckoMenu.ActionItemBarPresenter,
    87                                        GeckoEventListener {
    88     private static final String LOGTAG = "GeckoToolbar";
    90     public interface OnActivateListener {
    91         public void onActivate();
    92     }
    94     public interface OnCommitListener {
    95         public void onCommit();
    96     }
    98     public interface OnDismissListener {
    99         public void onDismiss();
   100     }
   102     public interface OnFilterListener {
   103         public void onFilter(String searchText, AutocompleteHandler handler);
   104     }
   106     public interface OnStartEditingListener {
   107         public void onStartEditing();
   108     }
   110     public interface OnStopEditingListener {
   111         public void onStopEditing();
   112     }
   114     private enum UIMode {
   115         EDIT,
   116         DISPLAY
   117     }
   119     enum ForwardButtonAnimation {
   120         SHOW,
   121         HIDE
   122     }
   124     private ToolbarDisplayLayout urlDisplayLayout;
   125     private ToolbarEditLayout urlEditLayout;
   126     private View urlBarEntry;
   127     private RelativeLayout.LayoutParams urlBarEntryDefaultLayoutParams;
   128     private RelativeLayout.LayoutParams urlBarEntryShrunkenLayoutParams;
   129     private ImageView urlBarTranslatingEdge;
   130     private boolean isSwitchingTabs;
   131     private ShapedButton tabsButton;
   132     private ImageButton backButton;
   133     private ImageButton forwardButton;
   135     private ToolbarProgressView progressBar;
   136     private TabCounter tabsCounter;
   137     private ThemedImageButton menuButton;
   138     private ThemedImageView menuIcon;
   139     private LinearLayout actionItemBar;
   140     private MenuPopup menuPopup;
   141     private List<View> focusOrder;
   143     private final ThemedImageView editCancel;
   145     private boolean shouldShrinkURLBar = false;
   147     private OnActivateListener activateListener;
   148     private OnFocusChangeListener focusChangeListener;
   149     private OnStartEditingListener startEditingListener;
   150     private OnStopEditingListener stopEditingListener;
   152     private final BrowserApp activity;
   153     private boolean hasSoftMenuButton;
   155     private UIMode uiMode;
   156     private boolean isAnimatingEntry;
   158     private int urlBarViewOffset;
   159     private int defaultForwardMargin;
   161     private static final Interpolator buttonsInterpolator = new AccelerateInterpolator();
   163     private static final int FORWARD_ANIMATION_DURATION = 450;
   165     private final LightweightTheme theme;
   167     public BrowserToolbar(Context context) {
   168         this(context, null);
   169     }
   171     public BrowserToolbar(Context context, AttributeSet attrs) {
   172         super(context, attrs);
   173         theme = ((GeckoApplication) context.getApplicationContext()).getLightweightTheme();
   175         // BrowserToolbar is attached to BrowserApp only.
   176         activity = (BrowserApp) context;
   178         // Inflate the content.
   179         LayoutInflater.from(context).inflate(R.layout.browser_toolbar, this);
   181         Tabs.registerOnTabsChangedListener(this);
   182         isSwitchingTabs = true;
   183         isAnimatingEntry = false;
   185         registerEventListener("Reader:Click");
   186         registerEventListener("Reader:LongClick");
   188         final Resources res = getResources();
   189         urlBarViewOffset = res.getDimensionPixelSize(R.dimen.url_bar_offset_left);
   190         defaultForwardMargin = res.getDimensionPixelSize(R.dimen.forward_default_offset);
   191         urlDisplayLayout = (ToolbarDisplayLayout) findViewById(R.id.display_layout);
   192         urlBarEntry = findViewById(R.id.url_bar_entry);
   193         urlEditLayout = (ToolbarEditLayout) findViewById(R.id.edit_layout);
   195         urlBarEntryDefaultLayoutParams = (RelativeLayout.LayoutParams) urlBarEntry.getLayoutParams();
   196         // API level 19 adds a RelativeLayout.LayoutParams copy constructor, so we explicitly cast
   197         // to ViewGroup.MarginLayoutParams to ensure consistency across platforms.
   198         urlBarEntryShrunkenLayoutParams = new RelativeLayout.LayoutParams(
   199                 (ViewGroup.MarginLayoutParams) urlBarEntryDefaultLayoutParams);
   200         urlBarEntryShrunkenLayoutParams.addRule(RelativeLayout.ALIGN_RIGHT, R.id.edit_layout);
   201         urlBarEntryShrunkenLayoutParams.rightMargin = 0;
   203         // This will clip the translating edge's image at 60% of its width
   204         urlBarTranslatingEdge = (ImageView) findViewById(R.id.url_bar_translating_edge);
   205         if (urlBarTranslatingEdge != null) {
   206             urlBarTranslatingEdge.getDrawable().setLevel(6000);
   207         }
   209         tabsButton = (ShapedButton) findViewById(R.id.tabs);
   210         tabsCounter = (TabCounter) findViewById(R.id.tabs_counter);
   211         if (Build.VERSION.SDK_INT >= 11) {
   212             tabsCounter.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
   213         }
   215         backButton = (ImageButton) findViewById(R.id.back);
   216         setButtonEnabled(backButton, false);
   217         forwardButton = (ImageButton) findViewById(R.id.forward);
   218         setButtonEnabled(forwardButton, false);
   220         menuButton = (ThemedImageButton) findViewById(R.id.menu);
   221         menuIcon = (ThemedImageView) findViewById(R.id.menu_icon);
   222         actionItemBar = (LinearLayout) findViewById(R.id.menu_items);
   223         hasSoftMenuButton = !HardwareUtils.hasMenuButton();
   225         editCancel = (ThemedImageView) findViewById(R.id.edit_cancel);
   227         // We use different layouts on phones and tablets, so adjust the focus
   228         // order appropriately.
   229         focusOrder = new ArrayList<View>();
   230         if (HardwareUtils.isTablet()) {
   231             focusOrder.addAll(Arrays.asList(tabsButton, backButton, forwardButton, this));
   232             focusOrder.addAll(urlDisplayLayout.getFocusOrder());
   233             focusOrder.addAll(Arrays.asList(actionItemBar, menuButton));
   234         } else {
   235             focusOrder.add(this);
   236             focusOrder.addAll(urlDisplayLayout.getFocusOrder());
   237             focusOrder.addAll(Arrays.asList(tabsButton, menuButton));
   238         }
   240         setUIMode(UIMode.DISPLAY);
   241     }
   243     @Override
   244     public void onAttachedToWindow() {
   245         super.onAttachedToWindow();
   247         setOnClickListener(new Button.OnClickListener() {
   248             @Override
   249             public void onClick(View v) {
   250                 if (activateListener != null) {
   251                     activateListener.onActivate();
   252                 }
   253             }
   254         });
   256         setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
   257             @Override
   258             public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
   259                 // We don't the context menu while editing
   260                 if (isEditing()) {
   261                     return;
   262                 }
   264                 // NOTE: Use MenuUtils.safeSetVisible because some actions might
   265                 // be on the Page menu
   267                 MenuInflater inflater = activity.getMenuInflater();
   268                 inflater.inflate(R.menu.titlebar_contextmenu, menu);
   270                 String clipboard = Clipboard.getText();
   271                 if (TextUtils.isEmpty(clipboard)) {
   272                     menu.findItem(R.id.pasteandgo).setVisible(false);
   273                     menu.findItem(R.id.paste).setVisible(false);
   274                 }
   276                 Tab tab = Tabs.getInstance().getSelectedTab();
   277                 if (tab != null) {
   278                     String url = tab.getURL();
   279                     if (url == null) {
   280                         menu.findItem(R.id.copyurl).setVisible(false);
   281                         menu.findItem(R.id.add_to_launcher).setVisible(false);
   282                         MenuUtils.safeSetVisible(menu, R.id.share, false);
   283                     }
   285                     MenuUtils.safeSetVisible(menu, R.id.subscribe, tab.hasFeeds());
   286                     MenuUtils.safeSetVisible(menu, R.id.add_search_engine, tab.hasOpenSearch());
   287                 } else {
   288                     // if there is no tab, remove anything tab dependent
   289                     menu.findItem(R.id.copyurl).setVisible(false);
   290                     menu.findItem(R.id.add_to_launcher).setVisible(false);
   291                     MenuUtils.safeSetVisible(menu, R.id.share, false);
   292                     MenuUtils.safeSetVisible(menu, R.id.subscribe, false);
   293                     MenuUtils.safeSetVisible(menu, R.id.add_search_engine, false);
   294                 }
   296                 MenuUtils.safeSetVisible(menu, R.id.share, !GeckoProfile.get(getContext()).inGuestMode());
   297             }
   298         });
   300         urlDisplayLayout.setOnStopListener(new OnStopListener() {
   301             @Override
   302             public Tab onStop() {
   303                 final Tab tab = Tabs.getInstance().getSelectedTab();
   304                 if (tab != null) {
   305                     tab.doStop();
   306                     return tab;
   307                 }
   309                 return null;
   310             }
   311         });
   313         urlDisplayLayout.setOnTitleChangeListener(new OnTitleChangeListener() {
   314             @Override
   315             public void onTitleChange(CharSequence title) {
   316                 final String contentDescription;
   317                 if (title != null) {
   318                     contentDescription = title.toString();
   319                 } else {
   320                     contentDescription = activity.getString(R.string.url_bar_default_text);
   321                 }
   323                 // The title and content description should
   324                 // always be sync.
   325                 setContentDescription(contentDescription);
   326             }
   327         });
   329         urlEditLayout.setOnFocusChangeListener(new View.OnFocusChangeListener() {
   330             @Override
   331             public void onFocusChange(View v, boolean hasFocus) {
   332                 // This will select the url bar when entering editing mode.
   333                 setSelected(hasFocus);
   334                 if (focusChangeListener != null) {
   335                     focusChangeListener.onFocusChange(v, hasFocus);
   336                 }
   337             }
   338         });
   340         tabsButton.setOnClickListener(new Button.OnClickListener() {
   341             @Override
   342             public void onClick(View v) {
   343                 toggleTabs();
   344             }
   345         });
   346         tabsButton.setImageLevel(0);
   348         backButton.setOnClickListener(new Button.OnClickListener() {
   349             @Override
   350             public void onClick(View view) {
   351                 Tabs.getInstance().getSelectedTab().doBack();
   352             }
   353         });
   354         backButton.setOnLongClickListener(new Button.OnLongClickListener() {
   355             @Override
   356             public boolean onLongClick(View view) {
   357                 return Tabs.getInstance().getSelectedTab().showBackHistory();
   358             }
   359         });
   361         forwardButton.setOnClickListener(new Button.OnClickListener() {
   362             @Override
   363             public void onClick(View view) {
   364                 Tabs.getInstance().getSelectedTab().doForward();
   365             }
   366         });
   367         forwardButton.setOnLongClickListener(new Button.OnLongClickListener() {
   368             @Override
   369             public boolean onLongClick(View view) {
   370                 return Tabs.getInstance().getSelectedTab().showForwardHistory();
   371             }
   372         });
   374         if (editCancel != null) {
   375             editCancel.setOnClickListener(new OnClickListener() {
   376                 @Override
   377                 public void onClick(View v) {
   378                     // If we exit editing mode during the animation,
   379                     // we're put into an inconsistent state (bug 1017276).
   380                     if (!isAnimatingEntry) {
   381                         Telemetry.sendUIEvent(TelemetryContract.Event.CANCEL,
   382                                               TelemetryContract.Method.ACTIONBAR,
   383                                               getResources().getResourceEntryName(editCancel.getId()));
   384                         cancelEdit();
   385                     }
   386                 }
   387             });
   388         }
   390         if (hasSoftMenuButton) {
   391             menuButton.setVisibility(View.VISIBLE);
   392             menuIcon.setVisibility(View.VISIBLE);
   394             menuButton.setOnClickListener(new Button.OnClickListener() {
   395                 @Override
   396                 public void onClick(View view) {
   397                     activity.openOptionsMenu();
   398                 }
   399             });
   400         }
   401     }
   403     public void setProgressBar(ToolbarProgressView progressBar) {
   404         this.progressBar = progressBar;
   405     }
   407     public void refresh() {
   408         urlDisplayLayout.dismissSiteIdentityPopup();
   409     }
   411     public boolean onBackPressed() {
   412         // If we exit editing mode during the animation,
   413         // we're put into an inconsistent state (bug 1017276).
   414         if (isEditing() && !isAnimatingEntry) {
   415             Telemetry.sendUIEvent(TelemetryContract.Event.CANCEL,
   416                                   TelemetryContract.Method.BACK);
   417             cancelEdit();
   418             return true;
   419         }
   421         return urlDisplayLayout.dismissSiteIdentityPopup();
   422     }
   424     @Override
   425     public boolean onTouchEvent(MotionEvent event) {
   426         // If the motion event has occured below the toolbar (due to the scroll
   427         // offset), let it pass through to the page.
   428         if (event != null && event.getY() > getHeight() + ViewHelper.getTranslationY(this)) {
   429             return false;
   430         }
   432         return super.onTouchEvent(event);
   433     }
   435     @Override
   436     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
   437         super.onSizeChanged(w, h, oldw, oldh);
   439         if (h != oldh) {
   440             // Post this to happen outside of onSizeChanged, as this may cause
   441             // a layout change and relayouts within a layout change don't work.
   442             post(new Runnable() {
   443                 @Override
   444                 public void run() {
   445                     activity.refreshToolbarHeight();
   446                 }
   447             });
   448         }
   449     }
   451     @Override
   452     public void onTabChanged(Tab tab, Tabs.TabEvents msg, Object data) {
   453         Log.d(LOGTAG, "onTabChanged: " + msg);
   454         final Tabs tabs = Tabs.getInstance();
   456         // These conditions are split into three phases:
   457         // * Always do first
   458         // * Handling specific to the selected tab
   459         // * Always do afterwards.
   461         switch (msg) {
   462             case ADDED:
   463             case CLOSED:
   464                 updateTabCount(tabs.getDisplayCount());
   465                 break;
   466             case RESTORED:
   467                 // TabCount fixup after OOM
   468             case SELECTED:
   469                 urlDisplayLayout.dismissSiteIdentityPopup();
   470                 updateTabCount(tabs.getDisplayCount());
   471                 isSwitchingTabs = true;
   472                 break;
   473         }
   475         if (tabs.isSelectedTab(tab)) {
   476             final EnumSet<UpdateFlags> flags = EnumSet.noneOf(UpdateFlags.class);
   478             // Progress-related handling
   479             switch (msg) {
   480                 case START:
   481                     updateProgressVisibility(tab, Tab.LOAD_PROGRESS_INIT);
   482                     // Fall through.
   483                 case ADDED:
   484                 case LOCATION_CHANGE:
   485                 case LOAD_ERROR:
   486                 case LOADED:
   487                 case STOP:
   488                     flags.add(UpdateFlags.PROGRESS);
   489                     if (progressBar.getVisibility() == View.VISIBLE) {
   490                         progressBar.animateProgress(tab.getLoadProgress());
   491                     }
   492                     break;
   494                 case SELECTED:
   495                     flags.add(UpdateFlags.PROGRESS);
   496                     updateProgressVisibility();
   497                     break;
   498             }
   500             switch (msg) {
   501                 case STOP:
   502                     // Reset the title in case we haven't navigated
   503                     // to a new page yet.
   504                     flags.add(UpdateFlags.TITLE);
   505                     // Fall through.
   506                 case START:
   507                 case CLOSED:
   508                 case ADDED:
   509                     updateBackButton(tab);
   510                     updateForwardButton(tab);
   511                     break;
   513                 case SELECTED:
   514                     flags.add(UpdateFlags.PRIVATE_MODE);
   515                     setPrivateMode(tab.isPrivate());
   516                     // Fall through.
   517                 case LOAD_ERROR:
   518                     flags.add(UpdateFlags.TITLE);
   519                     // Fall through.
   520                 case LOCATION_CHANGE:
   521                     // A successful location change will cause Tab to notify
   522                     // us of a title change, so we don't update the title here.
   523                     flags.add(UpdateFlags.FAVICON);
   524                     flags.add(UpdateFlags.SITE_IDENTITY);
   526                     updateBackButton(tab);
   527                     updateForwardButton(tab);
   528                     break;
   530                 case TITLE:
   531                     flags.add(UpdateFlags.TITLE);
   532                     break;
   534                 case FAVICON:
   535                     flags.add(UpdateFlags.FAVICON);
   536                     break;
   538                 case SECURITY_CHANGE:
   539                     flags.add(UpdateFlags.SITE_IDENTITY);
   540                     break;
   541             }
   543             if (!flags.isEmpty()) {
   544                 updateDisplayLayout(tab, flags);
   545             }
   546         }
   548         switch (msg) {
   549             case SELECTED:
   550             case LOAD_ERROR:
   551             case LOCATION_CHANGE:
   552                 isSwitchingTabs = false;
   553         }
   554     }
   556     private void updateProgressVisibility() {
   557         final Tab selectedTab = Tabs.getInstance().getSelectedTab();
   558         updateProgressVisibility(selectedTab, selectedTab.getLoadProgress());
   559     }
   561     private void updateProgressVisibility(Tab selectedTab, int progress) {
   562         if (!isEditing() && selectedTab.getState() == Tab.STATE_LOADING) {
   563             progressBar.setProgress(progress);
   564             progressBar.setVisibility(View.VISIBLE);
   565         } else {
   566             progressBar.setVisibility(View.GONE);
   567         }
   568     }
   570     private boolean isVisible() {
   571         return ViewHelper.getTranslationY(this) == 0;
   572     }
   574     @Override
   575     public void setNextFocusDownId(int nextId) {
   576         super.setNextFocusDownId(nextId);
   577         tabsButton.setNextFocusDownId(nextId);
   578         backButton.setNextFocusDownId(nextId);
   579         forwardButton.setNextFocusDownId(nextId);
   580         urlDisplayLayout.setNextFocusDownId(nextId);
   581         menuButton.setNextFocusDownId(nextId);
   582     }
   584     private int getUrlBarEntryTranslation() {
   585         if (editCancel == null) {
   586             // We are on tablet, and there is no animation so return a translation of 0.
   587             return 0;
   588         }
   590         // Find the distance from the right-edge of the url bar (where we're translating from) to
   591         // the left-edge of the cancel button (where we're translating to; note that the cancel
   592         // button must be laid out, i.e. not View.GONE).
   593         final LayoutParams lp = (LayoutParams) urlEditLayout.getLayoutParams();
   594         return editCancel.getLeft() - lp.leftMargin - urlBarEntry.getRight();
   595     }
   597     private int getUrlBarCurveTranslation() {
   598         return getWidth() - tabsButton.getLeft();
   599     }
   601     private boolean canDoBack(Tab tab) {
   602         return (tab.canDoBack() && !isEditing());
   603     }
   605     private boolean canDoForward(Tab tab) {
   606         return (tab.canDoForward() && !isEditing());
   607     }
   609     private void addTab() {
   610         activity.addTab();
   611     }
   613     private void toggleTabs() {
   614         if (activity.areTabsShown()) {
   615             if (activity.hasTabsSideBar())
   616                 activity.hideTabs();
   617         } else {
   618             // hide the virtual keyboard
   619             InputMethodManager imm =
   620                     (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
   621             imm.hideSoftInputFromWindow(tabsButton.getWindowToken(), 0);
   623             Tab tab = Tabs.getInstance().getSelectedTab();
   624             if (tab != null) {
   625                 if (!tab.isPrivate())
   626                     activity.showNormalTabs();
   627                 else
   628                     activity.showPrivateTabs();
   629             }
   630         }
   631     }
   633     private void updateTabCountAndAnimate(int count) {
   634         // Don't animate if the toolbar is hidden.
   635         if (!isVisible()) {
   636             updateTabCount(count);
   637             return;
   638         }
   640         // If toolbar is in edit mode on a phone, this means the entry is expanded
   641         // and the tabs button is translated offscreen. Don't trigger tabs counter
   642         // updates until the tabs button is back on screen.
   643         // See stopEditing()
   644         if (!isEditing() || HardwareUtils.isTablet()) {
   645             tabsCounter.setCount(count);
   647             tabsButton.setContentDescription((count > 1) ?
   648                                              activity.getString(R.string.num_tabs, count) :
   649                                              activity.getString(R.string.one_tab));
   650         }
   651     }
   653     private void updateTabCount(int count) {
   654         // If toolbar is in edit mode on a phone, this means the entry is expanded
   655         // and the tabs button is translated offscreen. Don't trigger tabs counter
   656         // updates until the tabs button is back on screen.
   657         // See stopEditing()
   658         if (isEditing() && !HardwareUtils.isTablet()) {
   659             return;
   660         }
   662         // Set TabCounter based on visibility
   663         if (isVisible() && ViewHelper.getAlpha(tabsCounter) != 0 && !isEditing()) {
   664             tabsCounter.setCountWithAnimation(count);
   665         } else {
   666             tabsCounter.setCount(count);
   667         }
   669         // Update A11y information
   670         tabsButton.setContentDescription((count > 1) ?
   671                                          activity.getString(R.string.num_tabs, count) :
   672                                          activity.getString(R.string.one_tab));
   673     }
   675     private void updateDisplayLayout(Tab tab, EnumSet<UpdateFlags> flags) {
   676         if (isSwitchingTabs) {
   677             flags.add(UpdateFlags.DISABLE_ANIMATIONS);
   678         }
   680         urlDisplayLayout.updateFromTab(tab, flags);
   682         if (flags.contains(UpdateFlags.TITLE)) {
   683             if (!isEditing()) {
   684                 urlEditLayout.setText(tab.getURL());
   685             }
   686         }
   688         if (flags.contains(UpdateFlags.PROGRESS)) {
   689             updateFocusOrder();
   690         }
   691     }
   693     private void updateFocusOrder() {
   694         View prevView = null;
   696         // If the element that has focus becomes disabled or invisible, focus
   697         // is given to the URL bar.
   698         boolean needsNewFocus = false;
   700         for (View view : focusOrder) {
   701             if (view.getVisibility() != View.VISIBLE || !view.isEnabled()) {
   702                 if (view.hasFocus()) {
   703                     needsNewFocus = true;
   704                 }
   705                 continue;
   706             }
   708             if (view == actionItemBar) {
   709                 final int childCount = actionItemBar.getChildCount();
   710                 for (int child = 0; child < childCount; child++) {
   711                     View childView = actionItemBar.getChildAt(child);
   712                     if (prevView != null) {
   713                         childView.setNextFocusLeftId(prevView.getId());
   714                         prevView.setNextFocusRightId(childView.getId());
   715                     }
   716                     prevView = childView;
   717                 }
   718             } else {
   719                 if (prevView != null) {
   720                     view.setNextFocusLeftId(prevView.getId());
   721                     prevView.setNextFocusRightId(view.getId());
   722                 }
   723                 prevView = view;
   724             }
   725         }
   727         if (needsNewFocus) {
   728             requestFocus();
   729         }
   730     }
   732     public void onEditSuggestion(String suggestion) {
   733         if (!isEditing()) {
   734             return;
   735         }
   737         urlEditLayout.onEditSuggestion(suggestion);
   738     }
   740     public void setTitle(CharSequence title) {
   741         urlDisplayLayout.setTitle(title);
   742     }
   744     public void prepareTabsAnimation(PropertyAnimator animator, boolean tabsAreShown) {
   745         if (!tabsAreShown) {
   746             PropertyAnimator buttonsAnimator =
   747                     new PropertyAnimator(animator.getDuration(), buttonsInterpolator);
   749             buttonsAnimator.attach(tabsCounter,
   750                                    PropertyAnimator.Property.ALPHA,
   751                                    1.0f);
   753             if (hasSoftMenuButton && !HardwareUtils.isTablet()) {
   754                 buttonsAnimator.attach(menuIcon,
   755                                        PropertyAnimator.Property.ALPHA,
   756                                        1.0f);
   757             }
   759             buttonsAnimator.start();
   761             return;
   762         }
   764         ViewHelper.setAlpha(tabsCounter, 0.0f);
   766         if (hasSoftMenuButton && !HardwareUtils.isTablet()) {
   767             ViewHelper.setAlpha(menuIcon, 0.0f);
   768         }
   769     }
   771     public void finishTabsAnimation(boolean tabsAreShown) {
   772         if (tabsAreShown) {
   773             return;
   774         }
   776         PropertyAnimator animator = new PropertyAnimator(150);
   778         animator.attach(tabsCounter,
   779                         PropertyAnimator.Property.ALPHA,
   780                         1.0f);
   782         if (hasSoftMenuButton && !HardwareUtils.isTablet()) {
   783             animator.attach(menuIcon,
   784                             PropertyAnimator.Property.ALPHA,
   785                             1.0f);
   786         }
   788         animator.start();
   789     }
   791     public void setOnActivateListener(OnActivateListener listener) {
   792         activateListener = listener;
   793     }
   795     public void setOnCommitListener(OnCommitListener listener) {
   796         urlEditLayout.setOnCommitListener(listener);
   797     }
   799     public void setOnDismissListener(OnDismissListener listener) {
   800         urlEditLayout.setOnDismissListener(listener);
   801     }
   803     public void setOnFilterListener(OnFilterListener listener) {
   804         urlEditLayout.setOnFilterListener(listener);
   805     }
   807     public void setOnFocusChangeListener(OnFocusChangeListener listener) {
   808         focusChangeListener = listener;
   809     }
   811     public void setOnStartEditingListener(OnStartEditingListener listener) {
   812         startEditingListener = listener;
   813     }
   815     public void setOnStopEditingListener(OnStopEditingListener listener) {
   816         stopEditingListener = listener;
   817     }
   819     private void showUrlEditLayout() {
   820         setUrlEditLayoutVisibility(true, null);
   821     }
   823     private void showUrlEditLayout(PropertyAnimator animator) {
   824         setUrlEditLayoutVisibility(true, animator);
   825     }
   827     private void hideUrlEditLayout() {
   828         setUrlEditLayoutVisibility(false, null);
   829     }
   831     private void hideUrlEditLayout(PropertyAnimator animator) {
   832         setUrlEditLayoutVisibility(false, animator);
   833     }
   835     private void setUrlEditLayoutVisibility(final boolean showEditLayout, PropertyAnimator animator) {
   836         if (showEditLayout) {
   837             urlEditLayout.prepareShowAnimation(animator);
   838         }
   840         if (animator == null) {
   841             final View viewToShow = (showEditLayout ? urlEditLayout : urlDisplayLayout);
   842             final View viewToHide = (showEditLayout ? urlDisplayLayout : urlEditLayout);
   844             viewToHide.setVisibility(View.GONE);
   845             viewToShow.setVisibility(View.VISIBLE);
   847             final int cancelVisibility = (showEditLayout ? View.VISIBLE : View.INVISIBLE);
   848             setCancelVisibility(cancelVisibility);
   849             return;
   850         }
   852         animator.addPropertyAnimationListener(new PropertyAnimationListener() {
   853             @Override
   854             public void onPropertyAnimationStart() {
   855                 if (!showEditLayout) {
   856                     urlEditLayout.setVisibility(View.GONE);
   857                     urlDisplayLayout.setVisibility(View.VISIBLE);
   859                     setCancelVisibility(View.INVISIBLE);
   860                 }
   861             }
   863             @Override
   864             public void onPropertyAnimationEnd() {
   865                 if (showEditLayout) {
   866                     urlDisplayLayout.setVisibility(View.GONE);
   867                     urlEditLayout.setVisibility(View.VISIBLE);
   869                     setCancelVisibility(View.VISIBLE);
   870                 }
   871             }
   872         });
   873     }
   875     private void setCancelVisibility(final int visibility) {
   876         if (editCancel != null) {
   877             editCancel.setVisibility(visibility);
   878         }
   879     }
   881     /**
   882      * Disables and dims all toolbar elements which are not
   883      * related to editing mode.
   884      */
   885     private void updateChildrenForEditing() {
   886         // This is for the tablet UI only
   887         if (!HardwareUtils.isTablet()) {
   888             return;
   889         }
   891         // Disable toolbar elemens while in editing mode
   892         final boolean enabled = !isEditing();
   894         // This alpha value has to be in sync with the one used
   895         // in setButtonEnabled().
   896         final float alpha = (enabled ? 1.0f : 0.24f);
   898         if (!enabled) {
   899             tabsCounter.onEnterEditingMode();
   900         }
   902         tabsButton.setEnabled(enabled);
   903         ViewHelper.setAlpha(tabsCounter, alpha);
   904         menuButton.setEnabled(enabled);
   905         ViewHelper.setAlpha(menuIcon, alpha);
   907         final int actionItemsCount = actionItemBar.getChildCount();
   908         for (int i = 0; i < actionItemsCount; i++) {
   909             actionItemBar.getChildAt(i).setEnabled(enabled);
   910         }
   911         ViewHelper.setAlpha(actionItemBar, alpha);
   913         final Tab tab = Tabs.getInstance().getSelectedTab();
   914         if (tab != null) {
   915             setButtonEnabled(backButton, canDoBack(tab));
   916             setButtonEnabled(forwardButton, canDoForward(tab));
   918             // Once the editing mode is finished, we have to ensure that the
   919             // forward button slides away if necessary. This is because we might
   920             // have only disabled it (without hiding it) when the toolbar entered
   921             // editing mode.
   922             if (!isEditing()) {
   923                 animateForwardButton(canDoForward(tab) ?
   924                                      ForwardButtonAnimation.SHOW : ForwardButtonAnimation.HIDE);
   925             }
   926         }
   927     }
   929     private void setUIMode(final UIMode uiMode) {
   930         this.uiMode = uiMode;
   931         urlEditLayout.setEnabled(uiMode == UIMode.EDIT);
   932     }
   934     /**
   935      * Returns whether or not the URL bar is in editing mode (url bar is expanded, hiding the new
   936      * tab button). Note that selection state is independent of editing mode.
   937      */
   938     public boolean isEditing() {
   939         return (uiMode == UIMode.EDIT);
   940     }
   942     public boolean isAnimating() {
   943         return isAnimatingEntry;
   944     }
   946     public void startEditing(String url, PropertyAnimator animator) {
   947         if (isEditing()) {
   948             return;
   949         }
   951         urlEditLayout.setText(url != null ? url : "");
   953         setUIMode(UIMode.EDIT);
   954         updateChildrenForEditing();
   956         updateProgressVisibility();
   958         if (startEditingListener != null) {
   959             startEditingListener.onStartEditing();
   960         }
   962         final int curveTranslation = getUrlBarCurveTranslation();
   963         final int entryTranslation = getUrlBarEntryTranslation();
   964         shouldShrinkURLBar = (entryTranslation < 0);
   966         if (urlBarTranslatingEdge != null) {
   967             urlBarTranslatingEdge.setVisibility(View.VISIBLE);
   968             if (shouldShrinkURLBar) {
   969                 urlBarEntry.setLayoutParams(urlBarEntryShrunkenLayoutParams);
   970             }
   971         }
   973         if (Build.VERSION.SDK_INT < 11) {
   974             showEditingWithoutAnimation(entryTranslation, curveTranslation);
   975         } else if (HardwareUtils.isTablet()) {
   976             // No animation.
   977             showUrlEditLayout();
   978         } else {
   979             showEditingWithPhoneAnimation(animator, entryTranslation, curveTranslation);
   980         }
   981     }
   983     private void showEditingWithoutAnimation(final int entryTranslation,
   984             final int curveTranslation) {
   985         showUrlEditLayout();
   987         if (urlBarTranslatingEdge != null) {
   988             ViewHelper.setTranslationX(urlBarTranslatingEdge, entryTranslation);
   989         }
   991         // Prevent taps through the editing mode cancel button (bug 1001243).
   992         tabsButton.setEnabled(false);
   994         ViewHelper.setTranslationX(tabsButton, curveTranslation);
   995         ViewHelper.setTranslationX(tabsCounter, curveTranslation);
   996         ViewHelper.setTranslationX(actionItemBar, curveTranslation);
   998         if (hasSoftMenuButton) {
   999             // Prevent tabs through the editing mode cancel button (bug 1001243).
  1000             menuButton.setEnabled(false);
  1002             ViewHelper.setTranslationX(menuButton, curveTranslation);
  1003             ViewHelper.setTranslationX(menuIcon, curveTranslation);
  1007     private void showEditingWithPhoneAnimation(final PropertyAnimator animator,
  1008             final int entryTranslation, final int curveTranslation) {
  1009         if (isAnimatingEntry)
  1010             return;
  1012         urlDisplayLayout.prepareStartEditingAnimation();
  1014         // Slide toolbar elements.
  1015         if (urlBarTranslatingEdge != null) {
  1016             animator.attach(urlBarTranslatingEdge,
  1017                             PropertyAnimator.Property.TRANSLATION_X,
  1018                             entryTranslation);
  1021         animator.attach(tabsButton,
  1022                         PropertyAnimator.Property.TRANSLATION_X,
  1023                         curveTranslation);
  1024         animator.attach(tabsCounter,
  1025                         PropertyAnimator.Property.TRANSLATION_X,
  1026                         curveTranslation);
  1027         animator.attach(actionItemBar,
  1028                         PropertyAnimator.Property.TRANSLATION_X,
  1029                         curveTranslation);
  1031         if (hasSoftMenuButton) {
  1032             animator.attach(menuButton,
  1033                             PropertyAnimator.Property.TRANSLATION_X,
  1034                             curveTranslation);
  1036             animator.attach(menuIcon,
  1037                             PropertyAnimator.Property.TRANSLATION_X,
  1038                             curveTranslation);
  1041         showUrlEditLayout(animator);
  1043         animator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
  1044             @Override
  1045             public void onPropertyAnimationStart() {
  1048             @Override
  1049             public void onPropertyAnimationEnd() {
  1050                 isAnimatingEntry = false;
  1052         });
  1054         isAnimatingEntry = true;
  1057     /**
  1058      * Exits edit mode without updating the toolbar title.
  1060      * @return the url that was entered
  1061      */
  1062     public String cancelEdit() {
  1063         Telemetry.stopUISession(TelemetryContract.Session.AWESOMESCREEN);
  1064         return stopEditing();
  1067     /**
  1068      * Exits edit mode, updating the toolbar title with the url that was just entered.
  1070      * @return the url that was entered
  1071      */
  1072     public String commitEdit() {
  1073         final String url = stopEditing();
  1074         if (!TextUtils.isEmpty(url)) {
  1075             setTitle(url);
  1077         return url;
  1080     private String stopEditing() {
  1081         final String url = urlEditLayout.getText();
  1082         if (!isEditing()) {
  1083             return url;
  1085         setUIMode(UIMode.DISPLAY);
  1087         updateChildrenForEditing();
  1089         if (stopEditingListener != null) {
  1090             stopEditingListener.onStopEditing();
  1093         updateProgressVisibility();
  1095         // The animation looks cleaner if the text in the URL bar is
  1096         // not selected so clear the selection by clearing focus.
  1097         urlEditLayout.clearFocus();
  1099         if (Build.VERSION.SDK_INT < 11) {
  1100             stopEditingWithoutAnimation();
  1101         } else if (HardwareUtils.isTablet()) {
  1102             // No animation.
  1103             hideUrlEditLayout();
  1104         } else {
  1105             stopEditingWithPhoneAnimation();
  1108         return url;
  1111     private void stopEditingWithoutAnimation() {
  1112         hideUrlEditLayout();
  1114         updateTabCountAndAnimate(Tabs.getInstance().getDisplayCount());
  1116         if (urlBarTranslatingEdge != null) {
  1117             urlBarTranslatingEdge.setVisibility(View.INVISIBLE);
  1118             ViewHelper.setTranslationX(urlBarTranslatingEdge, 0);
  1119             if (shouldShrinkURLBar) {
  1120                 urlBarEntry.setLayoutParams(urlBarEntryDefaultLayoutParams);
  1124         tabsButton.setEnabled(true);
  1126         ViewHelper.setTranslationX(tabsButton, 0);
  1127         ViewHelper.setTranslationX(tabsCounter, 0);
  1128         ViewHelper.setTranslationX(actionItemBar, 0);
  1130         if (hasSoftMenuButton) {
  1131             menuButton.setEnabled(true);
  1133             ViewHelper.setTranslationX(menuButton, 0);
  1134             ViewHelper.setTranslationX(menuIcon, 0);
  1138     private void stopEditingWithPhoneAnimation() {
  1139         final PropertyAnimator contentAnimator = new PropertyAnimator(250);
  1140         contentAnimator.setUseHardwareLayer(false);
  1142         // Slide the toolbar back to its original size.
  1143         if (urlBarTranslatingEdge != null) {
  1144             contentAnimator.attach(urlBarTranslatingEdge,
  1145                                    PropertyAnimator.Property.TRANSLATION_X,
  1146                                    0);
  1149         contentAnimator.attach(tabsButton,
  1150                                PropertyAnimator.Property.TRANSLATION_X,
  1151                                0);
  1152         contentAnimator.attach(tabsCounter,
  1153                                PropertyAnimator.Property.TRANSLATION_X,
  1154                                0);
  1155         contentAnimator.attach(actionItemBar,
  1156                                PropertyAnimator.Property.TRANSLATION_X,
  1157                                0);
  1159         if (hasSoftMenuButton) {
  1160             contentAnimator.attach(menuButton,
  1161                                    PropertyAnimator.Property.TRANSLATION_X,
  1162                                    0);
  1164             contentAnimator.attach(menuIcon,
  1165                                    PropertyAnimator.Property.TRANSLATION_X,
  1166                                    0);
  1169         hideUrlEditLayout(contentAnimator);
  1171         contentAnimator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
  1172             @Override
  1173             public void onPropertyAnimationStart() {
  1176             @Override
  1177             public void onPropertyAnimationEnd() {
  1178                 if (urlBarTranslatingEdge != null) {
  1179                     urlBarTranslatingEdge.setVisibility(View.INVISIBLE);
  1180                     if (shouldShrinkURLBar) {
  1181                         urlBarEntry.setLayoutParams(urlBarEntryDefaultLayoutParams);
  1185                 PropertyAnimator buttonsAnimator = new PropertyAnimator(300);
  1186                 urlDisplayLayout.prepareStopEditingAnimation(buttonsAnimator);
  1187                 buttonsAnimator.start();
  1189                 isAnimatingEntry = false;
  1191                 // Trigger animation to update the tabs counter once the
  1192                 // tabs button is back on screen.
  1193                 updateTabCountAndAnimate(Tabs.getInstance().getDisplayCount());
  1195         });
  1197         isAnimatingEntry = true;
  1198         contentAnimator.start();
  1201     private void setButtonEnabled(ImageButton button, boolean enabled) {
  1202         final Drawable drawable = button.getDrawable();
  1203         if (drawable != null) {
  1204             // This alpha value has to be in sync with the one used
  1205             // in updateChildrenForEditing().
  1206             drawable.setAlpha(enabled ? 255 : 61);
  1209         button.setEnabled(enabled);
  1212     public void updateBackButton(Tab tab) {
  1213         setButtonEnabled(backButton, canDoBack(tab));
  1216     private void animateForwardButton(final ForwardButtonAnimation animation) {
  1217         // If the forward button is not visible, we must be
  1218         // in the phone UI.
  1219         if (forwardButton.getVisibility() != View.VISIBLE) {
  1220             return;
  1223         final boolean showing = (animation == ForwardButtonAnimation.SHOW);
  1225         // if the forward button's margin is non-zero, this means it has already
  1226         // been animated to be visible¸ and vice-versa.
  1227         MarginLayoutParams fwdParams = (MarginLayoutParams) forwardButton.getLayoutParams();
  1228         if ((fwdParams.leftMargin > defaultForwardMargin && showing) ||
  1229             (fwdParams.leftMargin == defaultForwardMargin && !showing)) {
  1230             return;
  1233         // We want the forward button to show immediately when switching tabs
  1234         final PropertyAnimator forwardAnim =
  1235                 new PropertyAnimator(isSwitchingTabs ? 10 : FORWARD_ANIMATION_DURATION);
  1236         final int width = forwardButton.getWidth() / 2;
  1238         forwardAnim.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
  1239             @Override
  1240             public void onPropertyAnimationStart() {
  1241                 if (!showing) {
  1242                     // Set the margin before the transition when hiding the forward button. We
  1243                     // have to do this so that the favicon isn't clipped during the transition
  1244                     MarginLayoutParams layoutParams =
  1245                         (MarginLayoutParams) urlDisplayLayout.getLayoutParams();
  1246                     layoutParams.leftMargin = 0;
  1248                     // Do the same on the URL edit container
  1249                     layoutParams = (MarginLayoutParams) urlEditLayout.getLayoutParams();
  1250                     layoutParams.leftMargin = 0;
  1252                     requestLayout();
  1253                     // Note, we already translated the favicon, site security, and text field
  1254                     // in prepareForwardAnimation, so they should appear to have not moved at
  1255                     // all at this point.
  1259             @Override
  1260             public void onPropertyAnimationEnd() {
  1261                 if (showing) {
  1262                     MarginLayoutParams layoutParams =
  1263                         (MarginLayoutParams) urlDisplayLayout.getLayoutParams();
  1264                     layoutParams.leftMargin = urlBarViewOffset;
  1266                     layoutParams = (MarginLayoutParams) urlEditLayout.getLayoutParams();
  1267                     layoutParams.leftMargin = urlBarViewOffset;
  1270                 urlDisplayLayout.finishForwardAnimation();
  1272                 MarginLayoutParams layoutParams = (MarginLayoutParams) forwardButton.getLayoutParams();
  1273                 layoutParams.leftMargin = defaultForwardMargin + (showing ? width : 0);
  1274                 ViewHelper.setTranslationX(forwardButton, 0);
  1276                 requestLayout();
  1278         });
  1280         prepareForwardAnimation(forwardAnim, animation, width);
  1281         forwardAnim.start();
  1284     public void updateForwardButton(Tab tab) {
  1285         final boolean enabled = canDoForward(tab);
  1286         if (forwardButton.isEnabled() == enabled)
  1287             return;
  1289         // Save the state on the forward button so that we can skip animations
  1290         // when there's nothing to change
  1291         setButtonEnabled(forwardButton, enabled);
  1292         animateForwardButton(enabled ? ForwardButtonAnimation.SHOW : ForwardButtonAnimation.HIDE);
  1295     private void prepareForwardAnimation(PropertyAnimator anim, ForwardButtonAnimation animation, int width) {
  1296         if (animation == ForwardButtonAnimation.HIDE) {
  1297             anim.attach(forwardButton,
  1298                       PropertyAnimator.Property.TRANSLATION_X,
  1299                       -width);
  1300             anim.attach(forwardButton,
  1301                       PropertyAnimator.Property.ALPHA,
  1302                       0);
  1304         } else {
  1305             anim.attach(forwardButton,
  1306                       PropertyAnimator.Property.TRANSLATION_X,
  1307                       width);
  1308             anim.attach(forwardButton,
  1309                       PropertyAnimator.Property.ALPHA,
  1310                       1);
  1313         urlDisplayLayout.prepareForwardAnimation(anim, animation, width);
  1316     @Override
  1317     public boolean addActionItem(View actionItem) {
  1318         actionItemBar.addView(actionItem);
  1319         return true;
  1322     @Override
  1323     public void removeActionItem(View actionItem) {
  1324         actionItemBar.removeView(actionItem);
  1327     @Override
  1328     public void setPrivateMode(boolean isPrivate) {
  1329         super.setPrivateMode(isPrivate);
  1331         tabsButton.setPrivateMode(isPrivate);
  1332         menuButton.setPrivateMode(isPrivate);
  1333         menuIcon.setPrivateMode(isPrivate);
  1334         urlEditLayout.setPrivateMode(isPrivate);
  1336         if (backButton instanceof BackButton) {
  1337             ((BackButton) backButton).setPrivateMode(isPrivate);
  1340         if (forwardButton instanceof ForwardButton) {
  1341             ((ForwardButton) forwardButton).setPrivateMode(isPrivate);
  1345     public void show() {
  1346         setVisibility(View.VISIBLE);
  1349     public void hide() {
  1350         setVisibility(View.GONE);
  1353     public View getDoorHangerAnchor() {
  1354         return urlDisplayLayout.getDoorHangerAnchor();
  1357     public void onDestroy() {
  1358         Tabs.unregisterOnTabsChangedListener(this);
  1360         unregisterEventListener("Reader:Click");
  1361         unregisterEventListener("Reader:LongClick");
  1364     public boolean openOptionsMenu() {
  1365         if (!hasSoftMenuButton) {
  1366             return false;
  1369         // Initialize the popup.
  1370         if (menuPopup == null) {
  1371             View panel = activity.getMenuPanel();
  1372             menuPopup = new MenuPopup(activity);
  1373             menuPopup.setPanelView(panel);
  1375             menuPopup.setOnDismissListener(new PopupWindow.OnDismissListener() {
  1376                 @Override
  1377                 public void onDismiss() {
  1378                     activity.onOptionsMenuClosed(null);
  1380             });
  1383         GeckoAppShell.getGeckoInterface().invalidateOptionsMenu();
  1384         if (!menuPopup.isShowing()) {
  1385             menuPopup.showAsDropDown(menuButton);
  1388         return true;
  1391     public boolean closeOptionsMenu() {
  1392         if (!hasSoftMenuButton) {
  1393             return false;
  1396         if (menuPopup != null && menuPopup.isShowing()) {
  1397             menuPopup.dismiss();
  1400         return true;
  1403     private void registerEventListener(String event) {
  1404         GeckoAppShell.getEventDispatcher().registerEventListener(event, this);
  1407     private void unregisterEventListener(String event) {
  1408         GeckoAppShell.getEventDispatcher().unregisterEventListener(event, this);
  1411     @Override
  1412     public void handleMessage(String event, JSONObject message) {
  1413         Log.d(LOGTAG, "handleMessage: " + event);
  1414         if (event.equals("Reader:Click")) {
  1415             Tab tab = Tabs.getInstance().getSelectedTab();
  1416             if (tab != null) {
  1417                 tab.toggleReaderMode();
  1419         } else if (event.equals("Reader:LongClick")) {
  1420             Tab tab = Tabs.getInstance().getSelectedTab();
  1421             if (tab != null) {
  1422                 tab.addToReadingList();
  1427     @Override
  1428     public void onLightweightThemeChanged() {
  1429         Drawable drawable = theme.getDrawable(this);
  1430         if (drawable == null)
  1431             return;
  1433         StateListDrawable stateList = new StateListDrawable();
  1434         stateList.addState(PRIVATE_STATE_SET, getColorDrawable(R.color.background_private));
  1435         stateList.addState(EMPTY_STATE_SET, drawable);
  1437         setBackgroundDrawable(stateList);
  1439         if (editCancel != null) {
  1440             editCancel.onLightweightThemeChanged();
  1444     @Override
  1445     public void onLightweightThemeReset() {
  1446         setBackgroundResource(R.drawable.url_bar_bg);
  1447         if (editCancel != null) {
  1448             editCancel.onLightweightThemeReset();

mercurial