Introduce overflow menu button

Available when there's no hard menu key on the device.

Also remove Call Settings menu from favorite screen.

Bug: 5001942
Change-Id: Ib0ff3fb15a26001dbdad4756bfa4e4bfe1652da2
diff --git a/res/layout/dialpad_fragment.xml b/res/layout/dialpad_fragment.xml
index aee2c25..9f8c0cf 100644
--- a/res/layout/dialpad_fragment.xml
+++ b/res/layout/dialpad_fragment.xml
@@ -22,20 +22,35 @@
     android:layout_marginLeft="8dip"
     android:layout_marginRight="8dip" >
 
-    <!-- Text field above the keypad where the digits are displayed.
-         It's type is set to NULL (to disable the IME keyboard) in the
-         java code.
-
-         Background drawable can be controlled programatically.
-    -->
-    <EditText android:id="@+id/digits"
+    <!-- Text field and possibly soft menu button above the keypad where
+         the digits are displayed. -->
+    <RelativeLayout
         android:layout_width="match_parent"
         android:layout_height="@dimen/dialpad_digits_height"
         android:layout_marginTop="4dip"
         android:gravity="center"
-        android:textAppearance="@style/DialtactsDigitsTextAppearance"
-        android:background="@drawable/dialpad_background"
-        android:textColor="?android:attr/textColorPrimary" />
+        android:background="@drawable/dialpad_background" >
+
+        <!-- Type of this EditText is set to NULL (to disable the IME keyboard)
+             in the java code.
+
+             Background drawable can be controlled programatically. -->
+        <EditText android:id="@+id/digits"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_alignParentLeft="true"
+            android:layout_toLeftOf="@+id/moreoverflow"
+            android:gravity="center"
+            android:textAppearance="@style/DialtactsDigitsTextAppearance"
+            android:textColor="?android:attr/textColorPrimary" />
+
+        <ImageButton android:id="@+id/overflow_menu"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_alignParentRight="true"
+            android:src="@drawable/ic_menu_overflow" />
+
+    </RelativeLayout>
 
     <!-- Keypad section -->
     <include layout="@layout/dialpad" />
diff --git a/res/menu/call_log_options.xml b/res/menu/call_log_options.xml
index 57d637e..1f8de57 100644
--- a/res/menu/call_log_options.xml
+++ b/res/menu/call_log_options.xml
@@ -19,4 +19,9 @@
         android:icon="@android:drawable/ic_menu_close_clear_cancel"
         android:title="@string/recentCalls_deleteAll"
         android:showAsAction="withText" />
+
+    <item
+        android:id="@+id/menu_call_settings_call_log"
+        android:title="@string/call_settings"
+        android:showAsAction="withText" />
 </menu>
diff --git a/res/menu/dialpad_options.xml b/res/menu/dialpad_options.xml
index 77da9cb..c736e34 100644
--- a/res/menu/dialpad_options.xml
+++ b/res/menu/dialpad_options.xml
@@ -30,4 +30,9 @@
         android:icon="@drawable/ic_menu_wait"
         android:title="@string/add_wait"
         android:showAsAction="withText" />
+
+    <item
+        android:id="@+id/menu_call_settings_dialpad"
+        android:title="@string/call_settings"
+        android:showAsAction="withText" />
 </menu>
diff --git a/res/menu/dialtacts_options.xml b/res/menu/dialtacts_options.xml
index a5ed153..aa3af3f 100644
--- a/res/menu/dialtacts_options.xml
+++ b/res/menu/dialtacts_options.xml
@@ -15,11 +15,6 @@
 -->
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
     <item
-        android:id="@+id/menu_call_settings"
-        android:title="@string/call_settings"
-        android:showAsAction="withText" />
-
-    <item
         android:id="@+id/search_on_action_bar"
         android:icon="@android:drawable/ic_menu_search"
         android:showAsAction="always" />
diff --git a/src/com/android/contacts/activities/DialtactsActivity.java b/src/com/android/contacts/activities/DialtactsActivity.java
index 5dbe87b..e345db7 100644
--- a/src/com/android/contacts/activities/DialtactsActivity.java
+++ b/src/com/android/contacts/activities/DialtactsActivity.java
@@ -592,16 +592,6 @@
 
     @Override
     public boolean onPrepareOptionsMenu(Menu menu) {
-        final MenuItem callSettingsMenuItem = menu.findItem(R.id.menu_call_settings);
-        if (!mInSearchUi) {
-            callSettingsMenuItem.setVisible(!mInSearchUi);
-            Intent settingsIntent = new Intent(Intent.ACTION_MAIN);
-            settingsIntent.setClassName(PHONE_PACKAGE, CALL_SETTINGS_CLASS_NAME);
-            callSettingsMenuItem.setIntent(settingsIntent);
-        } else {
-            callSettingsMenuItem.setVisible(false);
-        }
-
         final MenuItem searchMenuItem = menu.findItem(R.id.search_on_action_bar);
         if (mInSearchUi || getActionBar().getSelectedTab().getPosition() == TAB_INDEX_DIALER) {
             searchMenuItem.setVisible(false);
@@ -753,4 +743,11 @@
             ((ViewPagerVisibilityListener) fragment).onVisibilityChanged(visibility);
         }
     }
+
+    /** Returns an Intent to launch Call Settings screen */
+    public static Intent getCallSettingsIntent() {
+        final Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setClassName(PHONE_PACKAGE, CALL_SETTINGS_CLASS_NAME);
+        return intent;
+    }
 }
diff --git a/src/com/android/contacts/calllog/CallLogFragment.java b/src/com/android/contacts/calllog/CallLogFragment.java
index 84e6a8a..12e5cda 100644
--- a/src/com/android/contacts/calllog/CallLogFragment.java
+++ b/src/com/android/contacts/calllog/CallLogFragment.java
@@ -21,6 +21,7 @@
 import com.android.contacts.ContactPhotoManager;
 import com.android.contacts.ContactsUtils;
 import com.android.contacts.R;
+import com.android.contacts.activities.DialtactsActivity;
 import com.android.contacts.activities.DialtactsActivity.ViewPagerVisibilityListener;
 import com.android.contacts.util.ExpirableCache;
 import com.android.internal.telephony.CallerInfo;
@@ -61,6 +62,7 @@
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
+import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.widget.AdapterView;
@@ -147,7 +149,7 @@
     private String mCurrentCountryIso;
     private boolean mScrollToTop;
 
-    private boolean mShowMenu;
+    private boolean mShowOptionsMenu;
 
     public static final class ContactInfo {
         public long personId;
@@ -981,7 +983,14 @@
 
     @Override
     public void onPrepareOptionsMenu(Menu menu) {
-        menu.findItem(R.id.delete_all).setVisible(mShowMenu);
+        menu.findItem(R.id.delete_all).setVisible(mShowOptionsMenu);
+        final MenuItem callSettingsMenuItem = menu.findItem(R.id.menu_call_settings_call_log);
+        if (mShowOptionsMenu) {
+            callSettingsMenuItem.setVisible(true);
+            callSettingsMenuItem.setIntent(DialtactsActivity.getCallSettingsIntent());
+        } else {
+            callSettingsMenuItem.setVisible(false);
+        }
     }
 
     @Override
@@ -1216,6 +1225,6 @@
 
     @Override
     public void onVisibilityChanged(boolean visible) {
-        mShowMenu = visible;
+        mShowOptionsMenu = visible;
     }
 }
diff --git a/src/com/android/contacts/dialpad/DialpadFragment.java b/src/com/android/contacts/dialpad/DialpadFragment.java
index af706b8..be873c6 100644
--- a/src/com/android/contacts/dialpad/DialpadFragment.java
+++ b/src/com/android/contacts/dialpad/DialpadFragment.java
@@ -24,7 +24,6 @@
 import com.android.internal.telephony.ITelephony;
 import com.android.phone.CallLogAsync;
 import com.android.phone.HapticFeedback;
-import com.google.i18n.phonenumbers.PhoneNumberUtil;
 
 import android.app.Activity;
 import android.app.Fragment;
@@ -62,12 +61,14 @@
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
+import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.EditText;
 import android.widget.ImageView;
 import android.widget.ListView;
+import android.widget.PopupMenu;
 import android.widget.TextView;
 
 /**
@@ -77,6 +78,7 @@
         implements View.OnClickListener,
         View.OnLongClickListener, View.OnKeyListener,
         AdapterView.OnItemClickListener, TextWatcher,
+        PopupMenu.OnMenuItemClickListener,
         ViewPagerVisibilityListener {
     private static final String TAG = DialpadFragment.class.getSimpleName();
 
@@ -111,7 +113,7 @@
     private ListView mDialpadChooser;
     private DialpadChooserAdapter mDialpadChooserAdapter;
 
-    private boolean mShowMenu;
+    private boolean mShowOptionsMenu;
 
     private boolean mHasVoicemail = false;
 
@@ -266,6 +268,16 @@
             mDigits.addTextChangedListener(mTextWatcher);
         }
 
+        // Soft menu button should appear only when there's no hardware menu button.
+        final View overflowMenuButton = fragmentView.findViewById(R.id.overflow_menu);
+        if (overflowMenuButton != null) {
+            if (ViewConfiguration.get(getActivity()).hasPermanentMenuKey()) {
+                overflowMenuButton.setVisibility(View.GONE);
+            } else {
+                overflowMenuButton.setOnClickListener(this);
+            }
+        }
+
         // Check for the presence of the keypad
         View oneButton = fragmentView.findViewById(R.id.one);
         if (oneButton != null) {
@@ -535,35 +547,51 @@
     @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
         super.onCreateOptionsMenu(menu, inflater);
-        inflater.inflate(R.menu.dialpad_options, menu);
+
+        // If the hardware doesn't have a hardware menu key, we'll show soft menu button on the
+        // right side of digits EditText.
+        if (ViewConfiguration.get(getActivity()).hasPermanentMenuKey()) {
+            inflater.inflate(R.menu.dialpad_options, menu);
+        }
     }
 
     @Override
     public void onPrepareOptionsMenu(Menu menu) {
-        if (mDialpadChooser == null || mDigits == null) {
-            // The layout itself isn't ready yet. Let's ignore this call.
-            return;
+        // Hardware menu key should be available and Views should already be ready.
+        if (ViewConfiguration.get(getActivity()).hasPermanentMenuKey() &&
+                mDialpadChooser != null && mDigits != null) {
+            if (mShowOptionsMenu) {
+                setupMenuItems(menu);
+            } else {
+                menu.findItem(R.id.menu_call_settings_dialpad).setVisible(false);
+                menu.findItem(R.id.menu_add_contacts).setVisible(false);
+                menu.findItem(R.id.menu_2s_pause).setVisible(false);
+                menu.findItem(R.id.menu_add_wait).setVisible(false);
+            }
         }
+    }
 
+    private void setupMenuItems(Menu menu) {
+        final MenuItem callSettingsMenuItem = menu.findItem(R.id.menu_call_settings_dialpad);
         final MenuItem addToContactMenuItem = menu.findItem(R.id.menu_add_contacts);
-        final MenuItem m2SecPauseMenuItem = menu.findItem(R.id.menu_2s_pause);
-        final MenuItem mWaitMenuItem = menu.findItem(R.id.menu_add_wait);
+        final MenuItem twoSecPauseMenuItem = menu.findItem(R.id.menu_2s_pause);
+        final MenuItem waitMenuItem = menu.findItem(R.id.menu_add_wait);
+
+        callSettingsMenuItem.setVisible(true);
+        callSettingsMenuItem.setIntent(DialtactsActivity.getCallSettingsIntent());
 
         // We show "add to contacts", "2sec pause", and "add wait" menus only when the user is
         // seeing usual dialpads and has typed at least one digit.
         // We never show a menu if the "choose dialpad" UI is up.
-        if (!mShowMenu || dialpadChooserVisible() || isDigitsEmpty()) {
+        if (dialpadChooserVisible() || isDigitsEmpty()) {
             addToContactMenuItem.setVisible(false);
-            m2SecPauseMenuItem.setVisible(false);
-            mWaitMenuItem.setVisible(false);
+            twoSecPauseMenuItem.setVisible(false);
+            waitMenuItem.setVisible(false);
         } else {
-            CharSequence digits = mDigits.getText();
+            final CharSequence digits = mDigits.getText();
 
             // Put the current digits string into an intent
-            Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
-            intent.putExtra(Insert.PHONE, digits);
-            intent.setType(People.CONTENT_ITEM_TYPE);
-            addToContactMenuItem.setIntent(intent);
+            addToContactMenuItem.setIntent(getAddToContactIntent(digits));
             addToContactMenuItem.setVisible(true);
 
             // Check out whether to show Pause & Wait option menu items
@@ -584,25 +612,32 @@
 
                 if (selectionStart != 0) {
                     // Pause can be visible if cursor is not in the begining
-                    m2SecPauseMenuItem.setVisible(true);
+                    twoSecPauseMenuItem.setVisible(true);
 
                     // For Wait to be visible set of condition to meet
-                    mWaitMenuItem.setVisible(showWait(selectionStart,
-                                                      selectionEnd, strDigits));
+                    waitMenuItem.setVisible(showWait(selectionStart, selectionEnd, strDigits));
                 } else {
                     // cursor in the beginning both pause and wait to be invisible
-                    m2SecPauseMenuItem.setVisible(false);
-                    mWaitMenuItem.setVisible(false);
+                    twoSecPauseMenuItem.setVisible(false);
+                    waitMenuItem.setVisible(false);
                 }
             } else {
+                twoSecPauseMenuItem.setVisible(true);
+
                 // cursor is not selected so assume new digit is added to the end
                 int strLength = strDigits.length();
-                mWaitMenuItem.setVisible(showWait(strLength,
-                                                      strLength, strDigits));
+                waitMenuItem.setVisible(showWait(strLength, strLength, strDigits));
             }
         }
     }
 
+    private static Intent getAddToContactIntent(CharSequence digits) {
+        final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
+        intent.putExtra(Insert.PHONE, digits);
+        intent.setType(People.CONTENT_ITEM_TYPE);
+        return intent;
+    }
+
     private void keyPressed(int keyCode) {
         mHaptic.vibrate();
         KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
@@ -706,9 +741,28 @@
                 }
                 return;
             }
+            case R.id.overflow_menu: {
+                PopupMenu popup = constructPopupMenu(view);
+                if (popup != null) {
+                    popup.show();
+                }
+            }
         }
     }
 
+    private PopupMenu constructPopupMenu(View anchorView) {
+        final Context context = getActivity();
+        if (context == null) {
+            return null;
+        }
+        final PopupMenu popupMenu = new PopupMenu(context, anchorView);
+        final Menu menu = popupMenu.getMenu();
+        popupMenu.inflate(R.menu.dialpad_options);
+        popupMenu.setOnMenuItemClickListener(this);
+        setupMenuItems(menu);
+        return popupMenu;
+    }
+
     public boolean onLongClick(View view) {
         final Editable digits = mDigits.getText();
         int id = view.getId();
@@ -1091,6 +1145,11 @@
         return false;
     }
 
+    @Override
+    public boolean onMenuItemClick(MenuItem item) {
+        return onOptionsItemSelected(item);
+    }
+
     /**
      * Updates the dial string (mDigits) after inserting a Pause character (,)
      * or Wait character (;).
@@ -1163,7 +1222,7 @@
      * otherwise returns false. Assumes the passed string is non-empty
      * and the 0th index check is not required.
      */
-    private boolean showWait(int start, int end, String digits) {
+    private static boolean showWait(int start, int end, String digits) {
         if (start == end) {
             // visible false in this case
             if (start > digits.length()) return false;
@@ -1241,6 +1300,6 @@
 
     @Override
     public void onVisibilityChanged(boolean visible) {
-        mShowMenu = visible;
+        mShowOptionsMenu = visible;
     }
 }