Merge "SystemUI: Use new USB notifications to detect USB disconnect." into gingerbread
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
index 7ccf210..0fc092e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
@@ -711,21 +711,20 @@
                 ConnectivityManager.EXTRA_NETWORK_INFO));
         int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0);
         Slog.d(TAG, "got CONNECTIVITY_ACTION - info=" + info + ", status = " + connectionStatus);
-        if (info.isConnected() == false) return;
+
+        int inetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
 
         switch (info.getType()) {
         case ConnectivityManager.TYPE_MOBILE:
-            if (info.isConnected()) {
-                updateDataNetType(info.getSubtype(), connectionStatus);
-                updateDataIcon();
-                updateSignalStrength(); // apply any change in connectionStatus
-            }
+            mInetCondition = inetCondition;
+            updateDataNetType(info.getSubtype());
+            updateDataIcon();
+            updateSignalStrength(); // apply any change in connectionStatus
             break;
         case ConnectivityManager.TYPE_WIFI:
+            mInetCondition = inetCondition;
             if (info.isConnected()) {
                 mIsWifiConnected = true;
-                mInetCondition =
-                        (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
                 int iconId;
                 if (mLastWifiSignalLevel == -1) {
                     iconId = sWifiSignalImages[mInetCondition][0];
@@ -738,7 +737,6 @@
             } else {
                 mLastWifiSignalLevel = -1;
                 mIsWifiConnected = false;
-                mInetCondition = 0;
                 int iconId = sWifiSignalImages[0][0];
 
                 mService.setIcon("wifi", iconId, 0);
@@ -777,9 +775,8 @@
         @Override
         public void onDataConnectionStateChanged(int state, int networkType) {
             mDataState = state;
-            updateDataNetType(networkType, 0);
+            updateDataNetType(networkType);
             updateDataIcon();
-            updateSignalStrength(); // apply the change in connection status
         }
 
         @Override
@@ -940,8 +937,7 @@
         return (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
     }
 
-    private final void updateDataNetType(int net, int inetCondition) {
-        mInetCondition = (inetCondition > INET_CONDITION_THRESHOLD ? 1 : 0);
+    private final void updateDataNetType(int net) {
         switch (net) {
         case TelephonyManager.NETWORK_TYPE_EDGE:
             mDataIconList = sDataNetType_e[mInetCondition];
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
index af736aa..b555277 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
@@ -82,7 +82,7 @@
 
 public class StatusBarService extends Service implements CommandQueue.Callbacks {
     static final String TAG = "StatusBarService";
-    static final boolean SPEW = false;
+    static final boolean SPEW = true;
 
     public static final String ACTION_STATUSBAR_START
             = "com.android.internal.policy.statusbar.START";
@@ -1534,4 +1534,3 @@
         }
     };
 }
-
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index c5505d1..f38748b 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -48,6 +48,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.GregorianCalendar;
 import java.util.List;
 
 /**
@@ -109,6 +110,10 @@
     private boolean mSystemReady;
     private Intent mInitialBroadcast;
 
+    // used in DBG mode to track inet condition reports
+    private static final int INET_CONDITION_LOG_MAX_SIZE = 15;
+    private ArrayList mInetLog;
+
     private static class NetworkAttributes {
         /**
          * Class for holding settings read from resources.
@@ -329,6 +334,9 @@
                                   mTethering.getTetherableWifiRegexs().length != 0) &&
                                  mTethering.getUpstreamIfaceRegexs().length != 0);
 
+        if (DBG) {
+            mInetLog = new ArrayList();
+        }
     }
 
 
@@ -912,11 +920,19 @@
             newNet = tryFailover(prevNetType);
             if (newNet != null) {
                 NetworkInfo switchTo = newNet.getNetworkInfo();
+                if (!switchTo.isConnected()) {
+                    // if the other net is connected they've already reset this and perhaps even gotten
+                    // a positive report we don't want to overwrite, but if not we need to clear this now
+                    // to turn our cellular sig strength white
+                    mDefaultInetConditionPublished = 0;
+                }
                 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
             } else {
+                mDefaultInetConditionPublished = 0; // we're not connected anymore
                 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
             }
         }
+        intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
         // do this before we broadcast the change
         handleConnectivityChange(prevNetType);
 
@@ -1075,12 +1091,20 @@
             newNet = tryFailover(info.getType());
             if (newNet != null) {
                 NetworkInfo switchTo = newNet.getNetworkInfo();
+                if (!switchTo.isConnected()) {
+                    // if the other net is connected they've already reset this and perhaps even gotten
+                    // a positive report we don't want to overwrite, but if not we need to clear this now
+                    // to turn our cellular sig strength white
+                    mDefaultInetConditionPublished = 0;
+                }
                 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
             } else {
+                mDefaultInetConditionPublished = 0;
                 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
             }
         }
 
+        intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
         sendStickyBroadcast(intent);
         /*
          * If the failover network is already connected, then immediately send
@@ -1365,6 +1389,14 @@
         pw.println();
 
         mTethering.dump(fd, pw, args);
+
+        if (mInetLog != null) {
+            pw.println();
+            pw.println("Inet condition reports:");
+            for(int i = 0; i < mInetLog.size(); i++) {
+                pw.println(mInetLog.get(i));
+            }
+        }
     }
 
     // must be stateless - things change under us.
@@ -1613,6 +1645,17 @@
                 android.Manifest.permission.STATUS_BAR,
                 "ConnectivityService");
 
+        if (DBG) {
+            int pid = getCallingPid();
+            int uid = getCallingUid();
+            String s = pid + "(" + uid + ") reports inet is " +
+                (percentage > 50 ? "connected" : "disconnected") + " (" + percentage + ") on " +
+                "network Type " + networkType + " at " + GregorianCalendar.getInstance().getTime();
+            mInetLog.add(s);
+            while(mInetLog.size() > INET_CONDITION_LOG_MAX_SIZE) {
+                mInetLog.remove(0);
+            }
+        }
         mHandler.sendMessage(mHandler.obtainMessage(
             NetworkStateTracker.EVENT_INET_CONDITION_CHANGE, networkType, percentage));
     }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 3172077..4f0d2d5 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -561,6 +561,11 @@
     BroadcastRecord mPendingBroadcast = null;
 
     /**
+     * The receiver index that is pending, to restart the broadcast if needed.
+     */
+    int mPendingBroadcastRecvIndex;
+
+    /**
      * Keeps track of all IIntentReceivers that have been registered for
      * broadcasts.  Hash keys are the receiver IBinder, hash value is
      * a ReceiverList.
@@ -747,6 +752,7 @@
     ComponentName mTopComponent;
     String mTopAction;
     String mTopData;
+    boolean mProcessesReady = false;
     boolean mSystemReady = false;
     boolean mBooting = false;
     boolean mWaitingUpdate = false;
@@ -964,7 +970,11 @@
                         return;
                     }
                     
-                    broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
+                    Intent intent = new Intent("android.intent.action.ANR");
+                    if (!mProcessesReady) {
+                        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                    }
+                    broadcastIntentLocked(null, null, intent,
                             null, null, 0, null, null, null,
                             false, false, MY_PID, Process.SYSTEM_UID);
 
@@ -1051,7 +1061,7 @@
                 // Only process broadcast timeouts if the system is ready. That way
                 // PRE_BOOT_COMPLETED broadcasts can't timeout as they are intended
                 // to do heavy lifting for system up
-                if (mSystemReady) {
+                if (mProcessesReady) {
                     broadcastTimeout();
                 }
             } break;
@@ -1717,10 +1727,12 @@
             if (!knownToBeDead || app.thread == null) {
                 // We already have the app running, or are waiting for it to
                 // come up (we have a pid but not yet its thread), so keep it.
+                if (DEBUG_PROCESSES) Slog.v(TAG, "App already running: " + app);
                 return app;
             } else {
                 // An application record is attached to a previous process,
                 // clean it up now.
+                if (DEBUG_PROCESSES) Slog.v(TAG, "App died: " + app);
                 handleAppDiedLocked(app, true);
             }
         }
@@ -1732,6 +1744,8 @@
             // If we are in the background, then check to see if this process
             // is bad.  If so, we will just silently fail.
             if (mBadProcesses.get(info.processName, info.uid) != null) {
+                if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
+                        + "/" + info.processName);
                 return null;
             }
         } else {
@@ -1739,6 +1753,8 @@
             // crash count so that we won't make it bad until they see at
             // least one crash dialog again, and make the process good again
             // if it had been bad.
+            if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
+                    + "/" + info.processName);
             mProcessCrashTimes.remove(info.processName, info.uid);
             if (mBadProcesses.get(info.processName, info.uid) != null) {
                 EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid,
@@ -1760,12 +1776,13 @@
 
         // If the system is not ready yet, then hold off on starting this
         // process until it is.
-        if (!mSystemReady
+        if (!mProcessesReady
                 && !isAllowedWhileBooting(info)
                 && !allowWhileBooting) {
             if (!mProcessesOnHold.contains(app)) {
                 mProcessesOnHold.add(app);
             }
+            if (DEBUG_PROCESSES) Slog.v(TAG, "System not ready, putting on hold: " + app);
             return app;
         }
 
@@ -1787,6 +1804,8 @@
             app.pid = 0;
         }
 
+        if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG,
+                "startProcessLocked removing on hold: " + app);
         mProcessesOnHold.remove(app);
 
         updateCpuStats();
@@ -3040,11 +3059,8 @@
                 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
                         Uri.fromParts("package", packageName, null));
                 intent.putExtra(Intent.EXTRA_UID, pkgUid);
-                synchronized (this) {
-                    broadcastIntentLocked(null, null, intent,
-                            null, null, 0, null, null, null,
-                            false, false, MY_PID, Process.SYSTEM_UID);
-                }
+                broadcastIntentInPackage("android", Process.SYSTEM_UID, intent,
+                        null, null, 0, null, null, null, false, false);
             } catch (RemoteException e) {
             }
         } finally {
@@ -3148,6 +3164,7 @@
 
     public void closeSystemDialogs(String reason) {
         Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
         if (reason != null) {
             intent.putExtra("reason", reason);
         }
@@ -3225,6 +3242,9 @@
         forceStopPackageLocked(packageName, uid, false, false, true);
         Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
                 Uri.fromParts("package", packageName, null));
+        if (!mProcessesReady) {
+            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+        }
         intent.putExtra(Intent.EXTRA_UID, uid);
         broadcastIntentLocked(null, null, intent,
                 null, null, 0, null, null, null,
@@ -3427,6 +3447,8 @@
             }
             if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
                 Slog.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
+                mPendingBroadcast.state = BroadcastRecord.IDLE;
+                mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
                 mPendingBroadcast = null;
                 scheduleBroadcastsLocked();
             }
@@ -3502,7 +3524,7 @@
 
         mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
 
-        boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
+        boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
         List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
 
         if (!normalMode) {
@@ -3561,6 +3583,8 @@
 
         // Remove this record from the list of starting applications.
         mPersistentStartingProcesses.remove(app);
+        if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG,
+                "Attach application locked removing on hold: " + app);
         mProcessesOnHold.remove(app);
 
         boolean badApp = false;
@@ -3702,7 +3726,9 @@
                 ArrayList<ProcessRecord> procs =
                     new ArrayList<ProcessRecord>(mProcessesOnHold);
                 for (int ip=0; ip<NP; ip++) {
-                    this.startProcessLocked(procs.get(ip), "on-hold", null);
+                    if (DEBUG_PROCESSES) Slog.v(TAG, "Starting process on hold: "
+                            + procs.get(ip));
+                    startProcessLocked(procs.get(ip), "on-hold", null);
                 }
             }
             
@@ -5253,7 +5279,7 @@
                     throw new SecurityException(msg);
                 }
 
-                if (!mSystemReady && !mDidUpdate && !mWaitingUpdate
+                if (!mProcessesReady && !mDidUpdate && !mWaitingUpdate
                         && !cpi.processName.equals("system")) {
                     // If this content provider does not run in the system
                     // process, and the system is not yet ready to run other
@@ -6040,6 +6066,11 @@
                     Slog.i(TAG, "Removing system update proc: " + proc);
                     removeProcessLocked(proc, true);
                 }
+
+                // Now that we have cleaned up any update processes, we
+                // are ready to start launching real processes and know that
+                // we won't trample on them any more.
+                mProcessesReady = true;
             }
         }
         
@@ -7283,8 +7314,9 @@
         if (dumpAll) {
             pw.println("  Total persistent processes: " + numPers);
             pw.println("  mStartRunning=" + mStartRunning
-                    + " mSystemReady=" + mSystemReady
-                    + " mBooting=" + mBooting
+                    + " mProcessesReady=" + mProcessesReady
+                    + " mSystemReady=" + mSystemReady);
+            pw.println("  mBooting=" + mBooting
                     + " mBooted=" + mBooted
                     + " mFactoryTest=" + mFactoryTest);
             pw.println("  mGoingToSleep=" + mMainStack.mGoingToSleep);
@@ -8098,6 +8130,8 @@
                 restart = true;
             }
         }
+        if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG,
+                "Clean-up removing on hold: " + app);
         mProcessesOnHold.remove(app);
 
         if (app == mHomeProcess) {
@@ -10118,7 +10152,7 @@
             }
             boolean replaced = false;
             if (replacePending) {
-                for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
+                for (int i=mOrderedBroadcasts.size()-1; i>0; i--) {
                     if (intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
                         if (DEBUG_BROADCAST) Slog.v(TAG,
                                 "***** DROPPING ORDERED: " + intent);
@@ -10137,35 +10171,41 @@
         return BROADCAST_SUCCESS;
     }
 
-    public final int broadcastIntent(IApplicationThread caller,
-            Intent intent, String resolvedType, IIntentReceiver resultTo,
-            int resultCode, String resultData, Bundle map,
-            String requiredPermission, boolean serialized, boolean sticky) {
+    final Intent verifyBroadcastLocked(Intent intent) {
         // Refuse possible leaked file descriptors
         if (intent != null && intent.hasFileDescriptors() == true) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
         }
 
+        int flags = intent.getFlags();
+
+        if (!mProcessesReady) {
+            // if the caller really truly claims to know what they're doing, go
+            // ahead and allow the broadcast without launching any receivers
+            if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
+                intent = new Intent(intent);
+                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+            } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
+                Slog.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
+                        + " before boot completion");
+                throw new IllegalStateException("Cannot broadcast before boot completed");
+            }
+        }
+
+        if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
+            throw new IllegalArgumentException(
+                    "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
+        }
+
+        return intent;
+    }
+
+    public final int broadcastIntent(IApplicationThread caller,
+            Intent intent, String resolvedType, IIntentReceiver resultTo,
+            int resultCode, String resultData, Bundle map,
+            String requiredPermission, boolean serialized, boolean sticky) {
         synchronized(this) {
-            int flags = intent.getFlags();
-            
-            if (!mSystemReady) {
-                // if the caller really truly claims to know what they're doing, go
-                // ahead and allow the broadcast without launching any receivers
-                if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
-                    intent = new Intent(intent);
-                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-                } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
-                    Slog.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
-                            + " before boot completion");
-                    throw new IllegalStateException("Cannot broadcast before boot completed");
-                }
-            }
-            
-            if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
-                throw new IllegalArgumentException(
-                        "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
-            }
+            intent = verifyBroadcastLocked(intent);
             
             final ProcessRecord callerApp = getRecordForAppLocked(caller);
             final int callingPid = Binder.getCallingPid();
@@ -10186,6 +10226,8 @@
             int resultCode, String resultData, Bundle map,
             String requiredPermission, boolean serialized, boolean sticky) {
         synchronized(this) {
+            intent = verifyBroadcastLocked(intent);
+
             final long origId = Binder.clearCallingIdentity();
             int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
                     resultTo, resultCode, resultData, map, requiredPermission,
@@ -10399,6 +10441,8 @@
 
     private final void processCurBroadcastLocked(BroadcastRecord r,
             ProcessRecord app) throws RemoteException {
+        if (DEBUG_BROADCAST)  Slog.v(TAG,
+                "Process cur broadcast " + r + " for app " + app);
         if (app.thread == null) {
             throw new RemoteException();
         }
@@ -10418,9 +10462,13 @@
             ensurePackageDexOpt(r.intent.getComponent().getPackageName());
             app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
                     r.resultCode, r.resultData, r.resultExtras, r.ordered);
+            if (DEBUG_BROADCAST)  Slog.v(TAG,
+                    "Process cur broadcast " + r + " DELIVERED for app " + app);
             started = true;
         } finally {
             if (!started) {
+                if (DEBUG_BROADCAST)  Slog.v(TAG,
+                        "Process cur broadcast " + r + ": NOT STARTED!");
                 r.receiver = null;
                 r.curApp = null;
                 app.curReceiver = null;
@@ -10585,6 +10633,8 @@
                 } else {
                     Slog.w(TAG, "pending app " + mPendingBroadcast.curApp
                             + " died before responding to broadcast");
+                    mPendingBroadcast.state = BroadcastRecord.IDLE;
+                    mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
                     mPendingBroadcast = null;
                 }
             }
@@ -10615,7 +10665,7 @@
                 // one time heavy lifting after system upgrades and can take
                 // significant amounts of time.
                 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
-                if (mSystemReady && r.dispatchTime > 0) {
+                if (mProcessesReady && r.dispatchTime > 0) {
                     long now = SystemClock.uptimeMillis();
                     if ((numReceivers > 0) &&
                             (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
@@ -10686,7 +10736,7 @@
                 if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast "
                         + r);
                 if (DEBUG_BROADCAST) Slog.v(TAG,
-                        "Submitting BROADCAST_TIMEOUT_MSG for "
+                        "Submitting BROADCAST_TIMEOUT_MSG for " + r + " at "
                         + (r.receiverTime + BROADCAST_TIMEOUT));
                 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
                 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
@@ -10754,10 +10804,15 @@
             }
             if (r.curApp != null && r.curApp.crashing) {
                 // If the target process is crashing, just skip it.
+                if (DEBUG_BROADCAST)  Slog.v(TAG,
+                        "Skipping deliver ordered " + r + " to " + r.curApp
+                        + ": process crashing");
                 skip = true;
             }
 
             if (skip) {
+                if (DEBUG_BROADCAST)  Slog.v(TAG,
+                        "Skipping delivery of ordered " + r + " for whatever reason");
                 r.receiver = null;
                 r.curFilter = null;
                 r.state = BroadcastRecord.IDLE;
@@ -10789,6 +10844,8 @@
             }
 
             // Not running -- get it started, to be executed when the app comes up.
+            if (DEBUG_BROADCAST)  Slog.v(TAG,
+                    "Need to start app " + targetProcess + " for broadcast " + r);
             if ((r.curApp=startProcessLocked(targetProcess,
                     info.activityInfo.applicationInfo, true,
                     r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
@@ -10810,6 +10867,7 @@
             }
 
             mPendingBroadcast = r;
+            mPendingBroadcastRecvIndex = recIdx;
         }
     }
 
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 4fc8020..a4497d6 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1104,26 +1104,30 @@
         // Okay we are now going to start a switch, to 'next'.  We may first
         // have to pause the current activity, but this is an important point
         // where we have decided to go to 'next' so keep track of that.
-        if (mLastStartedActivity != null && !mLastStartedActivity.finishing) {
-            long now = SystemClock.uptimeMillis();
-            final boolean inTime = mLastStartedActivity.startTime != 0
-                    && (mLastStartedActivity.startTime + START_WARN_TIME) >= now;
-            final int lastUid = mLastStartedActivity.info.applicationInfo.uid;
-            final int nextUid = next.info.applicationInfo.uid;
-            if (inTime && lastUid != nextUid
-                    && lastUid != next.launchedFromUid
-                    && mService.checkPermission(
-                            android.Manifest.permission.STOP_APP_SWITCHES,
-                            -1, next.launchedFromUid)
-                    != PackageManager.PERMISSION_GRANTED) {
-                mService.showLaunchWarningLocked(mLastStartedActivity, next);
+        // XXX "App Redirected" dialog is getting too many false positives
+        // at this point, so turn off for now.
+        if (false) {
+            if (mLastStartedActivity != null && !mLastStartedActivity.finishing) {
+                long now = SystemClock.uptimeMillis();
+                final boolean inTime = mLastStartedActivity.startTime != 0
+                        && (mLastStartedActivity.startTime + START_WARN_TIME) >= now;
+                final int lastUid = mLastStartedActivity.info.applicationInfo.uid;
+                final int nextUid = next.info.applicationInfo.uid;
+                if (inTime && lastUid != nextUid
+                        && lastUid != next.launchedFromUid
+                        && mService.checkPermission(
+                                android.Manifest.permission.STOP_APP_SWITCHES,
+                                -1, next.launchedFromUid)
+                        != PackageManager.PERMISSION_GRANTED) {
+                    mService.showLaunchWarningLocked(mLastStartedActivity, next);
+                } else {
+                    next.startTime = now;
+                    mLastStartedActivity = next;
+                }
             } else {
-                next.startTime = now;
+                next.startTime = SystemClock.uptimeMillis();
                 mLastStartedActivity = next;
             }
-        } else {
-            next.startTime = SystemClock.uptimeMillis();
-            mLastStartedActivity = next;
         }
         
         // We need to start pausing the current activity so the top one
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index 9f86378..23cb42a 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -238,9 +238,7 @@
         Phone.State s = Phone.State.IDLE;
 
         for (Phone phone : mPhones) {
-            if (phone.getState() == Phone.State.ANSWERING) {
-                return Phone.State.ANSWERING;
-            } else if (phone.getState() == Phone.State.RINGING) {
+            if (phone.getState() == Phone.State.RINGING) {
                 s = Phone.State.RINGING;
             } else if (phone.getState() == Phone.State.OFFHOOK) {
                 if (s == Phone.State.IDLE) s = Phone.State.OFFHOOK;
@@ -357,20 +355,6 @@
         return getFirstActiveRingingCall().getPhone();
     }
 
-    /**
-     * @return the first answering call
-     */
-    public Call getFirstAnsweringCall() {
-        for (Phone phone : mPhones) {
-            if (phone.getState() == Phone.State.ANSWERING) {
-                return phone.getForegroundCall();
-            }
-        }
-        return null;
-    }
-
-
-
     public void setAudioMode() {
         Context context = getContext();
         if (context == null) return;
@@ -1359,7 +1343,7 @@
      */
     public Call getFirstActiveBgCall() {
         for (Call call : mBackgroundCalls) {
-            if (!call.isIdle()) {
+            if (call.getState() != Call.State.IDLE) {
                 return call;
             }
         }
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 7464cc7..9afade3 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -55,12 +55,10 @@
      * <li>OFFHOOK = The phone is off hook. At least one call
      * exists that is dialing, active or holding and no calls are
      * ringing or waiting.</li>
-     * <li>ANSWERING = The incoming call is picked up but the
-     *  call is not established yet.</li>
      * </ul>
      */
     enum State {
-        IDLE, RINGING, OFFHOOK, ANSWERING;
+        IDLE, RINGING, OFFHOOK;
     };
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
index 0a87ddb..35aa3b3 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
@@ -143,23 +143,15 @@
             // in case the active/holding call disappeared and this
             // is no longer call waiting
 
-            if (ringingCall.getState() == Call.State.INCOMING) {
+            if ((ringingCall.getState() == Call.State.INCOMING) ||
+                    (ringingCall.getState() == Call.State.WAITING)) {
                 Log.v(LOG_TAG, "acceptCall");
                 // Always unmute when answering a new call
                 setMute(false);
-                // make ringingCall foreground
-                foregroundCall.switchWith(ringingCall);
-                foregroundCall.acceptCall();
-            } else if (ringingCall.getState() == Call.State.WAITING) {
-                setMute(false);
-                switchHoldingAndActive();
-                // make ringingCall foreground
-                foregroundCall.switchWith(ringingCall);
-                foregroundCall.acceptCall();
+                ringingCall.acceptCall();
             } else {
                 throw new CallStateException("phone not ringing");
             }
-            updatePhoneState();
         }
     }
 
@@ -482,8 +474,8 @@
         }
 
         void acceptCall() throws CallStateException {
-            if (this != foregroundCall) {
-                throw new CallStateException("acceptCall() in a non-fg call");
+            if (this != ringingCall) {
+                throw new CallStateException("acceptCall() in a non-ringing call");
             }
             if (connections.size() != 1) {
                 throw new CallStateException("acceptCall() in a conf call");
@@ -646,6 +638,18 @@
                     if (newState == Call.State.INCOMING) {
                         setState(mOwner.getState()); // INCOMING or WAITING
                     } else {
+                        if (mOwner == ringingCall) {
+                            if (ringingCall.getState() == Call.State.WAITING) {
+                                try {
+                                    switchHoldingAndActive();
+                                } catch (CallStateException e) {
+                                    // disconnect the call.
+                                    onCallEnded(DisconnectCause.LOCAL);
+                                    return;
+                                }
+                            }
+                            foregroundCall.switchWith(ringingCall);
+                        }
                         if (newState == Call.State.ACTIVE) call.startAudio();
                         setState(newState);
                     }
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
index 2efbd17..9098e6f 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
@@ -538,8 +538,6 @@
 
         if (getRingingCall().isRinging()) {
             state = State.RINGING;
-        } else if (getForegroundCall().isRinging()) {
-            state = State.ANSWERING;
         } else if (getForegroundCall().isIdle()
                 && getBackgroundCall().isIdle()) {
             state = State.IDLE;