Merge "Revert sendEnvelope changes [DO NOT MERGE]" into lmp-preview-dev
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f08ce8b..993f98a 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1463,12 +1463,6 @@
     -->
     <string name="description_delete_button">backspace</string>
 
-    <!-- Content description of the speakerphone enabled notification icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_speakerphone_enabled">Speakerphone enabled.</string>
-
-    <!-- Content description of the call muted notification icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_call_muted">Call muted.</string>
-
     <!-- Description of the answer target in the Slide unlock screen of Phone. [CHAR LIMIT=NONE] -->
     <string name="description_target_answer">Answer</string>
     <!-- Description of the send_sms target in the Slide unlock screen of Phone. [CHAR LIMIT=NONE] -->
diff --git a/src/com/android/phone/CallNotifier.java b/src/com/android/phone/CallNotifier.java
index 7fca845..986c366 100644
--- a/src/com/android/phone/CallNotifier.java
+++ b/src/com/android/phone/CallNotifier.java
@@ -345,7 +345,8 @@
                 break;
 
             case CallStateMonitor.PHONE_RINGBACK_TONE:
-                onRingbackTone((AsyncResult) msg.obj);
+                // DISABLED. The Telecomm and new ConnectionService layers are now responsible.
+                // onRingbackTone((AsyncResult) msg.obj);
                 break;
 
             case CallStateMonitor.PHONE_RESEND_MUTE:
@@ -941,12 +942,7 @@
         // the Incoming Call
         Call ringingCall = mCM.getFirstActiveRingingCall();
         if (ringingCall.getPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
-            if (PhoneUtils.isRealIncomingCall(ringingCall.getState())) {
-                // Also we need to take off the "In Call" icon from the Notification
-                // area as the Out going Call never got connected
-                if (DBG) log("cancelCallInProgressNotifications()... (onDisconnect)");
-                mApplication.notificationMgr.cancelCallInProgressNotifications();
-            } else {
+            if (!PhoneUtils.isRealIncomingCall(ringingCall.getState())) {
                 if (DBG) log("stopRing()... (onDisconnect)");
                 mRinger.stopRing();
             }
@@ -1035,8 +1031,6 @@
             if (toneToPlay == InCallTonePlayer.TONE_NONE) {
                 resetAudioStateAfterDisconnect();
             }
-
-            mApplication.notificationMgr.cancelCallInProgressNotifications();
         }
 
         if (c != null) {
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index d8a91f2..7435747 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -104,8 +104,6 @@
     private NotificationManager mNotificationManager;
     private StatusBarManager mStatusBarManager;
     private Toast mToast;
-    private boolean mShowingSpeakerphoneIcon;
-    private boolean mShowingMuteIcon;
 
     public StatusBarHelper statusBarHelper;
 
@@ -589,119 +587,6 @@
         mNotificationManager.cancel(MISSED_CALL_NOTIFICATION);
     }
 
-    private void notifySpeakerphone() {
-        if (!mShowingSpeakerphoneIcon) {
-            mStatusBarManager.setIcon("speakerphone", android.R.drawable.stat_sys_speakerphone, 0,
-                    mContext.getString(R.string.accessibility_speakerphone_enabled));
-            mShowingSpeakerphoneIcon = true;
-        }
-    }
-
-    private void cancelSpeakerphone() {
-        if (mShowingSpeakerphoneIcon) {
-            mStatusBarManager.removeIcon("speakerphone");
-            mShowingSpeakerphoneIcon = false;
-        }
-    }
-
-    /**
-     * Shows or hides the "speakerphone" notification in the status bar,
-     * based on the actual current state of the speaker.
-     *
-     * If you already know the current speaker state (e.g. if you just
-     * called AudioManager.setSpeakerphoneOn() yourself) then you should
-     * directly call {@link #updateSpeakerNotification(boolean)} instead.
-     *
-     * (But note that the status bar icon is *never* shown while the in-call UI
-     * is active; it only appears if you bail out to some other activity.)
-     */
-    private void updateSpeakerNotification() {
-        AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-        boolean showNotification =
-                (mPhone.getState() == PhoneConstants.State.OFFHOOK) && audioManager.isSpeakerphoneOn();
-
-        if (DBG) log(showNotification
-                     ? "updateSpeakerNotification: speaker ON"
-                     : "updateSpeakerNotification: speaker OFF (or not offhook)");
-
-        updateSpeakerNotification(showNotification);
-    }
-
-    /**
-     * Shows or hides the "speakerphone" notification in the status bar.
-     *
-     * @param showNotification if true, call notifySpeakerphone();
-     *                         if false, call cancelSpeakerphone().
-     *
-     * Use {@link updateSpeakerNotification()} to update the status bar
-     * based on the actual current state of the speaker.
-     *
-     * (But note that the status bar icon is *never* shown while the in-call UI
-     * is active; it only appears if you bail out to some other activity.)
-     */
-    public void updateSpeakerNotification(boolean showNotification) {
-        if (DBG) log("updateSpeakerNotification(" + showNotification + ")...");
-
-        // Regardless of the value of the showNotification param, suppress
-        // the status bar icon if the the InCallScreen is the foreground
-        // activity, since the in-call UI already provides an onscreen
-        // indication of the speaker state.  (This reduces clutter in the
-        // status bar.)
-
-        if (showNotification) {
-            notifySpeakerphone();
-        } else {
-            cancelSpeakerphone();
-        }
-    }
-
-    private void notifyMute() {
-        if (!mShowingMuteIcon) {
-            mStatusBarManager.setIcon("mute", android.R.drawable.stat_notify_call_mute, 0,
-                    mContext.getString(R.string.accessibility_call_muted));
-            mShowingMuteIcon = true;
-        }
-    }
-
-    private void cancelMute() {
-        if (mShowingMuteIcon) {
-            mStatusBarManager.removeIcon("mute");
-            mShowingMuteIcon = false;
-        }
-    }
-
-    /**
-     * Shows or hides the "mute" notification in the status bar,
-     * based on the current mute state of the Phone.
-     *
-     * (But note that the status bar icon is *never* shown while the in-call UI
-     * is active; it only appears if you bail out to some other activity.)
-     */
-    void updateMuteNotification() {
-        // Suppress the status bar icon if the the InCallScreen is the
-        // foreground activity, since the in-call UI already provides an
-        // onscreen indication of the mute state.  (This reduces clutter
-        // in the status bar.)
-
-        if ((mCM.getState() == PhoneConstants.State.OFFHOOK) && PhoneUtils.getMute()) {
-            if (DBG) log("updateMuteNotification: MUTED");
-            notifyMute();
-        } else {
-            if (DBG) log("updateMuteNotification: not muted (or not offhook)");
-            cancelMute();
-        }
-    }
-
-    /**
-     * Completely take down the in-call notification *and* the mute/speaker
-     * notifications as well, to indicate that the phone is now idle.
-     */
-    /* package */ void cancelCallInProgressNotifications() {
-        if (DBG) log("cancelCallInProgressNotifications");
-        cancelMute();
-        cancelSpeakerphone();
-    }
-
     /**
      * Updates the message waiting indicator (voicemail) notification.
      *
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 08edc91..4d858ec 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -23,7 +23,6 @@
 import android.app.TaskStackBuilder;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.IBluetoothHeadsetPhone;
-import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -32,13 +31,9 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
-import android.content.res.Configuration;
 import android.media.AudioManager;
-import android.media.session.MediaSession;
-import android.media.session.MediaSessionManager;
 import android.net.Uri;
 import android.os.AsyncResult;
-import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IPowerManager;
@@ -53,10 +48,7 @@
 import android.preference.PreferenceManager;
 import android.provider.Settings.System;
 import android.telephony.ServiceState;
-import android.text.TextUtils;
 import android.util.Log;
-import android.util.Slog;
-import android.view.KeyEvent;
 
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallManager;
@@ -69,11 +61,9 @@
 import com.android.internal.telephony.TelephonyCapabilities;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.cdma.TtyIntent;
-import com.android.phone.common.CallLogAsync;
-import com.android.phone.OtaUtils.CdmaOtaScreenState;
 import com.android.phone.WiredHeadsetManager.WiredHeadsetListener;
+import com.android.phone.common.CallLogAsync;
 import com.android.server.sip.SipService;
-import com.android.services.telephony.common.AudioMode;
 
 /**
  * Global state for the telephony subsystem when running in the primary
@@ -216,12 +206,6 @@
     // Broadcast receiver for various intent broadcasts (see onCreate())
     private final BroadcastReceiver mReceiver = new PhoneAppBroadcastReceiver();
 
-    // Broadcast receiver purely for ACTION_MEDIA_BUTTON broadcasts
-    private final BroadcastReceiver mMediaButtonReceiver = new MediaButtonBroadcastReceiver();
-    private final SessionCallback mSessionCallback = new SessionCallback();
-
-    private MediaSession mSession;
-
     /** boolean indicating restoring mute state on InCallScreen.onResume() */
     private boolean mShouldRestoreMuteOnInCallResume;
 
@@ -534,24 +518,6 @@
             intentFilter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
             registerReceiver(mReceiver, intentFilter);
 
-            // Use a separate receiver for ACTION_MEDIA_BUTTON broadcasts,
-            // since we need to manually adjust its priority (to make sure
-            // we get these intents *before* the media player.)
-            IntentFilter mediaButtonIntentFilter =
-                    new IntentFilter(Intent.ACTION_MEDIA_BUTTON);
-            // TODO verify the independent priority doesn't need to be handled thanks to the
-            //  private intent handler registration
-            // Make sure we're higher priority than the media player's
-            // MediaButtonIntentReceiver (which currently has the default
-            // priority of zero; see apps/Music/AndroidManifest.xml.)
-            mediaButtonIntentFilter.setPriority(1);
-            //
-            registerReceiver(mMediaButtonReceiver, mediaButtonIntentFilter);
-            // register the component so it gets priority for calls
-            AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
-            am.registerMediaButtonEventReceiverForCalls(new ComponentName(this.getPackageName(),
-                    MediaButtonBroadcastReceiver.class.getName()));
-
             //set the default values for the preferences in the phone.
             PreferenceManager.setDefaultValues(this, R.xml.network_setting, false);
 
@@ -561,14 +527,6 @@
             // audio-mode-related state of our own) is initialized
             // correctly, given the current state of the phone.
             PhoneUtils.setAudioMode(mCM);
-
-            // Register a MediaSession but don't enable it yet. This is a
-            // replacement for MediaButtonReceiver
-            MediaSessionManager msm = (MediaSessionManager) getSystemService(Context.MEDIA_SESSION_SERVICE);
-            mSession = msm.createSession(LOG_TAG);
-            mSession.addCallback(mSessionCallback);
-            mSession.setFlags(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY
-                    | MediaSession.FLAG_HANDLES_MEDIA_BUTTONS);
         }
 
         if (TelephonyCapabilities.supportsOtasp(phone)) {
@@ -933,16 +891,10 @@
                 if (!mUpdateLock.isHeld()) {
                     mUpdateLock.acquire();
                 }
-                if (!mSession.isActive()) {
-                    mSession.setActive(true);
-                }
             } else {
                 if (mUpdateLock.isHeld()) {
                     mUpdateLock.release();
                 }
-                if (mSession.isActive()) {
-                    mSession.setActive(false);
-                }
             }
         }
     }
@@ -1101,55 +1053,6 @@
         }
     }
 
-    private class SessionCallback extends MediaSession.Callback {
-        @Override
-        public void onMediaButton(Intent intent) {
-            KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
-            if (VDBG) Log.d(LOG_TAG, "SessionCallback.onMediaButton()...  event = " + event);
-            if ((event != null) && (event.getKeyCode() == KeyEvent.KEYCODE_HEADSETHOOK)) {
-                if (VDBG) Log.d(LOG_TAG, "SessionCallback: HEADSETHOOK");
-                boolean consumed = PhoneUtils.handleHeadsetHook(phone, event);
-                if (VDBG) Log.d(LOG_TAG, "==> handleHeadsetHook(): consumed = " + consumed);
-            }
-        }
-    }
-
-    /**
-     * Broadcast receiver for the ACTION_MEDIA_BUTTON broadcast intent.
-     *
-     * This functionality isn't lumped in with the other intents in
-     * PhoneAppBroadcastReceiver because we instantiate this as a totally
-     * separate BroadcastReceiver instance, since we need to manually
-     * adjust its IntentFilter's priority (to make sure we get these
-     * intents *before* the media player.)
-     */
-    private class MediaButtonBroadcastReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
-            if (VDBG) Log.d(LOG_TAG,
-                           "MediaButtonBroadcastReceiver.onReceive()...  event = " + event);
-            if ((event != null)
-                && (event.getKeyCode() == KeyEvent.KEYCODE_HEADSETHOOK)) {
-                if (VDBG) Log.d(LOG_TAG, "MediaButtonBroadcastReceiver: HEADSETHOOK");
-                boolean consumed = PhoneUtils.handleHeadsetHook(phone, event);
-                if (VDBG) Log.d(LOG_TAG, "==> handleHeadsetHook(): consumed = " + consumed);
-                if (consumed) {
-                    abortBroadcast();
-                }
-            } else {
-                if (mCM.getState() != PhoneConstants.State.IDLE) {
-                    // If the phone is anything other than completely idle,
-                    // then we consume and ignore any media key events,
-                    // Otherwise it is too easy to accidentally start
-                    // playing music while a phone call is in progress.
-                    if (VDBG) Log.d(LOG_TAG, "MediaButtonBroadcastReceiver: consumed");
-                    abortBroadcast();
-                }
-            }
-        }
-    }
-
     /**
      * Accepts broadcast Intents which will be prepared by {@link NotificationMgr} and thus
      * sent from framework's notification mechanism (which is outside Phone context).
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 1a99d33..35b9a19 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -555,36 +555,6 @@
         mApp.startActivity(intent);
     }
 
-    private boolean showCallScreenInternal(boolean specifyInitialDialpadState,
-                                           boolean showDialpad) {
-        if (!PhoneGlobals.sVoiceCapable) {
-            // Never allow the InCallScreen to appear on data-only devices.
-            return false;
-        }
-        if (isIdle()) {
-            return false;
-        }
-        // If the phone isn't idle then go to the in-call screen
-        long callingId = Binder.clearCallingIdentity();
-
-        mCallHandlerService.bringToForeground(showDialpad);
-
-        Binder.restoreCallingIdentity(callingId);
-        return true;
-    }
-
-    // Show the in-call screen without specifying the initial dialpad state.
-    public boolean showCallScreen() {
-        return showCallScreenInternal(false, false);
-    }
-
-    // The variation of showCallScreen() that specifies the initial dialpad state.
-    // (Ideally this would be called showCallScreen() too, just with a different
-    // signature, but AIDL doesn't allow that.)
-    public boolean showCallScreenWithDialpad(boolean showDialpad) {
-        return showCallScreenInternal(true, showDialpad);
-    }
-
     /**
      * End a call based on call state
      * @return true is a call was ended
diff --git a/src/com/android/phone/PhoneUtils.java b/src/com/android/phone/PhoneUtils.java
index 68c7879..f79f057 100644
--- a/src/com/android/phone/PhoneUtils.java
+++ b/src/com/android/phone/PhoneUtils.java
@@ -1955,9 +1955,6 @@
             sIsSpeakerEnabled = flag;
         }
 
-        // Update the status bar icon
-        app.notificationMgr.updateSpeakerNotification(flag);
-
         // We also need to make a fresh call to PhoneApp.updateWakeState()
         // any time the speaker state changes, since the screen timeout is
         // sometimes different depending on whether or not the speaker is
@@ -2108,7 +2105,6 @@
             if (DBG) log("setMuteInternal: using phone.setMute(" + muted + ")...");
             phone.setMute(muted);
         }
-        app.notificationMgr.updateMuteNotification();
         app.getAudioRouter().onMuteChange(muted);
     }
 
diff --git a/src/com/android/services/telephony/PstnConnection.java b/src/com/android/services/telephony/PstnConnection.java
index 8157fca..6f2c07f 100644
--- a/src/com/android/services/telephony/PstnConnection.java
+++ b/src/com/android/services/telephony/PstnConnection.java
@@ -16,6 +16,12 @@
 
 package com.android.services.telephony;
 
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
+
+import android.telephony.DisconnectCause;
+
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.Connection;
@@ -26,11 +32,33 @@
  */
 public abstract class PstnConnection extends TelephonyConnection {
 
+    private static final int EVENT_RINGBACK_TONE = 1;
+
+    private final Handler mHandler = new Handler() {
+        private Connection getForegroundConnection() {
+            return mPhone.getForegroundCall().getEarliestConnection();
+        }
+
+        public void handleMessage(Message msg) {
+            // TODO: This code assumes that there is only one connection in the foreground call,
+            // in other words, it punts on network-mediated conference calling.
+            if (getOriginalConnection() != getForegroundConnection()) {
+                return;
+            }
+            switch (msg.what) {
+                case EVENT_RINGBACK_TONE:
+                    setRequestingRingback((Boolean) ((AsyncResult) msg.obj).result);
+                    break;
+            }
+        }
+    };
+
     private final Phone mPhone;
 
     public PstnConnection(Phone phone, Connection connection) {
         super(connection);
         mPhone = phone;
+        phone.registerForRingbackTone(mHandler, EVENT_RINGBACK_TONE, null);
     }
 
     /** {@inheritDoc} */
@@ -55,15 +83,18 @@
     protected void onReject() {
         Log.i(this, "Reject call.");
         if (isValidRingingCall(getOriginalConnection())) {
-            try {
-                mPhone.rejectCall();
-            } catch (CallStateException e) {
-                Log.e(this, e, "Failed to reject call.");
-            }
+            hangup(DisconnectCause.INCOMING_REJECTED);
         }
         super.onReject();
     }
 
+    /** {@inheritDoc} */
+    @Override
+    protected void onDisconnect() {
+        mPhone.unregisterForRingbackTone(mHandler);
+        super.onDisconnect();
+    }
+
     protected Phone getPhone() {
         return mPhone;
     }
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 5f2de83..0d84134 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -50,13 +50,13 @@
 
     @Override
     protected void onAbort() {
-        hangup();
+        hangup(DisconnectCause.LOCAL);
         super.onAbort();
     }
 
     @Override
     protected void onDisconnect() {
-        hangup();
+        hangup(DisconnectCause.LOCAL);
         super.onDisconnect();
     }
 
@@ -123,13 +123,16 @@
         super.onSetAudioState(audioState);
     }
 
-    private void hangup() {
+    protected void hangup(int disconnectCause) {
         if (mOriginalConnection != null) {
             try {
-                mOriginalConnection.hangup();
+                Call call = mOriginalConnection.getCall();
+                if (call != null) {
+                    call.hangup();
+                }
                 // Set state deliberately since we are going to close() and will no longer be
                 // listening to state updates from mOriginalConnection
-                setDisconnected(DisconnectCause.NORMAL, null);
+                setDisconnected(disconnectCause, null);
             } catch (CallStateException e) {
                 Log.e(this, e, "Call to Connection.hangup failed with exception");
             }