diff options
author | Matt Garnes <matt@cyngn.com> | 2015-04-30 11:16:54 -0700 |
---|---|---|
committer | Matt Garnes <matt@cyngn.com> | 2015-04-30 11:16:54 -0700 |
commit | c4729a45f792543ad027912216065bc88a60da36 (patch) | |
tree | e51b4d566a61a3c38b2c8568e9dd8c132aaeb6ed | |
parent | 9492da9394de1cea33160dfd3dc7d44de4bf3852 (diff) | |
parent | a393379ec02ec9ba79e5eb77914c894418a6dc15 (diff) | |
download | packages_apps_InCallUI-c4729a45f792543ad027912216065bc88a60da36.tar.gz packages_apps_InCallUI-c4729a45f792543ad027912216065bc88a60da36.tar.bz2 packages_apps_InCallUI-c4729a45f792543ad027912216065bc88a60da36.zip |
Merge remote-tracking branch 'caf/LA.BR.1.2.3_1' into caf/cm-12.1caf/cm-12.1
28 files changed, 370 insertions, 79 deletions
diff --git a/res/drawable-hdpi/ic_hd_audio.png b/res/drawable-hdpi/ic_hd_audio.png Binary files differnew file mode 100644 index 00000000..cccaf494 --- /dev/null +++ b/res/drawable-hdpi/ic_hd_audio.png diff --git a/res/drawable-mdpi/ic_hd_audio.png b/res/drawable-mdpi/ic_hd_audio.png Binary files differnew file mode 100644 index 00000000..6353b7ac --- /dev/null +++ b/res/drawable-mdpi/ic_hd_audio.png diff --git a/res/drawable-xhdpi/ic_hd_audio.png b/res/drawable-xhdpi/ic_hd_audio.png Binary files differnew file mode 100644 index 00000000..6d05d45f --- /dev/null +++ b/res/drawable-xhdpi/ic_hd_audio.png diff --git a/res/drawable-xxhdpi/ic_hd_audio.png b/res/drawable-xxhdpi/ic_hd_audio.png Binary files differnew file mode 100644 index 00000000..44294ba0 --- /dev/null +++ b/res/drawable-xxhdpi/ic_hd_audio.png diff --git a/res/drawable-xxxhdpi/ic_hd_audio.png b/res/drawable-xxxhdpi/ic_hd_audio.png Binary files differnew file mode 100644 index 00000000..459cd8f4 --- /dev/null +++ b/res/drawable-xxxhdpi/ic_hd_audio.png diff --git a/res/layout/primary_call_info.xml b/res/layout/primary_call_info.xml index a5fdb9d9..9a8256c9 100644 --- a/res/layout/primary_call_info.xml +++ b/res/layout/primary_call_info.xml @@ -46,7 +46,6 @@ android:layout_height="16dp" android:layout_marginEnd="4dp" android:baselineAlignBottom="true" - android:tint="@color/incall_accent_color" android:alpha="0.0" android:scaleType="centerInside" android:visibility="gone" /> diff --git a/res/layout/select_account_list_item.xml b/res/layout/select_account_list_item.xml index 1999fced..3759e3e9 100644 --- a/res/layout/select_account_list_item.xml +++ b/res/layout/select_account_list_item.xml @@ -25,7 +25,6 @@ <ImageView android:id="@+id/icon" android:layout_width="48dp" android:layout_height="48dp" - android:tint="@color/dialtacts_secondary_text_color" android:scaleType="center" /> <TextView android:id="@+id/text" diff --git a/res/menu/incall_overflow_menu.xml b/res/menu/incall_overflow_menu.xml index 57d76350..97d12711 100644 --- a/res/menu/incall_overflow_menu.xml +++ b/res/menu/incall_overflow_menu.xml @@ -44,4 +44,7 @@ <item android:id="@+id/overflow_manage_conference_menu_item" android:title="@string/overflowManageConferenceMenuItemText" /> + + <item android:id="@+id/overflow_end_active_accept_incoming_menu_item" + android:title="@string/end_active_accept_mt_call" /> </menu> diff --git a/res/values/customize.xml b/res/values/customize.xml index 06adaef1..e8497865 100644 --- a/res/values/customize.xml +++ b/res/values/customize.xml @@ -44,4 +44,16 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <!-- On user confirmation, activity is launched to disable apm. Below config is used for the same --> <bool name="config_telephony_enable_apm_setting_launch">false</bool> + + <!-- Menu to end current active call will be added for the following use case : + Device A and Device B are in active call + Device A receives another call from Device C. Call with Device B goes on Hold + Device A receives another call from Device D. + At this point, menu will be displayed + a) To end active call i.e. Call with C + b) Accept call from Device D. + c) Call with Device B will continue to be on Hold + Below config is used for the same + --> + <bool name="config_end_active_accept_incoming">false</bool> </resources> diff --git a/res/values/strings.xml b/res/values/strings.xml index 2e86499f..d4f49e74 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -653,4 +653,9 @@ <string name="apm_turn_on_confirmation">"Flight mode is on. Would you like to turn off flight mode?"</string> <string name="cancel">Cancel</string> + <!--Multiparty call--> + <string name="end_active_accept_mt_call">End active,accept incoming</string> + <!-- Normal call UI will be shown for the emergency call + for the numbers which is mentioned in mask_emergency_number--> + <string name="mask_emergency_number"></string> </resources> diff --git a/src/com/android/incallui/AnswerPresenter.java b/src/com/android/incallui/AnswerPresenter.java index b0ca155c..d69f5f49 100755 --- a/src/com/android/incallui/AnswerPresenter.java +++ b/src/com/android/incallui/AnswerPresenter.java @@ -232,15 +232,17 @@ public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi> } final Call incall = CallList.getInstance().getIncomingCall(); - if (incall != null || isUpgradePending) { - getUi().showAnswerUi(true); + final AnswerPresenter.AnswerUi ui = getUi(); + if (ui == null) { + Log.d(TAG, "onCallChanged: AnswerPresenter.AnswerUi getUi returned null"); } else { - getUi().showAnswerUi(false); + ui.showAnswerUi(incall != null || isUpgradePending); } - // mCallId will hold the state of the call. We don't clear the mCall variable here as // it may be useful for sending text messages after phone disconnects. - mCallId[phoneId] = null; + if (!isUpgradePending) { + mCallId[phoneId] = null; + } mHasTextMessages = false; } else if (!mHasTextMessages) { final List<String> textMsgs = CallList.getInstance().getTextResponses(call.getId()); diff --git a/src/com/android/incallui/CallButtonFragment.java b/src/com/android/incallui/CallButtonFragment.java index 87b658f4..e2f8c9cb 100644 --- a/src/com/android/incallui/CallButtonFragment.java +++ b/src/com/android/incallui/CallButtonFragment.java @@ -206,6 +206,7 @@ public class CallButtonFragment !mPauseVideoButton.isSelected() /* pause */); break; case R.id.overflowButton: + updateEndActiveAcceptMtMenu(); mOverflowPopup.show(); break; case R.id.manageVideoCallConferenceButton: @@ -236,7 +237,10 @@ public class CallButtonFragment mAddCallButton.setEnabled(isEnabled); mMergeButton.setEnabled(isEnabled); mPauseVideoButton.setEnabled(isEnabled); - mOverflowButton.setEnabled(isEnabled); + boolean canShowMenuBtn = + getResources().getBoolean(R.bool.config_end_active_accept_incoming) + && ((InCallActivity)getActivity()).canEndActiveAcceptMT(); + mOverflowButton.setEnabled(isEnabled || canShowMenuBtn); mAddParticipantButton.setEnabled(isEnabled); mManageVideoCallConferenceButton.setEnabled(isEnabled); } @@ -481,6 +485,9 @@ public class CallButtonFragment case R.id.overflow_manage_conference_menu_item: onManageVideoCallConferenceClicked(); break; + case R.id.overflow_end_active_accept_incoming_menu_item: + ((InCallActivity)getActivity()).endActiveAcceptMT(); + break; default: Log.wtf(this, "onMenuItemClick: unexpected overflow menu click"); break; @@ -513,7 +520,7 @@ public class CallButtonFragment menu.findItem(R.id.overflow_add_participant_menu_item).setVisible(showAddParticipantOption); menu.findItem(R.id.overflow_manage_conference_menu_item).setVisible( showManageConferenceVideoCallOption); - + updateEndActiveAcceptMtMenu(); mOverflowButton.setEnabled(menu.hasVisibleItems()); } @@ -820,6 +827,16 @@ public class CallButtonFragment return getActivity(); } + private void updateEndActiveAcceptMtMenu() { + if(mOverflowPopup == null) { + return; + } + Menu menu = mOverflowPopup.getMenu(); + menu.findItem(R.id.overflow_end_active_accept_incoming_menu_item).setVisible( + getResources().getBoolean(R.bool.config_end_active_accept_incoming) + && ((InCallActivity)getActivity()).canEndActiveAcceptMT()); + } + private void maybeSendAccessibilityEvent(View view, int stringId) { final Context context = getActivity(); AccessibilityManager manager = diff --git a/src/com/android/incallui/CallCardFragment.java b/src/com/android/incallui/CallCardFragment.java index 717094cf..3154f19d 100644 --- a/src/com/android/incallui/CallCardFragment.java +++ b/src/com/android/incallui/CallCardFragment.java @@ -650,7 +650,7 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr int sessionModificationState, DisconnectCause disconnectCause, String connectionLabel, - Drawable connectionIcon, + Drawable callStateIcon, String gatewayNumber, boolean isWaitingForRemoteSide) { boolean isGatewayCall = !TextUtils.isEmpty(gatewayNumber); @@ -681,44 +681,55 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr mCallStateLabel.setAlpha(1); mCallStateLabel.setVisibility(View.VISIBLE); - if (connectionIcon == null) { - mCallStateIcon.clearAnimation(); - mCallStateIcon.setVisibility(View.GONE); + if (state == Call.State.ACTIVE || state == Call.State.CONFERENCED) { + mCallStateLabel.clearAnimation(); } else { - mCallStateIcon.setVisibility(View.VISIBLE); - // Invoke setAlpha(float) instead of setAlpha(int) to set the view's alpha. This is - // needed because the pulse animation operates on the view alpha. - mCallStateIcon.setAlpha(1.0f); - mCallStateIcon.setImageDrawable(connectionIcon); + mCallStateLabel.startAnimation(mPulseAnimation); } - - if (VideoProfile.VideoState.isVideo(videoState) - || (state == Call.State.ACTIVE && sessionModificationState - == Call.SessionModificationState.WAITING_FOR_RESPONSE)) { - mCallStateVideoCallIcon.setVisibility(View.VISIBLE); - } else { - mCallStateVideoCallIcon.setVisibility(View.GONE); + } else { + mCallStateLabel.clearAnimation(); + Animation callStateLabelAnimation = mCallStateLabel.getAnimation(); + if (callStateLabelAnimation != null) { + callStateLabelAnimation.cancel(); } + mCallStateLabel.setText(null); + mCallStateLabel.setAlpha(0); + mCallStateLabel.setVisibility(View.GONE); + } - if (state == Call.State.ACTIVE || state == Call.State.CONFERENCED) { - mCallStateLabel.clearAnimation(); + if (callStateIcon != null) { + mCallStateIcon.setVisibility(View.VISIBLE); + // Invoke setAlpha(float) instead of setAlpha(int) to set the view's alpha. This is + // needed because the pulse animation operates on the view alpha. + mCallStateIcon.setAlpha(1.0f); + mCallStateIcon.setImageDrawable(callStateIcon); + + if (state == Call.State.ACTIVE || state == Call.State.CONFERENCED + || TextUtils.isEmpty(callStateLabel)) { mCallStateIcon.clearAnimation(); } else { - mCallStateLabel.startAnimation(mPulseAnimation); if (mCallStateIcon.getVisibility() == View.VISIBLE) { mCallStateIcon.startAnimation(mPulseAnimation); } } } else { - mCallStateLabel.clearAnimation(); - mCallStateLabel.setText(null); - mCallStateLabel.setAlpha(0); - mCallStateLabel.setVisibility(View.GONE); + Animation callStateIconAnimation = mCallStateIcon.getAnimation(); + if (callStateIconAnimation != null) { + callStateIconAnimation.cancel(); + } + // Invoke setAlpha(float) instead of setAlpha(int) to set the view's alpha. This is // needed because the pulse animation operates on the view alpha. mCallStateIcon.setAlpha(0.0f); + mCallStateIcon.clearAnimation(); mCallStateIcon.setVisibility(View.GONE); + } + if (VideoProfile.VideoState.isBidirectional(videoState) + || (state == Call.State.ACTIVE && sessionModificationState + == Call.SessionModificationState.WAITING_FOR_RESPONSE)) { + mCallStateVideoCallIcon.setVisibility(View.VISIBLE); + } else { mCallStateVideoCallIcon.setVisibility(View.GONE); } } diff --git a/src/com/android/incallui/CallCardPresenter.java b/src/com/android/incallui/CallCardPresenter.java index b152eb51..7ecdb77d 100644 --- a/src/com/android/incallui/CallCardPresenter.java +++ b/src/com/android/incallui/CallCardPresenter.java @@ -277,8 +277,8 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> maybeShowManageConferenceCallButton(); //Note that both primary and secondary calls can be modified - final boolean isModifyRequest = isPendingModifyRequest(mPrimary) || - isPendingModifyRequest(mSecondary); + final boolean isModifyRequest = CallUtils.isPendingModifyRequest(mPrimary) || + CallUtils.isPendingModifyRequest(mSecondary); final boolean enableEndCallButton = Call.State.isConnectingOrConnected(callState) && callState != Call.State.INCOMING && mPrimary != null && !isModifyRequest; @@ -289,13 +289,6 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> !isModifyRequest /* animate */); } - //Return TRUE if there is a modify request pending user action - boolean isPendingModifyRequest(Call call) { - return (call != null && call.getSessionModificationState() == - Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST); - - } - @Override public void onDetailsChanged(Call call, android.telecom.Call.Details details) { updatePrimaryCallState(); @@ -330,7 +323,7 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> mPrimary.getSessionModificationState(), mPrimary.getDisconnectCause(), getConnectionLabel(), - getConnectionIcon(), + getCallStateIcon(), getGatewayNumber(), mPrimary.isWaitingForRemoteSide()); setCallbackNumber(); @@ -717,7 +710,8 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> return getCallProviderLabel(mPrimary); } - private Drawable getConnectionIcon() { + private Drawable getCallStateIcon() { + // Return connection icon if one exists. StatusHints statusHints = mPrimary.getTelecommCall().getDetails().getStatusHints(); if (statusHints != null && statusHints.getIconResId() != 0) { Drawable icon = statusHints.getIcon(mContext); @@ -725,6 +719,13 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> return icon; } } + + // Return high definition audio icon if the capability is indicated. + if (mPrimary.getTelecommCall().getDetails().can( + android.telecom.Call.Details.CAPABILITY_HIGH_DEF_AUDIO) + && mPrimary.getState() == Call.State.ACTIVE) { + return mContext.getResources().getDrawable(R.drawable.ic_hd_audio); + } return getCallProviderIcon(mPrimary); } @@ -780,8 +781,9 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> Log.i(this, "Disconnecting call: " + mPrimary); mPrimary.setState(Call.State.DISCONNECTING); + Call temp = mPrimary; CallList.getInstance().onUpdate(mPrimary); - TelecomAdapter.getInstance().disconnectCall(mPrimary.getId()); + TelecomAdapter.getInstance().disconnectCall(temp.getId()); } private String getNumberFromHandle(Uri handle) { diff --git a/src/com/android/incallui/CallUtils.java b/src/com/android/incallui/CallUtils.java index e8f145f5..45397c9e 100644 --- a/src/com/android/incallui/CallUtils.java +++ b/src/com/android/incallui/CallUtils.java @@ -86,4 +86,9 @@ public class CallUtils { return videoState | VideoProfile.VideoState.PAUSED; } + //Return TRUE if there is a modify request pending user action + public static boolean isPendingModifyRequest(Call call) { + return (call != null && call.getSessionModificationState() == + Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST); + } } diff --git a/src/com/android/incallui/CallerInfo.java b/src/com/android/incallui/CallerInfo.java index c7940691..337d302a 100644 --- a/src/com/android/incallui/CallerInfo.java +++ b/src/com/android/incallui/CallerInfo.java @@ -88,6 +88,8 @@ public class CallerInfo { public int namePresentation; public boolean contactExists; + public boolean fdnContactSearched; + public String phoneLabel; /* Split up the phoneLabel into number type and label name */ public int numberType; diff --git a/src/com/android/incallui/CallerInfoAsyncQuery.java b/src/com/android/incallui/CallerInfoAsyncQuery.java index 8c5abe05..7f3b0ac9 100644 --- a/src/com/android/incallui/CallerInfoAsyncQuery.java +++ b/src/com/android/incallui/CallerInfoAsyncQuery.java @@ -369,7 +369,17 @@ public class CallerInfoAsyncQuery { subId = call.getSubId(); } // check to see if these are recognized numbers, and use shortcuts if we can. - if (PhoneNumberUtils.isLocalEmergencyNumber(context, info.phoneNumber)) { + boolean isEmergencyNumber = true; + String maskEmergencyNumber = context.getResources() + .getString(R.string.mask_emergency_number); + if (!TextUtils.isEmpty(maskEmergencyNumber) + && info.phoneNumber.equals(maskEmergencyNumber)) { + isEmergencyNumber = false; + } else { + isEmergencyNumber = PhoneNumberUtils.isLocalEmergencyNumber(context, info.phoneNumber); + } + + if (isEmergencyNumber) { cw.event = EVENT_EMERGENCY_NUMBER; } else if (info.isVoiceMailNumber() || PhoneNumberUtils.isVoiceMailNumber(subId, info.phoneNumber)) { diff --git a/src/com/android/incallui/ContactInfoCache.java b/src/com/android/incallui/ContactInfoCache.java index 756ec320..fa9b8a03 100644 --- a/src/com/android/incallui/ContactInfoCache.java +++ b/src/com/android/incallui/ContactInfoCache.java @@ -16,7 +16,9 @@ package com.android.incallui; +import android.content.AsyncQueryHandler; import android.content.Context; +import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; @@ -24,7 +26,9 @@ import android.net.Uri; import android.os.Looper; import android.provider.ContactsContract.Contacts; import android.provider.ContactsContract.CommonDataKinds.Phone; +import android.telecom.PhoneCapabilities; import android.telecom.TelecomManager; +import android.telephony.PhoneNumberUtils; import android.text.TextUtils; import com.android.contacts.common.util.PhoneNumberHelper; @@ -149,8 +153,73 @@ public class ContactInfoCache implements ContactsAsyncHelper.OnImageLoadComplete findInfoQueryComplete(call, callerInfo, isIncoming, false); } + /** + * @param Call, CallerInfo, boolean isIncomingcall, boolean didlocalLookup + * @return void. + * Initiate the FDN query and once the query is completed, + * the fdn list will be searched for the phonenumber, + * If phone number is available then corresponding name will be set to + * callerinfo object. + */ + private void findFdnContact(final Call call, final CallerInfo callerInfo, + final boolean isIncoming, final boolean didLocalLookup) { + + AsyncQueryHandler queryHandler = new AsyncQueryHandler(mContext.getContentResolver()) { + + @Override + protected void onQueryComplete(int token, Object cookie, Cursor c) { + callerInfo.fdnContactSearched = true; + if (c != null && c.getCount() > 0) { + c.moveToFirst(); + String phoneNumber = getSeachableNumber(callerInfo.phoneNumber); + int numberIndex = c.getColumnIndex("number"); + int nameIndex = c.getColumnIndex("name"); + do { + String number = getSeachableNumber(c.getString(numberIndex)); + if (phoneNumber.equals(number)) { + String name = c.getString(nameIndex); + Log.d(TAG, " found FDN contact name : " + name); + callerInfo.name = name; + callerInfo.contactExists = true; + break; + } + } while (c.moveToNext()); + } + if (c != null) { + c.close(); + } + findInfoQueryComplete(call, callerInfo, isIncoming, didLocalLookup); + } + }; + Uri uri = Uri.parse("content://icc/fdn"); + queryHandler.startQuery(0, null, uri, null, null, null, null); + } + + /** + * @param String phonenumber. + * @return string. This function will convert the argument string + * phone number to normalized number, then reverse the string. And + * truncate with the min match length. And returns the truncated string. + */ + private String getSeachableNumber(String number) { + if (TextUtils.isEmpty(number)) { + return number; + } + String normalizedNumber = PhoneNumberUtils.normalizeNumber(number); + normalizedNumber = PhoneNumberUtils.toCallerIDMinMatch(normalizedNumber); + return normalizedNumber; + } + private void findInfoQueryComplete(Call call, CallerInfo callerInfo, boolean isIncoming, boolean didLocalLookup) { + if (!callerInfo.contactExists && !callerInfo.fdnContactSearched && isIncoming + && mContext.getResources() + .getBoolean(com.android.internal.R.bool.config_fdn_contact_search) + && call.can(PhoneCapabilities.FDN_ENABLED)) { + Log.d(TAG, "Contact doesn't exist, initiating FDN contact search"); + findFdnContact(call, callerInfo, isIncoming, didLocalLookup); + return; + } final String callId = call.getId(); int presentationMode = call.getNumberPresentation(); if (callerInfo.contactExists || callerInfo.isEmergencyNumber() || diff --git a/src/com/android/incallui/InCallActivity.java b/src/com/android/incallui/InCallActivity.java index db34da4c..8049bc88 100644 --- a/src/com/android/incallui/InCallActivity.java +++ b/src/com/android/incallui/InCallActivity.java @@ -47,6 +47,7 @@ import android.view.MenuItem; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.KeyEvent; +import android.view.Menu; import android.view.View; import android.view.Window; import android.view.WindowManager; @@ -81,6 +82,7 @@ public class InCallActivity extends Activity { private static final String METHOD_IS_CALL_RECORD_AVAILABLE = "is_call_record_available"; private static final String METHOD_GET_CALL_RECORD_DURATION = "get_call_record_duration"; private static final String EXTRA_RESULT = "result"; + private static final int END_ACTIVE_ACCEPT_INCOMING_MT = 2; private static final String ACTION_SUPP_SERVICE_FAILURE = "org.codeaurora.ACTION_SUPP_SERVICE_FAILURE"; @@ -392,9 +394,18 @@ public class InCallActivity extends Activity { @Override public boolean onOptionsItemSelected(MenuItem item) { final int itemId = item.getItemId(); - if (itemId == android.R.id.home) { - onBackPressed(); - return true; + switch (item.getItemId()) { + case android.R.id.home: + { + onBackPressed(); + return true; + } + case END_ACTIVE_ACCEPT_INCOMING_MT: + { + Log.w(this, "onOptionsItemSelected : END_ACTIVE_ACCEPT_INCOMING_MT = " + item); + endActiveAcceptMT(); + return true; + } } return super.onOptionsItemSelected(item); } @@ -1103,4 +1114,48 @@ public class InCallActivity extends Activity { } } } + + //Add menu to end active call and pick up active call. + @Override + public boolean onCreateOptionsMenu(Menu menu) { + Log.d(this, "onCreateOptionsMenu"); + + if (getResources().getBoolean(R.bool.config_end_active_accept_incoming)) { + menu.add(0, END_ACTIVE_ACCEPT_INCOMING_MT, + 1, getString(R.string.end_active_accept_mt_call)).setIcon( + R.drawable.ic_call_white_24dp); + return true; + } + return false; + } + + public boolean canEndActiveAcceptMT() { + Call incomingCall = CallList.getInstance().getIncomingCall(); + Call activeCall = CallList.getInstance().getActiveCall(); + Call backgroundCall = CallList.getInstance().getBackgroundCall(); + return incomingCall != null && activeCall != null && backgroundCall != null; + } + + public void endActiveAcceptMT() { + mAnswerFragment.onAnswer(0, getApplicationContext()); + } + + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + Log.d(this, "onPrepareOptionsMenu"); + super.onPrepareOptionsMenu(menu); + + MenuItem currentSelection = menu.findItem(END_ACTIVE_ACCEPT_INCOMING_MT); + if (currentSelection != null) { + if (canEndActiveAcceptMT()) { + currentSelection.setVisible(true); + Log.d(this, "setVisible = to true"); + return true; + } else { + currentSelection.setVisible(false); + Log.d(this, "setVisible = to false"); + } + } + return false; + } } diff --git a/src/com/android/incallui/InCallApp.java b/src/com/android/incallui/InCallApp.java index a0bdd43a..a87f5407 100644 --- a/src/com/android/incallui/InCallApp.java +++ b/src/com/android/incallui/InCallApp.java @@ -83,9 +83,9 @@ public class InCallApp extends Application { } else if (action.equals(ACTION_HANG_UP_ONGOING_CALL)) { InCallPresenter.getInstance().hangUpOngoingCall(context); } else if (action.equals(ACTION_ACCEPT_VIDEO_UPGRADE_REQUEST)) { - //TODO: Change calltype after adding support for TX and RX - InCallPresenter.getInstance().acceptUpgradeRequest( - VideoProfile.VideoState.BIDIRECTIONAL, context); + InCallPresenter inCallPresenter = InCallPresenter.getInstance(); + inCallPresenter.acceptUpgradeRequest(context); + inCallPresenter.bringToForeground(false); } else if (action.equals(ACTION_DECLINE_VIDEO_UPGRADE_REQUEST)) { InCallPresenter.getInstance().declineUpgradeRequest(context); } diff --git a/src/com/android/incallui/InCallPresenter.java b/src/com/android/incallui/InCallPresenter.java index caef6e60..1adc7193 100644 --- a/src/com/android/incallui/InCallPresenter.java +++ b/src/com/android/incallui/InCallPresenter.java @@ -36,6 +36,8 @@ import android.view.View; import android.view.Window; import android.view.WindowManager; +import android.os.PowerManager; + import com.google.common.base.Preconditions; import com.android.incalluibind.ObjectFactory; @@ -90,6 +92,8 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener { private boolean mServiceConnected = false; private boolean mAccountSelectionCancelled = false; private InCallCameraManager mInCallCameraManager = null; + private PowerManager mPowerManager; + private PowerManager.WakeLock mWakeLock = null; private final Phone.Listener mPhoneListener = new Phone.Listener() { @Override @@ -211,6 +215,10 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener { mProximitySensor = new ProximitySensor(context, mAudioModeProvider); addListener(mProximitySensor); + mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); + mWakeLock = mPowerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | + PowerManager.ACQUIRE_CAUSES_WAKEUP, "InCallPresenter"); + mCallList = callList; // This only gets called by the service so this is okay. @@ -617,6 +625,19 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener { } } + public void acceptUpgradeRequest(Context context) { + if (mCallList != null) { + Call call = mCallList.getVideoUpgradeRequestCall(); + if (call != null) { + acceptUpgradeRequest(call.getModifyToVideoState(), context); + } else { + Log.e(this, "acceptUpgradeRequest Call is null"); + } + } else { + Log.e(this, " acceptUpgradeRequest mCallList is empty"); + } + } + public void declineUpgradeRequest(Context context) { Log.d(this, " declineUpgradeRequest"); // Bail if we have been shut down and the call list is null. @@ -883,9 +904,13 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener { //If the call is auto answered bring up the InCallActivity boolean isAutoAnswer = false; - isAutoAnswer = (mInCallState == InCallState.INCOMING) && - (newState == InCallState.INCALL) && - (mInCallActivity == null); + + if ((mCallList.getDisconnectedCall() == null) && + (mCallList.getDisconnectingCall() == null)) { + isAutoAnswer = (mInCallState == InCallState.INCOMING) && + (newState == InCallState.INCALL) && + (mInCallActivity == null); + } Log.d(this, "startOrFinishUi: " + isAutoAnswer); @@ -1068,6 +1093,9 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener { } mProximitySensor = null; + mWakeLock = null; + mPowerManager = null; + mAudioModeProvider = null; if (mStatusBarNotifier != null) { @@ -1243,6 +1271,34 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener { } } + /* returns TRUE if screen is turned ON else false */ + private boolean isScreenInteractive() { + return mPowerManager.isInteractive(); + } + + public void wakeUpScreen() { + if (!isScreenInteractive()) { + acquireWakeLock(); + releaseWakeLock(); + } + } + + private void acquireWakeLock() { + Log.v(this, "acquireWakeLock"); + + if (mWakeLock != null) { + mWakeLock.acquire(); + } + } + + private void releaseWakeLock() { + Log.v(this, "releaseWakeLock"); + + if (mWakeLock != null && mWakeLock.isHeld()) { + mWakeLock.release(); + } + } + public void enableScreenTimeout(boolean v) { Log.v(this, "enableScreenTimeout: value=" + v); if (mInCallActivity == null) { diff --git a/src/com/android/incallui/InCallVideoCallListener.java b/src/com/android/incallui/InCallVideoCallListener.java index bbd33ca6..080acc57 100644 --- a/src/com/android/incallui/InCallVideoCallListener.java +++ b/src/com/android/incallui/InCallVideoCallListener.java @@ -49,6 +49,10 @@ public class InCallVideoCallListener extends VideoCall.Listener { @Override public void onSessionModifyRequestReceived(VideoProfile videoProfile) { Log.d(this, " onSessionModifyRequestReceived videoProfile=" + videoProfile); + + /* turn ON screen when already turned OFF */ + InCallPresenter.getInstance().wakeUpScreen(); + int previousVideoState = CallUtils.toUnPausedVideoState(mCall.getVideoState()); int newVideoState = CallUtils.toUnPausedVideoState(videoProfile.getVideoState()); @@ -133,7 +137,7 @@ public class InCallVideoCallListener extends VideoCall.Listener { * @param dataUsage The updated data usage. */ @Override - public void onCallDataUsageChanged(long dataUsage) { + public void onCallDataUsageChanged(int dataUsage) { Log.d(this, "onCallDataUsageChanged: dataUsage = " + dataUsage); InCallVideoCallListenerNotifier.getInstance().callDataUsageChanged(dataUsage); } diff --git a/src/com/android/incallui/InCallVideoCallListenerNotifier.java b/src/com/android/incallui/InCallVideoCallListenerNotifier.java index 126fa488..dd551598 100644 --- a/src/com/android/incallui/InCallVideoCallListenerNotifier.java +++ b/src/com/android/incallui/InCallVideoCallListenerNotifier.java @@ -244,7 +244,7 @@ public class InCallVideoCallListenerNotifier { * * @param dataUsage data usage value */ - public void callDataUsageChanged(long dataUsage) { + public void callDataUsageChanged(int dataUsage) { for (VideoEventListener listener : mVideoEventListeners) { listener.onCallDataUsageChange(dataUsage); } @@ -316,7 +316,7 @@ public class InCallVideoCallListenerNotifier { * * @param dataUsage call data usage value */ - public void onCallDataUsageChange(long dataUsage); + public void onCallDataUsageChange(int dataUsage); /** * Called when call session event is raised. diff --git a/src/com/android/incallui/StatusBarNotifier.java b/src/com/android/incallui/StatusBarNotifier.java index 6042a9b9..40ad090b 100644 --- a/src/com/android/incallui/StatusBarNotifier.java +++ b/src/com/android/incallui/StatusBarNotifier.java @@ -31,6 +31,7 @@ import android.os.Handler; import android.os.Message; import android.telecom.PhoneAccount; import android.telecom.PhoneCapabilities; +import android.telecom.VideoProfile; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -184,6 +185,13 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener { state == InCallState.OUTGOING && !InCallPresenter.getInstance().isActivityPreviouslyStarted(); + // In case of voicePrivacy the notification has to be shown even if the UI is + // already shwoing + boolean voicePrivacy = false; + if (call != null && call.can(PhoneCapabilities.VOICE_PRIVACY)) { + voicePrivacy = true; + } + // Whether to show a notification immediately. boolean showNotificationNow = @@ -197,7 +205,8 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener { // If the UI is already showing, then for most cases we do not want to show // a notification since that would be redundant, unless it is an incoming call, // in which case the notification is actually an important alert. - (!InCallPresenter.getInstance().isShowingInCallUi() || state.isIncoming()) && + (!InCallPresenter.getInstance().isShowingInCallUi() || state.isIncoming() || + voicePrivacy) && // If we have an outgoing call with no UI but the timer has fired, we show // a notification anyway. @@ -323,6 +332,9 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener { builder.setUsesChronometer(false); addDismissUpgradeRequestAction(builder); addAcceptUpgradeRequestAction(builder); + if (isMoreOptionRequired(call)) { + addMoreAction(builder); + } } else { createIncomingCallNotification(call, state, builder); } @@ -338,6 +350,11 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener { mIsShowingNotification = true; } + static private boolean isMoreOptionRequired(Call call) { + return VideoProfile.VideoState.isAudioOnly(call.getVideoState()) && + VideoProfile.VideoState.isBidirectional(call.getModifyToVideoState()); + } + private void createIncomingCallNotification( Call call, int state, Notification.Builder builder) { if (state == Call.State.ACTIVE) { @@ -590,19 +607,19 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener { } private void addAcceptUpgradeRequestAction(Notification.Builder builder) { - Log.i(this, "Will show \"accept\" action in the incoming call Notification"); + Log.i(this, "Will show \"accept\" video action in the incoming call Notification"); PendingIntent acceptVideoPendingIntent = createNotificationPendingIntent( - mContext, InCallApp.ACTION_ANSWER_VOICE_INCOMING_CALL); + mContext, InCallApp.ACTION_ACCEPT_VIDEO_UPGRADE_REQUEST); builder.addAction(0, mContext.getText(R.string.notification_action_accept), - acceptVideoPendingIntent); + acceptVideoPendingIntent); } private void addDismissUpgradeRequestAction(Notification.Builder builder) { Log.i(this, "Will show \"dismiss\" action in the incoming call Notification"); PendingIntent declineVideoPendingIntent = createNotificationPendingIntent( - mContext, InCallApp.ACTION_ANSWER_VOICE_INCOMING_CALL); + mContext, InCallApp.ACTION_DECLINE_VIDEO_UPGRADE_REQUEST); builder.addAction(0, mContext.getText(R.string.notification_action_dismiss), declineVideoPendingIntent); } diff --git a/src/com/android/incallui/TelecomAdapter.java b/src/com/android/incallui/TelecomAdapter.java index a64efcdc..1f796a03 100644 --- a/src/com/android/incallui/TelecomAdapter.java +++ b/src/com/android/incallui/TelecomAdapter.java @@ -250,7 +250,7 @@ final class TelecomAdapter implements InCallPhoneListener { void phoneAccountSelected(String callId, PhoneAccountHandle accountHandle) { if (mPhone != null) { - getTelecommCallById(callId).phoneAccountSelected(accountHandle); + getTelecommCallById(callId).phoneAccountSelected(accountHandle, false); } else { Log.e(this, "error phoneAccountSelected, mAdapter is null"); } diff --git a/src/com/android/incallui/VideoCallFragment.java b/src/com/android/incallui/VideoCallFragment.java index 930e96ae..f7b2cd87 100644 --- a/src/com/android/incallui/VideoCallFragment.java +++ b/src/com/android/incallui/VideoCallFragment.java @@ -964,7 +964,7 @@ public class VideoCallFragment extends BaseFragment<VideoCallPresenter, * @param dataUsage the data usage value */ @Override - public void setCallDataUsage(Context context, long dataUsage) { + public void setCallDataUsage(Context context, int dataUsage) { Log.d(this, "setDataUsage: dataUsage = " + dataUsage); Toast.makeText(context, "dataUsage=" + dataUsage, Toast.LENGTH_LONG).show(); } diff --git a/src/com/android/incallui/VideoCallPresenter.java b/src/com/android/incallui/VideoCallPresenter.java index b12b8187..2935a2fc 100644 --- a/src/com/android/incallui/VideoCallPresenter.java +++ b/src/com/android/incallui/VideoCallPresenter.java @@ -19,7 +19,9 @@ package com.android.incallui; import android.content.Context; import android.content.res.Configuration; import android.graphics.Point; +import android.os.AsyncResult; import android.os.Handler; +import android.os.Message; import android.telecom.AudioState; import android.telecom.CameraCapabilities; import android.telecom.Connection; @@ -166,10 +168,29 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi */ private int mCurrentCallSubstate; - /** Handler which resets request state to NO_REQUEST after an interval. */ - private Handler mSessionModificationResetHandler; + VideoCallHandler mSessionModificationResetHandler; + + private class VideoCallHandler extends Handler { + @Override + public void handleMessage(Message msg) { + Log.d(this, "Message received: what = " + msg.what); + switch (msg.what) { + case EVENT_CLEAR_SESSION_MODIFY_REQUEST: + if (msg.obj != null && msg.obj instanceof Call) { + Call call = (Call) msg.obj; + Log.d(this, "Clearing sessionModificationState to NO_REQUEST"); + call.setSessionModificationState(Call.SessionModificationState.NO_REQUEST); + } + break; + default: + Log.e(this, "Unknown message = " + msg.what); + } + } + }; + private static final long SESSION_MODIFICATION_RESET_DELAY_MS = 3000; + private static final int EVENT_CLEAR_SESSION_MODIFY_REQUEST = 0; /** * Initializes the presenter. @@ -180,7 +201,7 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi mContext = Preconditions.checkNotNull(context); mMinimumVideoDimension = mContext.getResources().getDimension( R.dimen.video_preview_small_dimension); - mSessionModificationResetHandler = new Handler(); + mSessionModificationResetHandler = new VideoCallHandler(); } /** @@ -482,6 +503,8 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi Log.d(this, "onPrimaryCallChanged: isVideoCall=" + isVideoCall + " isVideoMode=" + isVideoMode); + updateAudioMode(false); + if (!isVideoCall && isVideoMode) { // Terminate video mode if new primary call is not a video call // and we are currently in video mode. @@ -937,7 +960,7 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi * @param dataUsage call data usage value */ @Override - public void onCallDataUsageChange(long dataUsage) { + public void onCallDataUsageChange(int dataUsage) { Log.d(this, "onCallDataUsageChange dataUsage=" + dataUsage); VideoCallUi ui = getUi(); if (ui == null) { @@ -969,6 +992,7 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi return; } + mSessionModificationResetHandler.removeMessages(EVENT_CLEAR_SESSION_MODIFY_REQUEST); call.setSessionModificationTo(videoState); } @@ -997,23 +1021,18 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi return; } + mSessionModificationResetHandler.removeMessages(EVENT_CLEAR_SESSION_MODIFY_REQUEST); if (status == VideoProvider.SESSION_MODIFY_REQUEST_TIMED_OUT) { call.setSessionModificationState( Call.SessionModificationState.UPGRADE_TO_VIDEO_REQUEST_TIMED_OUT); } else { call.setSessionModificationState(Call.SessionModificationState.REQUEST_FAILED); - final Call modifyCall = call; // Start handler to change state from REQUEST_FAILED to NO_REQUEST after an interval. - mSessionModificationResetHandler.postDelayed(new Runnable() { - @Override - public void run() { - if (modifyCall != null) { - modifyCall - .setSessionModificationState(Call.SessionModificationState.NO_REQUEST); - } - } - }, SESSION_MODIFICATION_RESET_DELAY_MS); + Message msg = mSessionModificationResetHandler.obtainMessage( + EVENT_CLEAR_SESSION_MODIFY_REQUEST, call); + mSessionModificationResetHandler.sendMessageDelayed(msg + , SESSION_MODIFICATION_RESET_DELAY_MS); } } @@ -1180,7 +1199,7 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi void setPreviewSize(int width, int height); void setPreviewSurfaceSize(int width, int height); void setDisplayVideoSize(int width, int height); - void setCallDataUsage(Context context, long dataUsage); + void setCallDataUsage(Context context, int dataUsage); void displayCallSessionEvent(int event); Point getScreenSize(); void cleanupSurfaces(); diff --git a/src/com/android/incallui/VideoPauseController.java b/src/com/android/incallui/VideoPauseController.java index 727780e8..5b2f0fc7 100644 --- a/src/com/android/incallui/VideoPauseController.java +++ b/src/com/android/incallui/VideoPauseController.java @@ -187,6 +187,10 @@ class VideoPauseController implements InCallStateListener, IncomingCallListener, // Bring UI to foreground if VoLTE call becomes active while UI is in // background. bringToForeground(); + } else if (CallUtils.isPendingModifyRequest(call) && mIsInBackground) { + // Bring UI to foreground if upgrade request is received while UI is in + // background. + bringToForeground(); } updatePrimaryCallContext(call); |