diff options
-rw-r--r-- | InCallUI/res/layout/call_card.xml | 45 | ||||
-rw-r--r-- | InCallUI/res/layout/call_card_fragment.xml | 136 | ||||
-rw-r--r-- | InCallUI/res/layout/primary_call_info.xml | 284 | ||||
-rw-r--r-- | InCallUI/res/layout/secondary_call_info.xml | 66 | ||||
-rwxr-xr-x | InCallUI/res/values/strings.xml | 5 | ||||
-rw-r--r-- | InCallUI/src/com/android/incallui/AnswerFragment.java | 59 | ||||
-rw-r--r-- | InCallUI/src/com/android/incallui/AnswerPresenter.java | 45 | ||||
-rw-r--r-- | InCallUI/src/com/android/incallui/CallButtonPresenter.java | 29 | ||||
-rw-r--r-- | InCallUI/src/com/android/incallui/CallCardFragment.java | 29 | ||||
-rw-r--r-- | InCallUI/src/com/android/incallui/CallCardPresenter.java | 22 | ||||
-rw-r--r-- | InCallUI/src/com/android/incallui/CallHandlerService.java | 2 | ||||
-rw-r--r-- | InCallUI/src/com/android/incallui/CallList.java | 38 | ||||
-rw-r--r-- | InCallUI/src/com/android/incallui/InCallActivity.java | 65 |
13 files changed, 421 insertions, 404 deletions
diff --git a/InCallUI/res/layout/call_card.xml b/InCallUI/res/layout/call_card.xml new file mode 100644 index 000000000..af47ef751 --- /dev/null +++ b/InCallUI/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/InCallUI/res/layout/call_card_fragment.xml b/InCallUI/res/layout/call_card_fragment.xml deleted file mode 100644 index 44a9f6f64..000000000 --- a/InCallUI/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/InCallUI/res/layout/primary_call_info.xml b/InCallUI/res/layout/primary_call_info.xml index 39c3873d0..251ded30b 100644 --- a/InCallUI/res/layout/primary_call_info.xml +++ b/InCallUI/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/InCallUI/res/layout/secondary_call_info.xml b/InCallUI/res/layout/secondary_call_info.xml new file mode 100644 index 000000000..546278f95 --- /dev/null +++ b/InCallUI/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/InCallUI/res/values/strings.xml b/InCallUI/res/values/strings.xml index d92dc16e5..df88e7e56 100755 --- a/InCallUI/res/values/strings.xml +++ b/InCallUI/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/InCallUI/src/com/android/incallui/AnswerFragment.java b/InCallUI/src/com/android/incallui/AnswerFragment.java index 90bc43608..76c925163 100644 --- a/InCallUI/src/com/android/incallui/AnswerFragment.java +++ b/InCallUI/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/InCallUI/src/com/android/incallui/AnswerPresenter.java b/InCallUI/src/com/android/incallui/AnswerPresenter.java index d6f87c74c..a406b0a2b 100644 --- a/InCallUI/src/com/android/incallui/AnswerPresenter.java +++ b/InCallUI/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/InCallUI/src/com/android/incallui/CallButtonPresenter.java b/InCallUI/src/com/android/incallui/CallButtonPresenter.java index be76f2d21..10d4f7237 100644 --- a/InCallUI/src/com/android/incallui/CallButtonPresenter.java +++ b/InCallUI/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/InCallUI/src/com/android/incallui/CallCardFragment.java b/InCallUI/src/com/android/incallui/CallCardFragment.java index 2fb317221..3f46bb568 100644 --- a/InCallUI/src/com/android/incallui/CallCardFragment.java +++ b/InCallUI/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/InCallUI/src/com/android/incallui/CallCardPresenter.java b/InCallUI/src/com/android/incallui/CallCardPresenter.java index 85f05341e..0ba4176c3 100644 --- a/InCallUI/src/com/android/incallui/CallCardPresenter.java +++ b/InCallUI/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/InCallUI/src/com/android/incallui/CallHandlerService.java b/InCallUI/src/com/android/incallui/CallHandlerService.java index 4a14dab8e..a9516e8ad 100644 --- a/InCallUI/src/com/android/incallui/CallHandlerService.java +++ b/InCallUI/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/InCallUI/src/com/android/incallui/CallList.java b/InCallUI/src/com/android/incallui/CallList.java index ac3e3bfd5..f41af930b 100644 --- a/InCallUI/src/com/android/incallui/CallList.java +++ b/InCallUI/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/InCallUI/src/com/android/incallui/InCallActivity.java b/InCallUI/src/com/android/incallui/InCallActivity.java index 04f1f09b1..9732203bd 100644 --- a/InCallUI/src/com/android/incallui/InCallActivity.java +++ b/InCallUI/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(); + } } } |