summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSantos Cordon <santoscordon@google.com>2013-07-31 16:36:29 -0700
committerSantos Cordon <santoscordon@google.com>2013-08-01 10:28:54 -0700
commit150a5c58c67f230c8fd7293b180bbf50aa761480 (patch)
treec37d6cfe313c0666e7cacf02bdbde958c7534baf
parenta012c22dfbfedffe2e751f9b1ab776baa325a26f (diff)
downloadpackages_apps_InCallUI-150a5c58c67f230c8fd7293b180bbf50aa761480.tar.gz
packages_apps_InCallUI-150a5c58c67f230c8fd7293b180bbf50aa761480.tar.bz2
packages_apps_InCallUI-150a5c58c67f230c8fd7293b180bbf50aa761480.zip
Adding multi-call support.
Before this change, the UI came up when we were notified that a new call came in, but we did not actually look at the call state, etc. This seemingly worked while we only supported single calls but did not scale. This change does two main things: a) Plugs in CallList into the presenters so that they can perform their logic based on the actual state of the calls (necessary for multi-call support) b) Adds Secondary CallInfo UI to the Call Card so that we can display information foreground and background calls. As a result of (a) from above, a lot of changes you see will be to Presenters, which now take their cues from CallList and update their Ui's accordingly. A problem with this approach is that the presenters (callcard/buttons/answer-widget) perform their changes independently. A subsequent change will consolidate interactions with CallList to a Presenter-Manager class and away from the presenters. Change-Id: I89d1926fa1eef6f10d897d2ce360f666c8f341f8
-rw-r--r--res/layout/call_card.xml45
-rw-r--r--res/layout/call_card_fragment.xml136
-rw-r--r--res/layout/primary_call_info.xml284
-rw-r--r--res/layout/secondary_call_info.xml66
-rwxr-xr-xres/values/strings.xml5
-rw-r--r--src/com/android/incallui/AnswerFragment.java59
-rw-r--r--src/com/android/incallui/AnswerPresenter.java45
-rw-r--r--src/com/android/incallui/CallButtonPresenter.java29
-rw-r--r--src/com/android/incallui/CallCardFragment.java29
-rw-r--r--src/com/android/incallui/CallCardPresenter.java22
-rw-r--r--src/com/android/incallui/CallHandlerService.java2
-rw-r--r--src/com/android/incallui/CallList.java38
-rw-r--r--src/com/android/incallui/InCallActivity.java65
13 files changed, 421 insertions, 404 deletions
diff --git a/res/layout/call_card.xml b/res/layout/call_card.xml
new file mode 100644
index 00000000..af47ef75
--- /dev/null
+++ b/res/layout/call_card.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2013 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/call_card"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <!-- The main content of the CallCard is either one or two "call info"
+ blocks, depending on whether one or two lines are in use.
+
+ The call_info blocks are stacked vertically inside a CallCard (LinearLayout),
+ each with layout_weight="1". If only one line is in use (i.e. the
+ common case) then the 2nd call info will be GONE and thus the 1st one
+ will expand to fill the full height of the CallCard. -->
+
+
+ <!-- Primary "call card" block, for the foreground call. -->
+ <include android:id="@+id/primary_call_info"
+ layout="@layout/primary_call_info" />
+
+ <!-- Secondary "Call info" block, for the background ("on hold") call. -->
+ <ViewStub android:id="@+id/secondary_call_info"
+ android:layout="@layout/secondary_call_info"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+</LinearLayout>
diff --git a/res/layout/call_card_fragment.xml b/res/layout/call_card_fragment.xml
deleted file mode 100644
index 44a9f6f6..00000000
--- a/res/layout/call_card_fragment.xml
+++ /dev/null
@@ -1,136 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- ~ Copyright (C) 2013 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1">
-
- <!-- Contact photo for primary call info -->
- <ImageView android:id="@+id/photo"
- android:layout_alignParentStart="true"
- android:layout_alignParentTop="true"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="top|center_horizontal"
- android:scaleType="centerCrop"
- android:contentDescription="@string/contactPhoto"
- android:src="@drawable/picture_unknown"/>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <!-- "Call Banner" for primary call, the foregound or ringing call.
- The "call banner" is a block of info about a single call,
- including the contact name, phone number, call time counter,
- and other status info. This info is shown as a "banner"
- overlaid across the top of contact photo. -->
- <GridLayout android:id="@+id/primary_call_banner"
- style="@style/PrimaryCallInfoPrimaryCallBanner"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="@dimen/call_banner_height"
- android:background="@color/incall_call_banner_background"
- android:paddingStart="@dimen/call_banner_side_padding"
- android:paddingEnd="@dimen/call_banner_side_padding"
- android:paddingTop="@dimen/call_banner_top_bottom_padding"
- android:paddingBottom="@dimen/call_banner_top_bottom_padding"
- >
-
- <!-- Name (or the phone number, if we don't have a name to display). -->
- <TextView android:id="@+id/name"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="@color/incall_call_banner_text_color"
- android:singleLine="true"
- android:textAlignment="viewStart"
- android:layout_column="0"
- android:layout_row="0"
- android:layout_columnSpan="2"
- android:layout_gravity="fill"/>
-
- <!-- Label (like "Mobile" or "Work", if present) and phone number, side by side -->
- <TextView android:id="@+id/phoneNumber"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="@color/incall_call_banner_text_color"
- android:singleLine="true"
- android:textDirection="ltr"
- android:layout_column="0"
- android:layout_row="1"
- android:layout_gravity="fill"/>
-
- <TextView android:id="@+id/label"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="@color/incall_call_banner_text_color"
- android:textAllCaps="true"
- android:singleLine="true"
- android:paddingStart="6dp"
- android:layout_column="1"
- android:layout_row="1"
- android:layout_gravity="fill"/>
-
- <!-- Call type indication: a special label and/or branding
- for certain kinds of calls (like "Internet call" for a SIP call.) -->
- <TextView android:id="@+id/callTypeLabel"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="@color/incall_call_banner_text_color"
- android:maxLines="1"
- android:layout_column="0"
- android:layout_row="2"
- android:layout_columnSpan="2"
- android:ellipsize="end"
- android:layout_gravity="fill"/>
-
- <!-- Elapsed time indication for a call in progress. -->
- <TextView android:id="@+id/elapsedTime"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="@color/incall_call_banner_text_color"
- android:singleLine="true"
- android:visibility="invisible"
- android:layout_column="2"
- android:layout_row="0"
- android:layout_rowSpan="3"
- android:layout_gravity="fill"
- android:gravity="end|center_vertical"/>
- </GridLayout>
- <!-- End of call_banner -->
-
-
- <!-- The "call state label": In some states, this shows a special
- indication like "Dialing" or "Incoming call" or "Call ended".
- It's unused for the normal case of an active ongoing call. -->
- <TextView android:id="@+id/callStateLabel"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="@dimen/provider_info_top_bottom_padding"
- android:paddingBottom="@dimen/provider_info_top_bottom_padding"
- android:paddingStart="@dimen/call_banner_side_padding"
- android:paddingEnd="@dimen/call_banner_side_padding"
- android:gravity="end"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="@color/incall_call_banner_text_color"
- android:textAllCaps="true"
- android:background="@color/incall_secondary_info_background"
- android:singleLine="true"
- android:ellipsize="end"/>
-
- </LinearLayout>
-
-
-</FrameLayout> \ No newline at end of file
diff --git a/res/layout/primary_call_info.xml b/res/layout/primary_call_info.xml
index 39c3873d..251ded30 100644
--- a/res/layout/primary_call_info.xml
+++ b/res/layout/primary_call_info.xml
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
+
<!--
~ Copyright (C) 2013 The Android Open Source Project
~
@@ -15,199 +16,120 @@
~ limitations under the License
-->
-<!-- XML resource file for primary call info, which will be used by CallCard.
- See also call_card.xml. -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1">
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1">
<!-- Contact photo for primary call info -->
<ImageView android:id="@+id/photo"
- android:layout_alignParentStart="true"
- android:layout_alignParentTop="true"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="top|center_horizontal"
- android:scaleType="centerCrop"
- android:contentDescription="@string/contactPhoto" />
-
- <!-- Used when the phone call is on hold, dimming the primary photo
-
- Note: Theoretically it is possible to achieve this effect using
- Drawable#setColorFilter().
-
- But watch out: we also use cross fade between primary and
- secondary photo, which may interfere with the dim effect with
- setColorFilter(). To try it out, use GSM phones and do multiple
- calls.
-
- Detail: during the cross-fade effect we are currently using
- TransitionDrawable. TransitionDrawable#setColorFilter() will call
- the equivalent method for *both* drawables which are shared by
- the two ImageViews. If we set setColorFilter() for "on hold" effect
- during the cross-fade, *both* primary and secondary photos become
- dim.
-
- Theoretically it can be avoided (by copying drawable, or carefully
- calling setColorFilter() conditionally. But it doesn't bang for the
- buck for now.
-
- TODO: try that. It may be smoother with slower devices.
- -->
- <View android:id="@+id/dim_effect_for_primary_photo"
- android:layout_alignParentStart="true"
- android:layout_alignParentTop="true"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@color/on_hold_dim_effect"
- android:visibility="gone" />
-
- <!-- "Call Banner" for primary call, the foregound or ringing call.
- The "call banner" is a block of info about a single call,
- including the contact name, phone number, call time counter,
- and other status info. This info is shown as a "banner"
- overlaid across the top of contact photo. -->
- <RelativeLayout android:id="@+id/primary_call_banner"
- style="@style/PrimaryCallInfoPrimaryCallBanner"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="@dimen/call_banner_height"
- android:paddingStart="@dimen/call_banner_side_padding"
- android:paddingEnd="@dimen/call_banner_side_padding"
- android:paddingTop="@dimen/call_banner_top_bottom_padding"
- android:paddingBottom="@dimen/call_banner_top_bottom_padding"
- android:background="@color/incall_call_banner_background">
-
- <!-- Name (or the phone number, if we don't have a name to display). -->
- <TextView android:id="@+id/name"
- android:layout_alignParentTop="true"
- android:layout_alignParentStart="true"
+ android:layout_alignParentStart="true"
+ android:layout_alignParentTop="true"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="top|center_horizontal"
+ android:scaleType="centerCrop"
+ android:contentDescription="@string/contactPhoto"
+ android:src="@drawable/picture_unknown"/>
+
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingEnd="@dimen/call_banner_name_number_right_padding"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="@color/incall_call_banner_text_color"
- android:singleLine="true"
- android:textAlignment="viewStart"/>
-
- <!-- Label (like "Mobile" or "Work", if present) and phone number, side by side -->
- <LinearLayout android:id="@+id/labelAndNumber"
- android:layout_below="@id/name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingEnd="@dimen/call_banner_name_number_right_padding"
- android:orientation="horizontal">
+ android:orientation="vertical">
+
+ <!-- "Call Banner" for primary call, the foregound or ringing call.
+ The "call banner" is a block of info about a single call,
+ including the contact name, phone number, call time counter,
+ and other status info. This info is shown as a "banner"
+ overlaid across the top of contact photo. -->
+ <GridLayout android:id="@+id/primary_call_banner"
+ style="@style/PrimaryCallInfoPrimaryCallBanner"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/call_banner_height"
+ android:background="@color/incall_call_banner_background"
+ android:paddingStart="@dimen/call_banner_side_padding"
+ android:paddingEnd="@dimen/call_banner_side_padding"
+ android:paddingTop="@dimen/call_banner_top_bottom_padding"
+ android:paddingBottom="@dimen/call_banner_top_bottom_padding">
+
+ <!-- Name (or the phone number, if we don't have a name to display). -->
+ <TextView android:id="@+id/name"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@color/incall_call_banner_text_color"
+ android:singleLine="true"
+ android:textAlignment="viewStart"
+ android:layout_column="0"
+ android:layout_row="0"
+ android:layout_columnSpan="2"
+ android:layout_gravity="fill"/>
+
+ <!-- Label (like "Mobile" or "Work", if present) and phone number, side by side -->
<TextView android:id="@+id/phoneNumber"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="@color/incall_call_banner_text_color"
- android:singleLine="true"
- android:textDirection="ltr" />
- <TextView android:id="@+id/label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="@color/incall_call_banner_text_color"
- android:textAllCaps="true"
- android:singleLine="true"
- android:layout_marginStart="6dp" />
- </LinearLayout>
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="@color/incall_call_banner_text_color"
+ android:singleLine="true"
+ android:textDirection="ltr"
+ android:layout_column="0"
+ android:layout_row="1"
+ android:layout_gravity="fill"/>
- <!-- Elapsed time indication for a call in progress. -->
- <TextView android:id="@+id/elapsedTime"
- android:layout_alignParentEnd="true"
- android:layout_centerVertical="true"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="@color/incall_call_banner_text_color"
- android:singleLine="true"
- android:visibility="invisible" />
-
- <!-- Call type indication: a special label and/or branding
- for certain kinds of calls (like "Internet call" for a SIP call.) -->
- <TextView android:id="@+id/callTypeLabel"
- android:layout_below="@id/labelAndNumber"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="@color/incall_call_banner_text_color"
- android:maxLines="1"
- android:ellipsize="end" />
-
- </RelativeLayout> <!-- End of call_banner -->
-
- <LinearLayout android:id="@+id/secondary_info_container"
- style="@style/PrimaryCallInfoSecondaryInfoContainer"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical|right"
- android:orientation="vertical"
- android:background="@color/incall_secondary_info_background"
- android:animateLayoutChanges="true">
+ <TextView android:id="@+id/label"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="@color/incall_call_banner_text_color"
+ android:textAllCaps="true"
+ android:singleLine="true"
+ android:paddingStart="6dp"
+ android:layout_column="1"
+ android:layout_row="1"
+ android:layout_gravity="fill"/>
+
+ <!-- Call type indication: a special label and/or branding
+ for certain kinds of calls (like "Internet call" for a SIP call.) -->
+ <TextView android:id="@+id/callTypeLabel"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="@color/incall_call_banner_text_color"
+ android:maxLines="1"
+ android:layout_column="0"
+ android:layout_row="2"
+ android:layout_columnSpan="2"
+ android:ellipsize="end"
+ android:layout_gravity="fill"/>
+
+ <!-- Elapsed time indication for a call in progress. -->
+ <TextView android:id="@+id/elapsedTime"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@color/incall_call_banner_text_color"
+ android:singleLine="true"
+ android:visibility="invisible"
+ android:layout_column="2"
+ android:layout_row="0"
+ android:layout_rowSpan="3"
+ android:layout_gravity="fill"
+ android:gravity="end|center_vertical"/>
+ </GridLayout>
+ <!-- End of call_banner -->
- <!-- Shown when a gateway provider is used during any outgoing call. -->
- <LinearLayout android:id="@+id/providerInfo"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="@dimen/provider_info_top_bottom_padding"
- android:paddingBottom="@dimen/provider_info_top_bottom_padding"
- android:paddingStart="@dimen/call_banner_side_padding"
- android:paddingEnd="@dimen/call_banner_side_padding"
- android:gravity="end"
- android:orientation="horizontal"
- android:background="@android:color/transparent">
- <TextView android:id="@+id/providerLabel"
- android:layout_width="0px"
- android:layout_height="wrap_content"
- android:layout_weight="6"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textAllCaps="true"
- android:textColor="@color/incall_call_banner_text_color"
- android:singleLine="true"
- android:ellipsize="marquee" />
- <TextView android:id="@+id/providerAddress"
- android:layout_width="0px"
- android:layout_height="wrap_content"
- android:layout_weight="4"
- android:gravity="end"
- android:paddingStart="8dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textAllCaps="true"
- android:textColor="@color/incall_call_banner_text_color"
- android:singleLine="true"
- android:ellipsize="middle" />
- </LinearLayout>
<!-- The "call state label": In some states, this shows a special
indication like "Dialing" or "Incoming call" or "Call ended".
It's unused for the normal case of an active ongoing call. -->
<TextView android:id="@+id/callStateLabel"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="@dimen/provider_info_top_bottom_padding"
- android:paddingBottom="@dimen/provider_info_top_bottom_padding"
- android:paddingStart="@dimen/call_banner_side_padding"
- android:paddingEnd="@dimen/call_banner_side_padding"
- android:gravity="end"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="@color/incall_call_banner_text_color"
- android:textAllCaps="true"
- android:background="@android:color/transparent"
- android:singleLine="true"
- android:ellipsize="end" />
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/provider_info_top_bottom_padding"
+ android:paddingBottom="@dimen/provider_info_top_bottom_padding"
+ android:paddingStart="@dimen/call_banner_side_padding"
+ android:paddingEnd="@dimen/call_banner_side_padding"
+ android:gravity="end"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="@color/incall_call_banner_text_color"
+ android:textAllCaps="true"
+ android:background="@color/incall_secondary_info_background"
+ android:singleLine="true"
+ android:ellipsize="end"/>
+
</LinearLayout>
- <!-- Social status (currently unused) -->
- <!-- <TextView android:id="@+id/socialStatus"
- android:layout_below="@id/callTypeLabel"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="@color/incall_call_banner_text_color"
- android:maxLines="2"
- android:ellipsize="end"
- /> -->
-</LinearLayout>
+
+</FrameLayout>
diff --git a/res/layout/secondary_call_info.xml b/res/layout/secondary_call_info.xml
new file mode 100644
index 00000000..546278f9
--- /dev/null
+++ b/res/layout/secondary_call_info.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- XML resource file for secondary call info, which will be used by CallCard.
+ See also call_card.xml.
+
+ This should look similar to primary call info (primary_call_info.xml), but
+ to optimize the view usage, the structure is different. -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <!-- Contact photo for call_info #2 -->
+ <ImageView android:id="@+id/secondaryCallPhoto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="top|center_horizontal"
+ android:scaleType="centerCrop"
+ android:contentDescription="@string/onHold" />
+
+ <!-- TODO(klp): Add clickable dim effect -->
+
+ <!-- Name (or the phone number, if we don't have a name to display). -->
+ <TextView android:id="@+id/secondaryCallName"
+ style="@style/SecondaryCallInfoSecondaryCallName"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/call_banner_height"
+ android:gravity="top|start"
+ android:paddingStart="@dimen/call_banner_side_padding"
+ android:paddingEnd="@dimen/call_banner_side_padding"
+ android:paddingTop="@dimen/call_banner_top_bottom_padding"
+ android:paddingBottom="@dimen/call_banner_top_bottom_padding"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@color/incall_call_banner_text_color"
+ android:singleLine="true"
+ android:background="@color/incall_call_banner_background" />
+
+ <!-- Call status of the background call, usually the string "On hold". -->
+ <TextView android:id="@+id/secondaryCallStatus"
+ style="@style/SecondaryCallInfoSecondaryCallStatus"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/call_banner_height"
+ android:gravity="top|end"
+ android:paddingStart="@dimen/call_banner_side_padding"
+ android:paddingEnd="@dimen/call_banner_side_padding"
+ android:paddingTop="@dimen/call_banner_top_bottom_padding"
+ android:paddingBottom="@dimen/call_banner_top_bottom_padding"
+ android:text="@string/onHold"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="@color/incall_call_banner_text_color"
+ android:textAllCaps="true"
+ android:singleLine="true" />
+</FrameLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d92dc16e..df88e7e5 100755
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -20,6 +20,11 @@
<!-- Official label for the in-call UI -->
<string name="inCallLabel">InCallUI</string>
+ <!-- Call status -->
+
+ <!-- In-call screen: status label for a call that's on hold -->
+ <string name="onHold">On hold</string>
+
<!-- "Audio mode" popup menu: Item label to select the speakerphone [CHAR LIMIT=25] -->
<string name="audio_mode_speaker">Speaker</string>
<!-- "Audio mode" popup menu: Item label to select the handset earpiece [CHAR LIMIT=25] -->
diff --git a/src/com/android/incallui/AnswerFragment.java b/src/com/android/incallui/AnswerFragment.java
index 90bc4360..76c92516 100644
--- a/src/com/android/incallui/AnswerFragment.java
+++ b/src/com/android/incallui/AnswerFragment.java
@@ -16,6 +16,9 @@
package com.android.incallui;
+import com.google.common.base.Preconditions;
+
+import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.LayoutInflater;
@@ -26,16 +29,22 @@ import android.view.ViewGroup;
*
*/
public class AnswerFragment extends BaseFragment<AnswerPresenter> implements
- GlowPadWrapper.AnswerListener {
+ GlowPadWrapper.AnswerListener, AnswerPresenter.AnswerUi {
+ final private IFragmentHost mFragmentHost;
+
+ public AnswerFragment(IFragmentHost fragmentHost) {
+ mFragmentHost = fragmentHost;
+
+ // Normally called with onCreateView, however, AnswerPresenter's interaction
+ // begins before any UI is displayed.
+ // Order matters with this call because mFragmentHost mustn't be null when the presenter
+ // asks AnswerFragment to display itself (see showAnswerWidget).
+ getPresenter().onUiReady(this);
+ }
@Override
public AnswerPresenter createPresenter() {
- return new AnswerPresenter(new AnswerPresenter.Listener() {
- @Override
- public void onClose() {
- close();
- }
- });
+ return new AnswerPresenter();
}
@Override
@@ -47,12 +56,6 @@ public class AnswerFragment extends BaseFragment<AnswerPresenter> implements
return glowPad;
}
- private void close() {
- final FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
- fragmentTransaction.remove(this);
- fragmentTransaction.commit();
- }
-
@Override
public void onAnswer() {
getPresenter().onAnswer();
@@ -67,4 +70,34 @@ public class AnswerFragment extends BaseFragment<AnswerPresenter> implements
public void onText() {
getPresenter().onText();
}
+
+ @Override
+ public void showAnswerWidget(boolean show) {
+ Preconditions.checkNotNull(mFragmentHost);
+
+ if (show) {
+ mFragmentHost.addFragment(this);
+ } else {
+ close();
+ }
+ }
+
+ private void close() {
+ // TODO(klp): With a proper main presenter, we will not need to check for isAdded.
+ if (isAdded()) {
+ final FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
+ fragmentTransaction.remove(this);
+ fragmentTransaction.commit();
+ }
+ }
+
+ // Stop gap until we can consolidate presenters and make InCallActivity a UI Class that relies
+ // on it's the consolidated presenter.
+ //
+ // TODO(klp): Remove individual presenters for button/answer/callcard and have a single
+ // presenter that interacts directly with this activity. This will allow us to remove
+ // this unnecessary interface.
+ static interface IFragmentHost {
+ public void addFragment(Fragment fragment);
+ }
}
diff --git a/src/com/android/incallui/AnswerPresenter.java b/src/com/android/incallui/AnswerPresenter.java
index d6f87c74..a406b0a2 100644
--- a/src/com/android/incallui/AnswerPresenter.java
+++ b/src/com/android/incallui/AnswerPresenter.java
@@ -16,46 +16,45 @@
package com.android.incallui;
-import com.google.android.collect.Lists;
-
-import java.util.ArrayList;
-
/**
- *
+ * Presenter for the Incoming call widget.
*/
-public class AnswerPresenter extends Presenter<Ui> {
+public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi>
+ implements CallList.Listener {
- private ArrayList<Listener> mListeners = Lists.newArrayList();
-
- public AnswerPresenter(Listener listener) {
- this.mListeners.add(listener);
+ @Override
+ public void onUiReady(AnswerUi ui) {
+ super.onUiReady(ui);
+ CallList.getInstance().addListener(this);
}
- public void addCloseListener(Listener listener) {
- mListeners.add(listener);
+ @Override
+ public void onCallListChange(CallList callList) {
+ // TODO(klp): The answer widget and call cards are independently managing their behavior
+ // from CallList events. We need to create a class to manage the behavior of all the
+ // Presenters from a single place.
+ final boolean showWidget = (callList.getIncomingCall() != null);
+
+ final AnswerUi ui = getUi();
+ if (ui != null) {
+ ui.showAnswerWidget(showWidget);
+ }
}
public void onAnswer() {
// TODO(klp): hook in call id.
CallCommandClient.getInstance().answerCall(1);
- notifyListeners();
}
public void onDecline() {
- notifyListeners();
+ // TODO(klp): hook in call id.
+ CallCommandClient.getInstance().disconnectCall(1);
}
public void onText() {
- notifyListeners();
- }
-
- private void notifyListeners() {
- for (Listener listener : mListeners) {
- listener.onClose();
- }
}
- public interface Listener {
- void onClose();
+ interface AnswerUi extends Ui {
+ public void showAnswerWidget(boolean show);
}
}
diff --git a/src/com/android/incallui/CallButtonPresenter.java b/src/com/android/incallui/CallButtonPresenter.java
index be76f2d2..10d4f723 100644
--- a/src/com/android/incallui/CallButtonPresenter.java
+++ b/src/com/android/incallui/CallButtonPresenter.java
@@ -21,10 +21,10 @@ import android.media.AudioManager;
/**
* Logic for call buttons.
*/
-public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButtonUi> {
+public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButtonUi>
+ implements CallList.Listener {
private AudioManager mAudioManager;
- private EndCallListener mEndCallListener;
public void init(AudioManager audioManager) {
mAudioManager = audioManager;
@@ -35,19 +35,26 @@ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButto
super.onUiReady(ui);
getUi().setMute(mAudioManager.isMicrophoneMute());
getUi().setSpeaker(mAudioManager.isSpeakerphoneOn());
+
+ CallList.getInstance().addListener(this);
}
- public void show() {
- getUi().setVisible(true);
+ @Override
+ public void onCallListChange(CallList callList) {
+ // show the buttons if there is a live call AND there is no
+ // incoming call.
+ final boolean showButtons = callList.existsLiveCall() &&
+ callList.getIncomingCall() == null;
+ getUi().setVisible(showButtons);
}
public void endCallClicked() {
// TODO(klp): hook up call id.
CallCommandClient.getInstance().disconnectCall(1);
- mEndCallListener.onCallEnd();
-
- // TODO(klp): These states should come from Call objects from the CallList.
+ // TODO(klp): Remove once all state is gathered from CallList.
+ // This will be wrong when you disconnect from a call if
+ // the user has another call on hold.
reset();
}
@@ -74,18 +81,10 @@ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButto
getUi().setHold(checked);
}
- public void setEndCallListener(EndCallListener endCallListener) {
- mEndCallListener = endCallListener;
- }
-
public interface CallButtonUi extends Ui {
void setVisible(boolean on);
void setMute(boolean on);
void setSpeaker(boolean on);
void setHold(boolean on);
}
-
- public interface EndCallListener {
- void onCallEnd();
- }
}
diff --git a/src/com/android/incallui/CallCardFragment.java b/src/com/android/incallui/CallCardFragment.java
index 2fb31722..3f46bb56 100644
--- a/src/com/android/incallui/CallCardFragment.java
+++ b/src/com/android/incallui/CallCardFragment.java
@@ -20,6 +20,7 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewStub;
import android.widget.TextView;
/**
@@ -30,6 +31,9 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter>
private TextView mPhoneNumber;
+ private ViewStub mSecondaryCallInfo;
+ private TextView mSecondaryCallName;
+
@Override
CallCardPresenter createPresenter() {
return new CallCardPresenter();
@@ -38,12 +42,13 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter>
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
- return inflater.inflate(R.layout.call_card_fragment, container, false);
+ return inflater.inflate(R.layout.call_card, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
mPhoneNumber = (TextView) view.findViewById(R.id.phoneNumber);
+ mSecondaryCallInfo = (ViewStub) view.findViewById(R.id.secondary_call_info);
// This method call will begin the callbacks on CallCardUi. We need to ensure
// everything needed for the callbacks is set up before this is called.
@@ -51,6 +56,18 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter>
}
@Override
+ public void setSecondaryCallInfo(boolean show, String number) {
+ if (show) {
+ showAndInitializeSecondaryCallInfo();
+
+ // Until we have the name source, use the number as the main text for secondary calls.
+ mSecondaryCallName.setText(number);
+ } else {
+ mSecondaryCallInfo.setVisibility(View.GONE);
+ }
+ }
+
+ @Override
public void setNumber(String number) {
mPhoneNumber.setText(number);
}
@@ -59,4 +76,14 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter>
public void setName(String name) {
}
+ private void showAndInitializeSecondaryCallInfo() {
+ mSecondaryCallInfo.setVisibility(View.VISIBLE);
+
+ // mSecondaryCallName is initialized here (vs. onViewCreated) because it is inaccesible
+ // until mSecondaryCallInfo is inflated in the call above.
+ if (mSecondaryCallName == null) {
+ mSecondaryCallName = (TextView) getView().findViewById(R.id.secondaryCallName);
+ }
+ }
+
}
diff --git a/src/com/android/incallui/CallCardPresenter.java b/src/com/android/incallui/CallCardPresenter.java
index 85f05341..0ba4176c 100644
--- a/src/com/android/incallui/CallCardPresenter.java
+++ b/src/com/android/incallui/CallCardPresenter.java
@@ -30,26 +30,36 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
super.onUiReady(ui);
CallList.getInstance().addListener(this);
-
- // When UI is ready, manually trigger a change
- onCallListChange(CallList.getInstance());
}
@Override
public void onCallListChange(CallList callList) {
- Call call = callList.getIncomingOrActive();
+ final CallCardUi ui = getUi();
+ // Populate the primary call card based on the incoming call or the active call.
+ final Call call = callList.getIncomingOrActive();
if (call != null) {
- getUi().setNumber(call.getNumber());
+ ui.setNumber(call.getNumber());
} else {
// When there is no longer an incoming/active call, we need to reset everything
// so that no data survives for the next call.
- getUi().setNumber("");
+ ui.setNumber("");
+ }
+
+ // secondary call card info only comes from the background call (if any exist)
+ final Call backgroundCall = callList.getBackgroundCall();
+ if (backgroundCall != null) {
+ ui.setSecondaryCallInfo(true, backgroundCall.getNumber());
+ } else {
+ ui.setSecondaryCallInfo(false, null);
}
}
public interface CallCardUi extends Ui {
+ // TODO(klp): Consider passing in the Call object directly in these methods.
+
public void setNumber(String number);
public void setName(String name);
+ public void setSecondaryCallInfo(boolean show, String number);
}
}
diff --git a/src/com/android/incallui/CallHandlerService.java b/src/com/android/incallui/CallHandlerService.java
index 4a14dab8..a9516e8a 100644
--- a/src/com/android/incallui/CallHandlerService.java
+++ b/src/com/android/incallui/CallHandlerService.java
@@ -70,6 +70,8 @@ public class CallHandlerService extends Service {
@Override
public void onIncomingCall(Call call) {
+ // TODO(klp): New presenter manager should launch this task...not this service.
+ // TODO(klp): Update the flags to match the only activity
final Intent intent = new Intent(getApplication(), InCallActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
diff --git a/src/com/android/incallui/CallList.java b/src/com/android/incallui/CallList.java
index ac3e3bfd..f41af930 100644
--- a/src/com/android/incallui/CallList.java
+++ b/src/com/android/incallui/CallList.java
@@ -82,7 +82,11 @@ public class CallList {
public void addListener(Listener listener) {
Preconditions.checkNotNull(listener);
+
mListeners.add(listener);
+
+ // Let the listener know about the active calls immediately.
+ listener.onCallListChange(this);
}
public void removeListener(Listener listener) {
@@ -96,15 +100,39 @@ public class CallList {
* update the Call object when the active call changes.
*/
public Call getIncomingOrActive() {
- Call retval = null;
+ Call retval = getIncomingCall();
+ if (retval == null) {
+ retval = getFirstCallWithState(Call.State.ACTIVE);
+ }
+ return retval;
+ }
+
+ public Call getBackgroundCall() {
+ return getFirstCallWithState(Call.State.ONHOLD);
+ }
+
+ public Call getIncomingCall() {
+ return getFirstCallWithState(Call.State.INCOMING);
+ }
+ public boolean existsLiveCall() {
for (Call call : mCallMap.values()) {
- if (call.getState() == Call.State.INCOMING) {
+ if (!isCallDead(call)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns first call found in the call map with the specified state.
+ */
+ public Call getFirstCallWithState(int state) {
+ Call retval = null;
+ for (Call call : mCallMap.values()) {
+ if (call.getState() == state) {
retval = call;
- // incoming call takes precedence, cut out early.
break;
- } else if (retval == null && call.getState() == Call.State.ACTIVE) {
- retval = call;
}
}
diff --git a/src/com/android/incallui/InCallActivity.java b/src/com/android/incallui/InCallActivity.java
index 04f1f09b..9732203b 100644
--- a/src/com/android/incallui/InCallActivity.java
+++ b/src/com/android/incallui/InCallActivity.java
@@ -17,6 +17,7 @@
package com.android.incallui;
import android.app.Activity;
+import android.app.Fragment;
import android.app.FragmentTransaction;
import android.content.Intent;
import android.os.Bundle;
@@ -30,15 +31,17 @@ import android.widget.Toast;
/**
* Phone app "in call" screen.
*/
-public class InCallActivity extends Activity implements CallButtonPresenter.EndCallListener {
+public class InCallActivity extends Activity implements AnswerFragment.IFragmentHost,
+ CallList.Listener {
private static final String TAG = InCallActivity.class.getSimpleName();
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
- private CallButtonPresenter mCallButtonPresenter;
- private CallCardPresenter mCallCardPresenter;
+ private CallButtonFragment mCallButtonFragment;
+ private CallCardFragment mCallCardFragment;
+ private AnswerFragment mAnswerFragment;
@Override
protected void onCreate(Bundle icicle) {
@@ -68,19 +71,6 @@ public class InCallActivity extends Activity implements CallButtonPresenter.EndC
protected void onResume() {
logD("onResume()...");
- // TODO(klp): create once and reset when needed.
- final AnswerFragment answerFragment = new AnswerFragment();
- final AnswerPresenter presenter = answerFragment.getPresenter();
- presenter.addCloseListener(new AnswerPresenter.Listener() {
- @Override
- public void onClose() {
- mCallButtonPresenter.show();
- }
- });
-
- final FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
- fragmentTransaction.add(R.id.main, answerFragment);
- fragmentTransaction.commit();
super.onResume();
}
@@ -207,13 +197,23 @@ public class InCallActivity extends Activity implements CallButtonPresenter.EndC
private void initializeInCall() {
- final CallButtonFragment callButtonFragment = (CallButtonFragment) getFragmentManager()
- .findFragmentById(R.id.callButtonFragment);
- mCallButtonPresenter = callButtonFragment.getPresenter();
- mCallButtonPresenter.setEndCallListener(this);
+ // TODO(klp): Make sure that this doesn't need to move back to onResume() since they are
+ // statically added fragments.
+ if (mCallButtonFragment == null) {
+ mCallButtonFragment = (CallButtonFragment) getFragmentManager()
+ .findFragmentById(R.id.callButtonFragment);
+ }
+
+ if (mCallCardFragment == null) {
+ mCallCardFragment = (CallCardFragment) getFragmentManager()
+ .findFragmentById(R.id.callCardFragment);
+ }
+
+ if (mAnswerFragment == null) {
+ mAnswerFragment = new AnswerFragment(this);
+ }
- final CallCardFragment callCardFragment = (CallCardFragment) getFragmentManager()
- .findFragmentById(R.id.callCardFragment);
+ CallList.getInstance().addListener(this);
}
private void toast(String text) {
@@ -229,7 +229,24 @@ public class InCallActivity extends Activity implements CallButtonPresenter.EndC
}
@Override
- public void onCallEnd() {
- finish();
+ public void addFragment(Fragment fragment) {
+ Log.d(TAG, "AddFragment");
+
+ // TODO(klp): Do a check to make sure the fragment isn't already added before trying to
+ // add it again.
+ // TODO(klp): IsResumed check only required because CallList notifications are coming in
+ // an indeterminate order. This should no longer be required with a main Presenter class.
+ if (this.isResumed()) {
+ final FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
+ fragmentTransaction.add(R.id.main, fragment);
+ fragmentTransaction.commit();
+ }
+ }
+
+ @Override
+ public void onCallListChange(CallList callList) {
+ if (!callList.existsLiveCall()) {
+ finish();
+ }
}
}