diff options
author | Christine Chen <christinech@google.com> | 2013-09-06 14:53:04 -0700 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2013-09-06 14:53:04 -0700 |
commit | 5aa6f2ed64beecbc8f9cef41c87f1f6ab768ac78 (patch) | |
tree | 6d436500fa3eb6e91616eabfc27a8d03a51f5a45 /InCallUI | |
parent | aa3bf5aa44aad01888a0aa1efe336ab5c4ca9b36 (diff) | |
parent | d9ef38beea322a20328e39cd1f4c9b5c08a64f31 (diff) |
am 53e556bc: am 0f09a02b: Adds manage conference call UI
* commit '53e556bced4a5951b3d90f3ef1737bc4d9df0116':
Adds manage conference call UI
Diffstat (limited to 'InCallUI')
20 files changed, 739 insertions, 15 deletions
diff --git a/InCallUI/res/drawable-hdpi/ic_end_call_holo_dark.png b/InCallUI/res/drawable-hdpi/ic_end_call_holo_dark.png Binary files differnew file mode 100644 index 000000000..0f373bb26 --- /dev/null +++ b/InCallUI/res/drawable-hdpi/ic_end_call_holo_dark.png diff --git a/InCallUI/res/drawable-hdpi/ic_split_holo_dark.png b/InCallUI/res/drawable-hdpi/ic_split_holo_dark.png Binary files differnew file mode 100644 index 000000000..5b10cf948 --- /dev/null +++ b/InCallUI/res/drawable-hdpi/ic_split_holo_dark.png diff --git a/InCallUI/res/drawable-mdpi/ic_end_call_holo_dark.png b/InCallUI/res/drawable-mdpi/ic_end_call_holo_dark.png Binary files differnew file mode 100644 index 000000000..e090cc806 --- /dev/null +++ b/InCallUI/res/drawable-mdpi/ic_end_call_holo_dark.png diff --git a/InCallUI/res/drawable-mdpi/ic_split_holo_dark.png b/InCallUI/res/drawable-mdpi/ic_split_holo_dark.png Binary files differnew file mode 100644 index 000000000..3980acbb8 --- /dev/null +++ b/InCallUI/res/drawable-mdpi/ic_split_holo_dark.png diff --git a/InCallUI/res/drawable-xhdpi/ic_end_call_holo_dark.png b/InCallUI/res/drawable-xhdpi/ic_end_call_holo_dark.png Binary files differnew file mode 100644 index 000000000..f64f5e3d9 --- /dev/null +++ b/InCallUI/res/drawable-xhdpi/ic_end_call_holo_dark.png diff --git a/InCallUI/res/drawable-xhdpi/ic_split_holo_dark.png b/InCallUI/res/drawable-xhdpi/ic_split_holo_dark.png Binary files differnew file mode 100644 index 000000000..db558e49a --- /dev/null +++ b/InCallUI/res/drawable-xhdpi/ic_split_holo_dark.png diff --git a/InCallUI/res/layout/call_button_fragment.xml b/InCallUI/res/layout/call_button_fragment.xml index cec11f01f..6a76a1ca2 100644 --- a/InCallUI/res/layout/call_button_fragment.xml +++ b/InCallUI/res/layout/call_button_fragment.xml @@ -42,10 +42,10 @@ Most of the time this whole row is GONE. For now, at least, there's only ever one button visible here at a time, so this can be a simple FrameLayout. --> - <ViewStub android:id="@+id/extraButtonRow" - android:layout="@layout/extra_button_row" - android:layout_width="match_parent" - android:layout_height="wrap_content"/> + <include android:id="@+id/extraButtonRow" + layout="@layout/extra_button_row" + android:layout_width="match_parent" + android:layout_height="wrap_content"/> <!-- Row 2: The "End call" button. --> <ImageButton android:id="@+id/endButton" diff --git a/InCallUI/res/layout/caller_in_conference.xml b/InCallUI/res/layout/caller_in_conference.xml new file mode 100644 index 000000000..c2c68c836 --- /dev/null +++ b/InCallUI/res/layout/caller_in_conference.xml @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2008 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:layout_width="match_parent" + android:layout_height="64dp" + android:orientation="horizontal" + android:gravity="center_vertical"> + + <!-- Caller information --> + <LinearLayout + android:id="@+id/conferenceCallerSeparate" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:background="?android:attr/selectableItemBackground" + android:paddingStart="16dp" + android:orientation="horizontal" + android:gravity="center_vertical"> + + <!-- "Separate" (i.e. "go private") button for this caller --> + <ImageView + android:src="@drawable/ic_split_holo_dark" + android:layout_width="46dp" + android:layout_height="46dp" + android:scaleType="center" + android:contentDescription="@string/goPrivate"/> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingStart="8dp" + android:gravity="center_vertical" + android:orientation="vertical"> + + <!-- Name or number of this caller --> + <TextView + android:id="@+id/conferenceCallerName" + android:textAppearance="?android:attr/textAppearanceLarge" + android:textSize="18sp" + android:singleLine="true" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_marginEnd="2dp" + /> + + <!-- Number of this caller if name is supplied above --> + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:orientation="horizontal" + android:gravity="bottom"> + + <!-- Number --> + <TextView + android:id="@+id/conferenceCallerNumber" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="14sp" + android:ellipsize="marquee" + android:textColor="@color/manage_conference_secondary_text_color" + android:singleLine="true" + android:layout_marginEnd="8dp" /> + + <!-- Number type --> + <TextView + android:id="@+id/conferenceCallerNumberType" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="12sp" + android:textColor="@color/manage_conference_secondary_text_color" + android:ellipsize="marquee" + android:singleLine="true" + android:textAllCaps="true" + android:gravity="start" /> + + </LinearLayout> <!-- End of caller number --> + + </LinearLayout> <!-- End of caller information --> + </LinearLayout> + + <!-- "End" button for this caller which should look like the + "end call" button in the main in-call UI screen --> + <ImageButton + android:id="@+id/conferenceCallerDisconnect" + android:layout_width="80dp" + android:layout_height="match_parent" + android:src="@drawable/ic_end_call_holo_dark" + android:background="@drawable/end_call_background" + android:scaleType="center" + android:contentDescription="@string/onscreenEndCallText" /> + +</LinearLayout> <!-- End of single list element --> diff --git a/InCallUI/res/layout/conference_manager_fragment.xml b/InCallUI/res/layout/conference_manager_fragment.xml new file mode 100644 index 000000000..f1fbfdfac --- /dev/null +++ b/InCallUI/res/layout/conference_manager_fragment.xml @@ -0,0 +1,132 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2009 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. +--> + +<!-- The "Manage conference" UI. This panel is displayed (instead of + the inCallPanel) when the user clicks the "Manage conference" + button while on a conference call. --> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/manageConferencePanel" + android:background="#FF000000" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:visibility="gone" + > + <!-- This original header (with timer) is currently not being used, + but may be of use in the future. --> + <!-- Header, including chronometer and List divider --> + <Chronometer + android:id="@+id/manageConferencePanelHeader" + android:textAppearance="?android:attr/textAppearanceLarge" + android:textSize="24sp" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_horizontal" + android:layout_alignParentTop="true" + android:layout_marginTop="5dip" + android:layout_marginBottom="5dip" + android:visibility="gone"/> + + <ImageView + android:id="@+id/manageConferencePanelDivider" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:src="@android:drawable/divider_horizontal_dark" + android:scaleType="fitXY" + android:layout_below="@id/manageConferencePanelHeader" + android:visibility="gone"/> + <!-- End of the original header --> + + <!-- Header which looks like ActionBar. --> + <FrameLayout + android:id="@+id/manageConferenceHeader" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@*android:drawable/ab_transparent_dark_holo"> + + <LinearLayout + android:id="@+id/manage_done" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?android:attr/selectableItemBackground" + android:clickable="true" + android:orientation="horizontal"> + + <ImageView + android:src="?android:attr/homeAsUpIndicator" + android:layout_gravity="center_vertical|left" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + + <TextView + android:layout_width="match_parent" + android:layout_height="?android:attr/actionBarSize" + style="@*android:style/TextAppearance.Holo.Widget.ActionBar.Title" + android:gravity="center_vertical" + android:text="@string/manageConferenceLabel"/> + </LinearLayout> + + </FrameLayout> <!-- End of header --> + + <!-- The scrollview wrapper for the list of callers on + the conference call (in case the list gets too long). --> + <ScrollView + android:id="@+id/conferenceList" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/manageConferenceHeader"> + + <!-- The actual list of callers; this embedded LinearLayout + required since scrollview only supports a single child. --> + <LinearLayout + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:showDividers="middle|end" + android:divider="?android:attr/listDivider"> + + <!-- A conference can have at most MAX_CALLERS_IN_CONFERENCE (= 5) callers, + so just define all those UI elements here. --> + + <!-- Caller 0 --> + <include + layout="@layout/caller_in_conference" + android:id="@+id/caller0"/> + + <!-- Caller 1 --> + <include + layout="@layout/caller_in_conference" + android:id="@+id/caller1"/> + + <!-- Caller 2 --> + <include + layout="@layout/caller_in_conference" + android:id="@+id/caller2"/> + + <!-- Caller 3 --> + <include + layout="@layout/caller_in_conference" + android:id="@+id/caller3"/> + + <!-- Caller 4 --> + <include + layout="@layout/caller_in_conference" + android:id="@+id/caller4"/> + + </LinearLayout> <!-- End of "list of callers on conference call" --> + + </ScrollView> <!-- End of scrolling list wrapper for the linear layout --> + +</RelativeLayout> diff --git a/InCallUI/res/layout/extra_button_row.xml b/InCallUI/res/layout/extra_button_row.xml index 79c11366d..a1600e80a 100644 --- a/InCallUI/res/layout/extra_button_row.xml +++ b/InCallUI/res/layout/extra_button_row.xml @@ -32,7 +32,8 @@ android:layout_height="wrap_content" android:paddingStart="@dimen/button_cluster_side_padding" android:paddingEnd="@dimen/button_cluster_side_padding" - android:background="?android:attr/selectableItemBackground"> + android:background="?android:attr/selectableItemBackground" + android:visibility="gone"> <!-- The entire LinearLayout here is clickable, so we don't care about clicks on the ImageButton itself. --> <ImageButton android:id="@+id/manageConferenceButtonImage" @@ -55,7 +56,8 @@ android:layout_height="wrap_content" android:paddingStart="@dimen/button_cluster_side_padding" android:paddingEnd="@dimen/button_cluster_side_padding" - android:background="?android:attr/selectableItemBackground"> + android:background="?android:attr/selectableItemBackground" + android:visibility="gone"> <!-- The entire LinearLayout here is clickable, so we don't care about clicks on the ImageButton itself. --> <ImageButton android:id="@+id/cdmaMergeButtonImage" diff --git a/InCallUI/res/layout/incall_screen.xml b/InCallUI/res/layout/incall_screen.xml index 86f67c989..892f91707 100644 --- a/InCallUI/res/layout/incall_screen.xml +++ b/InCallUI/res/layout/incall_screen.xml @@ -67,4 +67,13 @@ android:layout_marginBottom="@dimen/glowpadview_margin_bottom" android:visibility="gone" /> + <fragment android:name="com.android.incallui.ConferenceManagerFragment" + android:id="@+id/conferenceManagerFragment" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_alignParentTop="true" + android:layout_alignParentStart="true" + android:layout_alignParentBottom="true" + android:layout_alignParentEnd="true" /> + </FrameLayout> diff --git a/InCallUI/res/values/strings.xml b/InCallUI/res/values/strings.xml index 785e36467..e7049e5b2 100755 --- a/InCallUI/res/values/strings.xml +++ b/InCallUI/res/values/strings.xml @@ -1467,4 +1467,7 @@ related settings. [CHAR LIMIT=30] --> <string name="preference_category_ringtone">Ringtone & Vibrate</string> + + <!-- Label for "Manage conference call" panel [CHAR LIMIT=40] --> + <string name="manageConferenceLabel">Manage conference call</string> </resources> diff --git a/InCallUI/src/com/android/incallui/CallButtonFragment.java b/InCallUI/src/com/android/incallui/CallButtonFragment.java index 1c3e737e6..4c42a7845 100644 --- a/InCallUI/src/com/android/incallui/CallButtonFragment.java +++ b/InCallUI/src/com/android/incallui/CallButtonFragment.java @@ -23,6 +23,7 @@ import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.view.ViewStub; import android.widget.CompoundButton; import android.widget.ImageButton; import android.widget.PopupMenu; @@ -51,6 +52,9 @@ public class CallButtonFragment private PopupMenu mAudioModePopup; private boolean mAudioModePopupVisible; private View mEndCallButton; + private View mExtraRowButton; + private View mManageConferenceButton; + private View mCDMAMergeButton; @Override CallButtonPresenter createPresenter() { @@ -74,6 +78,17 @@ public class CallButtonFragment Bundle savedInstanceState) { final View parent = inflater.inflate(R.layout.call_button_fragment, container, false); + mExtraRowButton = parent.findViewById(R.id.extraButtonRow); + + mManageConferenceButton = parent.findViewById(R.id.manageConferenceButton); + mManageConferenceButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + getPresenter().manageConferenceButtonClicked(); + } + }); + mCDMAMergeButton = parent.findViewById(R.id.cdmaMergeButton); + mEndCallButton = parent.findViewById(R.id.endButton); mEndCallButton.setOnClickListener(new View.OnClickListener() { @Override @@ -449,4 +464,39 @@ public class CallButtonFragment ((InCallActivity) getActivity()).displayDialpad(value); } } + + @Override + public boolean isDialpadVisible() { + if (getActivity() != null && getActivity() instanceof InCallActivity) { + return ((InCallActivity) getActivity()).isDialpadVisible(); + } + return false; + } + + @Override + public void displayManageConferencePanel(boolean value) { + if (getActivity() != null && getActivity() instanceof InCallActivity) { + ((InCallActivity) getActivity()).displayManageConferencePanel(value); + } + } + + + @Override + public void showManageConferenceCallButton() { + mExtraRowButton.setVisibility(View.VISIBLE); + mManageConferenceButton.setVisibility(View.VISIBLE); + mCDMAMergeButton.setVisibility(View.GONE); + } + + @Override + public void showCDMAMergeButton() { + mExtraRowButton.setVisibility(View.VISIBLE); + mManageConferenceButton.setVisibility(View.GONE); + mCDMAMergeButton.setVisibility(View.VISIBLE); + } + + @Override + public void hideExtraRow() { + mExtraRowButton.setVisibility(View.GONE); + } } diff --git a/InCallUI/src/com/android/incallui/CallButtonPresenter.java b/InCallUI/src/com/android/incallui/CallButtonPresenter.java index bc9efe507..17273a874 100644 --- a/InCallUI/src/com/android/incallui/CallButtonPresenter.java +++ b/InCallUI/src/com/android/incallui/CallButtonPresenter.java @@ -145,6 +145,10 @@ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButto CallCommandClient.getInstance().disconnectCall(mCall.getCallId()); } + public void manageConferenceButtonClicked() { + getUi().displayManageConferencePanel(true); + } + public void muteClicked(boolean checked) { Log.d(this, "turning on mute: " + checked); @@ -217,6 +221,34 @@ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButto ui.setMute(mPreviousMuteState); mAutomaticallyMuted = false; } + + // Finally, update the "extra button row": It's displayed above the + // "End" button, but only if necessary. Also, it's never displayed + // while the dialpad is visible (since it would overlap.) + // + // The row contains two buttons: + // + // - "Manage conference" (used only on GSM devices) + // - "Merge" button (used only on CDMA devices) + // TODO(klp) Add cdma merge button + final boolean showCdmaMerge = false; +// (phoneType == PhoneConstants.PHONE_TYPE_CDMA) && inCallControlState.canMerge; + final boolean showExtraButtonRow = + (showCdmaMerge || call.isConferenceCall()) && !getUi().isDialpadVisible(); + if (showExtraButtonRow) { + // Need to set up mCdmaMergeButton and mManageConferenceButton if this is the first + // time they're visible. + // TODO(klp) add cdma merge button +// if (mCdmaMergeButton == null) { +// setupExtraButtons(); +// } +// mCdmaMergeButton.setVisibility(showCdmaMerge ? View.VISIBLE : View.GONE); + if (call.isConferenceCall()) { + getUi().showManageConferenceCallButton(); + } + } else { + getUi().hideExtraRow(); + } } } @@ -241,7 +273,12 @@ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButto void showSwap(boolean show); void showAddCall(boolean show); void displayDialpad(boolean on); + boolean isDialpadVisible(); void setAudio(int mode); void setSupportedAudio(int mask); + void showManageConferenceCallButton(); + void showCDMAMergeButton(); + void hideExtraRow(); + void displayManageConferencePanel(boolean on); } } diff --git a/InCallUI/src/com/android/incallui/CallCardFragment.java b/InCallUI/src/com/android/incallui/CallCardFragment.java index 486b083f9..9c772cb05 100644 --- a/InCallUI/src/com/android/incallui/CallCardFragment.java +++ b/InCallUI/src/com/android/incallui/CallCardFragment.java @@ -185,6 +185,7 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr if (isConference) { name = getView().getResources().getString(R.string.card_title_conf_call); photo = getView().getResources().getDrawable(R.drawable.picture_conference); + nameIsNumber = false; } setPrimaryPhoneNumber(number); @@ -203,9 +204,15 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr @Override public void setSecondary(boolean show, String name, boolean nameIsNumber, String label, - Drawable photo) { + Drawable photo, boolean isConference) { if (show) { + if (isConference) { + name = getView().getResources().getString(R.string.card_title_conf_call); + photo = getView().getResources().getDrawable(R.drawable.picture_conference); + nameIsNumber = false; + } + showAndInitializeSecondaryCallInfo(); mSecondaryCallName.setText(name); diff --git a/InCallUI/src/com/android/incallui/CallCardPresenter.java b/InCallUI/src/com/android/incallui/CallCardPresenter.java index db5b66a9a..d2295d34e 100644 --- a/InCallUI/src/com/android/incallui/CallCardPresenter.java +++ b/InCallUI/src/com/android/incallui/CallCardPresenter.java @@ -156,13 +156,13 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> if (secondary == null) { // Secondary call may have ended. Update the ui. mSecondaryContactInfo = null; - updateSecondaryDisplayInfo(); + updateSecondaryDisplayInfo(false); } else { if (mSecondary == null || mSecondary.getCallId() != secondary.getCallId()) { // secondary call has changed mSecondaryContactInfo = ContactInfoCache.buildCacheEntryFromCall(mContext, secondary.getIdentification(), secondary.getState() == Call.State.INCOMING); - updateSecondaryDisplayInfo(); + updateSecondaryDisplayInfo(secondary.isConferenceCall()); startContactInfoSearch(secondary.getIdentification(), false, secondary.isConferenceCall(), secondary.getState() == Call.State.INCOMING); } @@ -289,7 +289,7 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> updatePrimaryDisplayInfo(entry, isConference); } else { mSecondaryContactInfo = entry; - updateSecondaryDisplayInfo(); + updateSecondaryDisplayInfo(isConference); } } @@ -358,7 +358,7 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> } - private void updateSecondaryDisplayInfo() { + private void updateSecondaryDisplayInfo(boolean isConference) { final CallCardUi ui = getUi(); if (ui == null) { @@ -372,10 +372,10 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> final boolean nameIsNumber = nameForCall != null && nameForCall.equals( mSecondaryContactInfo.number); ui.setSecondary(true, nameForCall, nameIsNumber, mSecondaryContactInfo.label, - mSecondaryContactInfo.photo); + mSecondaryContactInfo.photo, isConference); } else { // reset to nothing so that it starts off blank next time we use it. - ui.setSecondary(false, null, false, null, null); + ui.setSecondary(false, null, false, null, null, false); } } @@ -494,7 +494,7 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> void setPrimary(String number, String name, boolean nameIsNumber, String label, Drawable photo, boolean isConference, String gatewayLabel, String gatewayNumber); void setSecondary(boolean show, String name, boolean nameIsNumber, String label, - Drawable photo); + Drawable photo, boolean isConference); void setSecondaryImage(Bitmap bitmap); void setCallState(int state, Call.DisconnectCause cause, boolean bluetoothOn); void setPrimaryCallElapsedTime(boolean show, String duration); diff --git a/InCallUI/src/com/android/incallui/CallCommandClient.java b/InCallUI/src/com/android/incallui/CallCommandClient.java index 0cc7a8c2d..b59788b2c 100644 --- a/InCallUI/src/com/android/incallui/CallCommandClient.java +++ b/InCallUI/src/com/android/incallui/CallCommandClient.java @@ -79,7 +79,20 @@ public class CallCommandClient { try { mCommandService.disconnectCall(callId); } catch (RemoteException e) { - Log.e(this, "Error answering call.", e); + Log.e(this, "Error disconnecting call.", e); + } + } + + public void separateCall(int callId) { + Log.i(this, "separate Call: " + callId); + if (mCommandService == null) { + Log.e(this, "Cannot separate call; CallCommandService == null"); + return; + } + try { + mCommandService.separateCall(callId); + } catch (RemoteException e) { + Log.e(this, "Error separating call.", e); } } diff --git a/InCallUI/src/com/android/incallui/ConferenceManagerFragment.java b/InCallUI/src/com/android/incallui/ConferenceManagerFragment.java new file mode 100644 index 000000000..75ff17698 --- /dev/null +++ b/InCallUI/src/com/android/incallui/ConferenceManagerFragment.java @@ -0,0 +1,197 @@ +/* + * 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 + */ + +package com.android.incallui; + +import android.os.Bundle; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Chronometer; +import android.widget.TextView; + +/** + * Fragment for call control buttons + */ +public class ConferenceManagerFragment + extends BaseFragment<ConferenceManagerPresenter, + ConferenceManagerPresenter.ConferenceManagerUi> + implements ConferenceManagerPresenter.ConferenceManagerUi { + + private View mButtonManageConferenceDone; + private ViewGroup[] mConferenceCallList; + private Chronometer mConferenceTime; + + @Override + ConferenceManagerPresenter createPresenter() { + // having a singleton instance. + return new ConferenceManagerPresenter(); + } + + @Override + ConferenceManagerPresenter.ConferenceManagerUi getUi() { + return this; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + final View parent = inflater.inflate(R.layout.conference_manager_fragment, container, + false); + + // set up the Conference Call chronometer + mConferenceTime = (Chronometer) parent.findViewById(R.id.manageConferencePanelHeader); + mConferenceTime.setFormat(getActivity().getString(R.string.caller_manage_header)); + + // Create list of conference call widgets + mConferenceCallList = new ViewGroup[getPresenter().getMaxCallersInConference()]; + + final int[] viewGroupIdList = { R.id.caller0, R.id.caller1, R.id.caller2, + R.id.caller3, R.id.caller4 }; + for (int i = 0; i < getPresenter().getMaxCallersInConference(); i++) { + mConferenceCallList[i] = + (ViewGroup) parent.findViewById(viewGroupIdList[i]); + } + + mButtonManageConferenceDone = parent.findViewById(R.id.manage_done); + mButtonManageConferenceDone.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + getPresenter().manageConferenceDoneClicked(); + } + }); + + return parent; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + } + + @Override + public void setVisible(boolean on) { + if (on) { + final CallList calls = CallList.getInstance(); + getPresenter().init(getActivity(), calls); + getView().setVisibility(View.VISIBLE); + + } else { + getView().setVisibility(View.GONE); + } + } + + @Override + public boolean isFragmentVisible() { + return isVisible(); + } + + @Override + public void setRowVisible(int rowId, boolean on) { + if (on) { + mConferenceCallList[rowId].setVisibility(View.VISIBLE); + } else { + mConferenceCallList[rowId].setVisibility(View.GONE); + } + } + + /** + * Helper function to fill out the Conference Call(er) information + * for each item in the "Manage Conference Call" list. + */ + @Override + public final void displayCallerInfoForConferenceRow(int rowId, String callerName, + String callerNumber, String callerNumberType) { + + final TextView nameTextView = (TextView) mConferenceCallList[rowId].findViewById( + R.id.conferenceCallerName); + final TextView numberTextView = (TextView) mConferenceCallList[rowId].findViewById( + R.id.conferenceCallerNumber); + final TextView numberTypeTextView = (TextView) mConferenceCallList[rowId].findViewById( + R.id.conferenceCallerNumberType); + + // set the caller name + nameTextView.setText(callerName); + + // set the caller number in subscript, or make the field disappear. + if (TextUtils.isEmpty(callerNumber)) { + numberTextView.setVisibility(View.GONE); + numberTypeTextView.setVisibility(View.GONE); + } else { + numberTextView.setVisibility(View.VISIBLE); + numberTextView.setText(callerNumber); + numberTypeTextView.setVisibility(View.VISIBLE); + numberTypeTextView.setText(callerNumberType); + } + } + + @Override + public final void setupEndButtonForRow(final int rowId) { + View endButton = mConferenceCallList[rowId].findViewById(R.id.conferenceCallerDisconnect); + endButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + getPresenter().endConferenceConnection(rowId); + } + }); + } + + @Override + public final void setCanSeparateButtonForRow(final int rowId, boolean canSeparate) { + final View separateButton = mConferenceCallList[rowId].findViewById( + R.id.conferenceCallerSeparate); + + if (canSeparate) { + final View.OnClickListener separateThisConnection = new View.OnClickListener() { + @Override + public void onClick(View v) { + getPresenter().separateConferenceConnection(rowId); + } + }; + separateButton.setOnClickListener(separateThisConnection); + separateButton.setVisibility(View.VISIBLE); + } else { + separateButton.setVisibility(View.INVISIBLE); + } + } + + /** + * Starts the "conference time" chronometer. + */ + @Override + public void startConferenceTime(long base) { + if (mConferenceTime != null) { + mConferenceTime.setBase(base); + mConferenceTime.start(); + } + } + + /** + * Stops the "conference time" chronometer. + */ + @Override + public void stopConferenceTime() { + if (mConferenceTime != null) { + mConferenceTime.stop(); + } + } +}
\ No newline at end of file diff --git a/InCallUI/src/com/android/incallui/ConferenceManagerPresenter.java b/InCallUI/src/com/android/incallui/ConferenceManagerPresenter.java new file mode 100644 index 000000000..6b6f7d815 --- /dev/null +++ b/InCallUI/src/com/android/incallui/ConferenceManagerPresenter.java @@ -0,0 +1,149 @@ +/* + * 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 + */ + +package com.android.incallui; + +import android.content.Context; + +import com.android.incallui.ContactInfoCache.ContactCacheEntry; +import com.android.incallui.InCallPresenter.InCallState; +import com.android.incallui.InCallPresenter.InCallStateListener; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableSortedSet; + +/** + * Logic for call buttons. + */ +public class ConferenceManagerPresenter + extends Presenter<ConferenceManagerPresenter.ConferenceManagerUi> + implements InCallStateListener { + + private static final int MAX_CALLERS_IN_CONFERENCE = 5; + + private int mNumCallersInConference; + private Integer[] mCallerIds; + private Context mContext; + + @Override + public void onStateChange(InCallState state, CallList callList) { + if (getUi().isFragmentVisible()) { + if (state == InCallState.INCALL && callList.getActiveOrBackgroundCall() != null && + callList.getActiveOrBackgroundCall().isConferenceCall()) { + Log.v(this, "Number of existing calls is " + + String.valueOf(callList.getActiveCall().getChildCallIds().size())); + update(callList); + } else { + getUi().setVisible(false); + } + } + } + + public void init(Context context, CallList callList) { + mContext = Preconditions.checkNotNull(context); + mContext = context; + update(callList); + } + + private void update(CallList callList) { + mCallerIds = null; + mCallerIds = callList.getActiveCall().getChildCallIds().toArray(new Integer[0]); + mNumCallersInConference = mCallerIds.length; + Log.v(this, "Number of calls is " + String.valueOf(mNumCallersInConference)); + + // Users can split out a call from the conference call if there either the active call + // or the holding call is empty. If both are filled at the moment, users can not split out + // another call. + final boolean hasActiveCall = (callList.getActiveCall() != null); + final boolean hasHoldingCall = (callList.getBackgroundCall() != null); + boolean canSeparate = !(hasActiveCall && hasHoldingCall); + + for (int i = 0; i < MAX_CALLERS_IN_CONFERENCE; i++) { + if (i < mNumCallersInConference) { + // Fill in the row in the UI for this caller. + + final ContactCacheEntry contactCache = ContactInfoCache.getInstance(mContext). + getInfo(mCallerIds[i]); + updateManageConferenceRow(i, contactCache, canSeparate); + } else { + // Blank out this row in the UI + updateManageConferenceRow(i, null, false); + } + } + } + + /** + * Updates a single row of the "Manage conference" UI. (One row in this + * UI represents a single caller in the conference.) + * + * @param i the row to update + * @param contactCacheEntry the contact details corresponding to this caller. + * If null, that means this is an "empty slot" in the conference, + * so hide this row in the UI. + * @param canSeparate if true, show a "Separate" (i.e. "Private") button + * on this row in the UI. + */ + public void updateManageConferenceRow(final int i, + final ContactCacheEntry contactCacheEntry, + boolean canSeparate) { + + if (contactCacheEntry != null) { + // Activate this row of the Manage conference panel: + getUi().setRowVisible(i, true); + + final String name = contactCacheEntry.name; + final String number = contactCacheEntry.number; + + if (canSeparate) { + getUi().setCanSeparateButtonForRow(i, canSeparate); + } + // display the CallerInfo. + getUi().setupEndButtonForRow(i); + getUi().displayCallerInfoForConferenceRow(i, name, number, contactCacheEntry.label); + } else { + // Disable this row of the Manage conference panel: + getUi().setRowVisible(i, false); + } + } + + public void manageConferenceDoneClicked() { + getUi().setVisible(false); + } + + public int getMaxCallersInConference() { + return MAX_CALLERS_IN_CONFERENCE; + } + + public void separateConferenceConnection(int rowId) { + CallCommandClient.getInstance().separateCall(mCallerIds[rowId]); + } + + public void endConferenceConnection(int rowId) { + CallCommandClient.getInstance().disconnectCall(mCallerIds[rowId]); + } + + public interface ConferenceManagerUi extends Ui { + void setVisible(boolean on); + boolean isFragmentVisible(); + void setRowVisible(int rowId, boolean on); + void displayCallerInfoForConferenceRow(int rowId, String callerName, String callerNumber, + String callerNumberType); + void setCanSeparateButtonForRow(int rowId, boolean canSeparate); + void setupEndButtonForRow(int rowId); + void startConferenceTime(long base); + void stopConferenceTime(); + } +} diff --git a/InCallUI/src/com/android/incallui/InCallActivity.java b/InCallUI/src/com/android/incallui/InCallActivity.java index fee4d9510..6cae6b05e 100644 --- a/InCallUI/src/com/android/incallui/InCallActivity.java +++ b/InCallUI/src/com/android/incallui/InCallActivity.java @@ -34,6 +34,7 @@ public class InCallActivity extends Activity { private CallCardFragment mCallCardFragment; private AnswerFragment mAnswerFragment; private DialpadFragment mDialpadFragment; + private ConferenceManagerFragment mConferenceManagerFragment; private boolean mIsForegroundActivity; @Override @@ -287,6 +288,11 @@ public class InCallActivity extends Activity { mDialpadFragment.getView().setVisibility(View.INVISIBLE); } + if (mConferenceManagerFragment == null) { + mConferenceManagerFragment = (ConferenceManagerFragment) getFragmentManager() + .findFragmentById(R.id.conferenceManagerFragment); + mConferenceManagerFragment.getView().setVisibility(View.INVISIBLE); + } setUpPresenterCallbacks(); } @@ -302,6 +308,7 @@ public class InCallActivity extends Activity { mainPresenter.addListener(mCallButtonFragment.getPresenter()); mainPresenter.addListener(mCallCardFragment.getPresenter()); + mainPresenter.addListener(mConferenceManagerFragment.getPresenter()); // setting activity should be last thing in setup process mainPresenter.setActivity(this); @@ -313,6 +320,7 @@ public class InCallActivity extends Activity { mainPresenter.removeListener(mCallButtonFragment.getPresenter()); mainPresenter.removeListener(mCallCardFragment.getPresenter()); + mainPresenter.removeListener(mConferenceManagerFragment.getPresenter()); mainPresenter.setActivity(null); } @@ -332,4 +340,14 @@ public class InCallActivity extends Activity { mCallCardFragment.setVisible(true); } } + + public boolean isDialpadVisible() { + return mDialpadFragment.isVisible(); + } + + public void displayManageConferencePanel(boolean showPanel) { + if (showPanel) { + mConferenceManagerFragment.setVisible(true); + } + } } |