diff options
author | Sandeep Gutta <sangutta@codeaurora.org> | 2013-11-11 19:23:13 +0530 |
---|---|---|
committer | Sandeep Gutta <sangutta@codeaurora.org> | 2013-11-25 14:57:09 +0530 |
commit | d6e8ea435025aceadbf58ba78c4a2dd7fc745027 (patch) | |
tree | f33e72b81e5951dae3aa4a4679705b6892b4bed3 /src/com/android | |
parent | f053a386531bb464cd95e7069f2bd0c058792941 (diff) | |
download | android_packages_apps_InCallUI-d6e8ea435025aceadbf58ba78c4a2dd7fc745027.tar.gz android_packages_apps_InCallUI-d6e8ea435025aceadbf58ba78c4a2dd7fc745027.tar.bz2 android_packages_apps_InCallUI-d6e8ea435025aceadbf58ba78c4a2dd7fc745027.zip |
DSDA: Add InCallUI DSDA support.
-Add tab view support for DSDA
-Add support to display voice calls based on the
current active subscription.
-Add few utilities in CallList, which required for handling
voice calls across multiple subscription.
Change-Id: Ib683f7c3b41ed3bb04367be1e9c331908bc46004
Diffstat (limited to 'src/com/android')
-rw-r--r-- | src/com/android/incallui/CallButtonPresenter.java | 13 | ||||
-rw-r--r-- | src/com/android/incallui/CallCardFragment.java | 4 | ||||
-rw-r--r-- | src/com/android/incallui/CallHandlerService.java | 2 | ||||
-rw-r--r-- | src/com/android/incallui/CallList.java | 120 | ||||
-rw-r--r-- | src/com/android/incallui/InCallActivity.java | 33 | ||||
-rw-r--r-- | src/com/android/incallui/InCallPresenter.java | 24 | ||||
-rw-r--r-- | src/com/android/incallui/msim/MSimAnswerFragment.java | 325 | ||||
-rw-r--r-- | src/com/android/incallui/msim/MSimAnswerPresenter.java | 198 | ||||
-rw-r--r-- | src/com/android/incallui/msim/MSimInCallActivity.java | 232 |
9 files changed, 937 insertions, 14 deletions
diff --git a/src/com/android/incallui/CallButtonPresenter.java b/src/com/android/incallui/CallButtonPresenter.java index 1f0ee4d9..20049f76 100644 --- a/src/com/android/incallui/CallButtonPresenter.java +++ b/src/com/android/incallui/CallButtonPresenter.java @@ -35,7 +35,8 @@ import android.telephony.PhoneNumberUtils; * Logic for call buttons. */ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButtonUi> - implements InCallStateListener, AudioModeListener, IncomingCallListener { + implements InCallStateListener, AudioModeListener, IncomingCallListener, + CallList.ActiveSubChangeListener { private Call mCall; private boolean mAutomaticallyMuted = false; @@ -58,6 +59,7 @@ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButto // register for call state changes last InCallPresenter.getInstance().addListener(this); InCallPresenter.getInstance().addIncomingCallListener(this); + CallList.getInstance().addActiveSubChangeListener(this); } @Override @@ -67,6 +69,7 @@ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButto InCallPresenter.getInstance().removeListener(this); AudioModeProvider.getInstance().removeListener(this); InCallPresenter.getInstance().removeIncomingCallListener(this); + CallList.getInstance().removeActiveSubChangeListener(this); } @Override @@ -376,4 +379,12 @@ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButto void enableModifyCall(boolean enabled); void showModifyCall(boolean show); } + + @Override + public void onActiveSubChanged(int subscription) { + InCallState state = InCallPresenter.getInstance() + .getPotentialStateFromCallList(CallList.getInstance()); + + onStateChange(state, CallList.getInstance()); + } } diff --git a/src/com/android/incallui/CallCardFragment.java b/src/com/android/incallui/CallCardFragment.java index 077538a4..3fb7ff0c 100644 --- a/src/com/android/incallui/CallCardFragment.java +++ b/src/com/android/incallui/CallCardFragment.java @@ -227,7 +227,9 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr showInternetCallLabel(isSipCall); - if (MSimTelephonyManager.getDefault().isMultiSimEnabled()) { + if (MSimTelephonyManager.getDefault().isMultiSimEnabled() && + !(MSimTelephonyManager.getDefault().getMultiSimConfiguration() + == MSimTelephonyManager.MultiSimVariants.DSDA)) { String[] sub = {"SUB 1", "SUB 2", "SUB 3"}; int subscription = getPresenter().getActiveSubscription(); diff --git a/src/com/android/incallui/CallHandlerService.java b/src/com/android/incallui/CallHandlerService.java index a4825c6d..237e1234 100644 --- a/src/com/android/incallui/CallHandlerService.java +++ b/src/com/android/incallui/CallHandlerService.java @@ -51,7 +51,7 @@ public class CallHandlerService extends Service { private static final int ON_ACTIVE_SUB_CHANGE = 11; private static final int ON_UNSOL_CALLMODIFY = 12; - private static final int LARGEST_MSG_ID = ON_DESTROY; + private static final int LARGEST_MSG_ID = ON_ACTIVE_SUB_CHANGE; private CallList mCallList; diff --git a/src/com/android/incallui/CallList.java b/src/com/android/incallui/CallList.java index a6aef7e5..5decb9da 100644 --- a/src/com/android/incallui/CallList.java +++ b/src/com/android/incallui/CallList.java @@ -24,6 +24,8 @@ import com.google.common.base.Preconditions; import android.os.Handler; import android.os.Message; +import android.telephony.MSimTelephonyManager; +import com.android.internal.telephony.MSimConstants; import com.android.services.telephony.common.Call; import java.util.ArrayList; @@ -43,6 +45,7 @@ public class CallList { private static final int DISCONNECTED_CALL_LONG_TIMEOUT_MS = 5000; private static final int EVENT_DISCONNECTED_TIMEOUT = 1; + private static final int EVENT_NOTIFY_CHANGE = 2; private static CallList sInstance = new CallList(); @@ -54,6 +57,8 @@ public class CallList { .newHashMap(); private int mSubscription = 0; + private final ArrayList<ActiveSubChangeListener> mActiveSubChangeListeners = + Lists.newArrayList(); /** * Static singleton accessor method. @@ -74,6 +79,8 @@ public class CallList { public void onUpdate(Call call) { Log.d(this, "onUpdate - ", call); + updateActiveSuscription(); + updateCallInMap(call); notifyListenersOfChange(); } @@ -101,6 +108,8 @@ public class CallList { public void onIncoming(Call call, List<String> textMessages) { Log.d(this, "onIncoming - " + call); + updateActiveSuscription(); + updateCallInMap(call); updateCallTextMap(call, textMessages); @@ -115,6 +124,8 @@ public class CallList { public void onUpdate(List<Call> callsToUpdate) { Log.d(this, "onUpdate(...)"); + updateActiveSuscription(); + Preconditions.checkNotNull(callsToUpdate); for (Call call : callsToUpdate) { Log.d(this, "\t" + call); @@ -283,6 +294,11 @@ public class CallList { * TODO: Improve this logic to sort by call time. */ public Call getCallWithState(int state, int positionToFind) { + if (MSimTelephonyManager.getDefault().getMultiSimConfiguration() + == MSimTelephonyManager.MultiSimVariants.DSDA) { + return getCallWithState(state, positionToFind, getActiveSubscription()); + } + Call retval = null; int position = 0; for (Call call : mCallMap.values()) { @@ -435,6 +451,13 @@ public class CallList { Log.d(this, "EVENT_DISCONNECTED_TIMEOUT ", msg.obj); finishDisconnectedCall((Call) msg.obj); break; + case EVENT_NOTIFY_CHANGE: + Log.d(this, "EVENT_NOTIFY_CHANGE: "); + notifyListenersOfChange(); + for (ActiveSubChangeListener listener : mActiveSubChangeListeners) { + listener.onActiveSubChanged(getActiveSubscription()); + } + break; default: Log.wtf(this, "Message not expected: " + msg.what); break; @@ -480,12 +503,103 @@ public class CallList { * Called when active subscription changes. */ public void onActiveSubChanged(int activeSub) { - Log.d(this, "onActiveSubChanged: old = " + mSubscription + " new = " + activeSub); - - mSubscription = activeSub; + Log.d(this, "onActiveSubChanged = " + activeSub); + if (existsLiveCall(activeSub)) { + setActiveSubscription(activeSub); + } } public int getActiveSubscription() { return mSubscription; } + + /** + * Called to update the latest active subscription id, and also it + * notifies the registred clients about subscription change information. + */ + public void setActiveSubscription(int subscription) { + if (subscription != mSubscription) { + Log.i(this, "setActiveSubscription, old = " + mSubscription + " new = " + subscription); + mSubscription = subscription; + final Message msg = mHandler.obtainMessage(EVENT_NOTIFY_CHANGE, null); + mHandler.sendMessage(msg); + } + } + + /** + * Returns true, if any voice call in ACTIVE on the provided subscription. + */ + public boolean existsLiveCall(int subscription) { + for (Call call : mCallMap.values()) { + if (!isCallDead(call) && (call.getSubscription() == subscription)) { + return true; + } + } + return false; + } + + /** + * This method checks whether any other subscription currently has active voice + * call other than current active subscription, if yes it makes that other + * subscription as active subscription i.e user visible subscription. + */ + public boolean switchToOtherActiveSubscription() { + int activeSub = getActiveSubscription(); + boolean subSwitched = false; + + for (int i = 0; i < MSimTelephonyManager.getDefault().getPhoneCount(); i++) { + if ((i != activeSub) && existsLiveCall(i)) { + Log.i(this, "switchToOtherActiveSubscription, sub = " + i); + subSwitched = true; + setActiveSubscription(i); + break; + } + } + return subSwitched; + } + + /** + * Its a utility, gets the current active subscription from TeleService and + * updates the mSubscription member variable. + */ + public void updateActiveSuscription() { + if (!MSimTelephonyManager.getDefault().isMultiSimEnabled()) { + return; + } + setActiveSubscription(CallCommandClient.getInstance().getActiveSubscription()); + } + + /** + * Returns the [position]th call which belongs to provided subscription and + * found in the call map with the specified state. + */ + public Call getCallWithState(int state, int positionToFind, int subscription) { + Call retval = null; + int position = 0; + for (Call call : mCallMap.values()) { + if ((call.getState() == state) && (call.getSubscription() == subscription)) { + if (position >= positionToFind) { + retval = call; + break; + } else { + position++; + } + } + } + return retval; + } + + public void addActiveSubChangeListener(ActiveSubChangeListener listener) { + Preconditions.checkNotNull(listener); + mActiveSubChangeListeners.add(listener); + } + + public void removeActiveSubChangeListener(ActiveSubChangeListener listener) { + Preconditions.checkNotNull(listener); + mActiveSubChangeListeners.remove(listener); + } + + public interface ActiveSubChangeListener { + public void onActiveSubChanged(int subscription); + } } diff --git a/src/com/android/incallui/InCallActivity.java b/src/com/android/incallui/InCallActivity.java index 92343d3e..80692f32 100644 --- a/src/com/android/incallui/InCallActivity.java +++ b/src/com/android/incallui/InCallActivity.java @@ -36,6 +36,7 @@ import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; import android.os.Bundle; +import android.telephony.MSimTelephonyManager; import android.view.KeyEvent; import android.view.View; import android.view.Window; @@ -52,13 +53,13 @@ public class InCallActivity extends Activity { private static final int INVALID_RES_ID = -1; - private CallButtonFragment mCallButtonFragment; - private CallCardFragment mCallCardFragment; + protected CallButtonFragment mCallButtonFragment; + protected CallCardFragment mCallCardFragment; private AnswerFragment mAnswerFragment; - private DialpadFragment mDialpadFragment; - private ConferenceManagerFragment mConferenceManagerFragment; + protected DialpadFragment mDialpadFragment; + protected ConferenceManagerFragment mConferenceManagerFragment; private boolean mIsForegroundActivity; - private AlertDialog mDialog; + protected AlertDialog mDialog; private AlertDialog mModifyCallPromptDialog; /** Use to pass 'showDialpad' from {@link #onNewIntent} to {@link #onResume} */ @@ -70,6 +71,11 @@ public class InCallActivity extends Activity { super.onCreate(icicle); + if (MSimTelephonyManager.getDefault().getMultiSimConfiguration() + == MSimTelephonyManager.MultiSimVariants.DSDA) { + return; + } + // set this flag so this activity will stay in front of the keyguard // Have the WindowManager filter out touch events that are "too fat". getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED @@ -94,6 +100,11 @@ public class InCallActivity extends Activity { Log.d(this, "onStart()..."); super.onStart(); + if (MSimTelephonyManager.getDefault().getMultiSimConfiguration() + == MSimTelephonyManager.MultiSimVariants.DSDA) { + return; + } + // setting activity should be last thing in setup process InCallPresenter.getInstance().setActivity(this); } @@ -148,7 +159,7 @@ public class InCallActivity extends Activity { return mIsForegroundActivity; } - private boolean hasPendingErrorDialog() { + protected boolean hasPendingErrorDialog() { return mDialog != null; } /** @@ -168,6 +179,11 @@ public class InCallActivity extends Activity { */ @Override public void finish() { + if (MSimTelephonyManager.getDefault().getMultiSimConfiguration() + == MSimTelephonyManager.MultiSimVariants.DSDA) { + super.finish(); + return; + } Log.i(this, "finish(). Dialog showing: " + (mDialog != null)); // skip finish if we are still showing a dialog. @@ -347,7 +363,7 @@ public class InCallActivity extends Activity { } } - private void initializeInCall() { + protected void initializeInCall() { if (mCallButtonFragment == null) { mCallButtonFragment = (CallButtonFragment) getFragmentManager() .findFragmentById(R.id.callButtonFragment); @@ -661,4 +677,7 @@ public class InCallActivity extends Activity { Log.e(this, msg); } + public void updateDsdaTab() { + Log.e(this, "updateDsdaTab : Not supported "); + } } diff --git a/src/com/android/incallui/InCallPresenter.java b/src/com/android/incallui/InCallPresenter.java index 8ba186fa..d17e3e47 100644 --- a/src/com/android/incallui/InCallPresenter.java +++ b/src/com/android/incallui/InCallPresenter.java @@ -20,6 +20,8 @@ package com.android.incallui; +import android.telephony.MSimTelephonyManager; + import com.android.incallui.service.PhoneNumberService; import com.google.android.collect.Sets; import com.google.common.base.Preconditions; @@ -159,6 +161,11 @@ public class InCallPresenter implements CallList.Listener { final boolean doFinish = (mInCallActivity != null && isActivityStarted()); Log.i(this, "Hide in call UI: " + doFinish); + if ((mCallList != null) && !(mCallList.existsLiveCall(mCallList.getActiveSubscription())) + && mCallList.switchToOtherActiveSubscription()) { + return; + } + if (doFinish) { mInCallActivity.finish(); } @@ -329,6 +336,11 @@ public class InCallPresenter implements CallList.Listener { Log.d(this, "Notify " + listener + " of state " + mInCallState.toString()); listener.onStateChange(mInCallState, callList); } + + if (MSimTelephonyManager.getDefault().getMultiSimConfiguration() + == MSimTelephonyManager.MultiSimVariants.DSDA && (mInCallActivity != null)) { + mInCallActivity.updateDsdaTab(); + } } /** @@ -353,6 +365,11 @@ public class InCallPresenter implements CallList.Listener { for (IncomingCallListener listener : mIncomingCallListeners) { listener.onIncomingCall(mInCallState, call); } + + if (MSimTelephonyManager.getDefault().getMultiSimConfiguration() + == MSimTelephonyManager.MultiSimVariants.DSDA && (mInCallActivity != null)) { + mInCallActivity.updateDsdaTab(); + } } /** @@ -778,7 +795,12 @@ public class InCallPresenter implements CallList.Listener { intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | Intent.FLAG_ACTIVITY_NO_USER_ACTION); - intent.setClass(mContext, InCallActivity.class); + if (MSimTelephonyManager.getDefault().getMultiSimConfiguration() + == MSimTelephonyManager.MultiSimVariants.DSDA) { + intent.setClass(mContext, MSimInCallActivity.class); + } else { + intent.setClass(mContext, InCallActivity.class); + } if (showDialpad) { intent.putExtra(InCallActivity.SHOW_DIALPAD_EXTRA, true); } diff --git a/src/com/android/incallui/msim/MSimAnswerFragment.java b/src/com/android/incallui/msim/MSimAnswerFragment.java new file mode 100644 index 00000000..92ff5c2c --- /dev/null +++ b/src/com/android/incallui/msim/MSimAnswerFragment.java @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2013 The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * 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.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.os.Bundle; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ListView; + +import com.google.common.base.Preconditions; + +import java.util.ArrayList; + +/** + * + */ +public class MSimAnswerFragment extends BaseFragment<MSimAnswerPresenter, + MSimAnswerPresenter.AnswerUi> + implements GlowPadWrapper.AnswerListener, MSimAnswerPresenter.AnswerUi { + + /** + * The popup showing the list of canned responses. + * + * This is an AlertDialog containing a ListView showing the possible choices. This may be null + * if the InCallScreen hasn't ever called showRespondViaSmsPopup() yet, or if the popup was + * visible once but then got dismissed. + */ + private Dialog mCannedResponsePopup = null; + + /** + * The popup showing a text field for users to type in their custom message. + */ + private AlertDialog mCustomMessagePopup = null; + + private ArrayAdapter<String> mTextResponsesAdapter = null; + + private GlowPadWrapper mGlowpad; + + public MSimAnswerFragment() { + } + + @Override + public MSimAnswerPresenter createPresenter() { + return new MSimAnswerPresenter(); + } + + @Override + MSimAnswerPresenter.AnswerUi getUi() { + return this; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + mGlowpad = (GlowPadWrapper) inflater.inflate(R.layout.answer_fragment, + container, false); + + Log.d(this, "Creating view for answer fragment ", this); + Log.d(this, "Created from activity", getActivity()); + mGlowpad.setAnswerListener(this); + + return mGlowpad; + } + + @Override + public void onDestroyView() { + Log.d(this, "onDestroyView"); + if (mGlowpad != null) { + mGlowpad.stopPing(); + mGlowpad = null; + } + super.onDestroyView(); + } + + @Override + public void showAnswerUi(boolean show) { + getView().setVisibility(show ? View.VISIBLE : View.GONE); + + Log.d(this, "Show answer UI: " + show); + if (show) { + mGlowpad.startPing(); + } else { + mGlowpad.stopPing(); + } + } + + @Override + public void showTextButton(boolean show) { + final int targetResourceId = show + ? R.array.incoming_call_widget_3way_targets + : R.array.incoming_call_widget_2way_targets; + + if (targetResourceId != mGlowpad.getTargetResourceId()) { + if (show) { + // Answer, Decline, and Respond via SMS. + mGlowpad.setTargetResources(targetResourceId); + mGlowpad.setTargetDescriptionsResourceId( + R.array.incoming_call_widget_3way_target_descriptions); + mGlowpad.setDirectionDescriptionsResourceId( + R.array.incoming_call_widget_3way_direction_descriptions); + } else { + // Answer or Decline. + mGlowpad.setTargetResources(targetResourceId); + mGlowpad.setTargetDescriptionsResourceId( + R.array.incoming_call_widget_2way_target_descriptions); + mGlowpad.setDirectionDescriptionsResourceId( + R.array.incoming_call_widget_2way_direction_descriptions); + } + + mGlowpad.reset(false); + } + } + + @Override + public void showMessageDialog() { + final ListView lv = new ListView(getActivity()); + + Preconditions.checkNotNull(mTextResponsesAdapter); + lv.setAdapter(mTextResponsesAdapter); + lv.setOnItemClickListener(new RespondViaSmsItemClickListener()); + + final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()).setCancelable( + true).setView(lv); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialogInterface) { + if (mGlowpad != null) { + mGlowpad.startPing(); + } + } + }); + mCannedResponsePopup = builder.create(); + mCannedResponsePopup.show(); + } + + private boolean isCannedResponsePopupShowing() { + if (mCannedResponsePopup != null) { + return mCannedResponsePopup.isShowing(); + } + return false; + } + + private boolean isCustomMessagePopupShowing() { + if (mCustomMessagePopup != null) { + return mCustomMessagePopup.isShowing(); + } + return false; + } + + /** + * Dismiss the canned response list popup. + * + * This is safe to call even if the popup is already dismissed, and even if you never called + * showRespondViaSmsPopup() in the first place. + */ + private void dismissCannedResponsePopup() { + if (mCannedResponsePopup != null) { + mCannedResponsePopup.dismiss(); // safe even if already dismissed + mCannedResponsePopup = null; + } + } + + /** + * Dismiss the custom compose message popup. + */ + private void dismissCustomMessagePopup() { + if (mCustomMessagePopup != null) { + mCustomMessagePopup.dismiss(); + mCustomMessagePopup = null; + } + } + + public void dismissPendingDialogues() { + if (isCannedResponsePopupShowing()) { + dismissCannedResponsePopup(); + } + + if (isCustomMessagePopupShowing()) { + dismissCustomMessagePopup(); + } + } + + public boolean hasPendingDialogs() { + return !(mCannedResponsePopup == null && mCustomMessagePopup == null); + } + + /** + * Shows the custom message entry dialog. + */ + public void showCustomMessageDialog() { + // Create an alert dialog containing an EditText + final EditText et = new EditText(getActivity()); + final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()).setCancelable( + true).setView(et) + .setPositiveButton(R.string.custom_message_send, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + // The order is arranged in a way that the popup will be destroyed when the + // InCallActivity is about to finish. + final String textMessage = et.getText().toString().trim(); + dismissCustomMessagePopup(); + getPresenter().rejectCallWithMessage(textMessage); + } + }) + .setNegativeButton(R.string.custom_message_cancel, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dismissCustomMessagePopup(); + getPresenter().onDismissDialog(); + } + }) + .setTitle(R.string.respond_via_sms_custom_message); + mCustomMessagePopup = builder.create(); + + // Enable/disable the send button based on whether there is a message in the EditText + et.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + + @Override + public void afterTextChanged(Editable s) { + final Button sendButton = mCustomMessagePopup.getButton( + DialogInterface.BUTTON_POSITIVE); + sendButton.setEnabled(s != null && s.toString().trim().length() != 0); + } + }); + + // Keyboard up, show the dialog + mCustomMessagePopup.getWindow().setSoftInputMode( + WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); + mCustomMessagePopup.show(); + + // Send button starts out disabled + final Button sendButton = mCustomMessagePopup.getButton(DialogInterface.BUTTON_POSITIVE); + sendButton.setEnabled(false); + } + + @Override + public void configureMessageDialog(ArrayList<String> textResponses) { + final ArrayList<String> textResponsesForDisplay = new ArrayList<String>(textResponses); + + textResponsesForDisplay.add(getResources().getString( + R.string.respond_via_sms_custom_message)); + mTextResponsesAdapter = new ArrayAdapter<String>(getActivity(), + android.R.layout.simple_list_item_1, android.R.id.text1, textResponsesForDisplay); + } + + @Override + public void onAnswer(int callType) { + getPresenter().onAnswer(callType); + } + + @Override + public void onDecline() { + getPresenter().onDecline(); + } + + @Override + public void onText() { + getPresenter().onText(); + } + + /** + * OnItemClickListener for the "Respond via SMS" popup. + */ + public class RespondViaSmsItemClickListener implements AdapterView.OnItemClickListener { + + /** + * Handles the user selecting an item from the popup. + */ + @Override + public void onItemClick(AdapterView<?> parent, // The ListView + View view, // The TextView that was clicked + int position, long id) { + Log.d(this, "RespondViaSmsItemClickListener.onItemClick(" + position + ")..."); + final String message = (String) parent.getItemAtPosition(position); + Log.v(this, "- message: '" + message + "'"); + dismissCannedResponsePopup(); + + // The "Custom" choice is a special case. + // (For now, it's guaranteed to be the last item.) + if (position == (parent.getCount() - 1)) { + // Show the custom message dialog + showCustomMessageDialog(); + } else { + getPresenter().rejectCallWithMessage(message); + } + } + } +} diff --git a/src/com/android/incallui/msim/MSimAnswerPresenter.java b/src/com/android/incallui/msim/MSimAnswerPresenter.java new file mode 100644 index 00000000..375b05de --- /dev/null +++ b/src/com/android/incallui/msim/MSimAnswerPresenter.java @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2013 The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * 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.telephony.MSimTelephonyManager; +import com.android.services.telephony.common.Call; + +import java.util.ArrayList; + +/** + * Presenter for the Incoming call widget. + */ +public class MSimAnswerPresenter extends Presenter<MSimAnswerPresenter.AnswerUi> + implements CallList.CallUpdateListener, CallList.Listener, + CallList.ActiveSubChangeListener { + + private static final String TAG = MSimAnswerPresenter.class.getSimpleName(); + + private int mCallId[] = {Call.INVALID_CALL_ID, Call.INVALID_CALL_ID}; + private Call mCall[] = {null, null}; + + @Override + public void onUiReady(AnswerUi ui) { + super.onUiReady(ui); + + final CallList calls = CallList.getInstance(); + final Call call = calls.getIncomingCall(); + // TODO: change so that answer presenter never starts up if it's not incoming. + if (call != null) { + processIncomingCall(call); + } + + // Listen for incoming calls. + calls.addListener(this); + CallList.getInstance().addActiveSubChangeListener(this); + } + + @Override + public void onUiUnready(AnswerUi ui) { + super.onUiUnready(ui); + + int subscription = CallList.getInstance().getActiveSubscription(); + CallList.getInstance().removeListener(this); + + // This is necessary because the activity can be destroyed while an incoming call exists. + // This happens when back button is pressed while incoming call is still being shown. + if (mCallId[subscription] != Call.INVALID_CALL_ID) { + CallList.getInstance().removeCallUpdateListener(mCallId[subscription], this); + } + CallList.getInstance().removeActiveSubChangeListener(this); + } + + @Override + public void onCallListChange(CallList callList) { + // no-op + } + + @Override + public void onDisconnect(Call call) { + // no-op + } + + @Override + public void onIncomingCall(Call call) { + int subscription = call.getSubscription(); + // TODO: Ui is being destroyed when the fragment detaches. Need clean up step to stop + // getting updates here. + Log.d(this, "onIncomingCall: " + this); + if (getUi() != null) { + if (call.getCallId() != mCallId[subscription]) { + // A new call is coming in. + processIncomingCall(call); + } + } + } + + private void processIncomingCall(Call call) { + int subscription = call.getSubscription(); + mCallId[subscription] = call.getCallId(); + mCall[subscription] = call; + + // Listen for call updates for the current call. + CallList.getInstance().addCallUpdateListener(mCallId[subscription], this); + + Log.d(TAG, "Showing incoming for call id: " + mCallId[subscription] + " " + this); + final ArrayList<String> textMsgs = CallList.getInstance().getTextResponses( + call.getCallId()); + getUi().showAnswerUi(true); + + if (call.can(Call.Capabilities.RESPOND_VIA_TEXT) && textMsgs != null) { + getUi().showTextButton(true); + getUi().configureMessageDialog(textMsgs); + } else { + getUi().showTextButton(false); + } + } + + + @Override + public void onCallStateChanged(Call call) { + Log.d(this, "onCallStateChange() " + call + " " + this); + if (call.getState() != Call.State.INCOMING && call.getState() != Call.State.CALL_WAITING) { + int subscription = call.getSubscription(); + // Stop listening for updates. + CallList.getInstance().removeCallUpdateListener(mCallId[subscription], this); + + getUi().showAnswerUi(false); + + // 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[subscription] = Call.INVALID_CALL_ID; + } + } + + public void onAnswer(int callType) { + int subscription = CallList.getInstance().getActiveSubscription(); + if (mCallId[subscription] == Call.INVALID_CALL_ID) { + return; + } + + Log.d(this, "onAnswer " + mCallId[subscription]); + + CallCommandClient.getInstance().answerCall(mCallId[subscription]); + } + + public void onDecline() { + int subscription = CallList.getInstance().getActiveSubscription(); + Log.d(this, "onDecline " + mCallId[subscription]); + + CallCommandClient.getInstance().rejectCall(mCall[subscription], false, null); + } + + public void onText() { + if (getUi() != null) { + getUi().showMessageDialog(); + } + } + + public void rejectCallWithMessage(String message) { + int subscription = CallList.getInstance().getActiveSubscription(); + Log.d(this, "sendTextToDefaultActivity()..."); + + CallCommandClient.getInstance().rejectCall(mCall[subscription], true, message); + + onDismissDialog(); + } + + public void onDismissDialog() { + InCallPresenter.getInstance().onDismissDialog(); + } + + interface AnswerUi extends Ui { + public void showAnswerUi(boolean show); + public void showTextButton(boolean show); + public void showMessageDialog(); + public void configureMessageDialog(ArrayList<String> textResponses); + } + + @Override + public void onActiveSubChanged(int subscription) { + final CallList calls = CallList.getInstance(); + final Call call = calls.getIncomingCall(); + + if ((call != null) && (call.getCallId() == mCallId[subscription])) { + Log.i(TAG, "Show incoming for call id: " + mCallId[subscription] + " " + this); + final ArrayList<String> textMsgs = CallList.getInstance().getTextResponses( + call.getCallId()); + getUi().showAnswerUi(true); + + if (call.can(Call.Capabilities.RESPOND_VIA_TEXT) && textMsgs != null) { + getUi().showTextButton(true); + getUi().configureMessageDialog(textMsgs); + } else { + getUi().showTextButton(false); + } + } else if ((call == null) && (calls.existsLiveCall(subscription))) { + Log.i(TAG, "Hide incoming for call id: " + mCallId[subscription] + " " + this); + getUi().showAnswerUi(false); + } + } +} diff --git a/src/com/android/incallui/msim/MSimInCallActivity.java b/src/com/android/incallui/msim/MSimInCallActivity.java new file mode 100644 index 00000000..3f61a595 --- /dev/null +++ b/src/com/android/incallui/msim/MSimInCallActivity.java @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2013 The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2006 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.app.ActionBar; +import android.app.FragmentTransaction; +import android.app.ActionBar.Tab; +import android.content.res.TypedArray; +import android.os.Bundle; +import android.telephony.MSimTelephonyManager; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.ImageView; +import android.widget.TextView; + +/** + * Phone app "multisim in call" screen. + */ +public class MSimInCallActivity extends InCallActivity { + + private MSimAnswerFragment mAnswerFragment; + + private final int TAB_COUNT_ONE = 1; + private final int TAB_COUNT_TWO = 2; + private final int TAB_POSITION_FIRST = 0; + + private Tab[] mDsdaTab = new Tab[TAB_COUNT_TWO]; + private boolean[] mDsdaTabAdd = {false, false}; + + @Override + protected void onCreate(Bundle icicle) { + Log.d(this, "onCreate()... this = " + this); + + super.onCreate(icicle); + + // set this flag so this activity will stay in front of the keyguard + // Have the WindowManager filter out touch events that are "too fat". + getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED + | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON + | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD + | WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES); + + requestWindowFeature(Window.FEATURE_ACTION_BAR); + + getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); + getActionBar().setDisplayShowTitleEnabled(false); + getActionBar().setDisplayShowHomeEnabled(false); + + // Inflate everything in incall_screen.xml and add it to the screen. + setContentView(R.layout.incall_screen_msim); + + initializeInCall(); + + initializeDsdaSwitchTab(); + Log.d(this, "onCreate(): exit"); + } + + @Override + protected void onStart() { + Log.d(this, "onStart()..."); + super.onStart(); + + // setting activity should be last thing in setup process + InCallPresenter.getInstance().setActivity(this); + } + + @Override + public void finish() { + Log.i(this, "finish(). Dialog showing: " + (mDialog != null)); + + // skip finish if we are still showing a dialog. + if (!hasPendingErrorDialog() && !mAnswerFragment.hasPendingDialogs()) { + super.finish(); + } + } + + @Override + protected void initializeInCall() { + if (mCallButtonFragment == null) { + mCallButtonFragment = (CallButtonFragment) getFragmentManager() + .findFragmentById(R.id.callButtonFragment); + mCallButtonFragment.getView().setVisibility(View.INVISIBLE); + } + + if (mCallCardFragment == null) { + mCallCardFragment = (CallCardFragment) getFragmentManager() + .findFragmentById(R.id.callCardFragment); + } + + if (mAnswerFragment == null) { + mAnswerFragment = (MSimAnswerFragment) getFragmentManager() + .findFragmentById(R.id.answerFragment); + } + + if (mDialpadFragment == null) { + mDialpadFragment = (DialpadFragment) getFragmentManager() + .findFragmentById(R.id.dialpadFragment); + mDialpadFragment.getView().setVisibility(View.INVISIBLE); + } + + if (mConferenceManagerFragment == null) { + mConferenceManagerFragment = (ConferenceManagerFragment) getFragmentManager() + .findFragmentById(R.id.conferenceManagerFragment); + mConferenceManagerFragment.getView().setVisibility(View.INVISIBLE); + } + } + + @Override + public void dismissPendingDialogs() { + if (mDialog != null) { + mDialog.dismiss(); + mDialog = null; + } + mAnswerFragment.dismissPendingDialogues(); + } + + private void initializeDsdaSwitchTab() { + int phoneCount = MSimTelephonyManager.getDefault().getPhoneCount(); + ActionBar bar = getActionBar(); + View[] mDsdaTabLayout = new View[phoneCount]; + TypedArray icons = getResources().obtainTypedArray(R.array.sim_icons); + int[] subString = {R.string.sub_1, R.string.sub_2}; + + for (int i = 0; i < phoneCount; i++) { + mDsdaTabLayout[i] = getLayoutInflater() + .inflate(R.layout.msim_tab_sub_info, null); + + ((ImageView)mDsdaTabLayout[i].findViewById(R.id.tabSubIcon)) + .setBackground(icons.getDrawable(i)); + + ((TextView)mDsdaTabLayout[i].findViewById(R.id.tabSubText)) + .setText(subString[i]); + + mDsdaTab[i] = bar.newTab().setCustomView(mDsdaTabLayout[i]) + .setTabListener(new TabListener(i)); + } + } + + @Override + public void updateDsdaTab() { + int phoneCount = MSimTelephonyManager.getDefault().getPhoneCount(); + ActionBar bar = getActionBar(); + + for (int i = 0; i < phoneCount; i++) { + if (CallList.getInstance().existsLiveCall(i)) { + if (!mDsdaTabAdd[i]) { + addDsdaTab(i); + } + } else { + removeDsdaTab(i); + } + } + + updateDsdaTabSelection(); + } + + private void addDsdaTab(int subscription) { + ActionBar bar = getActionBar(); + int tabCount = bar.getTabCount(); + + if (tabCount < subscription) { + bar.addTab(mDsdaTab[subscription], false); + } else { + bar.addTab(mDsdaTab[subscription], subscription, false); + } + mDsdaTabAdd[subscription] = true; + } + + private void removeDsdaTab(int subscription) { + ActionBar bar = getActionBar(); + int tabCount = bar.getTabCount(); + + for (int i = 0; i < tabCount; i++) { + if (bar.getTabAt(i).equals(mDsdaTab[subscription])) { + bar.removeTab(mDsdaTab[subscription]); + mDsdaTabAdd[subscription] = false; + return; + } + } + } + + private void updateDsdaTabSelection() { + ActionBar bar = getActionBar(); + int barCount = bar.getTabCount(); + + if (barCount == TAB_COUNT_ONE) { + bar.selectTab(bar.getTabAt(TAB_POSITION_FIRST)); + } else if (barCount == TAB_COUNT_TWO) { + bar.selectTab(bar.getTabAt(CallList.getInstance().getActiveSubscription())); + } + } + + private class TabListener implements ActionBar.TabListener { + int mSubscription; + + public TabListener(int subId) { + mSubscription = subId; + } + + public void onTabSelected(Tab tab, FragmentTransaction ft) { + ActionBar bar = getActionBar(); + + if (CallList.getInstance().existsLiveCall(mSubscription)) { + CallCommandClient.getInstance().setActiveSubscription(mSubscription); + } + } + + public void onTabUnselected(Tab tab, FragmentTransaction ft) { + } + + public void onTabReselected(Tab tab, FragmentTransaction ft) { + } + } +} |