diff options
author | Christine Chen <christinech@google.com> | 2013-09-05 10:57:05 -0700 |
---|---|---|
committer | Christine Chen <christinech@google.com> | 2013-09-06 11:36:37 -0700 |
commit | 5345442d7238c1db00dc8d55a49f7f5dd713d994 (patch) | |
tree | 6d436500fa3eb6e91616eabfc27a8d03a51f5a45 /InCallUI/src/com/android/incallui | |
parent | 4f5b60270e59c8e7dfb22489361ef83c4630485a (diff) |
Adds manage conference call UI
Bug: 10334739
Change-Id: I46a52ec967a1c496dd4b797f2064d9099670711f
Diffstat (limited to 'InCallUI/src/com/android/incallui')
8 files changed, 480 insertions, 9 deletions
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); + } + } } |