Merge "Fade photos in contact-details and quick-contacts."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index e604de1..d57aab6 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -23,6 +23,8 @@
     <uses-permission android:name="android.permission.CALL_PRIVILEGED" />
     <uses-permission android:name="android.permission.READ_CONTACTS" />
     <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+    <uses-permission android:name="android.permission.READ_CALL_LOG" />
+    <uses-permission android:name="android.permission.WRITE_CALL_LOG" />
     <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
     <uses-permission android:name="android.permission.GET_ACCOUNTS" />
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
diff --git a/res/layout/call_log_fragment.xml b/res/layout/call_log_fragment.xml
index d652ad7..1ad71a4 100644
--- a/res/layout/call_log_fragment.xml
+++ b/res/layout/call_log_fragment.xml
@@ -20,8 +20,7 @@
     android:layout_height="match_parent"
     android:orientation="vertical"
     android:paddingBottom="?android:attr/actionBarSize"
-    android:divider="?android:attr/dividerHorizontal"
-    android:showDividers="end">
+    android:divider="?android:attr/dividerHorizontal">
 
     <FrameLayout
         android:id="@+id/voicemail_status"
diff --git a/res/layout/dialpad_fragment.xml b/res/layout/dialpad_fragment.xml
index a95e4cb..796eb28 100644
--- a/res/layout/dialpad_fragment.xml
+++ b/res/layout/dialpad_fragment.xml
@@ -64,27 +64,18 @@
        android:layout_height="@dimen/dialpad_vertical_margin"
        android:background="#66000000"/>
 
-    <LinearLayout
+    <!-- left and right paddings will be modified by the code. See DialpadFragment. -->
+    <FrameLayout
         android:id="@+id/dialButtonContainer"
         android:layout_width="match_parent"
         android:layout_height="0px"
         android:layout_weight="@integer/dialpad_layout_weight_additional_buttons"
         android:layout_gravity="center_horizontal"
         android:background="@drawable/dialpad_background">
-        <ImageButton
-            android:id="@+id/searchButton"
-            android:layout_width="wrap_content"
-            android:layout_height="?android:attr/actionBarSize"
-            android:layout_gravity="bottom|center_horizontal"
-            android:state_enabled="false"
-            android:background="?android:attr/selectableItemBackground"
-            android:contentDescription="@string/description_search_button"
-            android:src="@drawable/ic_dial_action_search"/>
 
         <ImageButton
             android:id="@+id/dialButton"
-            android:layout_width="0px"
-            android:layout_weight="1"
+            android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:layout_gravity="center"
             android:state_enabled="false"
@@ -92,16 +83,7 @@
             android:contentDescription="@string/description_dial_button"
             android:src="@drawable/ic_dial_action_call" />
 
-        <ImageButton
-            android:id="@+id/overflow_menu"
-            android:layout_width="wrap_content"
-            android:layout_height="?android:attr/actionBarSize"
-            android:layout_gravity="bottom|center_horizontal"
-            android:src="@drawable/ic_menu_overflow"
-            android:contentDescription="@string/action_menu_overflow_description"
-            android:nextFocusLeft="@id/digits"
-            android:background="?android:attr/selectableItemBackground"/>
-    </LinearLayout>
+    </FrameLayout>
 
     <!-- "Dialpad chooser" UI, shown only when the user brings up the
          Dialer while a call is already in progress.
diff --git a/res/layout/dialtacts_activity.xml b/res/layout/dialtacts_activity.xml
index 7bcddc1..35fa00f 100644
--- a/res/layout/dialtacts_activity.xml
+++ b/res/layout/dialtacts_activity.xml
@@ -24,4 +24,24 @@
         android:id="@+id/pager"
         android:layout_width="match_parent"
         android:layout_height="match_parent" />
+
+    <ImageButton
+         android:id="@+id/searchButton"
+         android:layout_width="wrap_content"
+         android:layout_height="?android:attr/actionBarSize"
+         android:layout_gravity="bottom|left"
+         android:state_enabled="false"
+         android:background="?android:attr/selectableItemBackground"
+         android:contentDescription="@string/description_search_button"
+         android:src="@drawable/ic_dial_action_search"/>
+
+    <ImageButton
+         android:id="@+id/overflow_menu"
+         android:layout_width="wrap_content"
+         android:layout_height="?android:attr/actionBarSize"
+         android:layout_gravity="bottom|right"
+         android:src="@drawable/ic_menu_overflow"
+         android:contentDescription="@string/action_menu_overflow_description"
+         android:nextFocusLeft="@id/digits"
+         android:background="?android:attr/selectableItemBackground"/>
 </FrameLayout>
diff --git a/res/layout/phone_contact_tile_list.xml b/res/layout/phone_contact_tile_list.xml
index 29ceb19..289fba3 100644
--- a/res/layout/phone_contact_tile_list.xml
+++ b/res/layout/phone_contact_tile_list.xml
@@ -21,8 +21,7 @@
     android:layout_height="match_parent"
     android:orientation="vertical"
     android:paddingBottom="?android:attr/actionBarSize"
-    android:divider="?android:attr/dividerHorizontal"
-    android:showDividers="end">
+    android:divider="?android:attr/dividerHorizontal">
     <FrameLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent">
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 8536a36..ba0318f 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -550,5 +550,5 @@
     <string name="dialog_phone_call_prohibited_message" msgid="6554711866586660441">"لم يتم إرسال المكالمة"</string>
     <string name="dialog_voicemail_not_ready_message" msgid="4384716252789515378">"لإعداد البريد الصوتي، انتقل إلى القائمة &gt; الإعدادات."</string>
     <string name="dialog_voicemail_airplane_mode_message" msgid="530922773669546093">"للاتصال بالبريد الصوتي، يجب أولاً إيقاف وضع الطائرة."</string>
-    <string name="action_menu_overflow_description" msgid="2303272250613084574">"المزيد من الخيارات"</string>
+    <string name="action_menu_overflow_description" msgid="2303272250613084574">"مزيد من الخيارات"</string>
 </resources>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 6bc2607..38190a3 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -550,5 +550,5 @@
     <string name="dialog_phone_call_prohibited_message" msgid="6554711866586660441">"Выклік не зроблены"</string>
     <string name="dialog_voicemail_not_ready_message" msgid="4384716252789515378">"Каб наладзіць галасавую пошту, націсніце \"Меню\" i перайдзiце ў налады."</string>
     <string name="dialog_voicemail_airplane_mode_message" msgid="530922773669546093">"Каб зрабiць выклік галасавой пошты, спачатку адключыце рэжым палёту."</string>
-    <string name="action_menu_overflow_description" msgid="2303272250613084574">"Больш налад"</string>
+    <string name="action_menu_overflow_description" msgid="2303272250613084574">"Дадатковыя параметры"</string>
 </resources>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 48b2075..47e03f3 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -550,5 +550,5 @@
     <string name="dialog_phone_call_prohibited_message" msgid="6554711866586660441">"Hovor nebyl odeslán"</string>
     <string name="dialog_voicemail_not_ready_message" msgid="4384716252789515378">"Chcete-li nastavit hlasovou schránku, přejděte do části Menu &gt; Nastavení."</string>
     <string name="dialog_voicemail_airplane_mode_message" msgid="530922773669546093">"Chcete-li volat hlasovou schránku, nejdříve vypněte režim V letadle."</string>
-    <string name="action_menu_overflow_description" msgid="2303272250613084574">"Další možnosti"</string>
+    <string name="action_menu_overflow_description" msgid="2303272250613084574">"Více možností"</string>
 </resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 59849db..21c2aca 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -550,5 +550,5 @@
     <string name="dialog_phone_call_prohibited_message" msgid="6554711866586660441">"تماس ارسال نشد"</string>
     <string name="dialog_voicemail_not_ready_message" msgid="4384716252789515378">"برای راه‌اندازی پست صوتی به منو &gt; تنظیمات بروید."</string>
     <string name="dialog_voicemail_airplane_mode_message" msgid="530922773669546093">"برای تماس با پست صوتی، ابتدا حالت هواپیما را غیرفعال کنید."</string>
-    <string name="action_menu_overflow_description" msgid="2303272250613084574">"سایر گزینه ها"</string>
+    <string name="action_menu_overflow_description" msgid="2303272250613084574">"گزینه‌های بیشتر"</string>
 </resources>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index ef666fb..d0bdcad 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -550,5 +550,5 @@
     <string name="dialog_phone_call_prohibited_message" msgid="6554711866586660441">"A hívás nem indítható."</string>
     <string name="dialog_voicemail_not_ready_message" msgid="4384716252789515378">"A hangposta beállításához válassza a Menü &gt; Beállítások pontot."</string>
     <string name="dialog_voicemail_airplane_mode_message" msgid="530922773669546093">"Hangposta hívásához kapcsolja ki a Repülőgép üzemmódot."</string>
-    <string name="action_menu_overflow_description" msgid="2303272250613084574">"További lehetőségek"</string>
+    <string name="action_menu_overflow_description" msgid="2303272250613084574">"További beállítások"</string>
 </resources>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 9451e90..ec797e7 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -481,8 +481,8 @@
   </plurals>
     <string name="toast_join_with_empty_contact" msgid="2238581529864542985">"Ketik nama kenalan sebelum menggabungkan dengan lainnya."</string>
     <string name="copy_text" msgid="3257145021583508761">"Salin ke papan klip"</string>
-    <string name="set_default" msgid="4417505153468300351">"Setel sebagai bawaan"</string>
-    <string name="clear_default" msgid="7193185801596678067">"Hapus bawaan"</string>
+    <string name="set_default" msgid="4417505153468300351">"Setel sebagai default"</string>
+    <string name="clear_default" msgid="7193185801596678067">"Hapus default"</string>
     <string name="toast_text_copied" msgid="5143776250008541719">"Teks disalin"</string>
     <string name="cancel_confirmation_dialog_message" msgid="5885724679874403115">"Buang perubahan Anda?"</string>
     <string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 9926f4f..9307797 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -550,5 +550,5 @@
     <string name="dialog_phone_call_prohibited_message" msgid="6554711866586660441">"Вызов невозможен"</string>
     <string name="dialog_voicemail_not_ready_message" msgid="4384716252789515378">"Чтобы настроить голосовую почту, выберите \"Меню &gt; Настройки\"."</string>
     <string name="dialog_voicemail_airplane_mode_message" msgid="530922773669546093">"Сначала отключите режим полета."</string>
-    <string name="action_menu_overflow_description" msgid="2303272250613084574">"Ещё"</string>
+    <string name="action_menu_overflow_description" msgid="2303272250613084574">"Еще"</string>
 </resources>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 71657bb..3a92da3 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -550,5 +550,5 @@
     <string name="dialog_phone_call_prohibited_message" msgid="6554711866586660441">"Hovor nebol spojený"</string>
     <string name="dialog_voicemail_not_ready_message" msgid="4384716252789515378">"Ak chcete nastaviť hlasovú schránku, prejdite na položku Menu &gt; Nastavenia."</string>
     <string name="dialog_voicemail_airplane_mode_message" msgid="530922773669546093">"Ak chcete volať hlasovú schránku, najprv vypnite režim V lietadle."</string>
-    <string name="action_menu_overflow_description" msgid="2303272250613084574">"Viac možností"</string>
+    <string name="action_menu_overflow_description" msgid="2303272250613084574">"Ďalšie možnosti"</string>
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index b6620f5..c0ea600 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -238,4 +238,7 @@
     <!-- Min height of the list of contacts when the contact picker is a dialog (on
         wide screen devices). -->
     <dimen name="contact_picker_contact_list_min_height">550dip</dimen>
+
+    <!-- Min with of fake menu buttons, which should be same as ActionBar's one -->
+    <dimen name="fake_menu_button_min_width">56dip</dimen>
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index ae2ecc2..2132dc3 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -284,7 +284,12 @@
     </style>
 
     <style name="DialtactsActionBarStyle" parent="android:Widget.Holo.ActionBar">
-        <!-- For making test easier. Should use @null. -->
+        <!-- For making test easier. Should use @null.
+             TODO: use @null once we're sure issue 6041917 is gone.
+             Don't forget to add android:showDividers="end" to call_log_fragment.xml
+             and phone_contact_tile_list.xml, to show horizontal divider between
+             the list and the split ActionBar.
+          -->
         <!-- <item name="android:backgroundSplit">@null</item> -->
         <item name="android:backgroundStacked">@drawable/ab_stacked_opaque_dark_holo</item>
         <item name="android:displayOptions"></item>
diff --git a/src/com/android/contacts/activities/DialtactsActivity.java b/src/com/android/contacts/activities/DialtactsActivity.java
index cdaaa68..90787e3 100644
--- a/src/com/android/contacts/activities/DialtactsActivity.java
+++ b/src/com/android/contacts/activities/DialtactsActivity.java
@@ -16,8 +16,8 @@
 
 package com.android.contacts.activities;
 
-import com.android.contacts.R;
 import com.android.contacts.ContactsUtils;
+import com.android.contacts.R;
 import com.android.contacts.calllog.CallLogFragment;
 import com.android.contacts.dialpad.DialpadFragment;
 import com.android.contacts.interactions.PhoneNumberInteraction;
@@ -27,7 +27,6 @@
 import com.android.contacts.list.OnPhoneNumberPickerActionListener;
 import com.android.contacts.list.PhoneFavoriteFragment;
 import com.android.contacts.list.PhoneNumberPickerFragment;
-import com.android.contacts.activities.TransactionSafeActivity;
 import com.android.contacts.util.AccountFilterUtil;
 import com.android.contacts.util.Constants;
 import com.android.internal.telephony.ITelephony;
@@ -55,6 +54,7 @@
 import android.support.v4.view.ViewPager;
 import android.support.v4.view.ViewPager.OnPageChangeListener;
 import android.text.TextUtils;
+import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -64,6 +64,7 @@
 import android.view.View.OnClickListener;
 import android.view.View.OnFocusChangeListener;
 import android.view.ViewConfiguration;
+import android.view.ViewGroup;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.PopupMenu;
 import android.widget.SearchView;
@@ -77,10 +78,14 @@
  * embedded using intents.
  * The dialer tab's title is 'phone', a more common name (see strings.xml).
  */
-public class DialtactsActivity extends TransactionSafeActivity {
+public class DialtactsActivity extends TransactionSafeActivity
+        implements View.OnClickListener {
     private static final String TAG = "DialtactsActivity";
 
-    private static final boolean DEBUG = false;
+    /**
+     * STOPSHIP: This must be turned off after issue 6127931 and 6041917 being resolved.
+     */
+    public static final boolean DEBUG = true;
 
     /** Used to open Call Setting */
     private static final String PHONE_PACKAGE = "com.android.phone";
@@ -135,6 +140,16 @@
         }
 
         @Override
+        public void setPrimaryItem(ViewGroup container, int position, Object object) {
+            // The parent's setPrimaryItem() also calls setMenuVisibility(), so we want to know
+            // when it happens.
+            if (DEBUG) {
+                Log.d(TAG, "FragmentPagerAdapter#setPrimaryItem(), position: " + position);
+            }
+            super.setPrimaryItem(container, position, object);
+        }
+
+        @Override
         public int getCount() {
             return TAB_INDEX_COUNT;
         }
@@ -174,13 +189,14 @@
         public void onPageSelected(int position) {
             if (DEBUG) Log.d(TAG, "onPageSelected: position: " + position);
             final ActionBar actionBar = getActionBar();
-            if (mDialpadFragment != null && !mDuringSwipe) {
-                if (DEBUG) {
-                    Log.d(TAG, "Immediately show/hide fake menu buttons. position: "
-                            + position + ", dragging: " + mDuringSwipe);
+            if (mDialpadFragment != null) {
+                if (mDuringSwipe && position == TAB_INDEX_DIALER) {
+                    // TODO: Figure out if we want this or not. Right now
+                    // - with this call, both fake buttons and real action bar overlap
+                    // - without this call, there's tiny flicker happening to search/menu buttons.
+                    // If we can reduce the flicker without this call, it would be much better.
+                    // updateFakeMenuButtonsVisibility(true);
                 }
-                mDialpadFragment.updateFakeMenuButtonsVisibility(
-                        position == TAB_INDEX_DIALER && !mDuringSwipe);
             }
 
             if (mCurrentPosition == position) {
@@ -189,46 +205,16 @@
 
             actionBar.selectTab(actionBar.getTabAt(position));
             mNextPosition = position;
-
-            // This method is called halfway between swiping between the two pages.
-            // When the next page is fully selected, the ViewPager will go back to IDLE state in
-            // onPageScrollStateChanged(). The order should be:
-            // (user's swipe) -> onPageSelected() -> IDLE in onPageScrollStateChanged()
-            //
-            // sendFragmentVisibilityChange() must be called from here or in the IDLE state to
-            // notify the visibility change events to two pages: the current page (pointed by
-            // mCurrentPosition) should receive sendFragmentVisibilityChange() with the second
-            // argument false, meaning "the page is now invisible", while the next page (pointed by
-            // mNextPosition) should receive the method with the second argument true, meaning
-            // "the page becomes visible".
-            //
-            // To make transition animation smooth enough, we need to delay the event in some cases:
-            // - We should delay both method calls when the dialpad screen is involved.
-            //   The screen does not have the bottom action bar, requiring different layout to
-            //   fill the screen. The layout refresh takes some time and thus should be done after
-            //   the page migration being completed.
-            // - We should delay the method for the call log screen. The screen will update
-            //   its internal state and may query full call log. which is too costly to do when
-            //   setMenuVisibility() is called, making the animation slower.
-            // - We should *not* delay the method for the phone favorite screen. The screen has
-            //   another icon the call log screen doesn't have. We want to show/hide it immediately
-            //   after user's choosing pages.
-            if (mCurrentPosition == TAB_INDEX_CALL_LOG && mNextPosition == TAB_INDEX_FAVORITES) {
-                sendFragmentVisibilityChange(mNextPosition, true /* visible */ );
-                invalidateOptionsMenu();
-            } else if (mCurrentPosition == TAB_INDEX_FAVORITES
-                    && mNextPosition == TAB_INDEX_CALL_LOG) {
-                sendFragmentVisibilityChange(mCurrentPosition, false /* not visible */ );
-                invalidateOptionsMenu();
-            } else {
-                // Delay sendFragmentVisibilityChange() for both positions.
-            }
         }
 
         public void setCurrentPosition(int position) {
             mCurrentPosition = position;
         }
 
+        public int getCurrentPosition() {
+            return mCurrentPosition;
+        }
+
         @Override
         public void onPageScrollStateChanged(int state) {
             switch (state) {
@@ -254,25 +240,9 @@
                     mDuringSwipe = false;
                     mUserTabClick = false;
 
-                    // Call delayed sendFragmentVisibilityChange() call(s).
-                    // See comments in onPageSelected() for more details.
-                    if (mCurrentPosition == TAB_INDEX_CALL_LOG
-                            && mNextPosition == TAB_INDEX_FAVORITES) {
-                        sendFragmentVisibilityChange(mCurrentPosition, false /* not visible */ );
-                    } else if (mCurrentPosition == TAB_INDEX_FAVORITES
-                            && mNextPosition == TAB_INDEX_CALL_LOG) {
-                        sendFragmentVisibilityChange(mNextPosition, true /* visible */ );
-                    } else if (mCurrentPosition == TAB_INDEX_DIALER
-                            && mNextPosition == TAB_INDEX_DIALER) {
-                        // Dragged the dialer screen, but remained in the dialer screen.
-                        // During user's dragging the dialer, we show the ActonBar, so we need to
-                        // explicitly reset it in this exact case.
-                        sendFragmentVisibilityChange(TAB_INDEX_DIALER, true);
-                        sendFragmentVisibilityChange(TAB_INDEX_CALL_LOG, false);
-                    } else {
-                        sendFragmentVisibilityChange(mCurrentPosition, false /* not visible */ );
-                        sendFragmentVisibilityChange(mNextPosition, true /* visible */ );
-                    }
+                    updateFakeMenuButtonsVisibility(mNextPosition == TAB_INDEX_DIALER);
+                    sendFragmentVisibilityChange(mCurrentPosition, false);
+                    sendFragmentVisibilityChange(mNextPosition, true);
 
                     invalidateOptionsMenu();
 
@@ -283,12 +253,6 @@
                     if (DEBUG) Log.d(TAG, "onPageScrollStateChanged() with SCROLL_STATE_DRAGGING");
                     mDuringSwipe = true;
                     mUserTabClick = false;
-
-                    if (mCurrentPosition == TAB_INDEX_DIALER) {
-                        sendFragmentVisibilityChange(TAB_INDEX_DIALER, false);
-                        sendFragmentVisibilityChange(TAB_INDEX_CALL_LOG, true);
-                        invalidateOptionsMenu();
-                    }
                     break;
                 }
                 case ViewPager.SCROLL_STATE_SETTLING: {
@@ -312,6 +276,9 @@
     private CallLogFragment mCallLogFragment;
     private PhoneFavoriteFragment mPhoneFavoriteFragment;
 
+    private View mSearchButton;
+    private View mMenuButton;
+
     private final ContactListFilterListener mContactListFilterListener =
             new ContactListFilterListener() {
         @Override
@@ -352,9 +319,12 @@
             // when the user clicks a tab at the ActionBar at the top, this will be called before
             // them. This logic interprets the order difference as a difference of the user action.
             if (!mDuringSwipe) {
+                if (DEBUG) {
+                    Log.d(TAG, "Tab select. from: " + mPageChangeListener.getCurrentPosition()
+                            + ", to: " + tab.getPosition());
+                }
                 if (mDialpadFragment != null) {
-                    if (DEBUG) Log.d(TAG, "Immediately hide fake buttons for tab selection case");
-                    mDialpadFragment.updateFakeMenuButtonsVisibility(false);
+                    updateFakeMenuButtonsVisibility(tab.getPosition() == TAB_INDEX_DIALER);
                 }
                 mUserTabClick = true;
             }
@@ -528,6 +498,30 @@
         mViewPager.setAdapter(new ViewPagerAdapter(getFragmentManager()));
         mViewPager.setOnPageChangeListener(mPageChangeListener);
 
+        // Do same width calculation as ActionBar does
+        DisplayMetrics dm = getResources().getDisplayMetrics();
+        int minCellSize = getResources().getDimensionPixelSize(R.dimen.fake_menu_button_min_width);
+        int cellCount = dm.widthPixels / minCellSize;
+        int fakeMenuItemWidth = dm.widthPixels / cellCount;
+        if (DEBUG) Log.d(TAG, "The size of fake menu buttons (in pixel): " + fakeMenuItemWidth);
+
+        // Soft menu button should appear only when there's no hardware menu button.
+        mMenuButton = findViewById(R.id.overflow_menu);
+        if (mMenuButton != null) {
+            mMenuButton.setMinimumWidth(fakeMenuItemWidth);
+            if (ViewConfiguration.get(this).hasPermanentMenuKey()) {
+                // This is required for dialpad button's layout, so must not use GONE here.
+                mMenuButton.setVisibility(View.INVISIBLE);
+            } else {
+                mMenuButton.setOnClickListener(this);
+            }
+        }
+        mSearchButton = findViewById(R.id.searchButton);
+        if (mSearchButton != null) {
+            mSearchButton.setMinimumWidth(fakeMenuItemWidth);
+            mSearchButton.setOnClickListener(this);
+        }
+
         // Setup the ActionBar tabs (the order matches the tab-index contants TAB_INDEX_*)
         setupDialer();
         setupCallLog();
@@ -568,6 +562,16 @@
             mDuringSwipe = false;
             mUserTabClick = false;
         }
+
+        final int currentPosition = mPageChangeListener.getCurrentPosition();
+        if (DEBUG) {
+            Log.d(TAG, "onStart(). current position: " + mPageChangeListener.getCurrentPosition()
+                    + ". Reset all menu visibility state.");
+        }
+        updateFakeMenuButtonsVisibility(currentPosition == TAB_INDEX_DIALER);
+        for (int i = 0; i < TAB_INDEX_COUNT; i++) {
+            sendFragmentVisibilityChange(i, i == currentPosition);
+        }
     }
 
     @Override
@@ -576,6 +580,31 @@
         mContactListFilterController.removeListener(mContactListFilterListener);
     }
 
+    @Override
+    public void onClick(View view) {
+        switch (view.getId()) {
+            case R.id.searchButton: {
+                enterSearchUi();
+                break;
+            }
+            case R.id.overflow_menu: {
+                if (mDialpadFragment != null) {
+                    PopupMenu popup = mDialpadFragment.constructPopupMenu(view);
+                    if (popup != null) {
+                        popup.show();
+                    }
+                } else {
+                    Log.w(TAG, "DialpadFragment is null during onClick() event for " + view);
+                }
+                break;
+            }
+            default: {
+                Log.wtf(TAG, "Unexpected onClick event from " + view);
+                break;
+            }
+        }
+    }
+
     /**
      * Add search fragment.  Note this is called during onLayout, so there's some restrictions,
      * such as executePendingTransaction can't be used in it.
@@ -642,7 +671,6 @@
 
         if (fragment instanceof DialpadFragment) {
             mDialpadFragment = (DialpadFragment) fragment;
-            mDialpadFragment.setListener(mDialpadListener);
         } else if (fragment instanceof CallLogFragment) {
             mCallLogFragment = (CallLogFragment) fragment;
         } else if (fragment instanceof PhoneFavoriteFragment) {
@@ -891,14 +919,7 @@
         }
     }
 
-    private DialpadFragment.Listener mDialpadListener = new DialpadFragment.Listener() {
-        @Override
-        public void onSearchButtonPressed() {
-            enterSearchUi();
-        }
-    };
-
-    private PhoneFavoriteFragment.Listener mPhoneFavoriteListener =
+    private final PhoneFavoriteFragment.Listener mPhoneFavoriteListener =
             new PhoneFavoriteFragment.Listener() {
         @Override
         public void onContactSelected(Uri contactUri) {
@@ -966,7 +987,8 @@
                 searchMenuItem.setVisible(true);
                 searchMenuItem.setOnMenuItemClickListener(mSearchMenuItemClickListener);
                 showCallSettingsMenu = true;
-                fakeMenuItem.setVisible(ViewConfiguration.get(this).hasPermanentMenuKey());
+                fakeMenuItem.setVisible(ViewConfiguration.get(this).hasPermanentMenuKey()
+                        && (tab != null && tab.getPosition() == TAB_INDEX_CALL_LOG));
             }
             if (tab != null && tab.getPosition() == TAB_INDEX_FAVORITES) {
                 filterOptionMenuItem.setVisible(true);
@@ -1042,7 +1064,9 @@
         actionBar.setDisplayShowHomeEnabled(true);
         actionBar.setDisplayHomeAsUpEnabled(true);
 
-        sendFragmentVisibilityChange(mViewPager.getCurrentItem(), false /* not visible */ );
+        for (int i = 0; i < TAB_INDEX_COUNT; i++) {
+            sendFragmentVisibilityChange(i, false /* not visible */ );
+        }
 
         // Show the search fragment and hide everything else.
         mSearchFragment.setUserVisibleHint(true);
@@ -1094,7 +1118,9 @@
         actionBar.setDisplayShowHomeEnabled(false);
         actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
 
-        sendFragmentVisibilityChange(mViewPager.getCurrentItem(), true /* visible */ );
+        for (int i = 0; i < TAB_INDEX_COUNT; i++) {
+            sendFragmentVisibilityChange(i, i == mViewPager.getCurrentItem());
+        }
 
         // Before exiting the search screen, reset swipe state.
         mDuringSwipe = false;
@@ -1135,6 +1161,35 @@
             final Fragment fragment = getFragmentAt(position);
             if (fragment != null) {
                 fragment.setMenuVisibility(visibility);
+                fragment.setUserVisibleHint(visibility);
+            }
+        }
+    }
+
+    /**
+     * Update visibility of the search button and menu button at the bottom.
+     * They should be invisible when bottom ActionBar's real items are available, and be visible
+     * otherwise.
+     *
+     * @param visible True when visible.
+     */
+    private void updateFakeMenuButtonsVisibility(boolean visible) {
+        if (DEBUG) {
+            Log.d(TAG, "updateFakeMenuButtonVisibility(" + visible + ")");
+        }
+
+        if (mSearchButton != null) {
+            if (visible) {
+                mSearchButton.setVisibility(View.VISIBLE);
+            } else {
+                mSearchButton.setVisibility(View.INVISIBLE);
+            }
+        }
+        if (mMenuButton != null) {
+            if (visible && !ViewConfiguration.get(this).hasPermanentMenuKey()) {
+                mMenuButton.setVisibility(View.VISIBLE);
+            } else {
+                mMenuButton.setVisibility(View.INVISIBLE);
             }
         }
     }
diff --git a/src/com/android/contacts/calllog/CallLogFragment.java b/src/com/android/contacts/calllog/CallLogFragment.java
index 39070e1..c3d5d0b 100644
--- a/src/com/android/contacts/calllog/CallLogFragment.java
+++ b/src/com/android/contacts/calllog/CallLogFragment.java
@@ -87,6 +87,9 @@
 
     private final Handler mHandler = new Handler();
 
+    // Exactly same variable is in Fragment as a package private.
+    private boolean mMenuVisible = true;
+
     @Override
     public void onCreate(Bundle state) {
         super.onCreate(state);
@@ -384,12 +387,13 @@
     @Override
     public void setMenuVisibility(boolean menuVisible) {
         super.setMenuVisibility(menuVisible);
-        if (menuVisible && isResumed()) {
-            refreshData();
-        }
-
-        if (!menuVisible) {
-            updateOnExit();
+        if (mMenuVisible != menuVisible) {
+            mMenuVisible = menuVisible;
+            if (!menuVisible) {
+                updateOnExit();
+            } else if (isResumed()) {
+                refreshData();
+            }
         }
     }
 
diff --git a/src/com/android/contacts/dialpad/DialpadFragment.java b/src/com/android/contacts/dialpad/DialpadFragment.java
index f58f3e3..0de0f11 100644
--- a/src/com/android/contacts/dialpad/DialpadFragment.java
+++ b/src/com/android/contacts/dialpad/DialpadFragment.java
@@ -51,7 +51,6 @@
 import android.text.style.RelativeSizeSpan;
 import android.util.DisplayMetrics;
 import android.util.Log;
-import android.util.SparseArray;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.Menu;
@@ -89,7 +88,7 @@
         DialpadImageButton.OnPressedListener {
     private static final String TAG = DialpadFragment.class.getSimpleName();
 
-    private static final boolean DEBUG = false;
+    private static final boolean DEBUG = DialtactsActivity.DEBUG;
 
     private static final String EMPTY_NUMBER = "";
 
@@ -103,10 +102,6 @@
     /** Stream type used to play the DTMF tones off call, and mapped to the volume control keys */
     private static final int DIAL_TONE_STREAM_TYPE = AudioManager.STREAM_MUSIC;
 
-    public interface Listener {
-        public void onSearchButtonPressed();
-    }
-
     /**
      * View (usually FrameLayout) containing mDigits field. This can be null, in which mDigits
      * isn't enclosed by the container.
@@ -122,11 +117,6 @@
     private final Object mToneGeneratorLock = new Object();
     private View mDialpad;
 
-    private boolean mShowOptionsMenu;
-    private View mSearchButton;
-    private View mMenuButton;
-    private Listener mListener;
-
     private View mDialButtonContainer;
     private View mDialButton;
     private ListView mDialpadChooser;
@@ -264,36 +254,22 @@
 
         PhoneNumberFormatter.setPhoneNumberFormattingTextWatcher(getActivity(), mDigits);
 
-        DisplayMetrics dm = getResources().getDisplayMetrics();
-        int minCellSize = (int) (56 * dm.density); // 56dip == minimum size of menu buttons
-        int cellCount = dm.widthPixels / minCellSize;
-        int fakeMenuItemWidth = dm.widthPixels / cellCount;
-        if (DEBUG) Log.d(TAG, "The size of fake menu buttons (in pixel): " + fakeMenuItemWidth);
-
-        // Soft menu button should appear only when there's no hardware menu button.
-        mMenuButton = fragmentView.findViewById(R.id.overflow_menu);
-        if (mMenuButton != null) {
-            mMenuButton.setMinimumWidth(fakeMenuItemWidth);
-            if (ViewConfiguration.get(getActivity()).hasPermanentMenuKey()) {
-                // This is required for dialpad button's layout, so must not use GONE here.
-                mMenuButton.setVisibility(View.INVISIBLE);
-            } else {
-                mMenuButton.setOnClickListener(this);
-            }
-        }
-        mSearchButton = fragmentView.findViewById(R.id.searchButton);
-        if (mSearchButton != null) {
-            mSearchButton.setMinimumWidth(fakeMenuItemWidth);
-            mSearchButton.setOnClickListener(this);
-        }
-
         // Check for the presence of the keypad
         View oneButton = fragmentView.findViewById(R.id.one);
         if (oneButton != null) {
             setupKeypad(fragmentView);
         }
 
+        DisplayMetrics dm = getResources().getDisplayMetrics();
+        int minCellSize = (int) (56 * dm.density); // 56dip == minimum size of menu buttons
+        int cellCount = dm.widthPixels / minCellSize;
+        int fakeMenuItemWidth = dm.widthPixels / cellCount;
         mDialButtonContainer = fragmentView.findViewById(R.id.dialButtonContainer);
+        if (mDialButtonContainer != null) {
+            mDialButtonContainer.setPadding(
+                    fakeMenuItemWidth, mDialButtonContainer.getPaddingTop(),
+                    fakeMenuItemWidth, mDialButtonContainer.getPaddingBottom());
+        }
         mDialButton = fragmentView.findViewById(R.id.dialButton);
         if (r.getBoolean(R.bool.config_show_onscreen_dial_button)) {
             mDialButton.setOnClickListener(this);
@@ -323,8 +299,6 @@
 
         configureScreenFromIntent(getActivity().getIntent());
 
-        updateFakeMenuButtonsVisibility(mShowOptionsMenu);
-
         return fragmentView;
     }
 
@@ -832,26 +806,12 @@
                 dialButtonPressed();
                 return;
             }
-            case R.id.searchButton: {
-                mHaptic.vibrate();
-                if (mListener != null) {
-                    mListener.onSearchButtonPressed();
-                }
-                return;
-            }
             case R.id.digits: {
                 if (!isDigitsEmpty()) {
                     mDigits.setCursorVisible(true);
                 }
                 return;
             }
-            case R.id.overflow_menu: {
-                PopupMenu popup = constructPopupMenu(view);
-                if (popup != null) {
-                    popup.show();
-                }
-                return;
-            }
             default: {
                 Log.wtf(TAG, "Unexpected onClick() event from: " + view);
                 return;
@@ -859,7 +819,7 @@
         }
     }
 
-    private PopupMenu constructPopupMenu(View anchorView) {
+    public PopupMenu constructPopupMenu(View anchorView) {
         final Context context = getActivity();
         if (context == null) {
             return null;
@@ -1568,40 +1528,4 @@
         intent.putExtra(EXTRA_SEND_EMPTY_FLASH, true);
         return intent;
     }
-
-    public void setListener(Listener listener) {
-        mListener = listener;
-    }
-
-    @Override
-    public void setMenuVisibility(boolean menuVisible) {
-        mShowOptionsMenu = menuVisible;
-        updateFakeMenuButtonsVisibility(menuVisible);
-    }
-
-    /**
-     * Update visibility of the search button and menu button at the bottom of dialer screen, which
-     * should be invisible when bottom ActionBar's real items are available and be visible
-     * otherwise.
-     *
-     * @param visible True when visible.
-     */
-    public void updateFakeMenuButtonsVisibility(boolean visible) {
-        if (DEBUG) Log.d(TAG, "updateFakeMenuButtonVisibility(" + visible + ")");
-
-        if (mSearchButton != null) {
-            if (visible) {
-                mSearchButton.setVisibility(View.VISIBLE);
-            } else {
-                mSearchButton.setVisibility(View.INVISIBLE);
-            }
-        }
-        if (mMenuButton != null) {
-            if (visible && !ViewConfiguration.get(getActivity()).hasPermanentMenuKey()) {
-                mMenuButton.setVisibility(View.VISIBLE);
-            } else {
-                mMenuButton.setVisibility(View.INVISIBLE);
-            }
-        }
-    }
 }