Merge "Make ContactPreferences use SharedPreferences instead of System settings (5/5)" into lmp-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 40a17f9..03b349f 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -277,7 +277,8 @@
                   android:launchMode="singleInstance"
                   android:configChanges="keyboardHidden"
                   android:exported="false"
-                  android:process="com.android.incallui">
+                  android:process="com.android.incallui"
+                  android:screenOrientation="nosensor">
         </activity>
 
         <!-- BroadcastReceiver for receiving Intents from Notification mechanism. -->
diff --git a/res/layout/call_log_list_item_actions.xml b/res/layout/call_log_list_item_actions.xml
index 22fcca0..ac83f4a 100644
--- a/res/layout/call_log_list_item_actions.xml
+++ b/res/layout/call_log_list_item_actions.xml
@@ -41,6 +41,22 @@
             android:textSize="@dimen/call_log_list_item_actions_text_size"
             android:textStyle="bold"
             android:nextFocusLeft="@+id/primary_action_view"
+            android:nextFocusRight="@+id/video_call_action"
+            android:focusable="true"
+            android:singleLine="true"/>
+        <TextView
+            android:id="@+id/video_call_action"
+            android:background="@drawable/action_button_background"
+            android:gravity="center"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:paddingStart="@dimen/call_log_action_horizontal_padding"
+            android:paddingEnd="@dimen/call_log_action_horizontal_padding"
+            android:text="@string/call_log_action_video_call"
+            android:textColor="?attr/call_log_secondary_text_color"
+            android:textSize="@dimen/call_log_list_item_actions_text_size"
+            android:textStyle="bold"
+            android:nextFocusLeft="@+id/call_back_action"
             android:nextFocusRight="@+id/voicemail_action"
             android:focusable="true"
             android:singleLine="true"/>
@@ -56,7 +72,7 @@
             android:textColor="@color/call_log_action_text"
             android:textSize="@dimen/call_log_list_item_actions_text_size"
             android:textStyle="bold"
-            android:nextFocusLeft="@+id/call_back_action"
+            android:nextFocusLeft="@+id/video_call_action"
             android:nextFocusRight="@+id/details_action"
             android:focusable="true"
             android:singleLine="true"/>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 29b9651..17984fd 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -425,6 +425,14 @@
     -->
     <string name="description_num_calls"><xliff:g id="numberOfCalls">%1$s</xliff:g> calls.</string>
 
+    <!-- String indicating a call log entry had video capabilities.
+
+    Note: AccessibilityServices use this attribute to announce what the view represents.
+          This is especially valuable for views without textual representation like ImageView.
+          [CHAR LIMIT=NONE]
+    -->
+    <string name="description_video_call">Video call.</string>
+
     <!-- String describing the button to SMS a number or contact.
 
         Note: AccessibilityServices use this attribute to announce what the view represents.
@@ -641,21 +649,6 @@
          [CHAR LIMIT=NONE] -->
     <string name="description_outgoing_call">Call to <xliff:g id="nameOrNumber" example="John Smith">%1$s</xliff:g>, <xliff:g id="typeOrLocation" example="Mobile">%2$s</xliff:g>, <xliff:g id="timeOfCall" example="2 min ago">%3$s</xliff:g>.</string>
 
-    <!-- String describing an incoming missed video call entry in the call log.
-         Note: AccessibilityServices uses this attribute to announce what the view represents.
-         [CHAR LIMIT=NONE] -->
-    <string name="description_incoming_missed_video_call">Missed video call from <xliff:g id="nameOrNumber" example="John Smith">%1$s</xliff:g>, <xliff:g id="typeOrLocation" example="Mobile">%2$s</xliff:g>, <xliff:g id="timeOfCall" example="2 min ago">%3$s</xliff:g>.</string>
-
-    <!-- String describing an incoming answered video call entry in the call log.
-         Note: AccessibilityServices uses this attribute to announce what the view represents.
-         [CHAR LIMIT=NONE] -->
-    <string name="description_incoming_answered_video_call">Answered video call from <xliff:g id="nameOrNumber" example="John Smith">%1$s</xliff:g>, <xliff:g id="typeOrLocation" example="Mobile">%2$s</xliff:g>, <xliff:g id="timeOfCall" example="2 min ago">%3$s</xliff:g>.</string>
-
-    <!-- String describing an outgoing video call entry in the call log.
-         Note: AccessibilityServices uses this attribute to announce what the view represents.
-         [CHAR LIMIT=NONE] -->
-    <string name="description_outgoing_video_call">Video call to <xliff:g id="nameOrNumber" example="John Smith">%1$s</xliff:g>, <xliff:g id="typeOrLocation" example="Mobile">%2$s</xliff:g>, <xliff:g id="timeOfCall" example="2 min ago">%3$s</xliff:g>.</string>
-
     <!-- String describing the "call back" action for an entry in the call log.  The call back
          action triggers a return call to the named user.
          Note: AccessibilityServices uses this attribute to announce the purpose of the button.
diff --git a/res/values/styles.xml b/res/values/styles.xml
index a7c1ec1..5df218b 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -28,6 +28,7 @@
         <item name="android:homeAsUpIndicator">@drawable/ic_back_arrow</item>
         <item name="android:windowContentOverlay">@null</item>
         <item name="android:listViewStyle">@style/ListViewStyle</item>
+        <item name="android:overlapAnchor">true</item>
         <item name="activated_background">@drawable/list_item_activated_background</item>
         <item name="section_header_background">@drawable/list_title_holo</item>
         <item name="list_section_header_height">32dip</item>
diff --git a/src/com/android/dialer/DialtactsActivity.java b/src/com/android/dialer/DialtactsActivity.java
index d08b38f..a19964b 100644
--- a/src/com/android/dialer/DialtactsActivity.java
+++ b/src/com/android/dialer/DialtactsActivity.java
@@ -42,6 +42,7 @@
 import android.text.TextWatcher;
 import android.util.Log;
 import android.view.DragEvent;
+import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -111,9 +112,6 @@
 
     public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    /** Temporary flag for disabling account selection menu */
-    public static final boolean ENABLE_ACCOUNT_SELECT = false;
-
     public static final String SHARED_PREFS_NAME = "com.android.dialer_preferences";
 
     /** Used to open Call Setting */
@@ -216,6 +214,7 @@
      */
     private String mPendingSearchViewQuery;
 
+    private PopupMenu mOverflowMenu;
     private EditText mSearchView;
     private View mVoiceSearchButton;
 
@@ -238,7 +237,7 @@
 
     private class OptionsPopupMenu extends PopupMenu {
         public OptionsPopupMenu(Context context, View anchor) {
-            super(context, anchor);
+            super(context, anchor, Gravity.END);
         }
 
         @Override
@@ -396,8 +395,8 @@
         ImageButton optionsMenuButton =
                 (ImageButton) searchEditTextLayout.findViewById(R.id.dialtacts_options_menu_button);
         optionsMenuButton.setOnClickListener(this);
-        final OptionsPopupMenu optionsMenu = buildOptionsMenu(optionsMenuButton);
-        optionsMenuButton.setOnTouchListener(optionsMenu.getDragToOpenListener());
+        mOverflowMenu = buildOptionsMenu(searchEditTextLayout);
+        optionsMenuButton.setOnTouchListener(mOverflowMenu.getDragToOpenListener());
 
         // Add the favorites fragment, and the dialpad fragment, but only if savedInstanceState
         // is null. Otherwise the fragment manager takes care of recreating these fragments.
@@ -546,7 +545,7 @@
                 }
                 break;
             case R.id.dialtacts_options_menu_button:
-                buildOptionsMenu(view).show();
+                mOverflowMenu.show();
                 break;
             default: {
                 Log.wtf(TAG, "Unexpected onClick event from " + view);
diff --git a/src/com/android/dialer/calllog/CallDetailHistoryAdapter.java b/src/com/android/dialer/calllog/CallDetailHistoryAdapter.java
index cc116e7..105462f 100644
--- a/src/com/android/dialer/calllog/CallDetailHistoryAdapter.java
+++ b/src/com/android/dialer/calllog/CallDetailHistoryAdapter.java
@@ -122,11 +122,12 @@
         TextView durationView = (TextView) result.findViewById(R.id.duration);
 
         int callType = details.callTypes[0];
+        boolean isVideoCall = (details.features & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO;
+
         callTypeIconView.clear();
         callTypeIconView.add(callType);
-        callTypeIconView.setShowVideo(
-                (details.features & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO);
-        callTypeTextView.setText(mCallTypeHelper.getCallTypeText(callType));
+        callTypeIconView.setShowVideo(isVideoCall);
+        callTypeTextView.setText(mCallTypeHelper.getCallTypeText(callType, isVideoCall));
         // Set the date.
         CharSequence dateValue = DateUtils.formatDateRange(mContext, details.date, details.date,
                 DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE |
diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java
index f4b9f3a..d70a40d 100644
--- a/src/com/android/dialer/calllog/CallLogAdapter.java
+++ b/src/com/android/dialer/calllog/CallLogAdapter.java
@@ -895,6 +895,7 @@
             // focus was successful.  The first successful focus will satisfy the OR
             // block and block further attempts to set focus.
             boolean focused = views.callBackButtonView.requestAccessibilityFocus() ||
+                    views.videoCallButtonView.requestAccessibilityFocus() ||
                     views.voicemailButtonView.requestAccessibilityFocus() ||
                     views.detailsButtonView.requestAccessibilityFocus();
         } else {
@@ -929,6 +930,11 @@
                     R.id.call_back_action);
         }
 
+        if (views.videoCallButtonView == null) {
+            views.videoCallButtonView = (TextView)views.actionsView.findViewById(
+                    R.id.video_call_action);
+        }
+
         if (views.voicemailButtonView == null) {
             views.voicemailButtonView = (TextView)views.actionsView.findViewById(
                     R.id.voicemail_action);
@@ -960,8 +966,10 @@
      * @param views  The call log item views.
      */
     private void bindActionButtons(CallLogListItemViews views) {
+        boolean canPlaceCallToNumber =
+                PhoneNumberUtilsWrapper.canPlaceCallsTo(views.number, views.numberPresentation);
         // Set return call intent, otherwise null.
-        if (PhoneNumberUtilsWrapper.canPlaceCallsTo(views.number, views.numberPresentation)) {
+        if (canPlaceCallToNumber) {
             // Sets the primary action to call the number.
             views.callBackButtonView.setTag(
                     IntentProvider.getReturnCallIntentProvider(views.number, views.mAccount));
@@ -973,6 +981,18 @@
             views.callBackButtonView.setVisibility(View.GONE);
         }
 
+        // If one of the calls had video capabilities, show the video call button.
+        if (canPlaceCallToNumber && views.phoneCallDetailsViews.callTypeIcons.isVideoShown()) {
+            views.videoCallButtonView.setTag(
+                    IntentProvider.getReturnVideoCallIntentProvider(views.number,
+                            views.mAccount));
+            views.videoCallButtonView.setVisibility(View.VISIBLE);
+            views.videoCallButtonView.setOnClickListener(mActionListener);
+        } else {
+            views.videoCallButtonView.setTag(null);
+            views.videoCallButtonView.setVisibility(View.GONE);
+        }
+
         // For voicemail calls, show the "VOICEMAIL" action button; hide otherwise.
         if (views.callType == Calls.VOICEMAIL_TYPE) {
             views.voicemailButtonView.setOnClickListener(mActionListener);
@@ -991,6 +1011,7 @@
                     IntentProvider.getCallDetailIntentProvider(
                             views.rowId, views.callIds, null)
             );
+
             if (views.isExternal && !views.reported) {
                 views.reportButtonView.setVisibility(View.VISIBLE);
             }
diff --git a/src/com/android/dialer/calllog/CallLogListItemHelper.java b/src/com/android/dialer/calllog/CallLogListItemHelper.java
index cb7c7cd..b2c1e2d 100644
--- a/src/com/android/dialer/calllog/CallLogListItemHelper.java
+++ b/src/com/android/dialer/calllog/CallLogListItemHelper.java
@@ -77,6 +77,9 @@
         views.callBackButtonView.setContentDescription(
                 mResources.getString(R.string.description_call_back_action, views.nameOrNumber));
 
+        views.videoCallButtonView.setContentDescription(
+                mResources.getString(R.string.description_video_call_action, views.nameOrNumber));
+
         views.voicemailButtonView.setContentDescription(
                 mResources.getString(R.string.description_voicemail_action, views.nameOrNumber));
 
@@ -149,6 +152,11 @@
                     details.callTypes.length));
         }
 
+        // If call had video capabilities, add the "Video Call" string.
+        if ((details.features & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO) {
+            callDescription.append(mResources.getString(R.string.description_video_call));
+        }
+
         int stringID = getCallDescriptionStringID(details);
 
         // Use chosen string resource to build up the message.
diff --git a/src/com/android/dialer/calllog/CallLogListItemViews.java b/src/com/android/dialer/calllog/CallLogListItemViews.java
index 3efa5cb..70d545e 100644
--- a/src/com/android/dialer/calllog/CallLogListItemViews.java
+++ b/src/com/android/dialer/calllog/CallLogListItemViews.java
@@ -44,6 +44,8 @@
     public View actionsView;
     /** The "call back" action button - assigned only when the action section is expanded. */
     public TextView callBackButtonView;
+    /** The "video call" action button - assigned only when the action section is expanded. */
+    public TextView videoCallButtonView;
     /** The "voicemail" action button - assigned only when the action section is expanded. */
     public TextView voicemailButtonView;
     /** The "details" action button - assigned only when the action section is expanded. */
diff --git a/src/com/android/dialer/calllog/CallTypeHelper.java b/src/com/android/dialer/calllog/CallTypeHelper.java
index 1c4f44f..36c0975 100644
--- a/src/com/android/dialer/calllog/CallTypeHelper.java
+++ b/src/com/android/dialer/calllog/CallTypeHelper.java
@@ -31,6 +31,12 @@
     private final CharSequence mOutgoingName;
     /** Name used to identify missed calls. */
     private final CharSequence mMissedName;
+    /** Name used to identify incoming video calls. */
+    private final CharSequence mIncomingVideoName;
+    /** Name used to identify outgoing video calls. */
+    private final CharSequence mOutgoingVideoName;
+    /** Name used to identify missed video calls. */
+    private final CharSequence mMissedVideoName;
     /** Name used to identify voicemail calls. */
     private final CharSequence mVoicemailName;
     /** Color used to identify new missed calls. */
@@ -43,22 +49,37 @@
         mIncomingName = resources.getString(R.string.type_incoming);
         mOutgoingName = resources.getString(R.string.type_outgoing);
         mMissedName = resources.getString(R.string.type_missed);
+        mIncomingVideoName = resources.getString(R.string.type_incoming_video);
+        mOutgoingVideoName = resources.getString(R.string.type_outgoing_video);
+        mMissedVideoName = resources.getString(R.string.type_missed_video);
         mVoicemailName = resources.getString(R.string.type_voicemail);
         mNewMissedColor = resources.getColor(R.color.call_log_missed_call_highlight_color);
         mNewVoicemailColor = resources.getColor(R.color.call_log_voicemail_highlight_color);
     }
 
     /** Returns the text used to represent the given call type. */
-    public CharSequence getCallTypeText(int callType) {
+    public CharSequence getCallTypeText(int callType, boolean isVideoCall) {
         switch (callType) {
             case Calls.INCOMING_TYPE:
-                return mIncomingName;
+                if (isVideoCall) {
+                    return mIncomingVideoName;
+                } else {
+                    return mIncomingName;
+                }
 
             case Calls.OUTGOING_TYPE:
-                return mOutgoingName;
+                if (isVideoCall) {
+                    return mOutgoingVideoName;
+                } else {
+                    return mOutgoingName;
+                }
 
             case Calls.MISSED_TYPE:
-                return mMissedName;
+                if (isVideoCall) {
+                    return mMissedVideoName;
+                } else {
+                    return mMissedName;
+                }
 
             case Calls.VOICEMAIL_TYPE:
                 return mVoicemailName;
diff --git a/src/com/android/dialer/calllog/CallTypeIconsView.java b/src/com/android/dialer/calllog/CallTypeIconsView.java
index 382056c..ef729ae 100644
--- a/src/com/android/dialer/calllog/CallTypeIconsView.java
+++ b/src/com/android/dialer/calllog/CallTypeIconsView.java
@@ -85,6 +85,15 @@
         }
     }
 
+    /**
+     * Determines if the video icon should be shown.
+     *
+     * @return True if the video icon should be shown.
+     */
+    public boolean isVideoShown() {
+        return mShowVideo;
+    }
+
     @NeededForTesting
     public int getCount() {
         return mCallTypes.size();
diff --git a/src/com/android/dialer/calllog/IntentProvider.java b/src/com/android/dialer/calllog/IntentProvider.java
index 9820102..c52dff8 100644
--- a/src/com/android/dialer/calllog/IntentProvider.java
+++ b/src/com/android/dialer/calllog/IntentProvider.java
@@ -47,6 +47,16 @@
         };
     }
 
+    public static IntentProvider getReturnVideoCallIntentProvider(final String number,
+            final PhoneAccount account) {
+        return new IntentProvider() {
+            @Override
+            public Intent getIntent(Context context) {
+                return CallUtil.getVideoCallIntent(number, account);
+            }
+        };
+    }
+
     public static IntentProvider getPlayVoicemailIntentProvider(final long rowId,
             final String voicemailUri) {
         return new IntentProvider() {
diff --git a/tests/src/com/android/dialer/PhoneCallDetailsHelperTest.java b/tests/src/com/android/dialer/PhoneCallDetailsHelperTest.java
index 147201b..d0c13ee 100644
--- a/tests/src/com/android/dialer/PhoneCallDetailsHelperTest.java
+++ b/tests/src/com/android/dialer/PhoneCallDetailsHelperTest.java
@@ -159,6 +159,22 @@
         assertCallTypeIconsEquals(Calls.VOICEMAIL_TYPE);
     }
 
+    /**
+     * Tests a case where the video call feature is present.
+     */
+    public void testSetPhoneCallDetails_Video() {
+        setPhoneCallDetailsWithFeatures(Calls.FEATURES_VIDEO);
+        assertIsVideoCall(true);
+    }
+
+    /**
+     * Tests a case where the video call feature is not present.
+     */
+    public void testSetPhoneCallDetails_NoVideo() {
+        setPhoneCallDetailsWithFeatures(Calls.FEATURES_NONE);
+        assertIsVideoCall(false);
+    }
+
     public void testSetPhoneCallDetails_MultipleCallTypeIcons() {
         setPhoneCallDetailsWithCallTypeIcons(Calls.INCOMING_TYPE, Calls.OUTGOING_TYPE);
         assertCallTypeIconsEquals(Calls.INCOMING_TYPE, Calls.OUTGOING_TYPE);
@@ -258,6 +274,11 @@
         assertTrue(mViews.callLocationAndDate.getText().toString().contains(text));
     }
 
+    /** Asserts that the video icon is shown. */
+    private void assertIsVideoCall(boolean isVideoCall) {
+        assertEquals(isVideoCall, mViews.callTypeIcons.isVideoShown());
+    }
+
     /** Asserts that the call type contains the images with the given drawables. */
     private void assertCallTypeIconsEquals(int... ids) {
         assertEquals(ids.length, mViews.callTypeIcons.getCount());
@@ -325,6 +346,18 @@
         );
     }
 
+    /**
+     * Sets the phone call details with default values and the given call features.
+     */
+    private void setPhoneCallDetailsWithFeatures(int features) {
+        mHelper.setPhoneCallDetails(mViews,
+                new PhoneCallDetails(TEST_NUMBER, Calls.PRESENTATION_ALLOWED,
+                        TEST_FORMATTED_NUMBER, TEST_COUNTRY_ISO, TEST_GEOCODE,
+                        new int[]{ Calls.INCOMING_TYPE }, TEST_DATE, TEST_DURATION, null,
+                        features, null)
+        );
+    }
+
     private void setCallDetailsHeaderWithNumber(String number, int presentation) {
         mHelper.setCallDetailsHeader(mNameView,
                 new PhoneCallDetails(number, presentation,
diff --git a/tests/src/com/android/dialer/calllog/CallLogListItemHelperTest.java b/tests/src/com/android/dialer/calllog/CallLogListItemHelperTest.java
index 8fbda15..4c9d92c 100644
--- a/tests/src/com/android/dialer/calllog/CallLogListItemHelperTest.java
+++ b/tests/src/com/android/dialer/calllog/CallLogListItemHelperTest.java
@@ -327,6 +327,21 @@
                 .contains(this.mResources.getString(R.string.description_num_calls, 2)));
     }
 
+    /**
+     * Test getCallDescription method used to get the accessibility description for calls.
+     * Test that the "Video call." message is present if the call had video capability.
+     */
+    public void testGetCallDescription_Video() {
+        PhoneCallDetails details = new PhoneCallDetails(TEST_NUMBER, Calls.PRESENTATION_ALLOWED,
+                TEST_FORMATTED_NUMBER,
+                TEST_COUNTRY_ISO, TEST_GEOCODE,
+                new int[]{Calls.INCOMING_TYPE, Calls.INCOMING_TYPE}, TEST_DATE, TEST_DURATION,
+                null, Calls.FEATURES_VIDEO, null);
+        CharSequence description = mHelper.getCallDescription(details);
+        assertTrue(description.toString()
+                .contains(this.mResources.getString(R.string.description_video_call, 2)));
+    }
+
     /** Asserts that the primary action view does not have a call intent. */
     private void assertNoCallIntent() {
         Object intentProvider = (IntentProvider)mViews.primaryActionView.getTag();
diff --git a/tests/src/com/android/dialer/calllog/CallLogQueryTestUtils.java b/tests/src/com/android/dialer/calllog/CallLogQueryTestUtils.java
index c13b936..dc3f525 100644
--- a/tests/src/com/android/dialer/calllog/CallLogQueryTestUtils.java
+++ b/tests/src/com/android/dialer/calllog/CallLogQueryTestUtils.java
@@ -29,7 +29,7 @@
     public static Object[] createTestValues() {
         Object[] values = new Object[]{
                 0L, "", 0L, 0L, Calls.INCOMING_TYPE, "", "", "", null, 0, null, null, null, null,
-                0L, null, 0, Calls.PRESENTATION_ALLOWED,
+                0L, null, 0, Calls.PRESENTATION_ALLOWED, null, null, Calls.FEATURES_NONE, null
         };
         assertEquals(CallLogQuery._PROJECTION.length, values.length);
         return values;