Merge "Fix regressions in TTS completion callbacks." into ics-mr1
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index fe81d2b..395c28b 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -120,6 +120,12 @@
 
     dump_file("NETWORK ROUTES", "/proc/net/route");
     dump_file("NETWORK ROUTES IPV6", "/proc/net/ipv6_route");
+    run_command("IP RULES", 10, "ip", "rule", "show", NULL);
+    run_command("IP RULES v6", 10, "ip", "-6", "rule", "show", NULL);
+    run_command("ROUTE TABLE 60", 10, "ip", "route", "show", "table", "60", NULL);
+    run_command("ROUTE TABLE 61 v6", 10, "ip", "-6", "route", "show", "table", "60", NULL);
+    run_command("ROUTE TABLE 61", 10, "ip", "route", "show", "table", "61", NULL);
+    run_command("ROUTE TABLE 61 v6", 10, "ip", "-6", "route", "show", "table", "61", NULL);
     dump_file("ARP CACHE", "/proc/net/arp");
     run_command("IPTABLES", 10, "su", "root", "iptables", "-L", "-nvx", NULL);
     run_command("IP6TABLES", 10, "su", "root", "ip6tables", "-L", "-nvx", NULL);
diff --git a/core/res/res/values-sw600dp/dimens.xml b/core/res/res/values-sw600dp/dimens.xml
index 921bcf4..431a502 100644
--- a/core/res/res/values-sw600dp/dimens.xml
+++ b/core/res/res/values-sw600dp/dimens.xml
@@ -62,8 +62,8 @@
 
     <!-- Default padding to apply to AppWidgetHostViews containing widgets targeting API level 14 and up. -->
     <dimen name="default_app_widget_padding_left">12dp</dimen>
-    <dimen name="default_app_widget_padding_top">12dp</dimen>
-    <dimen name="default_app_widget_padding_right">4dp</dimen>
+    <dimen name="default_app_widget_padding_top">4dp</dimen>
+    <dimen name="default_app_widget_padding_right">12dp</dimen>
     <dimen name="default_app_widget_padding_bottom">20dp</dimen>
 
     <!-- Minimum width for an action button in the menu area of an action bar -->
diff --git a/docs/html/guide/topics/providers/calendar-provider.jd b/docs/html/guide/topics/providers/calendar-provider.jd
index 3ab5125..d30dda4 100644
--- a/docs/html/guide/topics/providers/calendar-provider.jd
+++ b/docs/html/guide/topics/providers/calendar-provider.jd
@@ -280,11 +280,9 @@
 {@link android.provider.CalendarContract.Calendars#ACCOUNT_TYPE Calendars.ACCOUNT_TYPE}
 in the selection. That is because a given account is
 only considered unique given both its <code>ACCOUNT_NAME</code> and its
-<code>ACCOUNT_TYPE</code>. The <code>ACCOUNT_TYPE</code> refers to the way that
-the account is being  synced. It is often but not always the domain. For
-example, an account could be  synced through a corporate pop3 sync adapter, in which
-case the <code>ACCOUNT_TYPE</code> would not be a domain. There is also a
-special type of account called {@link
+<code>ACCOUNT_TYPE</code>. The <code>ACCOUNT_TYPE</code> is the string corresponding to the
+account authenticator that was used when the account was registered with the
+{@link android.accounts.AccountManager}. There is also a special type of account called {@link
 android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} for calendars not
 associated with a device account. {@link
 android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} accounts do not get
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 780c0d2..aea31a8 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -89,6 +89,12 @@
 
 static const nsecs_t kSetParametersTimeout = seconds(2);
 
+// minimum sleep time for the mixer thread loop when tracks are active but in underrun
+static const uint32_t kMinThreadSleepTimeUs = 5000;
+// maximum divider applied to the active sleep time in the mixer thread loop
+static const uint32_t kMaxThreadSleepTimeShift = 2;
+
+
 // ----------------------------------------------------------------------------
 
 static bool recordingAllowed() {
@@ -1846,6 +1852,7 @@
     uint32_t activeSleepTime = activeSleepTimeUs();
     uint32_t idleSleepTime = idleSleepTimeUs();
     uint32_t sleepTime = idleSleepTime;
+    uint32_t sleepTimeShift = 0;
     Vector< sp<EffectChain> > effectChains;
 #ifdef DEBUG_CPU_USAGE
     ThreadCpuUsage cpu;
@@ -1937,6 +1944,7 @@
 
                     standbyTime = systemTime() + kStandbyTimeInNsecs;
                     sleepTime = idleSleepTime;
+                    sleepTimeShift = 0;
                     continue;
                 }
             }
@@ -1953,6 +1961,10 @@
             // mix buffers...
             mAudioMixer->process();
             sleepTime = 0;
+            // increase sleep time progressively when application underrun condition clears
+            if (sleepTimeShift > 0) {
+                sleepTimeShift--;
+            }
             standbyTime = systemTime() + kStandbyTimeInNsecs;
             //TODO: delay standby when effects have a tail
         } else {
@@ -1960,7 +1972,17 @@
             // buffer size, then write 0s to the output
             if (sleepTime == 0) {
                 if (mixerStatus == MIXER_TRACKS_ENABLED) {
-                    sleepTime = activeSleepTime;
+                    sleepTime = activeSleepTime >> sleepTimeShift;
+                    if (sleepTime < kMinThreadSleepTimeUs) {
+                        sleepTime = kMinThreadSleepTimeUs;
+                    }
+                    // reduce sleep time in case of consecutive application underruns to avoid
+                    // starving the audio HAL. As activeSleepTimeUs() is larger than a buffer
+                    // duration we would end up writing less data than needed by the audio HAL if
+                    // the condition persists.
+                    if (sleepTimeShift < kMaxThreadSleepTimeShift) {
+                        sleepTimeShift++;
+                    }
                 } else {
                     sleepTime = idleSleepTime;
                 }
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index da960ae..75e5366 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -856,13 +856,17 @@
 
         NetworkInterface internalNetworkInterface =
                 NetworkInterface.getByName(internalInterface);
-        Collection<InterfaceAddress>interfaceAddresses =
-                internalNetworkInterface.getInterfaceAddresses();
-        cmd += " " + interfaceAddresses.size();
-        for (InterfaceAddress ia : interfaceAddresses) {
-            InetAddress addr = NetworkUtils.getNetworkPart(ia.getAddress(),
-                    ia.getNetworkPrefixLength());
-            cmd = cmd + " " + addr.getHostAddress() + "/" + ia.getNetworkPrefixLength();
+        if (internalNetworkInterface == null) {
+            cmd += " 0";
+        } else {
+            Collection<InterfaceAddress>interfaceAddresses =
+                    internalNetworkInterface.getInterfaceAddresses();
+            cmd += " " + interfaceAddresses.size();
+            for (InterfaceAddress ia : interfaceAddresses) {
+                InetAddress addr = NetworkUtils.getNetworkPart(ia.getAddress(),
+                        ia.getNetworkPrefixLength());
+                cmd = cmd + " " + addr.getHostAddress() + "/" + ia.getNetworkPrefixLength();
+            }
         }
 
         mConnector.doCommand(cmd);
diff --git a/telephony/java/com/android/internal/telephony/DataCallState.java b/telephony/java/com/android/internal/telephony/DataCallState.java
index 6d8956f..efbf608 100644
--- a/telephony/java/com/android/internal/telephony/DataCallState.java
+++ b/telephony/java/com/android/internal/telephony/DataCallState.java
@@ -126,6 +126,8 @@
                 // set link addresses
                 if (addresses != null && addresses.length > 0) {
                     for (String addr : addresses) {
+                        addr = addr.trim();
+                        if (addr.isEmpty()) continue;
                         LinkAddress la;
                         int addrPrefixLen;
 
@@ -159,6 +161,8 @@
                 // set dns servers
                 if (dnses != null && dnses.length > 0) {
                     for (String addr : dnses) {
+                        addr = addr.trim();
+                        if (addr.isEmpty()) continue;
                         InetAddress ia;
                         try {
                             ia = NetworkUtils.numericToInetAddress(addr);
@@ -174,6 +178,8 @@
                     dnsServers[0] = SystemProperties.get(propertyPrefix + "dns1");
                     dnsServers[1] = SystemProperties.get(propertyPrefix + "dns2");
                     for (String dnsAddr : dnsServers) {
+                        dnsAddr = dnsAddr.trim();
+                        if (dnsAddr.isEmpty()) continue;
                         InetAddress ia;
                         try {
                             ia = NetworkUtils.numericToInetAddress(dnsAddr);
@@ -198,6 +204,8 @@
                     }
                 }
                 for (String addr : gateways) {
+                    addr = addr.trim();
+                    if (addr.isEmpty()) continue;
                     InetAddress ia;
                     try {
                         ia = NetworkUtils.numericToInetAddress(addr);
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 7cd01a1..de09dfb 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -1848,8 +1848,14 @@
             DataConnection dc = apnContext.getDataConnection();
 
             if (DBG) {
-                log(String.format("onDataSetupComplete: success apn=%s",
-                    apnContext.getWaitingApns().get(0).apn));
+                // TODO We may use apnContext.getApnSetting() directly
+                // instead of getWaitingApns().get(0)
+                String apnStr = "<unknown>";
+                if (apnContext.getWaitingApns() != null
+                        && !apnContext.getWaitingApns().isEmpty()){
+                    apnStr = apnContext.getWaitingApns().get(0).apn;
+                }
+                log("onDataSetupComplete: success apn=" + apnStr);
             }
             ApnSetting apn = apnContext.getApnSetting();
             if (apn.proxy != null && apn.proxy.length() != 0) {
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index aadcaad..3ed9bd5 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -123,6 +123,8 @@
     private final LruCache<String, ScanResult> mScanResultCache;
 
     private String mInterfaceName;
+    /* Tethering interface could be seperate from wlan interface */
+    private String mTetherInterfaceName;
 
     private int mLastSignalLevel = -1;
     private String mLastBssid;
@@ -156,6 +158,14 @@
     /* Tracks sequence number on stop failure message */
     private int mSupplicantStopFailureToken = 0;
 
+    /**
+     * Tether state change notification time out
+     */
+    private static final int TETHER_NOTIFICATION_TIME_OUT_MSECS = 5000;
+
+    /* Tracks sequence number on a tether notification time out */
+    private int mTetherToken = 0;
+
     private LinkProperties mLinkProperties;
 
     // Wakelock held during wifi start/stop and driver load/unload
@@ -240,10 +250,12 @@
     static final int CMD_REQUEST_AP_CONFIG                = BASE + 27;
     /* Response to access point configuration request */
     static final int CMD_RESPONSE_AP_CONFIG               = BASE + 28;
-    /* Set configuration on tether interface */
-    static final int CMD_TETHER_INTERFACE                 = BASE + 29;
+    /* Invoked when getting a tether state change notification */
+    static final int CMD_TETHER_STATE_CHANGE              = BASE + 29;
+    /* A delayed message sent to indicate tether state change failed to arrive */
+    static final int CMD_TETHER_NOTIFICATION_TIMED_OUT    = BASE + 30;
 
-    static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE   = BASE + 30;
+    static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE   = BASE + 31;
 
     /* Supplicant commands */
     /* Is supplicant alive ? */
@@ -455,12 +467,25 @@
     private State mSoftApStartingState = new SoftApStartingState();
     /* Soft ap is running */
     private State mSoftApStartedState = new SoftApStartedState();
+    /* Soft ap is running and we are waiting for tether notification */
+    private State mTetheringState = new TetheringState();
     /* Soft ap is running and we are tethered through connectivity service */
     private State mTetheredState = new TetheredState();
+    /* Waiting for untether confirmation to stop soft Ap */
+    private State mSoftApStoppingState = new SoftApStoppingState();
 
     /* Wait till p2p is disabled */
     private State mWaitForP2pDisableState = new WaitForP2pDisableState();
 
+    private class TetherStateChange {
+        ArrayList<String> available;
+        ArrayList<String> active;
+        TetherStateChange(ArrayList<String> av, ArrayList<String> ac) {
+            available = av;
+            active = ac;
+        }
+    }
+
 
     /**
      * One of  {@link WifiManager#WIFI_STATE_DISABLED},
@@ -562,7 +587,9 @@
                 public void onReceive(Context context, Intent intent) {
                     ArrayList<String> available = intent.getStringArrayListExtra(
                             ConnectivityManager.EXTRA_AVAILABLE_TETHER);
-                    sendMessage(CMD_TETHER_INTERFACE, available);
+                    ArrayList<String> active = intent.getStringArrayListExtra(
+                            ConnectivityManager.EXTRA_ACTIVE_TETHER);
+                    sendMessage(CMD_TETHER_STATE_CHANGE, new TetherStateChange(available, active));
                 }
             },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
 
@@ -603,7 +630,9 @@
             addState(mSupplicantStoppingState, mDefaultState);
             addState(mSoftApStartingState, mDefaultState);
             addState(mSoftApStartedState, mDefaultState);
+                addState(mTetheringState, mSoftApStartedState);
                 addState(mTetheredState, mSoftApStartedState);
+            addState(mSoftApStoppingState, mDefaultState);
             addState(mWaitForP2pDisableState, mDefaultState);
 
         setInitialState(mInitialState);
@@ -1139,6 +1168,7 @@
                         loge("Error tethering on " + intf);
                         return false;
                     }
+                    mTetherInterfaceName = intf;
                     return true;
                 }
             }
@@ -1165,11 +1195,27 @@
             loge("Error resetting interface " + mInterfaceName + ", :" + e);
         }
 
-        if (mCm.untether(mInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+        if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
             loge("Untether initiate failed!");
         }
     }
 
+    private boolean isWifiTethered(ArrayList<String> active) {
+
+        checkAndSetConnectivityInstance();
+
+        String[] wifiRegexs = mCm.getTetherableWifiRegexs();
+        for (String intf : active) {
+            for (String regex : wifiRegexs) {
+                if (intf.matches(regex)) {
+                    return true;
+                }
+            }
+        }
+        // We found no interfaces that are tethered
+        return false;
+    }
+
     /**
      * Set the country code from the system setting value, if any.
      */
@@ -1800,7 +1846,8 @@
                 case CMD_START_AP_SUCCESS:
                 case CMD_START_AP_FAILURE:
                 case CMD_STOP_AP:
-                case CMD_TETHER_INTERFACE:
+                case CMD_TETHER_STATE_CHANGE:
+                case CMD_TETHER_NOTIFICATION_TIMED_OUT:
                 case CMD_START_SCAN:
                 case CMD_DISCONNECT:
                 case CMD_RECONNECT:
@@ -3284,7 +3331,7 @@
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
                 case CMD_STOP_PACKET_FILTERING:
-                case CMD_TETHER_INTERFACE:
+                case CMD_TETHER_STATE_CHANGE:
                 case WifiP2pService.P2P_ENABLE_PENDING:
                     deferMessage(message);
                     break;
@@ -3326,7 +3373,8 @@
                 case CMD_STOP_AP:
                     if (DBG) log("Stopping Soft AP");
                     setWifiApState(WIFI_AP_STATE_DISABLING);
-                    stopTethering();
+
+                    /* We have not tethered at this point, so we just shutdown soft Ap */
                     try {
                         mNwService.stopAccessPoint(mInterfaceName);
                     } catch(Exception e) {
@@ -3342,10 +3390,10 @@
                    loge("Cannot start supplicant with a running soft AP");
                     setWifiState(WIFI_STATE_UNKNOWN);
                     break;
-                case CMD_TETHER_INTERFACE:
-                    ArrayList<String> available = (ArrayList<String>) message.obj;
-                    if (startTethering(available)) {
-                        transitionTo(mTetheredState);
+                case CMD_TETHER_STATE_CHANGE:
+                    TetherStateChange stateChange = (TetherStateChange) message.obj;
+                    if (startTethering(stateChange.available)) {
+                        transitionTo(mTetheringState);
                     }
                     break;
                 case WifiP2pService.P2P_ENABLE_PENDING:
@@ -3405,6 +3453,58 @@
         }
     }
 
+    class TetheringState extends State {
+        @Override
+        public void enter() {
+            if (DBG) log(getName() + "\n");
+            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+
+            /* Send ourselves a delayed message to shut down if tethering fails to notify */
+            sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT,
+                    ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS);
+        }
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) log(getName() + message.toString() + "\n");
+            switch(message.what) {
+                case CMD_TETHER_STATE_CHANGE:
+                    TetherStateChange stateChange = (TetherStateChange) message.obj;
+                    if (isWifiTethered(stateChange.active)) {
+                        transitionTo(mTetheredState);
+                    }
+                    return HANDLED;
+                case CMD_TETHER_NOTIFICATION_TIMED_OUT:
+                    if (message.arg1 == mTetherToken) {
+                        loge("Failed to get tether update, shutdown soft access point");
+                        setWifiApEnabled(null, false);
+                    }
+                    break;
+                case CMD_LOAD_DRIVER:
+                case CMD_UNLOAD_DRIVER:
+                case CMD_START_SUPPLICANT:
+                case CMD_STOP_SUPPLICANT:
+                case CMD_START_AP:
+                case CMD_STOP_AP:
+                case CMD_START_DRIVER:
+                case CMD_STOP_DRIVER:
+                case CMD_SET_SCAN_MODE:
+                case CMD_SET_SCAN_TYPE:
+                case CMD_SET_HIGH_PERF_MODE:
+                case CMD_SET_COUNTRY_CODE:
+                case CMD_SET_FREQUENCY_BAND:
+                case CMD_START_PACKET_FILTERING:
+                case CMD_STOP_PACKET_FILTERING:
+                case WifiP2pService.P2P_ENABLE_PENDING:
+                    deferMessage(message);
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+            return HANDLED;
+        }
+    }
+
     class TetheredState extends State {
         @Override
         public void enter() {
@@ -3415,13 +3515,89 @@
         public boolean processMessage(Message message) {
             if (DBG) log(getName() + message.toString() + "\n");
             switch(message.what) {
-               case CMD_TETHER_INTERFACE:
-                    // Ignore any duplicate interface available notifications
-                    // when in tethered state
+                case CMD_TETHER_STATE_CHANGE:
+                    TetherStateChange stateChange = (TetherStateChange) message.obj;
+                    if (!isWifiTethered(stateChange.active)) {
+                        loge("Tethering reports wifi as untethered!, shut down soft Ap");
+                        setWifiApEnabled(null, false);
+                    }
                     return HANDLED;
+                case CMD_STOP_AP:
+                    if (DBG) log("Untethering before stopping AP");
+                    setWifiApState(WIFI_AP_STATE_DISABLING);
+                    stopTethering();
+                    transitionTo(mSoftApStoppingState);
+                    break;
                 default:
                     return NOT_HANDLED;
             }
+            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+            return HANDLED;
+        }
+    }
+
+    class SoftApStoppingState extends State {
+        @Override
+        public void enter() {
+            if (DBG) log(getName() + "\n");
+            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+
+            /* Send ourselves a delayed message to shut down if tethering fails to notify */
+            sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT,
+                    ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS);
+
+        }
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) log(getName() + message.toString() + "\n");
+            switch(message.what) {
+                case CMD_TETHER_STATE_CHANGE:
+                    TetherStateChange stateChange = (TetherStateChange) message.obj;
+
+                    /* Wait till wifi is untethered */
+                    if (isWifiTethered(stateChange.active)) break;
+
+                    try {
+                        mNwService.stopAccessPoint(mInterfaceName);
+                    } catch(Exception e) {
+                        loge("Exception in stopAccessPoint()");
+                    }
+                    transitionTo(mDriverLoadedState);
+                    break;
+                case CMD_TETHER_NOTIFICATION_TIMED_OUT:
+                    if (message.arg1 == mTetherToken) {
+                        loge("Failed to get tether update, force stop access point");
+                        try {
+                            mNwService.stopAccessPoint(mInterfaceName);
+                        } catch(Exception e) {
+                            loge("Exception in stopAccessPoint()");
+                        }
+                        transitionTo(mDriverLoadedState);
+                    }
+                    break;
+                case CMD_LOAD_DRIVER:
+                case CMD_UNLOAD_DRIVER:
+                case CMD_START_SUPPLICANT:
+                case CMD_STOP_SUPPLICANT:
+                case CMD_START_AP:
+                case CMD_STOP_AP:
+                case CMD_START_DRIVER:
+                case CMD_STOP_DRIVER:
+                case CMD_SET_SCAN_MODE:
+                case CMD_SET_SCAN_TYPE:
+                case CMD_SET_HIGH_PERF_MODE:
+                case CMD_SET_COUNTRY_CODE:
+                case CMD_SET_FREQUENCY_BAND:
+                case CMD_START_PACKET_FILTERING:
+                case CMD_STOP_PACKET_FILTERING:
+                case WifiP2pService.P2P_ENABLE_PENDING:
+                    deferMessage(message);
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+            return HANDLED;
         }
     }