Merge "Fixing a race condition in RSSurfaceView. Bug 5601083 When destroy is called shortly after creation, RS tries to set a surface on a partially destroyed context." into ics-mr1
diff --git a/api/current.txt b/api/current.txt
index 7c4bae2..f33c6cb 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10696,6 +10696,7 @@
     field public static final int METADATA_KEY_GENRE = 6; // 0x6
     field public static final int METADATA_KEY_HAS_AUDIO = 16; // 0x10
     field public static final int METADATA_KEY_HAS_VIDEO = 17; // 0x11
+    field public static final int METADATA_KEY_LOCATION = 23; // 0x17
     field public static final int METADATA_KEY_MIMETYPE = 12; // 0xc
     field public static final int METADATA_KEY_NUM_TRACKS = 10; // 0xa
     field public static final int METADATA_KEY_TITLE = 7; // 0x7
@@ -18890,7 +18891,8 @@
     method public int playSilence(long, int, java.util.HashMap<java.lang.String, java.lang.String>);
     method public deprecated int setEngineByPackageName(java.lang.String);
     method public int setLanguage(java.util.Locale);
-    method public int setOnUtteranceCompletedListener(android.speech.tts.TextToSpeech.OnUtteranceCompletedListener);
+    method public deprecated int setOnUtteranceCompletedListener(android.speech.tts.TextToSpeech.OnUtteranceCompletedListener);
+    method public int setOnUtteranceProgressListener(android.speech.tts.UtteranceProgressListener);
     method public int setPitch(float);
     method public int setSpeechRate(float);
     method public void shutdown();
@@ -18963,6 +18965,13 @@
     method protected abstract void onSynthesizeText(android.speech.tts.SynthesisRequest, android.speech.tts.SynthesisCallback);
   }
 
+  public abstract class UtteranceProgressListener {
+    ctor public UtteranceProgressListener();
+    method public abstract void onDone(java.lang.String);
+    method public abstract void onError(java.lang.String);
+    method public abstract void onStart(java.lang.String);
+  }
+
 }
 
 package android.telephony {
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 522f477..0c6baeb 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -901,6 +901,7 @@
         private RuntimeException mUnbindLocation;
 
         private boolean mDied;
+        private boolean mForgotten;
 
         private static class ConnectionInfo {
             IBinder binder;
@@ -959,6 +960,7 @@
                     ci.binder.unlinkToDeath(ci.deathMonitor, 0);
                 }
                 mActiveConnections.clear();
+                mForgotten = true;
             }
         }
 
@@ -1020,6 +1022,11 @@
             ServiceDispatcher.ConnectionInfo info;
 
             synchronized (this) {
+                if (mForgotten) {
+                    // We unbound before receiving the connection; ignore
+                    // any connection received.
+                    return;
+                }
                 old = mActiveConnections.get(name);
                 if (old != null && old.binder == service) {
                     // Huh, already have this one.  Oh well!
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index f81ea81..91398bc 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -212,7 +212,11 @@
              */
             mHandler.sendEmptyMessage(MSG_CLEAR_WALLPAPER);
         }
-        
+
+        public Handler getHandler() {
+            return mHandler;
+        }
+
         public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault) {
             synchronized (this) {
                 if (mWallpaper != null) {
@@ -604,7 +608,7 @@
             // Ignore
         }
     }
-    
+
     /**
      * Set the position of the current wallpaper within any larger space, when
      * that wallpaper is visible behind the given window.  The X and Y offsets
@@ -619,16 +623,23 @@
      * @param yOffset The offset along the Y dimension, from 0 to 1.
      */
     public void setWallpaperOffsets(IBinder windowToken, float xOffset, float yOffset) {
-        try {
-            //Log.v(TAG, "Sending new wallpaper offsets from app...");
-            ViewRootImpl.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
-                    windowToken, xOffset, yOffset, mWallpaperXStep, mWallpaperYStep);
-            //Log.v(TAG, "...app returning after sending offsets!");
-        } catch (RemoteException e) {
-            // Ignore.
-        }
+        final IBinder fWindowToken = windowToken;
+        final float fXOffset = xOffset;
+        final float fYOffset = yOffset;
+        sGlobals.getHandler().post(new Runnable() {
+            public void run() {
+                try {
+                    //Log.v(TAG, "Sending new wallpaper offsets from app...");
+                    ViewRootImpl.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
+                            fWindowToken, fXOffset, fYOffset, mWallpaperXStep, mWallpaperYStep);
+                    //Log.v(TAG, "...app returning after sending offsets!");
+                } catch (RemoteException e) {
+                    // Ignore.
+                }
+            }
+        });
     }
-    
+
     /**
      * For applications that use multiple virtual screens showing a wallpaper,
      * specify the step size between virtual screens. For example, if the
diff --git a/core/java/android/bluetooth/BluetoothDeviceProfileState.java b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
index 7addd4a..b1d0070 100644
--- a/core/java/android/bluetooth/BluetoothDeviceProfileState.java
+++ b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
@@ -86,7 +86,7 @@
     private static final int CONNECTION_ACCESS_REQUEST_REPLY = 104;
     private static final int CONNECTION_ACCESS_REQUEST_EXPIRY = 105;
 
-    private static final int CONNECT_OTHER_PROFILES_DELAY = 4000; // 4 secs
+    public static final int CONNECT_OTHER_PROFILES_DELAY = 4000; // 4 secs
     private static final int CONNECTION_ACCESS_REQUEST_EXPIRY_TIMEOUT = 7000; // 7 secs
     private static final int CONNECTION_ACCESS_UNDEFINED = -1;
     private static final long INIT_INCOMING_REJECT_TIMER = 1000; // 1 sec
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index fefeb93..deea2b8 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -90,7 +90,7 @@
 
     boolean connectHeadset(String address);
     boolean disconnectHeadset(String address);
-    boolean notifyIncomingConnection(String address);
+    boolean notifyIncomingConnection(String address, boolean rejected);
 
     // HID profile APIs
     boolean connectInputDevice(in BluetoothDevice device);
diff --git a/core/java/android/content/res/XmlBlock.java b/core/java/android/content/res/XmlBlock.java
index ad1bfb2..bea6529 100644
--- a/core/java/android/content/res/XmlBlock.java
+++ b/core/java/android/content/res/XmlBlock.java
@@ -484,7 +484,7 @@
 
     private final AssetManager mAssets;
     private final int mNative;
-    private final StringBlock mStrings;
+    /*package*/ final StringBlock mStrings;
     private boolean mOpen = true;
     private int mOpenCount = 1;
 
@@ -494,9 +494,9 @@
     private static final native int nativeGetStringBlock(int obj);
 
     private static final native int nativeCreateParseState(int obj);
-    private static final native int nativeNext(int state);
+    /*package*/ static final native int nativeNext(int state);
     private static final native int nativeGetNamespace(int state);
-    private static final native int nativeGetName(int state);
+    /*package*/ static final native int nativeGetName(int state);
     private static final native int nativeGetText(int state);
     private static final native int nativeGetLineNumber(int state);
     private static final native int nativeGetAttributeCount(int state);
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 3605652..f6e627c 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -464,6 +464,19 @@
      * time, and that none of them have disappeared.
      */
     public NetworkStats subtract(NetworkStats value) throws NonMonotonicException {
+        return subtract(value, false);
+    }
+
+    /**
+     * Subtract the given {@link NetworkStats}, effectively leaving the delta
+     * between two snapshots in time. Assumes that statistics rows collect over
+     * time, and that none of them have disappeared.
+     *
+     * @param clampNonMonotonic When non-monotonic stats are found, just clamp
+     *            to 0 instead of throwing {@link NonMonotonicException}.
+     */
+    public NetworkStats subtract(NetworkStats value, boolean clampNonMonotonic)
+            throws NonMonotonicException {
         final long deltaRealtime = this.elapsedRealtime - value.elapsedRealtime;
         if (deltaRealtime < 0) {
             throw new NonMonotonicException(this, value);
@@ -497,7 +510,15 @@
 
                 if (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0
                         || entry.txPackets < 0 || entry.operations < 0) {
-                    throw new NonMonotonicException(this, i, value, j);
+                    if (clampNonMonotonic) {
+                        entry.rxBytes = Math.max(entry.rxBytes, 0);
+                        entry.rxPackets = Math.max(entry.rxPackets, 0);
+                        entry.txBytes = Math.max(entry.txBytes, 0);
+                        entry.txPackets = Math.max(entry.txPackets, 0);
+                        entry.operations = Math.max(entry.operations, 0);
+                    } else {
+                        throw new NonMonotonicException(this, i, value, j);
+                    }
                 }
             }
 
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 016af58..0b93ad0 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -32,7 +32,7 @@
 interface INfcAdapter
 {
     INfcTag getNfcTagInterface();
-    INfcAdapterExtras getNfcAdapterExtrasInterface();
+    INfcAdapterExtras getNfcAdapterExtrasInterface(in String pkg);
 
     int getState();
     boolean disable();
diff --git a/core/java/android/nfc/INfcAdapterExtras.aidl b/core/java/android/nfc/INfcAdapterExtras.aidl
index 0c2a2fd..2b9d4f0 100644
--- a/core/java/android/nfc/INfcAdapterExtras.aidl
+++ b/core/java/android/nfc/INfcAdapterExtras.aidl
@@ -23,10 +23,10 @@
  * {@hide}
  */
 interface INfcAdapterExtras {
-    Bundle open(IBinder b);
-    Bundle close();
-    Bundle transceive(in byte[] data_in);
-    int getCardEmulationRoute();
-    void setCardEmulationRoute(int route);
-    void authenticate(in byte[] token);
+    Bundle open(in String pkg, IBinder b);
+    Bundle close(in String pkg, IBinder b);
+    Bundle transceive(in String pkg, in byte[] data_in);
+    int getCardEmulationRoute(in String pkg);
+    void setCardEmulationRoute(in String pkg, int route);
+    void authenticate(in String pkg, in byte[] token);
 }
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index fe0106d..a9f1685 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -16,6 +16,8 @@
 
 package android.nfc;
 
+import java.util.HashMap;
+
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.app.Activity;
@@ -197,15 +199,21 @@
     static INfcTag sTagService;
 
     /**
-     * NfcAdapter is currently a singleton, and does not require a context.
-     * However all the public API's are future-proofed to require a context.
-     * If we start using that then we'll need to keep a HashMap of
-     * Context.getApplicationContext() -> NfcAdapter, such that NfcAdapter
-     * is a singleton within each application context.
+     * The NfcAdapter object for each application context.
+     * There is a 1-1 relationship between application context and
+     * NfcAdapter object.
      */
-    static NfcAdapter sSingleton;  // protected by NfcAdapter.class
+    static HashMap<Context, NfcAdapter> sNfcAdapters = new HashMap(); //guard by NfcAdapter.class
+
+    /**
+     * NfcAdapter used with a null context. This ctor was deprecated but we have
+     * to support it for backwards compatibility. New methods that require context
+     * might throw when called on the null-context NfcAdapter.
+     */
+    static NfcAdapter sNullContextNfcAdapter;  // protected by NfcAdapter.class
 
     final NfcActivityManager mNfcActivityManager;
+    final Context mContext;
 
     /**
      * A callback to be invoked when the system successfully delivers your {@link NdefMessage}
@@ -280,12 +288,12 @@
     }
 
     /**
-     * Returns the singleton, or throws if NFC is not available.
+     * Returns the NfcAdapter for application context,
+     * or throws if NFC is not available.
+     * @hide
      */
-    static synchronized NfcAdapter getSingleton() {
+    public static synchronized NfcAdapter getNfcAdapter(Context context) {
         if (!sIsInitialized) {
-            sIsInitialized = true;
-
             /* is this device meant to have NFC */
             if (!hasNfcFeature()) {
                 Log.v(TAG, "this device does not have NFC support");
@@ -303,12 +311,21 @@
                 Log.e(TAG, "could not retrieve NFC Tag service");
                 throw new UnsupportedOperationException();
             }
-            sSingleton = new NfcAdapter();
+
+            sIsInitialized = true;
         }
-        if (sSingleton == null) {
-            throw new UnsupportedOperationException();
+        if (context == null) {
+            if (sNullContextNfcAdapter == null) {
+                sNullContextNfcAdapter = new NfcAdapter(null);
+            }
+            return sNullContextNfcAdapter;
         }
-        return sSingleton;
+        NfcAdapter adapter = sNfcAdapters.get(context);
+        if (adapter == null) {
+            adapter = new NfcAdapter(context);
+            sNfcAdapters.put(context, adapter);
+        }
+        return adapter;
     }
 
     /** get handle to NFC service interface */
@@ -336,6 +353,10 @@
      * @return the default NFC adapter, or null if no NFC adapter exists
      */
     public static NfcAdapter getDefaultAdapter(Context context) {
+        if (context == null) {
+            throw new IllegalArgumentException("context cannot be null");
+        }
+        context = context.getApplicationContext();
         /* use getSystemService() instead of just instantiating to take
          * advantage of the context's cached NfcManager & NfcAdapter */
         NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE);
@@ -343,25 +364,30 @@
     }
 
     /**
-     * Get a handle to the default NFC Adapter on this Android device.
-     * <p>
-     * Most Android devices will only have one NFC Adapter (NFC Controller).
-     *
-     * @return the default NFC adapter, or null if no NFC adapter exists
+     * Legacy NfcAdapter getter, always use {@link #getDefaultAdapter(Context)} instead.<p>
+     * This method was deprecated at API level 10 (Gingerbread MR1) because a context is required
+     * for many NFC API methods. Those methods will fail when called on an NfcAdapter
+     * object created from this method.<p>
      * @deprecated use {@link #getDefaultAdapter(Context)}
      */
     @Deprecated
     public static NfcAdapter getDefaultAdapter() {
         Log.w(TAG, "WARNING: NfcAdapter.getDefaultAdapter() is deprecated, use " +
                 "NfcAdapter.getDefaultAdapter(Context) instead", new Exception());
-        return getSingleton();
+
+        return NfcAdapter.getNfcAdapter(null);
+    }
+
+    NfcAdapter(Context context) {
+        mContext = context;
+        mNfcActivityManager = new NfcActivityManager(this);
     }
 
     /**
-     * Does not currently need a context.
+     * @hide
      */
-    NfcAdapter() {
-        mNfcActivityManager = new NfcActivityManager(this);
+    public Context getContext() {
+        return mContext;
     }
 
     /**
@@ -875,8 +901,12 @@
      * @hide
      */
     public INfcAdapterExtras getNfcAdapterExtrasInterface() {
+        if (mContext == null) {
+            throw new UnsupportedOperationException("You need a context on NfcAdapter to use the "
+                    + " NFC extras APIs");
+        }
         try {
-            return sService.getNfcAdapterExtrasInterface();
+            return sService.getNfcAdapterExtrasInterface(mContext.getPackageName());
         } catch (RemoteException e) {
             attemptDeadServiceRecovery(e);
             return null;
diff --git a/core/java/android/nfc/NfcManager.java b/core/java/android/nfc/NfcManager.java
index 300ab45..6ec2e21 100644
--- a/core/java/android/nfc/NfcManager.java
+++ b/core/java/android/nfc/NfcManager.java
@@ -39,8 +39,9 @@
      */
     public NfcManager(Context context) {
         NfcAdapter adapter;
+        context = context.getApplicationContext();
         try {
-            adapter = NfcAdapter.getSingleton();
+            adapter = NfcAdapter.getNfcAdapter(context);
         } catch (UnsupportedOperationException e) {
             adapter = null;
         }
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 1b473ec..aa62cd7 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -784,11 +784,12 @@
                 // machine.  We don't handle AVCTP signals currently. We only send
                 // intents for AVDTP state changes. We need to handle both of them in
                 // some cases. For now, just don't move to incoming state in this case.
-                mBluetoothService.notifyIncomingA2dpConnection(address);
+                mBluetoothService.notifyIncomingA2dpConnection(address, true);
             } else {
                 Log.i(TAG, "" + authorized +
                       "Incoming A2DP / AVRCP connection from " + address);
                 mA2dp.allowIncomingConnect(device, authorized);
+                mBluetoothService.notifyIncomingA2dpConnection(address, false);
             }
         } else if (BluetoothUuid.isInputDevice(uuid)) {
             // We can have more than 1 input device connected.
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 9ca5847..d604a01 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -89,7 +89,7 @@
 
     private int mNativeData;
     private BluetoothEventLoop mEventLoop;
-    private BluetoothHeadset mBluetoothHeadset;
+    private BluetoothHeadset mHeadsetProxy;
     private BluetoothInputDevice mInputDevice;
     private BluetoothPan mPan;
     private boolean mIsAirplaneSensitive;
@@ -605,6 +605,7 @@
         }
         mBondState.initBondState();
         initProfileState();
+        getProfileProxy();
     }
 
     /**
@@ -1766,8 +1767,8 @@
 
     private void dumpHeadsetService(PrintWriter pw) {
         pw.println("\n--Headset Service--");
-        if (mBluetoothHeadset != null) {
-            List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices();
+        if (mHeadsetProxy != null) {
+            List<BluetoothDevice> deviceList = mHeadsetProxy.getConnectedDevices();
             if (deviceList.size() == 0) {
                 pw.println("No headsets connected");
             } else {
@@ -1775,21 +1776,20 @@
                 pw.println("\ngetConnectedDevices[0] = " + device);
                 dumpHeadsetConnectionState(pw, device);
                 pw.println("getBatteryUsageHint() = " +
-                             mBluetoothHeadset.getBatteryUsageHint(device));
+                             mHeadsetProxy.getBatteryUsageHint(device));
             }
 
             deviceList.clear();
-            deviceList = mBluetoothHeadset.getDevicesMatchingConnectionStates(new int[] {
+            deviceList = mHeadsetProxy.getDevicesMatchingConnectionStates(new int[] {
                      BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
             pw.println("--Connected and Disconnected Headsets");
             for (BluetoothDevice device: deviceList) {
                 pw.println(device);
-                if (mBluetoothHeadset.isAudioConnected(device)) {
+                if (mHeadsetProxy.isAudioConnected(device)) {
                     pw.println("SCO audio connected to device:" + device);
                 }
             }
         }
-        mAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
     }
 
     private void dumpInputDeviceProfile(PrintWriter pw) {
@@ -1824,7 +1824,6 @@
                 pw.println(device);
             }
         }
-        mAdapter.closeProfileProxy(BluetoothProfile.INPUT_DEVICE, mBluetoothHeadset);
     }
 
     private void dumpPanProfile(PrintWriter pw) {
@@ -1862,7 +1861,7 @@
 
     private void dumpHeadsetConnectionState(PrintWriter pw,
             BluetoothDevice device) {
-        switch (mBluetoothHeadset.getConnectionState(device)) {
+        switch (mHeadsetProxy.getConnectionState(device)) {
             case BluetoothHeadset.STATE_CONNECTING:
                 pw.println("getConnectionState() = STATE_CONNECTING");
                 break;
@@ -1884,7 +1883,6 @@
             Integer pid = mServiceRecordToPid.get(handle).first;
             pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle));
         }
-        mAdapter.closeProfileProxy(BluetoothProfile.PAN, mBluetoothHeadset);
     }
 
     private void dumpAclConnectedDevices(PrintWriter pw) {
@@ -1927,11 +1925,16 @@
         }
     }
 
+    private void getProfileProxy() {
+        mAdapter.getProfileProxy(mContext,
+                                 mBluetoothProfileServiceListener, BluetoothProfile.HEADSET);
+    }
+
     private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
         new BluetoothProfile.ServiceListener() {
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
             if (profile == BluetoothProfile.HEADSET) {
-                mBluetoothHeadset = (BluetoothHeadset) proxy;
+                mHeadsetProxy = (BluetoothHeadset) proxy;
             } else if (profile == BluetoothProfile.INPUT_DEVICE) {
                 mInputDevice = (BluetoothInputDevice) proxy;
             } else if (profile == BluetoothProfile.PAN) {
@@ -1940,7 +1943,7 @@
         }
         public void onServiceDisconnected(int profile) {
             if (profile == BluetoothProfile.HEADSET) {
-                mBluetoothHeadset = null;
+                mHeadsetProxy = null;
             } else if (profile == BluetoothProfile.INPUT_DEVICE) {
                 mInputDevice = null;
             } else if (profile == BluetoothProfile.PAN) {
@@ -2424,25 +2427,43 @@
         }
     }
 
-    public boolean notifyIncomingConnection(String address) {
-        BluetoothDeviceProfileState state =
-             mDeviceProfileState.get(address);
+    public boolean notifyIncomingConnection(String address, boolean rejected) {
+        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
         if (state != null) {
             Message msg = new Message();
-            msg.what = BluetoothDeviceProfileState.CONNECT_HFP_INCOMING;
-            state.sendMessage(msg);
+            if (rejected) {
+                if (mA2dpService.getPriority(getRemoteDevice(address)) >=
+                    BluetoothProfile.PRIORITY_ON) {
+                    msg.what = BluetoothDeviceProfileState.CONNECT_OTHER_PROFILES;
+                    msg.arg1 = BluetoothDeviceProfileState.CONNECT_A2DP_OUTGOING;
+                    state.sendMessageDelayed(msg,
+                        BluetoothDeviceProfileState.CONNECT_OTHER_PROFILES_DELAY);
+                }
+            } else {
+                msg.what = BluetoothDeviceProfileState.CONNECT_HFP_INCOMING;
+                state.sendMessage(msg);
+            }
             return true;
         }
         return false;
     }
 
-    /*package*/ boolean notifyIncomingA2dpConnection(String address) {
-       BluetoothDeviceProfileState state =
-            mDeviceProfileState.get(address);
+    /*package*/ boolean notifyIncomingA2dpConnection(String address, boolean rejected) {
+       BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
        if (state != null) {
            Message msg = new Message();
-           msg.what = BluetoothDeviceProfileState.CONNECT_A2DP_INCOMING;
-           state.sendMessage(msg);
+           if (rejected) {
+               if (mHeadsetProxy.getPriority(getRemoteDevice(address)) >=
+                   BluetoothProfile.PRIORITY_ON) {
+                   msg.what = BluetoothDeviceProfileState.CONNECT_OTHER_PROFILES;
+                   msg.arg1 = BluetoothDeviceProfileState.CONNECT_HFP_OUTGOING;
+                   state.sendMessageDelayed(msg,
+                             BluetoothDeviceProfileState.CONNECT_OTHER_PROFILES_DELAY);
+               }
+           } else {
+               msg.what = BluetoothDeviceProfileState.CONNECT_A2DP_INCOMING;
+               state.sendMessage(msg);
+           }
            return true;
        }
        return false;
diff --git a/core/java/android/speech/tts/AudioMessageParams.java b/core/java/android/speech/tts/AudioMessageParams.java
index 68d8738..29b4367 100644
--- a/core/java/android/speech/tts/AudioMessageParams.java
+++ b/core/java/android/speech/tts/AudioMessageParams.java
@@ -15,12 +15,12 @@
  */
 package android.speech.tts;
 
-import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
+import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
 
 class AudioMessageParams extends MessageParams {
     private final BlockingMediaPlayer mPlayer;
 
-    AudioMessageParams(UtteranceCompletedDispatcher dispatcher,
+    AudioMessageParams(UtteranceProgressDispatcher dispatcher,
             String callingApp, BlockingMediaPlayer player) {
         super(dispatcher, callingApp);
         mPlayer = player;
diff --git a/core/java/android/speech/tts/AudioPlaybackHandler.java b/core/java/android/speech/tts/AudioPlaybackHandler.java
index d970ae6..0194240 100644
--- a/core/java/android/speech/tts/AudioPlaybackHandler.java
+++ b/core/java/android/speech/tts/AudioPlaybackHandler.java
@@ -312,10 +312,11 @@
     private void handleSilence(MessageParams msg) {
         if (DBG) Log.d(TAG, "handleSilence()");
         SilenceMessageParams params = (SilenceMessageParams) msg;
+        params.getDispatcher().dispatchOnStart();
         if (params.getSilenceDurationMs() > 0) {
             params.getConditionVariable().block(params.getSilenceDurationMs());
         }
-        params.getDispatcher().dispatchUtteranceCompleted();
+        params.getDispatcher().dispatchOnDone();
         if (DBG) Log.d(TAG, "handleSilence() done.");
     }
 
@@ -323,11 +324,12 @@
     private void handleAudio(MessageParams msg) {
         if (DBG) Log.d(TAG, "handleAudio()");
         AudioMessageParams params = (AudioMessageParams) msg;
+        params.getDispatcher().dispatchOnStart();
         // Note that the BlockingMediaPlayer spawns a separate thread.
         //
         // TODO: This can be avoided.
         params.getPlayer().startAndWait();
-        params.getDispatcher().dispatchUtteranceCompleted();
+        params.getDispatcher().dispatchOnDone();
         if (DBG) Log.d(TAG, "handleAudio() done.");
     }
 
@@ -361,6 +363,7 @@
         if (DBG) Log.d(TAG, "Created audio track [" + audioTrack.hashCode() + "]");
 
         param.setAudioTrack(audioTrack);
+        msg.getDispatcher().dispatchOnStart();
     }
 
     // More data available to be flushed to the audio track.
@@ -411,6 +414,7 @@
         final AudioTrack audioTrack = params.getAudioTrack();
 
         if (audioTrack == null) {
+            params.getDispatcher().dispatchOnError();
             return;
         }
 
@@ -439,7 +443,7 @@
             audioTrack.release();
             params.setAudioTrack(null);
         }
-        params.getDispatcher().dispatchUtteranceCompleted();
+        params.getDispatcher().dispatchOnDone();
         mLastSynthesisRequest = null;
         params.mLogger.onWriteData();
     }
diff --git a/core/java/android/speech/tts/ITextToSpeechCallback.aidl b/core/java/android/speech/tts/ITextToSpeechCallback.aidl
index 40902ae..f0287d4 100755
--- a/core/java/android/speech/tts/ITextToSpeechCallback.aidl
+++ b/core/java/android/speech/tts/ITextToSpeechCallback.aidl
@@ -21,5 +21,7 @@
  * {@hide}
  */
 oneway interface ITextToSpeechCallback {
-    void utteranceCompleted(String utteranceId);
+    void onStart(String utteranceId);
+    void onDone(String utteranceId);
+    void onError(String utteranceId);
 }
diff --git a/core/java/android/speech/tts/MessageParams.java b/core/java/android/speech/tts/MessageParams.java
index e7d6da3..de9cc07 100644
--- a/core/java/android/speech/tts/MessageParams.java
+++ b/core/java/android/speech/tts/MessageParams.java
@@ -15,22 +15,22 @@
  */
 package android.speech.tts;
 
-import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
+import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
 
 abstract class MessageParams {
     static final int TYPE_SYNTHESIS = 1;
     static final int TYPE_AUDIO = 2;
     static final int TYPE_SILENCE = 3;
 
-    private final UtteranceCompletedDispatcher mDispatcher;
+    private final UtteranceProgressDispatcher mDispatcher;
     private final String mCallingApp;
 
-    MessageParams(UtteranceCompletedDispatcher dispatcher, String callingApp) {
+    MessageParams(UtteranceProgressDispatcher dispatcher, String callingApp) {
         mDispatcher = dispatcher;
         mCallingApp = callingApp;
     }
 
-    UtteranceCompletedDispatcher getDispatcher() {
+    UtteranceProgressDispatcher getDispatcher() {
         return mDispatcher;
     }
 
diff --git a/core/java/android/speech/tts/PlaybackSynthesisCallback.java b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
index 0cca06ac..ce3522b 100644
--- a/core/java/android/speech/tts/PlaybackSynthesisCallback.java
+++ b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
@@ -15,7 +15,7 @@
  */
 package android.speech.tts;
 
-import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
+import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
 import android.util.Log;
 
 /**
@@ -62,12 +62,12 @@
 
     private volatile boolean mDone = false;
 
-    private final UtteranceCompletedDispatcher mDispatcher;
+    private final UtteranceProgressDispatcher mDispatcher;
     private final String mCallingApp;
     private final EventLogger mLogger;
 
     PlaybackSynthesisCallback(int streamType, float volume, float pan,
-            AudioPlaybackHandler audioTrackHandler, UtteranceCompletedDispatcher dispatcher,
+            AudioPlaybackHandler audioTrackHandler, UtteranceProgressDispatcher dispatcher,
             String callingApp, EventLogger logger) {
         mStreamType = streamType;
         mVolume = volume;
diff --git a/core/java/android/speech/tts/SilenceMessageParams.java b/core/java/android/speech/tts/SilenceMessageParams.java
index 7a4ff1c..9909126 100644
--- a/core/java/android/speech/tts/SilenceMessageParams.java
+++ b/core/java/android/speech/tts/SilenceMessageParams.java
@@ -16,13 +16,13 @@
 package android.speech.tts;
 
 import android.os.ConditionVariable;
-import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
+import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
 
 class SilenceMessageParams extends MessageParams {
     private final ConditionVariable mCondVar = new ConditionVariable();
     private final long mSilenceDurationMs;
 
-    SilenceMessageParams(UtteranceCompletedDispatcher dispatcher,
+    SilenceMessageParams(UtteranceProgressDispatcher dispatcher,
             String callingApp, long silenceDurationMs) {
         super(dispatcher, callingApp);
         mSilenceDurationMs = silenceDurationMs;
diff --git a/core/java/android/speech/tts/SynthesisMessageParams.java b/core/java/android/speech/tts/SynthesisMessageParams.java
index 779721e..0c0f033 100644
--- a/core/java/android/speech/tts/SynthesisMessageParams.java
+++ b/core/java/android/speech/tts/SynthesisMessageParams.java
@@ -17,7 +17,7 @@
 
 import android.media.AudioFormat;
 import android.media.AudioTrack;
-import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
+import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
 
 import java.util.LinkedList;
 
@@ -56,7 +56,7 @@
 
     SynthesisMessageParams(int streamType, int sampleRate,
             int audioFormat, int channelCount,
-            float volume, float pan, UtteranceCompletedDispatcher dispatcher,
+            float volume, float pan, UtteranceProgressDispatcher dispatcher,
             String callingApp, EventLogger logger) {
         super(dispatcher, callingApp);
 
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index fdc2570..38699ea 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -482,7 +482,7 @@
     private OnInitListener mInitListener;
     // Written from an unspecified application thread, read from
     // a binder thread.
-    private volatile OnUtteranceCompletedListener mUtteranceCompletedListener;
+    private volatile UtteranceProgressListener mUtteranceProgressListener;
     private final Object mStartLock = new Object();
 
     private String mRequestedEngine;
@@ -1146,9 +1146,28 @@
      * @param listener The listener to use.
      *
      * @return {@link #ERROR} or {@link #SUCCESS}.
+     *
+     * @deprecated Use {@link #setOnUtteranceProgressListener(UtteranceProgressListener)}
+     *        instead.
      */
+    @Deprecated
     public int setOnUtteranceCompletedListener(final OnUtteranceCompletedListener listener) {
-        mUtteranceCompletedListener = listener;
+        mUtteranceProgressListener = UtteranceProgressListener.from(listener);
+        return TextToSpeech.SUCCESS;
+    }
+
+    /**
+     * Sets the listener that will be notified of various events related to the
+     * synthesis of a given utterance.
+     *
+     * See {@link UtteranceProgressListener} and
+     * {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID}.
+     *
+     * @param listener the listener to use.
+     * @return {@link #ERROR} or {@link #SUCCESS}
+     */
+    public int setOnUtteranceProgressListener(UtteranceProgressListener listener) {
+        mUtteranceProgressListener = listener;
         return TextToSpeech.SUCCESS;
     }
 
@@ -1204,10 +1223,26 @@
         private ITextToSpeechService mService;
         private final ITextToSpeechCallback.Stub mCallback = new ITextToSpeechCallback.Stub() {
             @Override
-            public void utteranceCompleted(String utteranceId) {
-                OnUtteranceCompletedListener listener = mUtteranceCompletedListener;
+            public void onDone(String utteranceId) {
+                UtteranceProgressListener listener = mUtteranceProgressListener;
                 if (listener != null) {
-                    listener.onUtteranceCompleted(utteranceId);
+                    listener.onDone(utteranceId);
+                }
+            }
+
+            @Override
+            public void onError(String utteranceId) {
+                UtteranceProgressListener listener = mUtteranceProgressListener;
+                if (listener != null) {
+                    listener.onError(utteranceId);
+                }
+            }
+
+            @Override
+            public void onStart(String utteranceId) {
+                UtteranceProgressListener listener = mUtteranceProgressListener;
+                if (listener != null) {
+                    listener.onStart(utteranceId);
                 }
             }
         };
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 83b6d4c..39922da 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -306,6 +306,7 @@
          */
         public int enqueueSpeechItem(int queueMode, final SpeechItem speechItem) {
             if (!speechItem.isValid()) {
+                speechItem.dispatchOnError();
                 return TextToSpeech.ERROR;
             }
 
@@ -332,6 +333,7 @@
                 return TextToSpeech.SUCCESS;
             } else {
                 Log.w(TAG, "SynthThread has quit");
+                speechItem.dispatchOnError();
                 return TextToSpeech.ERROR;
             }
         }
@@ -381,14 +383,16 @@
         }
     }
 
-    interface UtteranceCompletedDispatcher {
-        public void dispatchUtteranceCompleted();
+    interface UtteranceProgressDispatcher {
+        public void dispatchOnDone();
+        public void dispatchOnStart();
+        public void dispatchOnError();
     }
 
     /**
      * An item in the synth thread queue.
      */
-    private abstract class SpeechItem implements UtteranceCompletedDispatcher {
+    private abstract class SpeechItem implements UtteranceProgressDispatcher {
         private final String mCallingApp;
         protected final Bundle mParams;
         private boolean mStarted = false;
@@ -443,10 +447,27 @@
             stopImpl();
         }
 
-        public void dispatchUtteranceCompleted() {
+        @Override
+        public void dispatchOnDone() {
             final String utteranceId = getUtteranceId();
             if (!TextUtils.isEmpty(utteranceId)) {
-                mCallbacks.dispatchUtteranceCompleted(getCallingApp(), utteranceId);
+                mCallbacks.dispatchOnDone(getCallingApp(), utteranceId);
+            }
+        }
+
+        @Override
+        public void dispatchOnStart() {
+            final String utteranceId = getUtteranceId();
+            if (!TextUtils.isEmpty(utteranceId)) {
+                mCallbacks.dispatchOnStart(getCallingApp(), utteranceId);
+            }
+        }
+
+        @Override
+        public void dispatchOnError() {
+            final String utteranceId = getUtteranceId();
+            if (!TextUtils.isEmpty(utteranceId)) {
+                mCallbacks.dispatchOnError(getCallingApp(), utteranceId);
             }
         }
 
@@ -617,9 +638,12 @@
 
         @Override
         protected int playImpl() {
+            dispatchOnStart();
             int status = super.playImpl();
             if (status == TextToSpeech.SUCCESS) {
-                dispatchUtteranceCompleted();
+                dispatchOnDone();
+            } else {
+                dispatchOnError();
             }
             return status;
         }
@@ -856,16 +880,34 @@
             }
         }
 
-        public void dispatchUtteranceCompleted(String packageName, String utteranceId) {
-            ITextToSpeechCallback cb;
-            synchronized (mAppToCallback) {
-                cb = mAppToCallback.get(packageName);
-            }
+        public void dispatchOnDone(String packageName, String utteranceId) {
+            ITextToSpeechCallback cb = getCallbackFor(packageName);
             if (cb == null) return;
             try {
-                cb.utteranceCompleted(utteranceId);
+                cb.onDone(utteranceId);
             } catch (RemoteException e) {
-                Log.e(TAG, "Callback failed: " + e);
+                Log.e(TAG, "Callback onDone failed: " + e);
+            }
+        }
+
+        public void dispatchOnStart(String packageName, String utteranceId) {
+            ITextToSpeechCallback cb = getCallbackFor(packageName);
+            if (cb == null) return;
+            try {
+                cb.onStart(utteranceId);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Callback onStart failed: " + e);
+            }
+
+        }
+
+        public void dispatchOnError(String packageName, String utteranceId) {
+            ITextToSpeechCallback cb = getCallbackFor(packageName);
+            if (cb == null) return;
+            try {
+                cb.onError(utteranceId);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Callback onError failed: " + e);
             }
         }
 
@@ -886,6 +928,15 @@
             }
         }
 
+        private ITextToSpeechCallback getCallbackFor(String packageName) {
+            ITextToSpeechCallback cb;
+            synchronized (mAppToCallback) {
+                cb = mAppToCallback.get(packageName);
+            }
+
+            return cb;
+        }
+
     }
 
 }
diff --git a/core/java/android/speech/tts/UtteranceProgressListener.java b/core/java/android/speech/tts/UtteranceProgressListener.java
new file mode 100644
index 0000000..a04458a
--- /dev/null
+++ b/core/java/android/speech/tts/UtteranceProgressListener.java
@@ -0,0 +1,68 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+package android.speech.tts;
+
+/**
+ * Listener for events relating to the progress of an utterance through
+ * the synthesis queue. Each utterance is associated with a call to
+ * {@link TextToSpeech#speak} or {@link TextToSpeech#synthesizeToFile} with an
+ * associated utterance identifier, as per {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID}.
+ *
+ * The callbacks specified in this method can be called from multiple threads.
+ */
+public abstract class UtteranceProgressListener {
+    /**
+     * Called when an utterance "starts" as perceived by the caller. This will
+     * be soon before audio is played back in the case of a {@link TextToSpeech#speak}
+     * or before the first bytes of a file are written to storage in the case
+     * of {@link TextToSpeech#synthesizeToFile}.
+     *
+     * @param utteranceId the utterance ID of the utterance.
+     */
+    public abstract void onStart(String utteranceId);
+
+    /**
+     * Called when an utterance has successfully completed processing.
+     * All audio will have been played back by this point for audible output, and all
+     * output will have been written to disk for file synthesis requests.
+     *
+     * This request is guaranteed to be called after {@link #onStart(String)}.
+     *
+     * @param utteranceId the utterance ID of the utterance.
+     */
+    public abstract void onDone(String utteranceId);
+
+    /**
+     * Called when an error has occurred during processing. This can be called
+     * at any point in the synthesis process. Note that there might be calls
+     * to {@link #onStart(String)} for specified utteranceId but there will never
+     * be a call to both {@link #onDone(String)} and {@link #onError(String)} for
+     * the same utterance.
+     *
+     * @param utteranceId the utterance ID of the utterance.
+     */
+    public abstract void onError(String utteranceId);
+
+    /**
+     * Wraps an old deprecated OnUtteranceCompletedListener with a shiny new
+     * progress listener.
+     *
+     * @hide
+     */
+    static UtteranceProgressListener from(
+            final TextToSpeech.OnUtteranceCompletedListener listener) {
+        return new UtteranceProgressListener() {
+            @Override
+            public synchronized void onDone(String utteranceId) {
+                listener.onUtteranceCompleted(utteranceId);
+            }
+
+            // The following methods are left unimplemented.
+            @Override
+            public void onStart(String utteranceId) { }
+
+            @Override
+            public void onError(String utteranceId) { }
+        };
+    }
+}
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index d948ec2..ac06d2d 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -154,6 +154,7 @@
     static native void nSetTextureLayerTransform(int layerId, int matrix);
     static native void nDestroyLayer(int layerId);
     static native void nDestroyLayerDeferred(int layerId);
+    static native void nFlushLayer(int layerId);
     static native boolean nCopyLayer(int layerId, int bitmap);
 
     ///////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/view/GLES20Layer.java b/core/java/android/view/GLES20Layer.java
index fd3b9e5..4f25792 100644
--- a/core/java/android/view/GLES20Layer.java
+++ b/core/java/android/view/GLES20Layer.java
@@ -60,6 +60,13 @@
         }
         mLayer = 0;
     }
+    
+    @Override
+    void flush() {
+        if (mLayer != 0) {
+            GLES20Canvas.nFlushLayer(mLayer);
+        }
+    }
 
     static class Finalizer {
         private int mLayerId;
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 28389ab..d5666f3 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -116,6 +116,11 @@
     abstract void destroy();
 
     /**
+     * Flush the render queue associated with this layer.
+     */
+    abstract void flush();
+
+    /**
      * This must be invoked before drawing onto this layer.
      * @param currentCanvas
      */
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index dc46d42..3bddeef 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10146,6 +10146,12 @@
                 break;
         }
     }
+    
+    void flushLayer() {
+        if (mLayerType == LAYER_TYPE_HARDWARE && mHardwareLayer != null) {
+            mHardwareLayer.flush();
+        }
+    }
 
     /**
      * <p>Returns a hardware layer that can be used to draw this view again
@@ -10158,6 +10164,9 @@
                 !mAttachInfo.mHardwareRenderer.isEnabled()) {
             return null;
         }
+        
+        if (!mAttachInfo.mHardwareRenderer.validate()) return null;
+        
 
         final int width = mRight - mLeft;
         final int height = mBottom - mTop;
@@ -10232,8 +10241,14 @@
      */
     boolean destroyLayer() {
         if (mHardwareLayer != null) {
-            mHardwareLayer.destroy();
-            mHardwareLayer = null;
+            AttachInfo info = mAttachInfo;
+            if (info != null && info.mHardwareRenderer != null &&
+                    info.mHardwareRenderer.isEnabled()) {
+                if (!info.mHardwareRenderer.validate()) {
+                    mHardwareLayer.destroy();
+                    mHardwareLayer = null;                    
+                }
+            }
             return true;
         }
         return false;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index e366e72..50b34b0 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2957,6 +2957,16 @@
         if (enabled != mDrawLayers) {
             mDrawLayers = enabled;
             invalidate(true);
+            
+            AttachInfo info = mAttachInfo;
+            if (info != null && info.mHardwareRenderer != null &&
+                    info.mHardwareRenderer.isEnabled()) {
+                if (!info.mHardwareRenderer.validate()) {
+                    enabled = false;
+                }
+            } else {
+                enabled = false;
+            }
 
             // We need to invalidate any child with a layer. For instance,
             // if a child is backed by a hardware layer and we disable layers
@@ -2968,6 +2978,7 @@
             for (int i = 0; i < mChildrenCount; i++) {
                 View child = mChildren[i];
                 if (child.mLayerType != LAYER_TYPE_NONE) {
+                    if (!enabled) child.flushLayer();
                     child.invalidate(true);
                 }
             }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 03d6511..7249497 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2861,8 +2861,8 @@
     }
 
     // Used to avoid sending many visible rect messages.
-    private Rect mLastVisibleRectSent;
-    private Rect mLastGlobalRect;
+    private Rect mLastVisibleRectSent = new Rect();
+    private Rect mLastGlobalRect = new Rect();
     private Rect mVisibleRect = new Rect();
     private Rect mGlobalVisibleRect = new Rect();
     private Point mScrollOffset = new Point();
@@ -2878,7 +2878,7 @@
                 mWebViewCore.sendMessage(EventHub.SET_SCROLL_OFFSET,
                         nativeMoveGeneration(), mSendScrollEvent ? 1 : 0, mScrollOffset);
             }
-            mLastVisibleRectSent = mVisibleRect;
+            mLastVisibleRectSent.set(mVisibleRect);
             mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
         }
         if (getGlobalVisibleRect(mGlobalVisibleRect)
@@ -2894,7 +2894,7 @@
             if (!mBlockWebkitViewMessages) {
                 mWebViewCore.sendMessage(EventHub.SET_GLOBAL_BOUNDS, mGlobalVisibleRect);
             }
-            mLastGlobalRect = mGlobalVisibleRect;
+            mLastGlobalRect.set(mGlobalVisibleRect);
         }
         return mVisibleRect;
     }
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index fd2abc2..326587e 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -129,7 +129,7 @@
         mEdge = res.getDrawable(R.drawable.overscroll_edge);
         mGlow = res.getDrawable(R.drawable.overscroll_glow);
 
-        mMinWidth = (int) (context.getResources().getDisplayMetrics().density * MIN_WIDTH + 0.5f);
+        mMinWidth = (int) (res.getDisplayMetrics().density * MIN_WIDTH + 0.5f);
         mInterpolator = new DecelerateInterpolator();
     }
 
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index c1e36ed..73e1273 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -1036,6 +1036,7 @@
         }
     }
 
+    @RemotableViewMethod
     @Override
     public void setVisibility(int visibility) {
         super.setVisibility(visibility);
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 8ba7bee..5fa4ad0 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1248,6 +1248,8 @@
      */
     public void dismiss() {
         if (isShowing() && mPopupView != null) {
+            mIsShowing = false;
+
             unregisterForScrollChanged();
 
             try {
@@ -1257,7 +1259,6 @@
                     ((ViewGroup) mPopupView).removeView(mContentView);
                 }
                 mPopupView = null;
-                mIsShowing = false;
     
                 if (mOnDismissListener != null) {
                     mOnDismissListener.onDismiss();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index bc8721a..b106cc5 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -24,6 +24,7 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.res.ColorStateList;
+import android.content.res.CompatibilityInfo;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
@@ -449,18 +450,19 @@
         super(context, attrs, defStyle);
         mText = "";
 
+        final Resources res = getResources();
+        final CompatibilityInfo compat = res.getCompatibilityInfo();
+
         mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
-        mTextPaint.density = getResources().getDisplayMetrics().density;
-        mTextPaint.setCompatibilityScaling(
-                getResources().getCompatibilityInfo().applicationScale);
+        mTextPaint.density = res.getDisplayMetrics().density;
+        mTextPaint.setCompatibilityScaling(compat.applicationScale);
 
         // If we get the paint from the skin, we should set it to left, since
         // the layout always wants it to be left.
         // mTextPaint.setTextAlign(Paint.Align.LEFT);
 
         mHighlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mHighlightPaint.setCompatibilityScaling(
-                getResources().getCompatibilityInfo().applicationScale);
+        mHighlightPaint.setCompatibilityScaling(compat.applicationScale);
 
         mMovement = getDefaultMovementMethod();
         mTransformation = null;
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 4714be8..b689f53 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -537,7 +537,7 @@
 
         if ((flagsChanged & DISPLAY_RELAYOUT_MASK) != 0) {
             final boolean showHome = (options & ActionBar.DISPLAY_SHOW_HOME) != 0;
-            final int vis = showHome ? VISIBLE : GONE;
+            final int vis = showHome && mExpandedActionView == null ? VISIBLE : GONE;
             mHomeLayout.setVisibility(vis);
 
             if ((flagsChanged & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 79aa43b..7076e2a 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -249,7 +249,7 @@
         flags(other.flags),
         hinting(other.hinting) {
     if (other.text) {
-        textCopy.setTo(other.text);
+        textCopy.setTo(other.text, other.contextCount);
     }
 }
 
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 4f75fad..78b8e8e 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -718,6 +718,10 @@
     LayerRenderer::destroyLayerDeferred(layer);
 }
 
+static void android_view_GLES20Canvas_flushLayer(JNIEnv* env, jobject clazz, Layer* layer) {
+    LayerRenderer::flushLayer(layer);
+}
+
 static void android_view_GLES20Canvas_drawLayer(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, Layer* layer, jfloat x, jfloat y, SkPaint* paint) {
     renderer->drawLayer(layer, x, y, paint);
@@ -860,6 +864,7 @@
     { "nSetTextureLayerTransform", "(II)V",    (void*) android_view_GLES20Canvas_setTextureLayerTransform },
     { "nDestroyLayer",           "(I)V",       (void*) android_view_GLES20Canvas_destroyLayer },
     { "nDestroyLayerDeferred",   "(I)V",       (void*) android_view_GLES20Canvas_destroyLayerDeferred },
+    { "nFlushLayer",             "(I)V",       (void*) android_view_GLES20Canvas_flushLayer },
     { "nDrawLayer",              "(IIFFI)V",   (void*) android_view_GLES20Canvas_drawLayer },
     { "nCopyLayer",              "(II)Z",      (void*) android_view_GLES20Canvas_copyLayer },
 
diff --git a/docs/html/guide/developing/building/building-cmdline.jd b/docs/html/guide/developing/building/building-cmdline.jd
index d78a4f5..c43962a 100644
--- a/docs/html/guide/developing/building/building-cmdline.jd
+++ b/docs/html/guide/developing/building/building-cmdline.jd
@@ -365,7 +365,7 @@
   <dd>Builds a test project and the tested project, installs both <code>.apk</code> files, and
   runs the tests.</dd>
 
-  <dt><code>ant emma debug installt test</code></dt>
+  <dt><code>ant emma debug install test</code></dt>
   <dd>Builds a test project and the tested project, installs both <code>.apk</code> files, and
   runs the tests with code coverage enabled.</dd>
 
diff --git a/docs/html/guide/topics/resources/drawable-resource.jd b/docs/html/guide/topics/resources/drawable-resource.jd
index fdf6c5a..80de9f9 100644
--- a/docs/html/guide/topics/resources/drawable-resource.jd
+++ b/docs/html/guide/topics/resources/drawable-resource.jd
@@ -646,6 +646,7 @@
         android:state_checkable=["true" | "false"]
         android:state_checked=["true" | "false"]
         android:state_enabled=["true" | "false"]
+        android:state_activated=["true" | "false"]
         android:state_window_focused=["true" | "false"] />
 &lt;/selector>
 </pre>
@@ -690,8 +691,8 @@
           <dd><em>Boolean</em>. "true" if this item should be used when the object is pressed (such as when a button
 is touched/clicked); "false" if this item should be used in the default, non-pressed state.</dd>
         <dt><code>android:state_focused</code></dt>
-          <dd><em>Boolean</em>. "true" if this item should be used when the object is focused (such as when a button
-is highlighted using the trackball/d-pad); "false" if this item should be used in the default,
+          <dd><em>Boolean</em>. "true" if this item should be used when the object has input focus
+(such as when the user selects a text input); "false" if this item should be used in the default,
 non-focused state.</dd>
         <dt><code>android:state_hovered</code></dt>
           <dd><em>Boolean</em>. "true" if this item should be used when the object is being hovered
@@ -699,8 +700,11 @@
 drawable may be the same drawable used for the "focused" state.
           <p>Introduced in API level 14.</p></dd>
         <dt><code>android:state_selected</code></dt>
-          <dd><em>Boolean</em>. "true" if this item should be used when the object is selected (such as when a
-tab is opened); "false" if this item should be used when the object is not selected.</dd>
+          <dd><em>Boolean</em>. "true" if this item should be used when the object is the current
+user selection when navigating with a directional control (such as when navigating through a list
+with a d-pad); "false" if this item should be used when the object is not selected.
+<p>The selected state is used when focus (<code>android:state_focused</code>) is not sufficient
+(such as when list view has focus and an item within it is selected with a d-pad).</p></dd>
         <dt><code>android:state_checkable</code></dt>
           <dd><em>Boolean</em>. "true" if this item should be used when the object is checkable; "false" if this
 item should be used when the object is not checkable. (Only useful if the object can
@@ -709,8 +713,14 @@
           <dd><em>Boolean</em>. "true" if this item should be used when the object is checked; "false" if it
 should be used when the object is un-checked.</dd>
         <dt><code>android:state_enabled</code></dt>
-          <dd><em>Boolean</em>. "true" if this item should be used when the object is enabled (capable of
-receiving touch/click events); "false" if it should be used when the object is disabled.</dd>
+          <dd><em>Boolean</em>. "true" if this item should be used when the object is enabled
+(capable of receiving touch/click events); "false" if it should be used when the object is
+disabled.</dd>
+        <dt><code>android:state_activated</code></dt>
+          <dd><em>Boolean</em>. "true" if this item should be used when the object is activated as
+the persistent selection (such as to "highlight" the previously selected list item in a persistent
+navigation view); "false" if it should be used when the object is not activated.
+<p>Introduced in API level 11.</p></dd>
         <dt><code>android:state_window_focused</code></dt>
           <dd><em>Boolean</em>. "true" if this item should be used when the application window has focus (the
 application is in the foreground), "false" if this item should be used when the application
diff --git a/docs/html/sdk/ndk/index.jd b/docs/html/sdk/ndk/index.jd
index f87e1f6..afbad57 100644
--- a/docs/html/sdk/ndk/index.jd
+++ b/docs/html/sdk/ndk/index.jd
@@ -1,18 +1,19 @@
 ndk=true
 
-ndk.win_download=android-ndk-r6b-windows.zip
-ndk.win_bytes=67670219
-ndk.win_checksum=f496b48fffb6d341303de170a081b812
+ndk.win_download=android-ndk-r7-windows.zip
+ndk.win_bytes=81270552
+ndk.win_checksum=55483482cf2b75e8dd1a5d9a7caeb6e5
 
-ndk.mac_download=android-ndk-r6b-darwin-x86.tar.bz2
-ndk.mac_bytes=52798843
-ndk.mac_checksum=65f2589ac1b08aabe3183f9ed1a8ce8e
+ndk.mac_download=android-ndk-r7-darwin-x86.tar.bz2
+ndk.mac_bytes=71262092
+ndk.mac_checksum=817ca5675a1dd44078098e43070f19b6
 
-ndk.linux_download=android-ndk-r6b-linux-x86.tar.bz2
-ndk.linux_bytes=46532436
-ndk.linux_checksum=309f35e49b64313cfb20ac428df4cec2
+ndk.linux_download=android-ndk-r7-linux-x86.tar.bz2
+ndk.linux_bytes=64884365
+ndk.linux_checksum=bf15e6b47bf50824c4b96849bf003ca3
 
 page.title=Android NDK
+
 @jd:body
 
 <h2 id="notes">Revisions</h2>
@@ -61,6 +62,310 @@
 <div class="toggleable open">
   <a href="#" onclick="return toggleDiv(this)"><img src=
   "{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px">
+  Android NDK, Revision 7</a> <em>(November 2011)</em>
+
+  <div class="toggleme">
+    <p>This release of the NDK includes new features to support the Android 4.0 platform as well
+    as many other additions and improvements:</p>
+
+    <dl>
+      <dt>New features</dt>
+
+      <dd>
+        <ul>
+          <li>Added official NDK APIs for Android 4.0 (API level 14), which adds the following
+          native features to the platform:
+
+            <ul>
+              <li>Added native multimedia API based on the Khronos Group OpenMAX AL™ 1.0.1
+              standard. The new <code>&lt;OMXAL/OpenMAXAL.h&gt;</code> and
+              <code>&lt;OMXAL/OpenMAXAL_Android.h&gt;</code> headers allow applications targeting
+              API level 14 to perform multimedia output directly from native code by using a new
+              Android-specific buffer queue interface. For more details, see
+              <code>docs/openmaxal/index.html</code> and <a href=
+              "http://www.khronos.org/openmax/">http://www.khronos.org/openmax/</a>.</li>
+
+              <li>Updated the native audio API based on the Khronos Group OpenSL ES 1.0.1™
+              standard. With API Level 14, you can now decode compressed audio (e.g. MP3, AAC,
+              Vorbis) to PCM. For more details, see <code>docs/opensles/index.html</code> and
+              <a href=
+              "http://www.khronos.org/opensles">http://www.khronos.org/opensles/</a>.</li>
+            </ul>
+          </li>
+
+          <li>Added CCache support. To speed up large rebuilds, define the
+          <code>NDK_CCACHE</code> environment variable to <code>ccache</code> (or the path to
+          your <code>ccache</code> binary). When declared, the NDK build system automatically
+          uses CCache when compiling any source file. For example:
+            <pre>
+export NDK_CCACHE=ccache
+</pre>
+          <p class="note"><strong>Note:</strong> CCache is not included in the NDK release
+          so you must have it installed prior to using it. For more information about CCache, see
+          <a href="http://ccache.samba.org">http://ccache.samba.org</a>.</p>
+          </li>
+
+          <li>Added support for setting <code>APP_ABI</code> to <code>all</code> to indicate that
+          you want to build your NDK modules for all the ABIs supported by your given NDK
+          release. This means that either one of the following two lines in your
+          <code>Application.mk</code> are equivalent with this release:
+            <pre>
+APP_ABI := all
+APP_ABI := armeabi armeabi-v7a x86
+</pre>
+
+            <p>This also works if you define <code>APP_ABI</code> when calling
+            <code>ndk-build</code> from the command-line, which is a quick way to check that your
+            project builds for all supported ABIs without changing the project's
+            <code>Application.mk file</code>. For example:</p>
+            <pre>
+ndk-build APP_ABI=all
+</pre>
+          </li>
+
+          <li>Added a <code>LOCAL_CPP_FEATURES</code> variable in <code>Android.mk</code> that
+          allows you to declare which C++ features (RTTI or Exceptions) your module uses. This
+          ensures that the final linking works correctly if you have prebuilt modules that depend
+          on these features. See <code>docs/ANDROID-MK.html</code> and
+          <code>docs/CPLUSPLUS-SUPPORT.html</code> for more details.</li>
+
+          <li>Shortened paths to source and object files that are used in build commands. When
+          invoking <code>$NDK/ndk-build</code> from your project path, the paths to the source,
+          object, and binary files that are passed to the build commands are significantly
+          shorter now, because they are passed relative to the current directory. This is useful
+          when building projects with a lot of source files, to avoid limits on the maximum
+          command line length supported by your host operating system. The behavior is unchanged
+          if you invoke <code>ndk-build</code> from a sub-directory of your project tree, or if
+          you define <code>NDK_PROJECT_PATH</code> to point to a specific directory.</li>
+        </ul>
+      </dd>
+
+      <dt>Experimental features</dt>
+
+      <dd>
+        You can now build your NDK source files on Windows <em>without</em> Cygwin by calling the
+        <code>ndk-build.cmd</code> script from the command line from your project path. The
+        script takes exactly the same arguments as the original <code>ndk-build</code> script.
+        The Windows NDK package comes with its own prebuilt binaries for GNU Make, Awk and other
+        tools required by the build. You should not need to install anything else to get a
+        working build system.
+
+        <p class="caution"><strong>Important:</strong> <code>ndk-gdb</code> does not work on
+        Windows, so you still need Cygwin to debug.</p>
+
+        <p>This feature is still experimental, so feel free to try it and report issues on the
+        <a href="http://b.android.com">public bug database</a> or <a href=
+        "http://groups.google.com/group/android-ndk">public forum</a>. All samples and unit tests
+        shipped with the NDK succesfully compile with this feature.</p>
+      </dd>
+
+      <dt>Important bug fixes</dt>
+
+      <dd>
+        <ul>
+          <li>Imported shared libraries are now installed by default to the target installation
+          location (<code>libs/&lt;abi&gt;</code>) if <code>APP_MODULES</code> is not defined in
+          your <code>Application.mk</code>. For example, if a top-level module <code>foo</code>
+          imports a module <code>bar</code>, then both <code>libfoo.so</code> and
+          <code>libbar.so</code> are copied to the install location. Previously, only
+          <code>libfoo.so</code> was copied, unless you listed <code>bar</code> in your
+          <code>APP_MODULES</code> too. If you define <code>APP_MODULES</code> explicitly, the
+          behavior is unchanged.</li>
+
+          <li><code>ndk-gdb</code> now works correctly for activities with multiple categories in
+          their MAIN intent filters.</li>
+
+          <li>Static library imports are now properly transitive. For example, if a top-level
+          module <code>foo</code> imports static library <code>bar</code> that imports static
+          library <code>zoo</code>, the <code>libfoo.so</code> will now be linked against both
+          <code>libbar.a</code> and <code>libzoo.a</code>.</li>
+        </ul>
+      </dd>
+
+      <dt>Other changes</dt>
+
+      <dd>
+        <ul>
+          <li><code>docs/NATIVE-ACTIVITY.HTML</code>: Fixed typo. The minimum API level should be
+          9, not 8 for native activities.</li>
+
+          <li><code>docs/STABLE-APIS.html</code>: Added missing documentation listing EGL as a
+          supported stable API, starting from API level 9.</li>
+
+          <li><code>download-toolchain-sources.sh</code>: Updated to download the toolchain
+          sources from <a href="http://android.googlesource.com">android.googlesource.com</a>,
+          which is the new location for the AOSP servers.</li>
+
+          <li>Added a new C++ support runtime named <code>gabi++</code>. More details about it
+          are available in the updated <code>docs/CPLUSPLUS-SUPPORT.html</code>.</li>
+
+          <li>Added a new C++ support runtime named <code>gnustl_shared</code> that corresponds
+          to the shared library version of GNU libstdc++ v3 (GPLv3 license). See more info at
+          <code>docs/CPLUSPLUS-SUPPORT.html</code></li>
+
+          <li>Added support for RTTI in the STLport C++ runtimes (no support for
+          exceptions).</li>
+
+          <li>Added support for multiple file extensions in <code>LOCAL_CPP_EXTENSION</code>. For
+          example, to compile both <code>foo.cpp</code> and <code>bar.cxx</code> as C++ sources,
+          declare the following:
+            <pre>
+LOCAL_CPP_EXTENSION := .cpp .cxx
+</pre>
+          </li>
+
+          <li>Removed many unwanted exported symbols from the link-time shared system libraries
+          provided by the NDK. This ensures that code generated with the standalone toolchain
+          doesn't risk to accidentally depend on a non-stable ABI symbol (e.g. any libgcc.a
+          symbol that changes each time the toolchain used to build the platform is changed)</li>
+
+          <li>Refreshed the EGL and OpenGLES Khronos headers to support more extensions. Note
+          that this does <em>not</em> change the NDK ABIs for the corresponding libraries,
+          because each extension must be probed at runtime by the client application.
+
+            <p>The extensions that are available depend on your actual device and GPU drivers,
+            not the platform version the device runs on. The header changes simply add new
+            constants and types to make it easier to use the extensions when they have been
+            probed with <code>eglGetProcAddress()</code> or <code>glGetProcAddress()</code>. The
+            following list describes the newly supported extensions:</p>
+
+            <dl>
+              <dt>GLES 1.x</dt>
+
+              <dd>
+                <ul>
+                  <li><code>GL_OES_vertex_array_object</code></li>
+
+                  <li><code>GL_OES_EGL_image_external</code></li>
+
+                  <li><code>GL_APPLE_texture_2D_limited_npot</code></li>
+
+                  <li><code>GL_EXT_blend_minmax</code></li>
+
+                  <li><code>GL_EXT_discard_framebuffer</code></li>
+
+                  <li><code>GL_EXT_multi_draw_arrays</code></li>
+
+                  <li><code>GL_EXT_read_format_bgra</code></li>
+
+                  <li><code>GL_EXT_texture_filter_anisotropic</code></li>
+
+                  <li><code>GL_EXT_texture_format_BGRA8888</code></li>
+
+                  <li><code>GL_EXT_texture_lod_bias</code></li>
+
+                  <li><code>GL_IMG_read_format</code></li>
+
+                  <li><code>GL_IMG_texture_compression_pvrtc</code></li>
+
+                  <li><code>GL_IMG_texture_env_enhanced_fixed_function</code></li>
+
+                  <li><code>GL_IMG_user_clip_plane</code></li>
+
+                  <li><code>GL_IMG_multisampled_render_to_texture</code></li>
+
+                  <li><code>GL_NV_fence</code></li>
+
+                  <li><code>GL_QCOM_driver_control</code></li>
+
+                  <li><code>GL_QCOM_extended_get</code></li>
+
+                  <li><code>GL_QCOM_extended_get2</code></li>
+
+                  <li><code>GL_QCOM_perfmon_global_mode</code></li>
+
+                  <li><code>GL_QCOM_writeonly_rendering</code></li>
+
+                  <li><code>GL_QCOM_tiled_rendering</code></li>
+                </ul>
+              </dd>
+
+              <dt>GLES 2.0</dt>
+
+              <dd>
+                <ul>
+                  <li><code>GL_OES_element_index_uint</code></li>
+
+                  <li><code>GL_OES_get_program_binary</code></li>
+
+                  <li><code>GL_OES_mapbuffer</code></li>
+
+                  <li><code>GL_OES_packed_depth_stencil</code></li>
+
+                  <li><code>GL_OES_texture_3D</code></li>
+
+                  <li><code>GL_OES_texture_float</code></li>
+
+                  <li><code>GL_OES_texture_float_linear</code></li>
+
+                  <li><code>GL_OES_texture_half_float_linear</code></li>
+
+                  <li><code>GL_OES_texture_npot</code></li>
+
+                  <li><code>GL_OES_vertex_array_object</code></li>
+
+                  <li><code>GL_OES_EGL_image_external</code></li>
+
+                  <li><code>GL_AMD_program_binary_Z400</code></li>
+
+                  <li><code>GL_EXT_blend_minmax</code></li>
+
+                  <li><code>GL_EXT_discard_framebuffer</code></li>
+
+                  <li><code>GL_EXT_multi_draw_arrays</code></li>
+
+                  <li><code>GL_EXT_read_format_bgra</code></li>
+
+                  <li><code>GL_EXT_texture_format_BGRA8888</code></li>
+
+                  <li><code>GL_EXT_texture_compression_dxt1</code></li>
+
+                  <li><code>GL_IMG_program_binary</code></li>
+
+                  <li><code>GL_IMG_read_format</code></li>
+
+                  <li><code>GL_IMG_shader_binary</code></li>
+
+                  <li><code>GL_IMG_texture_compression_pvrtc</code></li>
+
+                  <li><code>GL_IMG_multisampled_render_to_texture</code></li>
+
+                  <li><code>GL_NV_coverage_sample</code></li>
+
+                  <li><code>GL_NV_depth_nonlinear</code></li>
+
+                  <li><code>GL_QCOM_extended_get</code></li>
+
+                  <li><code>GL_QCOM_extended_get2</code></li>
+
+                  <li><code>GL_QCOM_writeonly_rendering</code></li>
+
+                  <li><code>GL_QCOM_tiled_rendering</code></li>
+                </ul>
+              </dd>
+
+              <dt>EGL</dt>
+
+              <dd>
+                <ul>
+                  <li><code>EGL_ANDROID_recordable</code></li>
+
+                  <li><code>EGL_NV_system_time</code></li>
+                </ul>
+              </dd>
+            </dl>
+          </li>
+        </ul>
+      </dd>
+    </dl>
+  </div>
+</div>
+
+
+
+<div class="toggleable closed">
+  <a href="#" onclick="return toggleDiv(this)"><img src=
+  "{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px">
   Android NDK, Revision 6b</a> <em>(August 2011)</em>
 
    <div class="toggleme">
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index 9a18f7da..afe6a6e 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -192,7 +192,8 @@
       <span style="display:none" class="zh-TW"></span>
     </h2>
     <ul>
-      <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r6b</a>
+      <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r7</a>
+        <span class="new">new!</span>
         </li>
       <li><a href="<?cs var:toroot ?>sdk/ndk/overview.html">What is the NDK?</a></li>
     </ul>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 79acd55..380b3d8 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -604,10 +604,13 @@
         }
         Bitmap bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true);
         if (config == Config.ARGB_8888 && !hasAlpha) {
-            bm.eraseColor(0xff000000);
+            nativeErase(bm.mNativeBitmap, 0xff000000);
             nativeSetHasAlpha(bm.mNativeBitmap, hasAlpha);
         } else {
-            bm.eraseColor(0);
+            // No need to initialize it to zeroes; it is backed by a VM byte array
+            // which is by definition preinitialized to all zeroes.
+            //
+            //nativeErase(bm.mNativeBitmap, 0);
         }
         return bm;
     }
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
index 9aa6700..534afce 100644
--- a/include/media/mediametadataretriever.h
+++ b/include/media/mediametadataretriever.h
@@ -54,6 +54,7 @@
     METADATA_KEY_BITRATE         = 20,
     METADATA_KEY_TIMED_TEXT_LANGUAGES      = 21,
     METADATA_KEY_IS_DRM          = 22,
+    METADATA_KEY_LOCATION        = 23,
 
     // Add more here...
 };
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 57f678c..4cdee17 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -85,6 +85,7 @@
     kKeyDate              = 'date',  // cstring
     kKeyWriter            = 'writ',  // cstring
     kKeyCompilation       = 'cpil',  // cstring
+    kKeyLocation          = 'loc ',  // cstring
     kKeyTimeScale         = 'tmsl',  // int32_t
 
     // video profile and level
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 9bfc94c..95e0a18 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -38,7 +38,7 @@
 		external/skia/src/ports \
 		external/skia/include/utils
 
-	LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER
+	LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER -DGL_GLEXT_PROTOTYPES
 	LOCAL_CFLAGS += -fvisibility=hidden
 	LOCAL_MODULE_CLASS := SHARED_LIBRARIES
 	LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2 libskia libui
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 38d1130..48e4247 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -66,6 +66,7 @@
 
         mHasNPot = hasExtension("GL_OES_texture_npot");
         mHasFramebufferFetch = hasExtension("GL_NV_shader_framebuffer_fetch");
+        mHasDiscardFramebuffer = hasExtension("GL_EXT_discard_framebuffer");
 
         const char* vendor = (const char*) glGetString(GL_VENDOR);
         EXT_LOGD("Vendor: %s", vendor);
@@ -80,6 +81,7 @@
     inline bool hasNPot() const { return mHasNPot; }
     inline bool hasFramebufferFetch() const { return mHasFramebufferFetch; }
     inline bool needsHighpTexCoords() const { return mNeedsHighpTexCoords; }
+    inline bool hasDiscardFramebuffer() const { return mHasDiscardFramebuffer; }
 
     bool hasExtension(const char* extension) const {
         const String8 s(extension);
@@ -98,6 +100,7 @@
     bool mHasNPot;
     bool mNeedsHighpTexCoords;
     bool mHasFramebufferFetch;
+    bool mHasDiscardFramebuffer;
 }; // class Extensions
 
 }; // namespace uirenderer
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index e38b479..b7c079b 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -305,8 +305,10 @@
         LAYER_RENDERER_LOGD("Recycling layer, %dx%d fbo = %d",
                 layer->getWidth(), layer->getHeight(), layer->getFbo());
 
-        if (layer->getFbo()) {
-            Caches::getInstance().fboCache.put(layer->getFbo());
+        GLuint fbo = layer->getFbo();
+        if (fbo) {
+            flushLayer(layer);
+            Caches::getInstance().fboCache.put(fbo);
         }
 
         if (!Caches::getInstance().layerCache.put(layer)) {
@@ -331,6 +333,26 @@
     }
 }
 
+void LayerRenderer::flushLayer(Layer* layer) {
+#ifdef GL_EXT_discard_framebuffer
+    GLuint fbo = layer->getFbo();
+    if (layer && fbo) {
+        // If possible, discard any enqued operations on deferred
+        // rendering architectures
+        if (Caches::getInstance().extensions.hasDiscardFramebuffer()) {
+            GLuint previousFbo;
+            glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
+
+            GLenum attachments = GL_COLOR_ATTACHMENT0;
+            glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+            glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, &attachments);
+
+            glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
+        }
+    }
+#endif
+}
+
 bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) {
     Caches& caches = Caches::getInstance();
     if (layer && layer->isTextureLayer() && bitmap->width() <= caches.maxTextureSize &&
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index 6104301..72d8d81 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -61,6 +61,7 @@
             bool isOpaque, GLenum renderTarget, float* transform);
     ANDROID_API static void destroyLayer(Layer* layer);
     ANDROID_API static void destroyLayerDeferred(Layer* layer);
+    ANDROID_API static void flushLayer(Layer* layer);
     ANDROID_API static bool copyLayer(Layer* layer, SkBitmap* bitmap);
 
 private:
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 32595e4..1a8c1997 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -611,6 +611,11 @@
     }
 
     if (fboLayer) {
+        // Note: No need to use glDiscardFramebufferEXT() since we never
+        //       create/compose layers that are not on screen with this
+        //       code path
+        // See LayerRenderer::destroyLayer(Layer*)
+
         // Detach the texture from the FBO
         glBindFramebuffer(GL_FRAMEBUFFER, current->fbo);
         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 10694c3..11ecd1f 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -458,5 +458,12 @@
      * @hide
      */
     public static final int METADATA_KEY_IS_DRM          = 22;
+    /**
+     * This key retrieves the location information, if available.
+     * The location should be specified according to ISO-6709 standard, under
+     * a mp4/3gp box "@xyz". Location with longitude of -90 degrees and latitude
+     * of 180 degrees will be retrieved as "-90.0000+180.0000", for instance.
+     */
+    public static final int METADATA_KEY_LOCATION        = 23;
     // Add more here...
 }
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index 3c3af8f..1a06cc6 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -47,17 +47,22 @@
     VISUALIZER_STATE_ACTIVE,
 };
 
+// maximum number of reads from same buffer before resetting capture buffer. This means
+// that the framework has stopped playing audio and we must start returning silence
+#define MAX_STALL_COUNT 10
+
 struct VisualizerContext {
     const struct effect_interface_s *mItfe;
     effect_config_t mConfig;
-    uint32_t mState;
     uint32_t mCaptureIdx;
     uint32_t mCaptureSize;
-    uint32_t mCurrentBuf;
+    uint8_t mState;
+    uint8_t mCurrentBuf;
+    uint8_t mLastBuf;
+    uint8_t mStallCount;
     uint8_t mCaptureBuf[2][VISUALIZER_CAPTURE_SIZE_MAX];
 };
 
-
 //
 //--- Local functions
 //
@@ -66,6 +71,8 @@
 {
     pContext->mCaptureIdx = 0;
     pContext->mCurrentBuf = 0;
+    pContext->mLastBuf = 1;
+    pContext->mStallCount = 0;
     memset(pContext->mCaptureBuf[0], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
     memset(pContext->mCaptureBuf[1], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
 }
@@ -417,9 +424,24 @@
             memcpy(pReplyData,
                    pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
                    pContext->mCaptureSize);
+            // if audio framework has stopped playing audio although the effect is still
+            // active we must clear the capture buffer to return silence
+            if (pContext->mLastBuf == pContext->mCurrentBuf) {
+                if (pContext->mStallCount < MAX_STALL_COUNT) {
+                    if (++pContext->mStallCount == MAX_STALL_COUNT) {
+                        memset(pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
+                                0x80,
+                                pContext->mCaptureSize);
+                    }
+                }
+            } else {
+                pContext->mStallCount = 0;
+            }
+            pContext->mLastBuf = pContext->mCurrentBuf;
         } else {
             memset(pReplyData, 0x80, pContext->mCaptureSize);
         }
+
         break;
 
     default:
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 1e24599..1ebf0a8 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1136,6 +1136,41 @@
             break;
         }
 
+        // @xyz
+        case FOURCC('\xA9', 'x', 'y', 'z'):
+        {
+            // Best case the total data length inside "@xyz" box
+            // would be 8, for instance "@xyz" + "\x00\x04\x15\xc7" + "0+0/",
+            // where "\x00\x04" is the text string length with value = 4,
+            // "\0x15\xc7" is the language code = en, and "0+0" is a
+            // location (string) value with longitude = 0 and latitude = 0.
+            if (chunk_data_size < 8) {
+                return ERROR_MALFORMED;
+            }
+
+            // Worst case the location string length would be 18,
+            // for instance +90.0000-180.0000, without the trailing "/" and
+            // the string length + language code.
+            char buffer[18];
+
+            // Substracting 5 from the data size is because the text string length +
+            // language code takes 4 bytes, and the trailing slash "/" takes 1 byte.
+            off64_t location_length = chunk_data_size - 5;
+            if (location_length >= (off64_t) sizeof(buffer)) {
+                return ERROR_MALFORMED;
+            }
+
+            if (mDataSource->readAt(
+                        data_offset + 4, buffer, location_length) < location_length) {
+                return ERROR_IO;
+            }
+
+            buffer[location_length] = '\0';
+            mFileMetaData->setCString(kKeyLocation, buffer);
+            *offset += chunk_size;
+            break;
+        }
+
         case FOURCC('e', 's', 'd', 's'):
         {
             if (chunk_data_size < 4) {
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index c74cb5a..4491c97 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -418,6 +418,7 @@
         { kKeyYear, METADATA_KEY_YEAR },
         { kKeyWriter, METADATA_KEY_WRITER },
         { kKeyCompilation, METADATA_KEY_COMPILATION },
+        { kKeyLocation, METADATA_KEY_LOCATION },
     };
     static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
 
diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp
index 47de4e09..cd374e2 100644
--- a/media/libstagefright/rtsp/ARTPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTPConnection.cpp
@@ -220,7 +220,7 @@
     }
 
     if (it == mStreams.end()) {
-        TRESPASS();
+        return;
     }
 
     mStreams.erase(it);
@@ -274,41 +274,52 @@
     }
 
     int res = select(maxSocket + 1, &rs, NULL, NULL, &tv);
-    CHECK_GE(res, 0);
 
     if (res > 0) {
-        for (List<StreamInfo>::iterator it = mStreams.begin();
-             it != mStreams.end(); ++it) {
+        List<StreamInfo>::iterator it = mStreams.begin();
+        while (it != mStreams.end()) {
             if ((*it).mIsInjected) {
+                ++it;
                 continue;
             }
 
+            status_t err = OK;
             if (FD_ISSET(it->mRTPSocket, &rs)) {
-                receive(&*it, true);
+                err = receive(&*it, true);
             }
-            if (FD_ISSET(it->mRTCPSocket, &rs)) {
-                receive(&*it, false);
+            if (err == OK && FD_ISSET(it->mRTCPSocket, &rs)) {
+                err = receive(&*it, false);
             }
+
+            if (err == -ECONNRESET) {
+                // socket failure, this stream is dead, Jim.
+
+                LOGW("failed to receive RTP/RTCP datagram.");
+                it = mStreams.erase(it);
+                continue;
+            }
+
+            ++it;
         }
     }
 
-    postPollEvent();
-
     int64_t nowUs = ALooper::GetNowUs();
     if (mLastReceiverReportTimeUs <= 0
             || mLastReceiverReportTimeUs + 5000000ll <= nowUs) {
         sp<ABuffer> buffer = new ABuffer(kMaxUDPSize);
-        for (List<StreamInfo>::iterator it = mStreams.begin();
-             it != mStreams.end(); ++it) {
+        List<StreamInfo>::iterator it = mStreams.begin();
+        while (it != mStreams.end()) {
             StreamInfo *s = &*it;
 
             if (s->mIsInjected) {
+                ++it;
                 continue;
             }
 
             if (s->mNumRTCPPacketsReceived == 0) {
                 // We have never received any RTCP packets on this stream,
                 // we don't even know where to send a report.
+                ++it;
                 continue;
             }
 
@@ -327,16 +338,34 @@
             if (buffer->size() > 0) {
                 LOGV("Sending RR...");
 
-                ssize_t n = sendto(
+                ssize_t n;
+                do {
+                    n = sendto(
                         s->mRTCPSocket, buffer->data(), buffer->size(), 0,
                         (const struct sockaddr *)&s->mRemoteRTCPAddr,
                         sizeof(s->mRemoteRTCPAddr));
+                } while (n < 0 && errno == EINTR);
+
+                if (n <= 0) {
+                    LOGW("failed to send RTCP receiver report (%s).",
+                         n == 0 ? "connection gone" : strerror(errno));
+
+                    it = mStreams.erase(it);
+                    continue;
+                }
+
                 CHECK_EQ(n, (ssize_t)buffer->size());
 
                 mLastReceiverReportTimeUs = nowUs;
             }
+
+            ++it;
         }
     }
+
+    if (!mStreams.empty()) {
+        postPollEvent();
+    }
 }
 
 status_t ARTPConnection::receive(StreamInfo *s, bool receiveRTP) {
@@ -350,16 +379,19 @@
         (!receiveRTP && s->mNumRTCPPacketsReceived == 0)
             ? sizeof(s->mRemoteRTCPAddr) : 0;
 
-    ssize_t nbytes = recvfrom(
+    ssize_t nbytes;
+    do {
+        nbytes = recvfrom(
             receiveRTP ? s->mRTPSocket : s->mRTCPSocket,
             buffer->data(),
             buffer->capacity(),
             0,
             remoteAddrLen > 0 ? (struct sockaddr *)&s->mRemoteRTCPAddr : NULL,
             remoteAddrLen > 0 ? &remoteAddrLen : NULL);
+    } while (nbytes < 0 && errno == EINTR);
 
-    if (nbytes < 0) {
-        return -1;
+    if (nbytes <= 0) {
+        return -ECONNRESET;
     }
 
     buffer->setRange(0, nbytes);
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index bd0e491..4f0363b 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -187,10 +187,13 @@
     return true;
 }
 
-static void MakeSocketBlocking(int s, bool blocking) {
+static status_t MakeSocketBlocking(int s, bool blocking) {
     // Make socket non-blocking.
     int flags = fcntl(s, F_GETFL, 0);
-    CHECK_NE(flags, -1);
+
+    if (flags == -1) {
+        return UNKNOWN_ERROR;
+    }
 
     if (blocking) {
         flags &= ~O_NONBLOCK;
@@ -198,7 +201,9 @@
         flags |= O_NONBLOCK;
     }
 
-    CHECK_NE(fcntl(s, F_SETFL, flags), -1);
+    flags = fcntl(s, F_SETFL, flags);
+
+    return flags == -1 ? UNKNOWN_ERROR : OK;
 }
 
 void ARTSPConnection::onConnect(const sp<AMessage> &msg) {
@@ -302,27 +307,32 @@
     reply->post();
 }
 
+void ARTSPConnection::performDisconnect() {
+    if (mUIDValid) {
+        HTTPBase::UnRegisterSocketUserTag(mSocket);
+    }
+    close(mSocket);
+    mSocket = -1;
+
+    flushPendingRequests();
+
+    mUser.clear();
+    mPass.clear();
+    mAuthType = NONE;
+    mNonce.clear();
+
+    mState = DISCONNECTED;
+}
+
 void ARTSPConnection::onDisconnect(const sp<AMessage> &msg) {
     if (mState == CONNECTED || mState == CONNECTING) {
-        if (mUIDValid) {
-            HTTPBase::UnRegisterSocketUserTag(mSocket);
-        }
-        close(mSocket);
-        mSocket = -1;
-
-        flushPendingRequests();
+        performDisconnect();
     }
 
     sp<AMessage> reply;
     CHECK(msg->findMessage("reply", &reply));
 
     reply->setInt32("result", OK);
-    mState = DISCONNECTED;
-
-    mUser.clear();
-    mPass.clear();
-    mAuthType = NONE;
-    mNonce.clear();
 
     reply->post();
 }
@@ -427,21 +437,25 @@
             send(mSocket, request.c_str() + numBytesSent,
                  request.size() - numBytesSent, 0);
 
-        if (n == 0) {
-            // Server closed the connection.
-            LOGE("Server unexpectedly closed the connection.");
+        if (n < 0 && errno == EINTR) {
+            continue;
+        }
 
-            reply->setInt32("result", ERROR_IO);
-            reply->post();
-            return;
-        } else if (n < 0) {
-            if (errno == EINTR) {
-                continue;
+        if (n <= 0) {
+            performDisconnect();
+
+            if (n == 0) {
+                // Server closed the connection.
+                LOGE("Server unexpectedly closed the connection.");
+
+                reply->setInt32("result", ERROR_IO);
+                reply->post();
+            } else {
+                LOGE("Error sending rtsp request. (%s)", strerror(errno));
+                reply->setInt32("result", -errno);
+                reply->post();
             }
 
-            LOGE("Error sending rtsp request.");
-            reply->setInt32("result", -errno);
-            reply->post();
             return;
         }
 
@@ -512,17 +526,22 @@
     size_t offset = 0;
     while (offset < size) {
         ssize_t n = recv(mSocket, (uint8_t *)data + offset, size - offset, 0);
-        if (n == 0) {
-            // Server closed the connection.
-            LOGE("Server unexpectedly closed the connection.");
-            return ERROR_IO;
-        } else if (n < 0) {
-            if (errno == EINTR) {
-                continue;
-            }
 
-            LOGE("Error reading rtsp response.");
-            return -errno;
+        if (n < 0 && errno == EINTR) {
+            continue;
+        }
+
+        if (n <= 0) {
+            performDisconnect();
+
+            if (n == 0) {
+                // Server closed the connection.
+                LOGE("Server unexpectedly closed the connection.");
+                return ERROR_IO;
+            } else {
+                LOGE("Error reading rtsp response. (%s)", strerror(errno));
+                return -errno;
+            }
         }
 
         offset += (size_t)n;
@@ -681,24 +700,8 @@
     if (contentLength > 0) {
         response->mContent = new ABuffer(contentLength);
 
-        size_t numBytesRead = 0;
-        while (numBytesRead < contentLength) {
-            ssize_t n = recv(
-                    mSocket, response->mContent->data() + numBytesRead,
-                    contentLength - numBytesRead, 0);
-
-            if (n == 0) {
-                // Server closed the connection.
-                TRESPASS();
-            } else if (n < 0) {
-                if (errno == EINTR) {
-                    continue;
-                }
-
-                TRESPASS();
-            }
-
-            numBytesRead += (size_t)n;
+        if (receive(response->mContent->data(), contentLength) != OK) {
+            return false;
         }
     }
 
@@ -765,17 +768,20 @@
             send(mSocket, response.c_str() + numBytesSent,
                  response.size() - numBytesSent, 0);
 
-        if (n == 0) {
-            // Server closed the connection.
-            LOGE("Server unexpectedly closed the connection.");
+        if (n < 0 && errno == EINTR) {
+            continue;
+        }
 
-            return false;
-        } else if (n < 0) {
-            if (errno == EINTR) {
-                continue;
+        if (n <= 0) {
+            if (n == 0) {
+                // Server closed the connection.
+                LOGE("Server unexpectedly closed the connection.");
+            } else {
+                LOGE("Error sending rtsp response (%s).", strerror(errno));
             }
 
-            LOGE("Error sending rtsp response.");
+            performDisconnect();
+
             return false;
         }
 
diff --git a/media/libstagefright/rtsp/ARTSPConnection.h b/media/libstagefright/rtsp/ARTSPConnection.h
index 5cb84fd..68f2d59 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.h
+++ b/media/libstagefright/rtsp/ARTSPConnection.h
@@ -91,6 +91,8 @@
 
     AString mUserAgent;
 
+    void performDisconnect();
+
     void onConnect(const sp<AMessage> &msg);
     void onDisconnect(const sp<AMessage> &msg);
     void onCompleteConnection(const sp<AMessage> &msg);
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 6a5efa4..794c60b 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -463,8 +463,17 @@
                                 mBaseURL = tmp;
                             }
 
-                            CHECK_GT(mSessionDesc->countTracks(), 1u);
-                            setupTrack(1);
+                            if (mSessionDesc->countTracks() < 2) {
+                                // There's no actual tracks in this session.
+                                // The first "track" is merely session meta
+                                // data.
+
+                                LOGW("Session doesn't contain any playable "
+                                     "tracks. Aborting.");
+                                result = ERROR_UNSUPPORTED;
+                            } else {
+                                setupTrack(1);
+                            }
                         }
                     }
                 }
@@ -783,9 +792,13 @@
                 }
 
                 if (mNumAccessUnitsReceived == 0) {
+#if 1
                     LOGI("stream ended? aborting.");
                     (new AMessage('abor', id()))->post();
                     break;
+#else
+                    LOGI("haven't seen an AU in a looong time.");
+#endif
                 }
 
                 mNumAccessUnitsReceived = 0;
diff --git a/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
index 99cbb86..62213de 100644
--- a/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
+++ b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
@@ -16,8 +16,7 @@
 
 package com.android.nfc_extras;
 
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
+import android.content.Context;
 import android.nfc.INfcAdapterExtras;
 import android.nfc.NfcAdapter;
 import android.os.RemoteException;
@@ -60,10 +59,14 @@
     // best effort recovery
     private static NfcAdapter sAdapter;
     private static INfcAdapterExtras sService;
-    private static NfcAdapterExtras sSingleton;
-    private static NfcExecutionEnvironment sEmbeddedEe;
-    private static CardEmulationRoute sRouteOff;
-    private static CardEmulationRoute sRouteOnWhenScreenOn;
+    private static final CardEmulationRoute ROUTE_OFF =
+            new CardEmulationRoute(CardEmulationRoute.ROUTE_OFF, null);
+
+    private final NfcExecutionEnvironment mEmbeddedEe;
+    private final CardEmulationRoute mRouteOnWhenScreenOn;
+
+    final Context mContext;
+    final String mPackageName;
 
     /** get service handles */
     private static void initService() {
@@ -84,31 +87,35 @@
      * @return the {@link NfcAdapterExtras} object for the given {@link NfcAdapter}
      */
     public static NfcAdapterExtras get(NfcAdapter adapter) {
-        synchronized(NfcAdapterExtras.class) {
-            if (sSingleton == null) {
+        Context context = adapter.getContext();
+        if (context == null) {
+            throw new UnsupportedOperationException(
+                    "You must pass a context to your NfcAdapter to use the NFC extras APIs");
+        }
+
+        synchronized (NfcAdapterExtras.class) {
+            if (sService == null) {
                 try {
                     sAdapter = adapter;
-                    sSingleton = new NfcAdapterExtras();
-                    sEmbeddedEe = new NfcExecutionEnvironment(sSingleton);
-                    sRouteOff = new CardEmulationRoute(CardEmulationRoute.ROUTE_OFF, null);
-                    sRouteOnWhenScreenOn = new CardEmulationRoute(
-                            CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON, sEmbeddedEe);
                     initService();
                 } finally {
                     if (sService == null) {
-                        sRouteOnWhenScreenOn = null;
-                        sRouteOff = null;
-                        sEmbeddedEe = null;
-                        sSingleton = null;
                         sAdapter = null;
                     }
                 }
             }
-            return sSingleton;
         }
+
+        return new NfcAdapterExtras(context);
     }
 
-    private NfcAdapterExtras() {}
+    private NfcAdapterExtras(Context context) {
+        mContext = context.getApplicationContext();
+        mPackageName = context.getPackageName();
+        mEmbeddedEe = new NfcExecutionEnvironment(this);
+        mRouteOnWhenScreenOn = new CardEmulationRoute(CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON,
+                mEmbeddedEe);
+    }
 
     /**
      * Immutable data class that describes a card emulation route.
@@ -166,18 +173,16 @@
      *
      * <p class="note">
      * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
-     *
-     * @return
      */
     public CardEmulationRoute getCardEmulationRoute() {
         try {
-            int route = sService.getCardEmulationRoute();
+            int route = sService.getCardEmulationRoute(mPackageName);
             return route == CardEmulationRoute.ROUTE_OFF ?
-                    sRouteOff :
-                    sRouteOnWhenScreenOn;
+                    ROUTE_OFF :
+                    mRouteOnWhenScreenOn;
         } catch (RemoteException e) {
             attemptDeadServiceRecovery(e);
-            return sRouteOff;
+            return ROUTE_OFF;
         }
     }
 
@@ -189,11 +194,11 @@
      * <p class="note">
      * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
      *
-     * @param route a {@link #CardEmulationRoute}
+     * @param route a {@link CardEmulationRoute}
      */
     public void setCardEmulationRoute(CardEmulationRoute route) {
         try {
-            sService.setCardEmulationRoute(route.route);
+            sService.setCardEmulationRoute(mPackageName, route.route);
         } catch (RemoteException e) {
             attemptDeadServiceRecovery(e);
         }
@@ -201,7 +206,7 @@
 
     /**
      * Get the {@link NfcExecutionEnvironment} that is embedded with the
-     * {@link NFcAdapter}.
+     * {@link NfcAdapter}.
      *
      * <p class="note">
      * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
@@ -209,7 +214,7 @@
      * @return a {@link NfcExecutionEnvironment}, or null if there is no embedded NFC-EE
      */
     public NfcExecutionEnvironment getEmbeddedExecutionEnvironment() {
-        return sEmbeddedEe;
+        return mEmbeddedEe;
     }
 
     /**
@@ -218,12 +223,12 @@
      * Some implementations of NFC Adapter Extras may require applications
      * to authenticate with a token, before using other methods.
      *
-     * @param a implementation specific token
-     * @throws a {@link java.lang.SecurityException} if authentication failed
+     * @param token a implementation specific token
+     * @throws java.lang.SecurityException if authentication failed
      */
     public void authenticate(byte[] token) {
         try {
-            sService.authenticate(token);
+            sService.authenticate(mPackageName, token);
         } catch (RemoteException e) {
             attemptDeadServiceRecovery(e);
         }
diff --git a/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java b/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java
index 63c2de2..f47327a 100644
--- a/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java
+++ b/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java
@@ -16,20 +16,17 @@
 
 package com.android.nfc_extras;
 
-import java.io.IOException;
-
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
-import android.content.Context;
-import android.nfc.INfcAdapterExtras;
-import android.nfc.NfcAdapter;
 import android.os.Binder;
 import android.os.Bundle;
-import android.os.IBinder;
 import android.os.RemoteException;
 
+import java.io.IOException;
+
 public class NfcExecutionEnvironment {
     private final NfcAdapterExtras mExtras;
+    private final Binder mToken;
 
     /**
      * Broadcast Action: An ISO-DEP AID was selected.
@@ -115,6 +112,7 @@
 
     NfcExecutionEnvironment(NfcAdapterExtras extras) {
         mExtras = extras;
+        mToken = new Binder();
     }
 
     /**
@@ -133,7 +131,7 @@
      */
     public void open() throws IOException {
         try {
-            Bundle b = mExtras.getService().open(new Binder());
+            Bundle b = mExtras.getService().open(mExtras.mPackageName, mToken);
             throwBundle(b);
         } catch (RemoteException e) {
             mExtras.attemptDeadServiceRecovery(e);
@@ -151,7 +149,7 @@
      */
     public void close() throws IOException {
         try {
-            throwBundle(mExtras.getService().close());
+            throwBundle(mExtras.getService().close(mExtras.mPackageName, mToken));
         } catch (RemoteException e) {
             mExtras.attemptDeadServiceRecovery(e);
             throw new IOException("NFC Service was dead");
@@ -169,7 +167,7 @@
     public byte[] transceive(byte[] in) throws IOException {
         Bundle b;
         try {
-            b = mExtras.getService().transceive(in);
+            b = mExtras.getService().transceive(mExtras.mPackageName, in);
         } catch (RemoteException e) {
             mExtras.attemptDeadServiceRecovery(e);
             throw new IOException("NFC Service was dead, need to re-open");
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notification_open.png b/packages/SystemUI/res/drawable-hdpi/ic_notification_open.png
index d697c2f..cd9a54a 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_notification_open.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notification_open.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notification_open.png b/packages/SystemUI/res/drawable-mdpi/ic_notification_open.png
index 839c134..5661eaf 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_notification_open.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notification_open.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notification_open.png b/packages/SystemUI/res/drawable-xhdpi/ic_notification_open.png
index 4f8c987..98455cf 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notification_open.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_notification_open.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
index 93ac22e..9be9041 100644
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ b/packages/SystemUI/res/layout/signal_cluster_view.xml
@@ -51,7 +51,7 @@
         android:visibility="gone"
         android:id="@+id/spacer"
         />
-    <FrameLayout
+    <!--<FrameLayout
         android:id="@+id/wimax_combo"
         android:layout_height="wrap_content"
         android:layout_width="wrap_content"
@@ -72,6 +72,7 @@
             android:layout_gravity="center|bottom"
             />
     </FrameLayout>
+    -->
     <FrameLayout
         android:layout_height="wrap_content"
         android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index a0d7b13..fc81f8e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -257,10 +257,16 @@
     <string name="accessibility_wifi_three_bars">Wi-Fi three bars.</string>
     <!-- Content description of the WIFI signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_wifi_signal_full">WiFi signal full.</string>
+
+    <!-- Content description of the WiMAX signal when no signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_no_wimax">No WiMAX.</string>
+    <!-- Content description of the WiMAX signal when it is one bar for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_wimax_one_bar">WiMAX one bar.</string>
+    <!-- Content description of the WiMAX signal when it is two bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_wimax_two_bars">WiMAX two bars.</string>
+    <!-- Content description of the WiMAX signal when it is three bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_wimax_three_bars">WiMAX three bars.</string>
+    <!-- Content description of the WiMAX signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_wimax_signal_full">WiMAX signal full.</string>
 
     <!-- Content description of the data connection type GPRS for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
index 2e1803e..2be35b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
@@ -118,15 +118,20 @@
                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                     | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
                     | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
-                PixelFormat.OPAQUE);
+                // We use a pixel format of RGB565 for the status bar to save memory bandwidth and
+                // to ensure that the layer can be handled by HWComposer.  On some devices the
+                // HWComposer is unable to handle SW-rendered RGBX_8888 layers.
+                PixelFormat.RGB_565);
         
         // the status bar should be in an overlay if possible
         final Display defaultDisplay 
             = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
                 .getDefaultDisplay();
-        if (ActivityManager.isHighEndGfx(defaultDisplay)) {
-            lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
-        }
+
+        // We explicitly leave FLAG_HARDWARE_ACCELERATED out of the flags.  The status bar occupies
+        // very little screen real-estate and is updated fairly frequently.  By using CPU rendering
+        // for the status bar, we prevent the GPU from having to wake up just to do these small
+        // updates, which should help keep power consumption down.
 
         lp.gravity = getStatusBarGravity();
         lp.setTitle("StatusBar");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index b0e6968..51fb262 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -350,11 +350,11 @@
                 (SignalClusterView)sb.findViewById(R.id.signal_cluster);
         mNetworkController.addSignalCluster(signalCluster);
         signalCluster.setNetworkController(mNetworkController);
-	final ImageView wimaxRSSI = 
-                (ImageView)sb.findViewById(R.id.wimax_signal);
-        if (wimaxRSSI != null) {
-            mNetworkController.addWimaxIconView(wimaxRSSI);
-        }
+//        final ImageView wimaxRSSI = 
+//                (ImageView)sb.findViewById(R.id.wimax_signal);
+//        if (wimaxRSSI != null) {
+//            mNetworkController.addWimaxIconView(wimaxRSSI);
+//        }
         // Recents Panel
         mRecentTasksLoader = new RecentTasksLoader(context);
         updateRecentsPanel();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index f77e93f..55a5b0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -111,6 +111,7 @@
         com.android.internal.R.drawable.stat_sys_tether_bluetooth;
 
     //wimax
+    private boolean mWimaxSupported = false;
     private boolean mIsWimaxEnabled = false;
     private boolean mWimaxConnected = false;
     private boolean mWimaxIdle = false;
@@ -213,9 +214,9 @@
         filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
         filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
         filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-        boolean isWimaxConfigEnabled = mContext.getResources().getBoolean(
+        mWimaxSupported = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_wimaxEnabled);
-        if(isWimaxConfigEnabled) {
+        if(mWimaxSupported) {
             filter.addAction(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION);
             filter.addAction(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION);
             filter.addAction(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION);
@@ -262,19 +263,36 @@
 
     public void addSignalCluster(SignalCluster cluster) {
         mSignalClusters.add(cluster);
+        refreshSignalCluster(cluster);
+    }
+
+    public void refreshSignalCluster(SignalCluster cluster) {
         cluster.setWifiIndicators(
                 mWifiConnected, // only show wifi in the cluster if connected
                 mWifiIconId,
                 mWifiActivityIconId,
                 mContentDescriptionWifi);
-        cluster.setMobileDataIndicators(
-                mHasMobileDataFeature,
-                mShowPhoneRSSIForData ? mPhoneSignalIconId : mDataSignalIconId,
-                mMobileActivityIconId,
-                mDataTypeIconId,
-                mContentDescriptionPhoneSignal,
-                mContentDescriptionDataType);
 
+        if (mIsWimaxEnabled && mWimaxConnected) {
+            // wimax is special
+            cluster.setMobileDataIndicators(
+                    true,
+                    mWimaxIconId,
+                    mMobileActivityIconId,
+                    mDataTypeIconId,
+                    mContentDescriptionWimax,
+                    mContentDescriptionDataType);
+        } else {
+            // normal mobile data
+            cluster.setMobileDataIndicators(
+                    mHasMobileDataFeature,
+                    mShowPhoneRSSIForData ? mPhoneSignalIconId : mDataSignalIconId,
+                    mMobileActivityIconId,
+                    mDataTypeIconId,
+                    mContentDescriptionPhoneSignal,
+                    mContentDescriptionDataType);
+        }
+        cluster.setIsAirplaneMode(mAirplaneMode);
     }
 
     public void setStackedMode(boolean stacked) {
@@ -311,7 +329,7 @@
         } else if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION) ||
                 action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION) ||
                 action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
-           updateWimaxState(intent);
+            updateWimaxState(intent);
             refreshViews();
         }
     }
@@ -466,91 +484,100 @@
     }
 
     private final void updateDataNetType() {
-        switch (mDataNetType) {
-            case TelephonyManager.NETWORK_TYPE_UNKNOWN:
-                if (!mShowAtLeastThreeGees) {
-                    mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
-                    mDataTypeIconId = 0;
-                    mContentDescriptionDataType = mContext.getString(
-                            R.string.accessibility_data_connection_gprs);
-                    break;
-                } else {
-                    // fall through
-                }
-            case TelephonyManager.NETWORK_TYPE_EDGE:
-                if (!mShowAtLeastThreeGees) {
-                    mDataIconList = TelephonyIcons.DATA_E[mInetCondition];
-                    mDataTypeIconId = R.drawable.stat_sys_data_connected_e;
-                    mContentDescriptionDataType = mContext.getString(
-                            R.string.accessibility_data_connection_edge);
-                    break;
-                } else {
-                    // fall through
-                }
-            case TelephonyManager.NETWORK_TYPE_UMTS:
-                mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
-                mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
-                mContentDescriptionDataType = mContext.getString(
-                        R.string.accessibility_data_connection_3g);
-                break;
-            case TelephonyManager.NETWORK_TYPE_HSDPA:
-            case TelephonyManager.NETWORK_TYPE_HSUPA:
-            case TelephonyManager.NETWORK_TYPE_HSPA:
-            case TelephonyManager.NETWORK_TYPE_HSPAP:
-                if (mHspaDataDistinguishable) {
-                    mDataIconList = TelephonyIcons.DATA_H[mInetCondition];
-                    mDataTypeIconId = R.drawable.stat_sys_data_connected_h;
-                    mContentDescriptionDataType = mContext.getString(
-                            R.string.accessibility_data_connection_3_5g);
-                } else {
+        if (mIsWimaxEnabled && mWimaxConnected) {
+            // wimax is a special 4g network not handled by telephony
+            mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
+            mDataTypeIconId = R.drawable.stat_sys_data_connected_4g;
+            mContentDescriptionDataType = mContext.getString(
+                    R.string.accessibility_data_connection_4g);
+        } else {
+            switch (mDataNetType) {
+                case TelephonyManager.NETWORK_TYPE_UNKNOWN:
+                    if (!mShowAtLeastThreeGees) {
+                        mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
+                        mDataTypeIconId = 0;
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_gprs);
+                        break;
+                    } else {
+                        // fall through
+                    }
+                case TelephonyManager.NETWORK_TYPE_EDGE:
+                    if (!mShowAtLeastThreeGees) {
+                        mDataIconList = TelephonyIcons.DATA_E[mInetCondition];
+                        mDataTypeIconId = R.drawable.stat_sys_data_connected_e;
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_edge);
+                        break;
+                    } else {
+                        // fall through
+                    }
+                case TelephonyManager.NETWORK_TYPE_UMTS:
                     mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
                     mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
                     mContentDescriptionDataType = mContext.getString(
                             R.string.accessibility_data_connection_3g);
-                }
-                break;
-            case TelephonyManager.NETWORK_TYPE_CDMA:
-                // display 1xRTT for IS95A/B
-                mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
-                mDataTypeIconId = R.drawable.stat_sys_data_connected_1x;
-                mContentDescriptionDataType = mContext.getString(
-                        R.string.accessibility_data_connection_cdma);
-                break;
-            case TelephonyManager.NETWORK_TYPE_1xRTT:
-                mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
-                mDataTypeIconId = R.drawable.stat_sys_data_connected_1x;
-                mContentDescriptionDataType = mContext.getString(
-                        R.string.accessibility_data_connection_cdma);
-                break;
-            case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
-            case TelephonyManager.NETWORK_TYPE_EVDO_A:
-            case TelephonyManager.NETWORK_TYPE_EVDO_B:
-            case TelephonyManager.NETWORK_TYPE_EHRPD:
-                mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
-                mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
-                mContentDescriptionDataType = mContext.getString(
-                        R.string.accessibility_data_connection_3g);
-                break;
-            case TelephonyManager.NETWORK_TYPE_LTE:
-                mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
-                mDataTypeIconId = R.drawable.stat_sys_data_connected_4g;
-                mContentDescriptionDataType = mContext.getString(
-                        R.string.accessibility_data_connection_4g);
-                break;
-            default:
-                if (!mShowAtLeastThreeGees) {
-                    mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
-                    mDataTypeIconId = R.drawable.stat_sys_data_connected_g;
+                    break;
+                case TelephonyManager.NETWORK_TYPE_HSDPA:
+                case TelephonyManager.NETWORK_TYPE_HSUPA:
+                case TelephonyManager.NETWORK_TYPE_HSPA:
+                case TelephonyManager.NETWORK_TYPE_HSPAP:
+                    if (mHspaDataDistinguishable) {
+                        mDataIconList = TelephonyIcons.DATA_H[mInetCondition];
+                        mDataTypeIconId = R.drawable.stat_sys_data_connected_h;
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_3_5g);
+                    } else {
+                        mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
+                        mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_3g);
+                    }
+                    break;
+                case TelephonyManager.NETWORK_TYPE_CDMA:
+                    // display 1xRTT for IS95A/B
+                    mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
+                    mDataTypeIconId = R.drawable.stat_sys_data_connected_1x;
                     mContentDescriptionDataType = mContext.getString(
-                            R.string.accessibility_data_connection_gprs);
-                } else {
+                            R.string.accessibility_data_connection_cdma);
+                    break;
+                case TelephonyManager.NETWORK_TYPE_1xRTT:
+                    mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
+                    mDataTypeIconId = R.drawable.stat_sys_data_connected_1x;
+                    mContentDescriptionDataType = mContext.getString(
+                            R.string.accessibility_data_connection_cdma);
+                    break;
+                case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
+                case TelephonyManager.NETWORK_TYPE_EVDO_A:
+                case TelephonyManager.NETWORK_TYPE_EVDO_B:
+                case TelephonyManager.NETWORK_TYPE_EHRPD:
                     mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
                     mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
                     mContentDescriptionDataType = mContext.getString(
                             R.string.accessibility_data_connection_3g);
-                }
-                break;
+                    break;
+                case TelephonyManager.NETWORK_TYPE_LTE:
+                    mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
+                    mDataTypeIconId = R.drawable.stat_sys_data_connected_4g;
+                    mContentDescriptionDataType = mContext.getString(
+                            R.string.accessibility_data_connection_4g);
+                    break;
+                default:
+                    if (!mShowAtLeastThreeGees) {
+                        mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
+                        mDataTypeIconId = R.drawable.stat_sys_data_connected_g;
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_gprs);
+                    } else {
+                        mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
+                        mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_3g);
+                    }
+                    break;
+            }
         }
+
         if ((isCdma() && isCdmaEri()) || mPhone.isNetworkRoaming()) {
             mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
         }
@@ -763,8 +790,7 @@
     }
 
 
- // ===== Wimax ===================================================================
-
+    // ===== Wimax ===================================================================
     private final void updateWimaxState(Intent intent) {
         final String action = intent.getAction();
         boolean wasConnected = mWimaxConnected;
@@ -772,42 +798,41 @@
             int wimaxStatus = intent.getIntExtra(WimaxManagerConstants.EXTRA_4G_STATE,
                     WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
             mIsWimaxEnabled = (wimaxStatus ==
-		WimaxManagerConstants.NET_4G_STATE_ENABLED)? true : false;
+                    WimaxManagerConstants.NET_4G_STATE_ENABLED);
         } else if (action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION)) {
             mWimaxSignal = intent.getIntExtra(WimaxManagerConstants.EXTRA_NEW_SIGNAL_LEVEL, 0);
         } else if (action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
-		mWimaxState = intent.getIntExtra(WimaxManagerConstants.EXTRA_WIMAX_STATE,
+            mWimaxState = intent.getIntExtra(WimaxManagerConstants.EXTRA_WIMAX_STATE,
                     WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
             mWimaxExtraState = intent.getIntExtra(
                     WimaxManagerConstants.EXTRA_WIMAX_STATE_DETAIL,
                     WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
             mWimaxConnected = (mWimaxState ==
-		WimaxManagerConstants.WIMAX_STATE_CONNECTED) ? true : false;
-            mWimaxIdle = (mWimaxExtraState == WimaxManagerConstants.WIMAX_IDLE)? true : false;
+                    WimaxManagerConstants.WIMAX_STATE_CONNECTED);
+            mWimaxIdle = (mWimaxExtraState == WimaxManagerConstants.WIMAX_IDLE);
         }
+        updateDataNetType();
         updateWimaxIcons();
     }
-       private void updateWimaxIcons() {
-            Slog.d(TAG, "in ....  updateWimaxIcons function    :  "+mIsWimaxEnabled);
-                if (mIsWimaxEnabled) {
-                        if (mWimaxConnected) {
-                                Slog.d(TAG, "in ....  updateWimaxIcons function WiMAX COnnected");
-                                if (mWimaxIdle)
-                                        mWimaxIconId = WimaxIcons.WIMAX_IDLE;
-                                else
-                                        mWimaxIconId = WimaxIcons.WIMAX_SIGNAL_STRENGTH[mInetCondition][mWimaxSignal];
-                                mContentDescriptionWimax = mContext.getString(
-                                                AccessibilityContentDescriptions.WIMAX_CONNECTION_STRENGTH[mWimaxSignal]);
-                        } else {
-                                 Slog.d(TAG, "in ....  updateWimaxIcons function WiMAX Disconnected");
-                                mWimaxIconId = WimaxIcons.WIMAX_DISCONNECTED;
-                                mContentDescriptionWimax = mContext.getString(R.string.accessibility_no_wimax);
-                        }
-                } else {
-                         Slog.d(TAG, "in ....  updateWimaxIcons function wimax icon id 0");
-                        mWimaxIconId = 0;
-                }
+
+    private void updateWimaxIcons() {
+        if (mIsWimaxEnabled) {
+            if (mWimaxConnected) {
+                if (mWimaxIdle)
+                    mWimaxIconId = WimaxIcons.WIMAX_IDLE;
+                else
+                    mWimaxIconId = WimaxIcons.WIMAX_SIGNAL_STRENGTH[mInetCondition][mWimaxSignal];
+                mContentDescriptionWimax = mContext.getString(
+                        AccessibilityContentDescriptions.WIMAX_CONNECTION_STRENGTH[mWimaxSignal]);
+            } else {
+                mWimaxIconId = WimaxIcons.WIMAX_DISCONNECTED;
+                mContentDescriptionWimax = mContext.getString(R.string.accessibility_no_wimax);
+            }
+        } else {
+            mWimaxIconId = 0;
         }
+    }
+
     // ===== Full or limited Internet connectivity ==================================
 
     private void updateConnectivity(Intent intent) {
@@ -827,14 +852,14 @@
         mInetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
 
         if (info != null && info.getType() == ConnectivityManager.TYPE_BLUETOOTH) {
-            mBluetoothTethered = info.isConnected() ? true: false;
+            mBluetoothTethered = info.isConnected();
         } else {
             mBluetoothTethered = false;
         }
 
         // We want to update all the icons, all at once, for any condition change
         updateDataNetType();
-		updateWimaxIcons();
+        updateWimaxIcons();
         updateDataIcon();
         updateTelephonySignalStrength();
         updateWifiIcons();
@@ -921,7 +946,7 @@
 
             combinedSignalIconId = mDataSignalIconId;
         }
-        else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered) {
+        else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered && !mWimaxConnected) {
             // pretty much totally disconnected
 
             label = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
@@ -961,23 +986,12 @@
         if (mLastPhoneSignalIconId          != mPhoneSignalIconId
          || mLastDataDirectionOverlayIconId != combinedActivityIconId
          || mLastWifiIconId                 != mWifiIconId
+         || mLastWimaxIconId                != mWimaxIconId
          || mLastDataTypeIconId             != mDataTypeIconId)
         {
             // NB: the mLast*s will be updated later
             for (SignalCluster cluster : mSignalClusters) {
-                cluster.setWifiIndicators(
-                        mWifiConnected, // only show wifi in the cluster if connected
-                        mWifiIconId,
-                        mWifiActivityIconId,
-                        mContentDescriptionWifi);
-                cluster.setMobileDataIndicators(
-                        mHasMobileDataFeature,
-                        mShowPhoneRSSIForData ? mPhoneSignalIconId : mDataSignalIconId,
-                        mMobileActivityIconId,
-                        mDataTypeIconId,
-                        mContentDescriptionPhoneSignal,
-                        mContentDescriptionDataType);
-                cluster.setIsAirplaneMode(mAirplaneMode);
+                refreshSignalCluster(cluster);
             }
         }
 
@@ -1152,11 +1166,22 @@
         pw.println(mWifiLevel);
         pw.print("  mWifiSsid=");
         pw.println(mWifiSsid);
-        pw.print(String.format("  mWifiIconId=0x%08x/%s",
+        pw.println(String.format("  mWifiIconId=0x%08x/%s",
                     mWifiIconId, getResourceName(mWifiIconId)));
         pw.print("  mWifiActivity=");
         pw.println(mWifiActivity);
 
+        if (mWimaxSupported) {
+            pw.println("  - wimax ------");
+            pw.print("  mIsWimaxEnabled="); pw.println(mIsWimaxEnabled);
+            pw.print("  mWimaxConnected="); pw.println(mWimaxConnected);
+            pw.print("  mWimaxIdle="); pw.println(mWimaxIdle);
+            pw.println(String.format("  mWimaxIconId=0x%08x/%s",
+                        mWimaxIconId, getResourceName(mWimaxIconId)));
+            pw.println(String.format("  mWimaxSignal=%d", mWimaxSignal));
+            pw.println(String.format("  mWimaxState=%d", mWimaxState));
+            pw.println(String.format("  mWimaxExtraState=%d", mWimaxExtraState));
+        }
 
         pw.println("  - Bluetooth ----");
         pw.print("  mBtReverseTethered=");
@@ -1190,7 +1215,7 @@
         pw.print("  mLastDataTypeIconId=0x");
         pw.print(Integer.toHexString(mLastDataTypeIconId));
         pw.print("/");
-        pw.println(getResourceName(mLastCombinedSignalIconId));
+        pw.println(getResourceName(mLastDataTypeIconId));
         pw.print("  mLastLabel=");
         pw.print(mLastLabel);
         pw.println("");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WimaxIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WimaxIcons.java
index 8605489..d3d4338 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WimaxIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WimaxIcons.java
@@ -1,5 +1,5 @@
 /*

- * Copyright (C) 2008 The Android Open Source Project

+ * Copyright (C) 2011 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.

@@ -16,22 +16,13 @@
 

 package com.android.systemui.statusbar.policy;

 

+import com.android.systemui.statusbar.policy.TelephonyIcons;

 import com.android.systemui.R;

 

 class WimaxIcons {

-    static final int[][] WIMAX_SIGNAL_STRENGTH = {

-	{ R.drawable.stat_sys_data_wimax_signal_0,

-            R.drawable.stat_sys_data_wimax_signal_1,

-            R.drawable.stat_sys_data_wimax_signal_2,

-            R.drawable.stat_sys_data_wimax_signal_3 },

-          { R.drawable.stat_sys_data_wimax_signal_0_fully,

-            R.drawable.stat_sys_data_wimax_signal_1_fully,

-            R.drawable.stat_sys_data_wimax_signal_2_fully,

-            R.drawable.stat_sys_data_wimax_signal_3_fully }

-        };

+    static final int[][] WIMAX_SIGNAL_STRENGTH = TelephonyIcons.DATA_SIGNAL_STRENGTH;

 

-    static final int WIMAX_DISCONNECTED =

-            R.drawable.stat_sys_data_wimax_signal_disconnected;

-    static final int WIMAX_IDLE = R.drawable.stat_sys_data_wimax_signal_idle;

-    static final int WIFI_LEVEL_COUNT = WIMAX_SIGNAL_STRENGTH[0].length;

+    static final int WIMAX_DISCONNECTED = WIMAX_SIGNAL_STRENGTH[0][0];

+

+    static final int WIMAX_IDLE = WIMAX_DISCONNECTED; // XXX: unclear if we need a different icon

 }

diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index ed9ba79..921f331 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -360,6 +360,9 @@
     int mResettingSystemUiFlags = 0;
     // Bits that we are currently always keeping cleared.
     int mForceClearedSystemUiFlags = 0;
+    // What we last reported to system UI about whether the compatibility
+    // menu needs to be displayed.
+    boolean mLastFocusNeedsMenu = false;
 
     FakeWindow mHideNavFakeWindow = null;
 
@@ -370,8 +373,6 @@
     static final Rect mTmpNavigationFrame = new Rect();
     
     WindowState mTopFullscreenOpaqueWindowState;
-    WindowState mTopAppWindowState;
-    WindowState mLastTopAppWindowState;
     boolean mTopIsFullscreen;
     boolean mForceStatusBar;
     boolean mHideLockScreen;
@@ -2250,7 +2251,6 @@
     /** {@inheritDoc} */
     public void beginAnimationLw(int displayWidth, int displayHeight) {
         mTopFullscreenOpaqueWindowState = null;
-        mTopAppWindowState = null;
         mForceStatusBar = false;
         
         mHideLockScreen = false;
@@ -2288,12 +2288,6 @@
                 }
             }
         }
-        if (mTopAppWindowState == null && win.isVisibleOrBehindKeyguardLw()) {
-            if (attrs.type >= FIRST_APPLICATION_WINDOW
-                    && attrs.type <= LAST_APPLICATION_WINDOW) {
-                mTopAppWindowState = win;
-            }
-        }
     }
 
     /** {@inheritDoc} */
@@ -2349,35 +2343,6 @@
 
         mTopIsFullscreen = topIsFullscreen;
 
-        if (mTopAppWindowState != null && mTopAppWindowState != mLastTopAppWindowState) {
-            mLastTopAppWindowState = mTopAppWindowState;
-
-            final boolean topNeedsMenu = (mTopAppWindowState.getAttrs().flags
-                    & WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY) != 0;
-
-            mHandler.post(new Runnable() {
-                    public void run() {
-                        if (mStatusBarService == null) {
-                            // This is the one that can not go away, but it doesn't come up
-                            // before the window manager does, so don't fail if it doesn't
-                            // exist. This works as long as no fullscreen windows come up
-                            // before the status bar service does.
-                            mStatusBarService = IStatusBarService.Stub.asInterface(
-                                    ServiceManager.getService("statusbar"));
-                        }
-                        final IStatusBarService sbs = mStatusBarService;
-                        if (mStatusBarService != null) {
-                            try {
-                                sbs.topAppWindowChanged(topNeedsMenu);
-                            } catch (RemoteException e) {
-                                // This should be impossible because we're in the same process.
-                                mStatusBarService = null;
-                            }
-                        }
-                    }
-                });
-        }
-
         // Hide the key guard if a visible window explicitly specifies that it wants to be displayed
         // when the screen is locked
         if (mKeyguard != null) {
@@ -3711,10 +3676,13 @@
                 & ~mResettingSystemUiFlags
                 & ~mForceClearedSystemUiFlags;
         int diff = visibility ^ mLastSystemUiFlags;
-        if (diff == 0) {
+        final boolean needsMenu = (mFocusedWindow.getAttrs().flags
+                & WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY) != 0;
+        if (diff == 0 && mLastFocusNeedsMenu == needsMenu) {
             return 0;
         }
         mLastSystemUiFlags = visibility;
+        mLastFocusNeedsMenu = needsMenu;
         mHandler.post(new Runnable() {
                 public void run() {
                     if (mStatusBarService == null) {
@@ -3724,6 +3692,7 @@
                     if (mStatusBarService != null) {
                         try {
                             mStatusBarService.setSystemUiVisibility(visibility);
+                            mStatusBarService.topAppWindowChanged(needsMenu);
                         } catch (RemoteException e) {
                             // not much to be done
                             mStatusBarService = null;
@@ -3756,6 +3725,10 @@
                     pw.print(" mForceClearedSystemUiFlags=0x");
                     pw.println(Integer.toHexString(mForceClearedSystemUiFlags));
         }
+        if (mLastFocusNeedsMenu) {
+            pw.print(prefix); pw.print("mLastFocusNeedsMenu=");
+                    pw.println(mLastFocusNeedsMenu);
+        }
         pw.print(prefix); pw.print("mUiMode="); pw.print(mUiMode);
                 pw.print(" mDockMode="); pw.print(mDockMode);
                 pw.print(" mCarDockRotation="); pw.print(mCarDockRotation);
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index ff262f1..780c0d2 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -7028,11 +7028,17 @@
 
 AudioFlinger::EffectChain::EffectChain(const wp<ThreadBase>& wThread,
                                         int sessionId)
-    : mThread(wThread), mSessionId(sessionId), mActiveTrackCnt(0), mTrackCnt(0),
+    : mThread(wThread), mSessionId(sessionId), mActiveTrackCnt(0), mTrackCnt(0), mTailBufferCount(0),
       mOwnInBuffer(false), mVolumeCtrlIdx(-1), mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX),
       mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX)
 {
     mStrategy = AudioSystem::getStrategyForStream(AUDIO_STREAM_MUSIC);
+    sp<ThreadBase> thread = mThread.promote();
+    if (thread == 0) {
+        return;
+    }
+    mMaxTailBuffers = ((kProcessTailDurationMs * thread->sampleRate()) / 1000) /
+                                    thread->frameCount();
 }
 
 AudioFlinger::EffectChain::~EffectChain()
@@ -7100,22 +7106,31 @@
     }
     bool isGlobalSession = (mSessionId == AUDIO_SESSION_OUTPUT_MIX) ||
             (mSessionId == AUDIO_SESSION_OUTPUT_STAGE);
-    bool tracksOnSession = false;
+    // always process effects unless no more tracks are on the session and the effect tail
+    // has been rendered
+    bool doProcess = true;
     if (!isGlobalSession) {
-        tracksOnSession = (trackCnt() != 0);
-    }
+        bool tracksOnSession = (trackCnt() != 0);
 
-    // if no track is active, input buffer must be cleared here as the mixer process
-    // will not do it
-    if (tracksOnSession &&
-            activeTrackCnt() == 0) {
-        size_t numSamples = thread->frameCount() * thread->channelCount();
-        memset(mInBuffer, 0, numSamples * sizeof(int16_t));
+        if (!tracksOnSession && mTailBufferCount == 0) {
+            doProcess = false;
+        }
+
+        if (activeTrackCnt() == 0) {
+            // if no track is active and the effect tail has not been rendered,
+            // the input buffer must be cleared here as the mixer process will not do it
+            if (tracksOnSession || mTailBufferCount > 0) {
+                size_t numSamples = thread->frameCount() * thread->channelCount();
+                memset(mInBuffer, 0, numSamples * sizeof(int16_t));
+                if (mTailBufferCount > 0) {
+                    mTailBufferCount--;
+                }
+            }
+        }
     }
 
     size_t size = mEffects.size();
-    // do not process effect if no track is present in same audio session
-    if (isGlobalSession || tracksOnSession) {
+    if (doProcess) {
         for (size_t i = 0; i < size; i++) {
             mEffects[i]->process();
         }
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 4b794ef..897bc78 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -1247,6 +1247,10 @@
         // corresponding to a suspend all request.
         static const int        kKeyForSuspendAll = 0;
 
+        // minimum duration during which we force calling effect process when last track on
+        // a session is stopped or removed to allow effect tail to be rendered
+        static const int        kProcessTailDurationMs = 1000;
+
         void process_l();
 
         void lock() {
@@ -1287,7 +1291,8 @@
         void decTrackCnt() { android_atomic_dec(&mTrackCnt); }
         int32_t trackCnt() { return mTrackCnt;}
 
-        void incActiveTrackCnt() { android_atomic_inc(&mActiveTrackCnt); }
+        void incActiveTrackCnt() { android_atomic_inc(&mActiveTrackCnt);
+                                   mTailBufferCount = mMaxTailBuffers; }
         void decActiveTrackCnt() { android_atomic_dec(&mActiveTrackCnt); }
         int32_t activeTrackCnt() { return mActiveTrackCnt;}
 
@@ -1338,6 +1343,8 @@
         int16_t *mOutBuffer;        // chain output buffer
         volatile int32_t mActiveTrackCnt;  // number of active tracks connected
         volatile int32_t mTrackCnt;        // number of tracks connected
+        int32_t mTailBufferCount;   // current effect tail buffer count
+        int32_t mMaxTailBuffers;    // maximum effect tail buffers
         bool mOwnInBuffer;          // true if the chain owns its input buffer
         int mVolumeCtrlIdx;         // index of insert effect having control over volume
         uint32_t mLeftVolume;       // previous volume on left channel
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index fc87033..6e4aca7 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -1597,6 +1597,7 @@
                 if (checkType == prevNetType) continue;
                 if (mNetConfigs[checkType] == null) continue;
                 if (!mNetConfigs[checkType].isDefault()) continue;
+                if (mNetTrackers[checkType] == null) continue;
 
 // Enabling the isAvailable() optimization caused mobile to not get
 // selected if it was in the middle of error handling. Specifically
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 05d42ada..cd63090 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1669,7 +1669,7 @@
     final void setFocusedActivityLocked(ActivityRecord r) {
         if (mFocusedActivity != r) {
             mFocusedActivity = r;
-            mWindowManager.setFocusedApp(r, true);
+            mWindowManager.setFocusedApp(r.appToken, true);
         }
     }
 
@@ -2346,7 +2346,8 @@
             // XXX we are not dealing with propagating grantedUriPermissions...
             // those are not yet exposed to user code, so there is no need.
             int res = mMainStack.startActivityLocked(r.app.thread, intent,
-                    r.resolvedType, null, 0, aInfo, resultTo, resultWho,
+                    r.resolvedType, null, 0, aInfo,
+                    resultTo != null ? resultTo.appToken : null, resultWho,
                     requestCode, -1, r.launchedFromUid, false, false, null);
             Binder.restoreCallingIdentity(origId);
 
@@ -2429,10 +2430,10 @@
                 return;
             }
             final long origId = Binder.clearCallingIdentity();
-            mWindowManager.setAppOrientation(r, requestedOrientation);
+            mWindowManager.setAppOrientation(r.appToken, requestedOrientation);
             Configuration config = mWindowManager.updateOrientationFromAppTokens(
                     mConfiguration,
-                    r.mayFreezeScreenLocked(r.app) ? r : null);
+                    r.mayFreezeScreenLocked(r.app) ? r.appToken : null);
             if (config != null) {
                 r.frozenBeforeDestroy = true;
                 if (!updateConfigurationLocked(config, r, false)) {
@@ -2449,7 +2450,7 @@
             if (r == null) {
                 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
             }
-            return mWindowManager.getAppOrientation(r);
+            return mWindowManager.getAppOrientation(r.appToken);
         }
     }
 
@@ -2515,7 +2516,7 @@
             for (int i=0; i<activities.size(); i++) {
                 ActivityRecord r = activities.get(i);
                 if (!r.finishing) {
-                    int index = mMainStack.indexOfTokenLocked(r);
+                    int index = mMainStack.indexOfTokenLocked(r.appToken);
                     if (index >= 0) {
                         mMainStack.finishActivityLocked(r, index, Activity.RESULT_CANCELED,
                                 null, "finish-heavy");
@@ -2617,7 +2618,7 @@
             int i;
             for (i=mMainStack.mHistory.size()-1; i>=0; i--) {
                 ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
-                if (r == token) {
+                if (r.appToken == token) {
                     return true;
                 }
                 if (r.fullscreen && !r.finishing) {
@@ -2705,9 +2706,9 @@
                     r.makeFinishing();
                     mMainStack.mHistory.remove(i);
                     r.takeFromHistory();
-                    mWindowManager.removeAppToken(r);
+                    mWindowManager.removeAppToken(r.appToken);
                     if (VALIDATE_TOKENS) {
-                        mWindowManager.validateAppTokens(mMainStack.mHistory);
+                        mMainStack.validateAppTokensLocked();
                     }
                     r.removeUriPermissionsLocked();
 
@@ -5173,10 +5174,10 @@
         if (topThumbnail != null) {
             if (localLOGV) Slog.v(TAG, "Requesting top thumbnail");
             try {
-                topThumbnail.requestThumbnail(topRecord);
+                topThumbnail.requestThumbnail(topRecord.appToken);
             } catch (Exception e) {
                 Slog.w(TAG, "Exception thrown when requesting thumbnail", e);
-                sendPendingThumbnail(null, topRecord, null, null, true);
+                sendPendingThumbnail(null, topRecord.appToken, null, null, true);
             }
         }
 
@@ -5547,7 +5548,7 @@
         TaskRecord lastTask = null;
         for (int i=0; i<N; i++) {
             ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
-            if (r == token) {
+            if (r.appToken == token) {
                 if (!onlyRoot || lastTask != r.task) {
                     return r.task.taskId;
                 }
@@ -5568,7 +5569,7 @@
             for (int i=0; i<N; i++) {
                 ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
                 if (r.realActivity.equals(className)
-                        && r != token && lastTask != r.task) {
+                        && r.appToken != token && lastTask != r.task) {
                     if (r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
                             null, "others")) {
                         i--;
@@ -7112,7 +7113,7 @@
                 // process, then terminate it to avoid getting in a loop.
                 Slog.w(TAG, "  Force finishing activity "
                         + r.intent.getComponent().flattenToShortString());
-                int index = mMainStack.indexOfTokenLocked(r);
+                int index = mMainStack.indexOfActivityLocked(r);
                 r.stack.finishActivityLocked(r, index,
                         Activity.RESULT_CANCELED, null, "crashed");
                 // Also terminate any activities below it that aren't yet
@@ -8631,8 +8632,8 @@
             try {
                 TransferPipe tp = new TransferPipe();
                 try {
-                    r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(), r,
-                            innerPrefix, args);
+                    r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(),
+                            r.appToken, innerPrefix, args);
                     tp.go(fd);
                 } finally {
                     tp.kill();
@@ -9048,8 +9049,8 @@
                 try {
                     TransferPipe tp = new TransferPipe();
                     try {
-                        r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(), r,
-                                innerPrefix, args);
+                        r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(),
+                                r.appToken, innerPrefix, args);
                         // Short timeout, since blocking here can
                         // deadlock with the application.
                         tp.go(fd, 2000);
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 00e6cb2..951a946 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -29,6 +29,7 @@
 import android.graphics.Bitmap;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.os.Message;
 import android.os.Process;
 import android.os.RemoteException;
@@ -48,9 +49,10 @@
 /**
  * An entry in the history stack, representing an activity.
  */
-final class ActivityRecord extends IApplicationToken.Stub {
+final class ActivityRecord {
     final ActivityManagerService service; // owner
     final ActivityStack stack; // owner
+    final IApplicationToken.Stub appToken; // window manager token
     final ActivityInfo info; // all about me
     final int launchedFromUid; // always the uid who started the activity.
     final Intent intent;    // the original intent that generated us
@@ -200,6 +202,70 @@
         }
     }
 
+    static class Token extends IApplicationToken.Stub {
+        final WeakReference<ActivityRecord> weakActivity;
+
+        Token(ActivityRecord activity) {
+            weakActivity = new WeakReference<ActivityRecord>(activity);
+        }
+
+        @Override public void windowsDrawn() throws RemoteException {
+            ActivityRecord activity = weakActivity.get();
+            if (activity != null) {
+                activity.windowsDrawn();
+            }
+        }
+
+        @Override public void windowsVisible() throws RemoteException {
+            ActivityRecord activity = weakActivity.get();
+            if (activity != null) {
+                activity.windowsVisible();
+            }
+        }
+
+        @Override public void windowsGone() throws RemoteException {
+            ActivityRecord activity = weakActivity.get();
+            if (activity != null) {
+                activity.windowsGone();
+            }
+        }
+
+        @Override public boolean keyDispatchingTimedOut() throws RemoteException {
+            ActivityRecord activity = weakActivity.get();
+            if (activity != null) {
+                return activity.keyDispatchingTimedOut();
+            }
+            return false;
+        }
+
+        @Override public long getKeyDispatchingTimeout() throws RemoteException {
+            ActivityRecord activity = weakActivity.get();
+            if (activity != null) {
+                return activity.getKeyDispatchingTimeout();
+            }
+            return 0;
+        }
+
+        public String toString() {
+            StringBuilder sb = new StringBuilder(128);
+            sb.append("Token{");
+            sb.append(Integer.toHexString(System.identityHashCode(this)));
+            sb.append(' ');
+            sb.append(weakActivity.get());
+            sb.append('}');
+            return sb.toString();
+        }
+    }
+
+    static ActivityRecord forToken(IBinder token) {
+        try {
+            return token != null ? ((Token)token).weakActivity.get() : null;
+        } catch (ClassCastException e) {
+            Slog.w(ActivityManagerService.TAG, "Bad activity token: " + token, e);
+            return null;
+        }
+    }
+
     ActivityRecord(ActivityManagerService _service, ActivityStack _stack, ProcessRecord _caller,
             int _launchedFromUid, Intent _intent, String _resolvedType,
             ActivityInfo aInfo, Configuration _configuration,
@@ -207,6 +273,7 @@
             boolean _componentSpecified) {
         service = _service;
         stack = _stack;
+        appToken = new Token(this);
         info = aInfo;
         launchedFromUid = _launchedFromUid;
         intent = _intent;
@@ -445,7 +512,7 @@
                 ar.add(intent);
                 service.grantUriPermissionFromIntentLocked(callingUid, packageName,
                         intent, getUriPermissionsLocked());
-                app.thread.scheduleNewIntent(ar, this);
+                app.thread.scheduleNewIntent(ar, appToken);
                 sent = true;
             } catch (RemoteException e) {
                 Slog.w(ActivityManagerService.TAG,
@@ -470,14 +537,14 @@
     void pauseKeyDispatchingLocked() {
         if (!keysPaused) {
             keysPaused = true;
-            service.mWindowManager.pauseKeyDispatching(this);
+            service.mWindowManager.pauseKeyDispatching(appToken);
         }
     }
 
     void resumeKeyDispatchingLocked() {
         if (keysPaused) {
             keysPaused = false;
-            service.mWindowManager.resumeKeyDispatching(this);
+            service.mWindowManager.resumeKeyDispatching(appToken);
         }
     }
 
@@ -512,14 +579,14 @@
     
     public void startFreezingScreenLocked(ProcessRecord app, int configChanges) {
         if (mayFreezeScreenLocked(app)) {
-            service.mWindowManager.startAppFreezingScreen(this, configChanges);
+            service.mWindowManager.startAppFreezingScreen(appToken, configChanges);
         }
     }
     
     public void stopFreezingScreenLocked(boolean force) {
         if (force || frozenBeforeDestroy) {
             frozenBeforeDestroy = false;
-            service.mWindowManager.stopAppFreezingScreen(this, force);
+            service.mWindowManager.stopAppFreezingScreen(appToken, force);
         }
     }
     
@@ -687,7 +754,7 @@
         }
         if (app != null && app.thread != null) {
             try {
-                app.thread.scheduleSleeping(this, _sleeping);
+                app.thread.scheduleSleeping(appToken, _sleeping);
                 if (sleeping && !stack.mGoingToSleepActivities.contains(this)) {
                     stack.mGoingToSleepActivities.add(this);
                 }
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 8435eaa..c892cb1 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -145,7 +145,12 @@
      * running) activities.  It contains HistoryRecord objects.
      */
     final ArrayList<ActivityRecord> mHistory = new ArrayList<ActivityRecord>();
-    
+
+    /**
+     * Used for validating app tokens with window manager.
+     */
+    final ArrayList<IBinder> mValidateAppTokens = new ArrayList<IBinder>();
+
     /**
      * List of running activities, sorted by recent usage.
      * The first entry in the list is the least recently used.
@@ -294,11 +299,11 @@
                     }
                 } break;
                 case PAUSE_TIMEOUT_MSG: {
-                    IBinder token = (IBinder)msg.obj;
+                    ActivityRecord r = (ActivityRecord)msg.obj;
                     // We don't at this point know if the activity is fullscreen,
                     // so we need to be conservative and assume it isn't.
-                    Slog.w(TAG, "Activity pause timeout for " + token);
-                    activityPaused(token, true);
+                    Slog.w(TAG, "Activity pause timeout for " + r);
+                    activityPaused(r != null ? r.appToken : null, true);
                 } break;
                 case IDLE_TIMEOUT_MSG: {
                     if (mService.mDidDexOpt) {
@@ -310,20 +315,20 @@
                     }
                     // We don't at this point know if the activity is fullscreen,
                     // so we need to be conservative and assume it isn't.
-                    IBinder token = (IBinder)msg.obj;
-                    Slog.w(TAG, "Activity idle timeout for " + token);
-                    activityIdleInternal(token, true, null);
+                    ActivityRecord r = (ActivityRecord)msg.obj;
+                    Slog.w(TAG, "Activity idle timeout for " + r);
+                    activityIdleInternal(r != null ? r.appToken : null, true, null);
                 } break;
                 case DESTROY_TIMEOUT_MSG: {
-                    IBinder token = (IBinder)msg.obj;
+                    ActivityRecord r = (ActivityRecord)msg.obj;
                     // We don't at this point know if the activity is fullscreen,
                     // so we need to be conservative and assume it isn't.
-                    Slog.w(TAG, "Activity destroy timeout for " + token);
-                    activityDestroyed(token);
+                    Slog.w(TAG, "Activity destroy timeout for " + r);
+                    activityDestroyed(r != null ? r.appToken : null);
                 } break;
                 case IDLE_NOW_MSG: {
-                    IBinder token = (IBinder)msg.obj;
-                    activityIdleInternal(token, false, null);
+                    ActivityRecord r = (ActivityRecord)msg.obj;
+                    activityIdleInternal(r != null ? r.appToken : null, false, null);
                 } break;
                 case LAUNCH_TIMEOUT_MSG: {
                     if (mService.mDidDexOpt) {
@@ -397,7 +402,7 @@
         while (i >= 0) {
             ActivityRecord r = mHistory.get(i);
             // Note: the taskId check depends on real taskId fields being non-zero
-            if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
+            if (!r.finishing && (token != r.appToken) && (taskId != r.task.taskId)) {
                 return r;
             }
             i--;
@@ -406,23 +411,17 @@
     }
 
     final int indexOfTokenLocked(IBinder token) {
-        try {
-            ActivityRecord r = (ActivityRecord)token;
-            return mHistory.indexOf(r);
-        } catch (ClassCastException e) {
-            Slog.w(TAG, "Bad activity token: " + token, e);
-            return -1;
-        }
+        return mHistory.indexOf(ActivityRecord.forToken(token));
+    }
+
+    final int indexOfActivityLocked(ActivityRecord r) {
+        return mHistory.indexOf(r);
     }
 
     final ActivityRecord isInStackLocked(IBinder token) {
-        try {
-            ActivityRecord r = (ActivityRecord)token;
-            if (mHistory.contains(r)) {
-                return r;
-            }
-        } catch (ClassCastException e) {
-            Slog.w(TAG, "Bad activity token: " + token, e);
+        ActivityRecord r = ActivityRecord.forToken(token);
+        if (mHistory.contains(r)) {
+            return r;
         }
         return null;
     }
@@ -517,7 +516,7 @@
             throws RemoteException {
 
         r.startFreezingScreenLocked(app, 0);
-        mService.mWindowManager.setAppVisibility(r, true);
+        mService.mWindowManager.setAppVisibility(r.appToken, true);
 
         // Have the window manager re-evaluate the orientation of
         // the screen based on the new activity order.  Note that
@@ -528,7 +527,7 @@
         if (checkConfig) {
             Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
                     mService.mConfiguration,
-                    r.mayFreezeScreenLocked(app) ? r : null);
+                    r.mayFreezeScreenLocked(app) ? r.appToken : null);
             mService.updateConfigurationLocked(config, r, false);
         }
 
@@ -590,7 +589,7 @@
                     profileFd = null;
                 }
             }
-            app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
+            app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                     System.identityHashCode(r), r.info, mService.mConfiguration,
                     r.compat, r.icicle, results, newIntents, !andResume,
                     mService.isNextTransitionForward(), profileFile, profileFd,
@@ -624,7 +623,7 @@
                       + r.intent.getComponent().flattenToShortString()
                       + ", giving up", e);
                 mService.appDiedLocked(app, app.pid, app.thread);
-                requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
+                requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
                         "2nd-crash");
                 return false;
             }
@@ -821,7 +820,7 @@
         }
 
         if (w > 0) {
-            return mService.mWindowManager.screenshotApplications(who, w, h);
+            return mService.mWindowManager.screenshotApplications(who.appToken, w, h);
         }
         return null;
     }
@@ -856,8 +855,8 @@
                 EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
                         System.identityHashCode(prev),
                         prev.shortComponentName);
-                prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
-                        prev.configChangeFlags);
+                prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
+                        userLeaving, prev.configChangeFlags);
                 if (mMainStack) {
                     mService.updateUsageStats(prev, false);
                 }
@@ -1129,7 +1128,7 @@
                     if (!r.visible) {
                         if (DEBUG_VISBILITY) Slog.v(
                                 TAG, "Starting and making visible: " + r);
-                        mService.mWindowManager.setAppVisibility(r, true);
+                        mService.mWindowManager.setAppVisibility(r.appToken, true);
                     }
                     if (r != starting) {
                         startSpecificActivityLocked(r, false, false);
@@ -1153,10 +1152,10 @@
                     if (DEBUG_VISBILITY) Slog.v(
                             TAG, "Making visible and scheduling visibility: " + r);
                     try {
-                        mService.mWindowManager.setAppVisibility(r, true);
+                        mService.mWindowManager.setAppVisibility(r.appToken, true);
                         r.sleeping = false;
                         r.app.pendingUiClean = true;
-                        r.app.thread.scheduleWindowVisibility(r, true);
+                        r.app.thread.scheduleWindowVisibility(r.appToken, true);
                         r.stopFreezingScreenLocked(false);
                     } catch (Exception e) {
                         // Just skip on any failure; we'll make it
@@ -1195,13 +1194,13 @@
                                 TAG, "Making invisible: " + r);
                         r.visible = false;
                         try {
-                            mService.mWindowManager.setAppVisibility(r, false);
+                            mService.mWindowManager.setAppVisibility(r.appToken, false);
                             if ((r.state == ActivityState.STOPPING
                                     || r.state == ActivityState.STOPPED)
                                     && r.app != null && r.app.thread != null) {
                                 if (DEBUG_VISBILITY) Slog.v(
                                         TAG, "Scheduling invisibility: " + r);
-                                r.app.thread.scheduleWindowVisibility(r, false);
+                                r.app.thread.scheduleWindowVisibility(r.appToken, false);
                             }
                         } catch (Exception e) {
                             // Just skip on any failure; we'll make it
@@ -1351,7 +1350,7 @@
                 // previous should actually be hidden depending on whether the
                 // new one is found to be full-screen or not.
                 if (prev.finishing) {
-                    mService.mWindowManager.setAppVisibility(prev, false);
+                    mService.mWindowManager.setAppVisibility(prev.appToken, false);
                     if (DEBUG_SWITCH) Slog.v(TAG, "Not waiting for visible to hide: "
                             + prev + ", waitingVisible="
                             + (prev != null ? prev.waitingVisible : null)
@@ -1399,8 +1398,8 @@
                             ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
                             : WindowManagerPolicy.TRANSIT_TASK_CLOSE, false);
                 }
-                mService.mWindowManager.setAppWillBeHidden(prev);
-                mService.mWindowManager.setAppVisibility(prev, false);
+                mService.mWindowManager.setAppWillBeHidden(prev.appToken);
+                mService.mWindowManager.setAppVisibility(prev.appToken, false);
             } else {
                 if (DEBUG_TRANSITION) Slog.v(TAG,
                         "Prepare open transition: prev=" + prev);
@@ -1414,8 +1413,8 @@
                 }
             }
             if (false) {
-                mService.mWindowManager.setAppWillBeHidden(prev);
-                mService.mWindowManager.setAppVisibility(prev, false);
+                mService.mWindowManager.setAppWillBeHidden(prev.appToken);
+                mService.mWindowManager.setAppVisibility(prev.appToken, false);
             }
         } else if (mHistory.size() > 1) {
             if (DEBUG_TRANSITION) Slog.v(TAG,
@@ -1433,7 +1432,7 @@
             if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " + next);
 
             // This activity is now becoming visible.
-            mService.mWindowManager.setAppVisibility(next, true);
+            mService.mWindowManager.setAppVisibility(next.appToken, true);
 
             ActivityRecord lastResumedActivity = mResumedActivity;
             ActivityState lastState = next.state;
@@ -1457,7 +1456,7 @@
                 synchronized (mService) {
                     Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
                             mService.mConfiguration,
-                            next.mayFreezeScreenLocked(next.app) ? next : null);
+                            next.mayFreezeScreenLocked(next.app) ? next.appToken : null);
                     if (config != null) {
                         next.frozenBeforeDestroy = true;
                     }
@@ -1496,12 +1495,12 @@
                         if (DEBUG_RESULTS) Slog.v(
                                 TAG, "Delivering results to " + next
                                 + ": " + a);
-                        next.app.thread.scheduleSendResult(next, a);
+                        next.app.thread.scheduleSendResult(next.appToken, a);
                     }
                 }
 
                 if (next.newIntents != null) {
-                    next.app.thread.scheduleNewIntent(next.newIntents, next);
+                    next.app.thread.scheduleNewIntent(next.newIntents, next.appToken);
                 }
 
                 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
@@ -1511,7 +1510,7 @@
                 next.sleeping = false;
                 showAskCompatModeDialogLocked(next);
                 next.app.pendingUiClean = true;
-                next.app.thread.scheduleResumeActivity(next,
+                next.app.thread.scheduleResumeActivity(next.appToken,
                         mService.isNextTransitionForward());
                 
                 checkReadyForSleepLocked();
@@ -1528,7 +1527,7 @@
                 } else {
                     if (SHOW_APP_STARTING_PREVIEW && mMainStack) {
                         mService.mWindowManager.setAppStartingWindow(
-                                next, next.packageName, next.theme,
+                                next.appToken, next.packageName, next.theme,
                                 mService.compatibilityInfoForPackageLocked(
                                         next.info.applicationInfo),
                                 next.nonLocalizedLabel,
@@ -1549,7 +1548,7 @@
                 // If any exception gets thrown, toss away this
                 // activity and try the next one.
                 Slog.w(TAG, "Exception thrown during resume of " + next, e);
-                requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
+                requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null,
                         "resume-exception");
                 return true;
             }
@@ -1567,7 +1566,7 @@
             } else {
                 if (SHOW_APP_STARTING_PREVIEW) {
                     mService.mWindowManager.setAppStartingWindow(
-                            next, next.packageName, next.theme,
+                            next.appToken, next.packageName, next.theme,
                             mService.compatibilityInfoForPackageLocked(
                                     next.info.applicationInfo),
                             next.nonLocalizedLabel,
@@ -1610,10 +1609,10 @@
                         }
                         mHistory.add(addPos, r);
                         r.putInHistory();
-                        mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,
+                        mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
                                 r.info.screenOrientation, r.fullscreen);
                         if (VALIDATE_TOKENS) {
-                            mService.mWindowManager.validateAppTokens(mHistory);
+                            validateAppTokensLocked();
                         }
                         return;
                     }
@@ -1677,7 +1676,7 @@
                 mNoAnimActivities.remove(r);
             }
             mService.mWindowManager.addAppToken(
-                    addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
+                    addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen);
             boolean doShow = true;
             if (newTask) {
                 // Even though this activity is starting fresh, we still need
@@ -1705,19 +1704,20 @@
                     else if (prev.nowVisible) prev = null;
                 }
                 mService.mWindowManager.setAppStartingWindow(
-                        r, r.packageName, r.theme,
+                        r.appToken, r.packageName, r.theme,
                         mService.compatibilityInfoForPackageLocked(
                                 r.info.applicationInfo), r.nonLocalizedLabel,
-                        r.labelRes, r.icon, r.windowFlags, prev, showStartingIcon);
+                        r.labelRes, r.icon, r.windowFlags,
+                        prev != null ? prev.appToken : null, showStartingIcon);
             }
         } else {
             // If this is the first activity, don't do any fancy animations,
             // because there is nothing for it to animate on top of.
-            mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,
+            mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
                     r.info.screenOrientation, r.fullscreen);
         }
         if (VALIDATE_TOKENS) {
-            mService.mWindowManager.validateAppTokens(mHistory);
+            validateAppTokensLocked();
         }
 
         if (doResume) {
@@ -1725,6 +1725,15 @@
         }
     }
 
+    final void validateAppTokensLocked() {
+        mValidateAppTokens.clear();
+        mValidateAppTokens.ensureCapacity(mHistory.size());
+        for (int i=0; i<mHistory.size(); i++) {
+            mValidateAppTokens.add(mHistory.get(i).appToken);
+        }
+        mService.mWindowManager.validateAppTokens(mValidateAppTokens);
+    }
+
     /**
      * Perform a reset of the given task, if needed as part of launching it.
      * Returns the new HistoryRecord at the top of the task.
@@ -1826,7 +1835,7 @@
                             if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
                                     + " out to new task " + target.task);
                         }
-                        mService.mWindowManager.setAppGroupId(target, task.taskId);
+                        mService.mWindowManager.setAppGroupId(target.appToken, task.taskId);
                         if (replyChainEnd < 0) {
                             replyChainEnd = targetI;
                         }
@@ -1849,11 +1858,11 @@
                             }
                             mHistory.remove(srcPos);
                             mHistory.add(dstPos, p);
-                            mService.mWindowManager.moveAppToken(dstPos, p);
-                            mService.mWindowManager.setAppGroupId(p, p.task.taskId);
+                            mService.mWindowManager.moveAppToken(dstPos, p.appToken);
+                            mService.mWindowManager.setAppGroupId(p.appToken, p.task.taskId);
                             dstPos++;
                             if (VALIDATE_TOKENS) {
-                                mService.mWindowManager.validateAppTokens(mHistory);
+                                validateAppTokensLocked();
                             }
                             i++;
                         }
@@ -1985,10 +1994,10 @@
                         mHistory.add(lastReparentPos, p);
                         if (DEBUG_TASKS) Slog.v(TAG, "Pulling activity " + p
                                 + " in to resetting task " + task);
-                        mService.mWindowManager.moveAppToken(lastReparentPos, p);
-                        mService.mWindowManager.setAppGroupId(p, p.task.taskId);
+                        mService.mWindowManager.moveAppToken(lastReparentPos, p.appToken);
+                        mService.mWindowManager.setAppGroupId(p.appToken, p.task.taskId);
                         if (VALIDATE_TOKENS) {
-                            mService.mWindowManager.validateAppTokens(mHistory);
+                            validateAppTokensLocked();
                         }
                     }
                     replyChainEnd = -1;
@@ -2081,7 +2090,7 @@
                 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
                         && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
                     if (!ret.finishing) {
-                        int index = indexOfTokenLocked(ret);
+                        int index = indexOfTokenLocked(ret.appToken);
                         if (index >= 0) {
                             finishActivityLocked(ret, index, Activity.RESULT_CANCELED,
                                     null, "clear");
@@ -3007,7 +3016,7 @@
                         return res;
                     }
 
-                    resultTo = outActivity[0];
+                    resultTo = outActivity[0] != null ? outActivity[0].appToken : null;
                 }
             }
         } finally {
@@ -3065,7 +3074,7 @@
                 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
                 list.add(new ResultInfo(resultWho, requestCode,
                         resultCode, data));
-                r.app.thread.scheduleSendResult(r, list);
+                r.app.thread.scheduleSendResult(r.appToken, list);
                 return;
             } catch (Exception e) {
                 Slog.w(TAG, "Exception thrown sending result to " + r, e);
@@ -3080,7 +3089,7 @@
         if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
                 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
             if (!r.finishing) {
-                requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
+                requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
                         "no-history");
             }
         } else if (r.app != null && r.app.thread != null) {
@@ -3098,9 +3107,9 @@
                 if (DEBUG_VISBILITY) Slog.v(
                         TAG, "Stopping visible=" + r.visible + " for " + r);
                 if (!r.visible) {
-                    mService.mWindowManager.setAppVisibility(r, false);
+                    mService.mWindowManager.setAppVisibility(r.appToken, false);
                 }
-                r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
+                r.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags);
                 if (mService.isSleeping()) {
                     r.setSleeping(true);
                 }
@@ -3145,7 +3154,7 @@
                     // normal flow and hide it once we determine that it is
                     // hidden by the activities in front of it.
                     if (localLOGV) Slog.v(TAG, "Before stopping, can hide: " + s);
-                    mService.mWindowManager.setAppVisibility(s, false);
+                    mService.mWindowManager.setAppVisibility(s.appToken, false);
                 }
             }
             if ((!s.waitingVisible || mService.isSleeping()) && remove) {
@@ -3186,14 +3195,14 @@
         boolean enableScreen = false;
 
         synchronized (mService) {
-            if (token != null) {
-                mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
+            ActivityRecord r = ActivityRecord.forToken(token);
+            if (r != null) {
+                mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
             }
 
             // Get the activity record.
-            int index = indexOfTokenLocked(token);
+            int index = indexOfActivityLocked(r);
             if (index >= 0) {
-                ActivityRecord r = mHistory.get(index);
                 res = r;
 
                 if (fromTimeout) {
@@ -3413,7 +3422,7 @@
                     : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE, false);
     
             // Tell window manager to prepare for this one to be removed.
-            mService.mWindowManager.setAppVisibility(r, false);
+            mService.mWindowManager.setAppVisibility(r.appToken, false);
                 
             if (mPausingActivity == null) {
                 if (DEBUG_PAUSE) Slog.v(TAG, "Finish needs to pause: " + r);
@@ -3440,7 +3449,7 @@
 
     private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
             int mode) {
-        final int index = indexOfTokenLocked(r);
+        final int index = indexOfActivityLocked(r);
         if (index < 0) {
             return null;
         }
@@ -3570,9 +3579,9 @@
             if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
                     + " (removed from history)");
             r.state = ActivityState.DESTROYED;
-            mService.mWindowManager.removeAppToken(r);
+            mService.mWindowManager.removeAppToken(r.appToken);
             if (VALIDATE_TOKENS) {
-                mService.mWindowManager.validateAppTokens(mHistory);
+                validateAppTokensLocked();
             }
             cleanUpActivityServicesLocked(r);
             r.removeUriPermissionsLocked();
@@ -3653,7 +3662,7 @@
             
             try {
                 if (DEBUG_SWITCH) Slog.i(TAG, "Destroying: " + r);
-                r.app.thread.scheduleDestroyActivity(r, r.finishing,
+                r.app.thread.scheduleDestroyActivity(r.appToken, r.finishing,
                         r.configChangeFlags);
             } catch (Exception e) {
                 // We can just ignore exceptions here...  if the process
@@ -3712,11 +3721,13 @@
 
     final void activityDestroyed(IBinder token) {
         synchronized (mService) {
-            mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
+            ActivityRecord r = ActivityRecord.forToken(token);
+            if (r != null) {
+                mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
+            }
             
-            int index = indexOfTokenLocked(token);
+            int index = indexOfActivityLocked(r);
             if (index >= 0) {
-                ActivityRecord r = mHistory.get(index);
                 if (r.state == ActivityState.DESTROYING) {
                     final long origId = Binder.clearCallingIdentity();
                     removeActivityFromHistoryLocked(r);
@@ -3781,7 +3792,7 @@
             return;
         }
 
-        ArrayList moved = new ArrayList();
+        ArrayList<IBinder> moved = new ArrayList<IBinder>();
 
         // Applying the affinities may have removed entries from the history,
         // so get the size again.
@@ -3803,7 +3814,7 @@
                 }
                 mHistory.remove(pos);
                 mHistory.add(top, r);
-                moved.add(0, r);
+                moved.add(0, r.appToken);
                 top--;
             }
             pos--;
@@ -3826,7 +3837,7 @@
         
         mService.mWindowManager.moveAppTokensToTop(moved);
         if (VALIDATE_TOKENS) {
-            mService.mWindowManager.validateAppTokens(mHistory);
+            validateAppTokensLocked();
         }
 
         finishTaskMoveLocked(task);
@@ -3873,7 +3884,7 @@
             }
         }
 
-        ArrayList moved = new ArrayList();
+        ArrayList<IBinder> moved = new ArrayList<IBinder>();
 
         if (DEBUG_TRANSITION) Slog.v(TAG,
                 "Prepare to back transition: task=" + task);
@@ -3898,7 +3909,7 @@
                 }
                 mHistory.remove(pos);
                 mHistory.add(bottom, r);
-                moved.add(r);
+                moved.add(r.appToken);
                 bottom++;
             }
             pos++;
@@ -3918,7 +3929,7 @@
         }
         mService.mWindowManager.moveAppTokensToBottom(moved);
         if (VALIDATE_TOKENS) {
-            mService.mWindowManager.validateAppTokens(mHistory);
+            validateAppTokensLocked();
         }
 
         finishTaskMoveLocked(task);
@@ -4148,7 +4159,7 @@
         if (r.app != null && r.app.thread != null) {
             try {
                 if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + r);
-                r.app.thread.scheduleActivityConfigurationChanged(r);
+                r.app.thread.scheduleActivityConfigurationChanged(r.appToken);
             } catch (RemoteException e) {
                 // If process died, whatever.
             }
@@ -4178,7 +4189,7 @@
         try {
             if (DEBUG_SWITCH) Slog.i(TAG, "Switch is restarting resumed " + r);
             r.forceNewConfig = false;
-            r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
+            r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents,
                     changes, !andResume, mService.mConfiguration);
             // Note: don't need to call pauseIfSleepingLocked() here, because
             // the caller will only pass in 'andResume' if this activity is
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index 423a78f..c344bc6 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -73,7 +73,7 @@
     private Context mContext;
     private final static String TAG = "Tethering";
     private final static boolean DBG = true;
-    private final static boolean VDBG = true;
+    private final static boolean VDBG = false;
 
     // TODO - remove both of these - should be part of interface inspection/selection stuff
     private String[] mTetherableUsbRegexs;
@@ -228,7 +228,7 @@
                 if (isUsb(iface)) {
                     // ignore usb0 down after enabling RNDIS
                     // we will handle disconnect in interfaceRemoved instead
-                    if (VDBG) Log.d(TAG, "ignoring interface down for " + iface);
+                    if (VDBG) Log.d(TAG, "ignore interface down for " + iface);
                 } else if (sm != null) {
                     sm.sendMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN);
                     mIfaces.remove(iface);
@@ -298,7 +298,6 @@
             mIfaces.put(iface, sm);
             sm.start();
         }
-        if (VDBG) Log.d(TAG, "interfaceAdded :" + iface);
     }
 
     public void interfaceRemoved(String iface) {
@@ -415,7 +414,7 @@
         broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER,
                 erroredList);
         mContext.sendStickyBroadcast(broadcast);
-        if (VDBG) {
+        if (DBG) {
             Log.d(TAG, "sendTetherStateChangedBroadcast " + availableList.size() + ", " +
                     activeList.size() + ", " + erroredList.size());
         }
@@ -865,7 +864,7 @@
 
             @Override
             public boolean processMessage(Message message) {
-                if (VDBG) Log.d(TAG, "InitialState.processMessage what=" + message.what);
+                if (DBG) Log.d(TAG, "InitialState.processMessage what=" + message.what);
                 boolean retValue = true;
                 switch (message.what) {
                     case CMD_TETHER_REQUESTED:
@@ -906,7 +905,7 @@
             }
             @Override
             public boolean processMessage(Message message) {
-                if (VDBG) Log.d(TAG, "StartingState.processMessage what=" + message.what);
+                if (DBG) Log.d(TAG, "StartingState.processMessage what=" + message.what);
                 boolean retValue = true;
                 switch (message.what) {
                     // maybe a parent class?
@@ -985,7 +984,7 @@
 
             @Override
             public boolean processMessage(Message message) {
-                if (VDBG) Log.d(TAG, "TetheredState.processMessage what=" + message.what);
+                if (DBG) Log.d(TAG, "TetheredState.processMessage what=" + message.what);
                 boolean retValue = true;
                 boolean error = false;
                 switch (message.what) {
@@ -1061,7 +1060,7 @@
                                     ConnectivityManager.TETHER_ERROR_MASTER_ERROR);
                             break;
                         }
-                        if (VDBG) Log.d(TAG, "Tether lost upstream connection " + mIfaceName);
+                        if (DBG) Log.d(TAG, "Tether lost upstream connection " + mIfaceName);
                         sendTetherStateChangedBroadcast();
                         if (mUsb) {
                             if (!Tethering.this.configureUsbIface(false)) {
@@ -1296,7 +1295,7 @@
                     }
                 }
 
-                if (VDBG) {
+                if (DBG) {
                     Log.d(TAG, "chooseUpstreamType(" + tryCell + "), preferredApn ="
                             + mPreferredUpstreamMobileApn + ", got type=" + upType);
                 }
@@ -1328,7 +1327,7 @@
             }
 
             protected void notifyTetheredOfNewUpstreamIface(String ifaceName) {
-                if (VDBG) Log.d(TAG, "notifying tethered with iface =" + ifaceName);
+                if (DBG) Log.d(TAG, "notifying tethered with iface =" + ifaceName);
                 mUpstreamIfaceName = ifaceName;
                 for (Object o : mNotifyList) {
                     TetherInterfaceSM sm = (TetherInterfaceSM)o;
@@ -1344,7 +1343,7 @@
             }
             @Override
             public boolean processMessage(Message message) {
-                if (VDBG) Log.d(TAG, "MasterInitialState.processMessage what=" + message.what);
+                if (DBG) Log.d(TAG, "MasterInitialState.processMessage what=" + message.what);
                 boolean retValue = true;
                 switch (message.what) {
                     case CMD_TETHER_MODE_REQUESTED:
@@ -1386,7 +1385,7 @@
             }
             @Override
             public boolean processMessage(Message message) {
-                if (VDBG) Log.d(TAG, "TetherModeAliveState.processMessage what=" + message.what);
+                if (DBG) Log.d(TAG, "TetherModeAliveState.processMessage what=" + message.what);
                 boolean retValue = true;
                 switch (message.what) {
                     case CMD_TETHER_MODE_REQUESTED:
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 77b0d96..6365525 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -806,9 +806,7 @@
         final NetworkStats networkDevSnapshot;
         try {
             // collect any tethering stats
-            final String[] tetheredIfacePairs = mConnManager.getTetheredIfacePairs();
-            final NetworkStats tetherSnapshot = mNetworkManager.getNetworkStatsTethering(
-                    tetheredIfacePairs);
+            final NetworkStats tetherSnapshot = getNetworkStatsTethering();
 
             // record uid stats, folding in tethering stats
             uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
@@ -1505,7 +1503,7 @@
             NetworkStats before, NetworkStats current, boolean collectStale, String type) {
         if (before != null) {
             try {
-                return current.subtract(before);
+                return current.subtract(before, false);
             } catch (NonMonotonicException e) {
                 Log.w(TAG, "found non-monotonic values; saving to dropbox");
 
@@ -1517,8 +1515,13 @@
                 builder.append("right=").append(e.right).append('\n');
                 mDropBox.addText(TAG_NETSTATS_ERROR, builder.toString());
 
-                // return empty delta to avoid recording broken stats
-                return new NetworkStats(0L, 10);
+                try {
+                    // return clamped delta to help recover
+                    return current.subtract(before, true);
+                } catch (NonMonotonicException e1) {
+                    Log.wtf(TAG, "found non-monotonic values; returning empty delta", e1);
+                    return new NetworkStats(0L, 10);
+                }
             }
         } else if (collectStale) {
             // caller is okay collecting stale stats for first call.
@@ -1530,6 +1533,20 @@
         }
     }
 
+    /**
+     * Return snapshot of current tethering statistics. Will return empty
+     * {@link NetworkStats} if any problems are encountered.
+     */
+    private NetworkStats getNetworkStatsTethering() throws RemoteException {
+        try {
+            final String[] tetheredIfacePairs = mConnManager.getTetheredIfacePairs();
+            return mNetworkManager.getNetworkStatsTethering(tetheredIfacePairs);
+        } catch (IllegalStateException e) {
+            Log.wtf(TAG, "problem reading network stats", e);
+            return new NetworkStats(0L, 10);
+        }
+    }
+
     private static NetworkStats computeNetworkXtSnapshotFromUid(NetworkStats uidSnapshot) {
         return uidSnapshot.groupedByIface();
     }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 4ffc201..50321b3 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -3070,7 +3070,7 @@
     // Application Window Tokens
     // -------------------------------------------------------------
 
-    public void validateAppTokens(List tokens) {
+    public void validateAppTokens(List<IBinder> tokens) {
         int v = tokens.size()-1;
         int m = mAppTokens.size()-1;
         while (v >= 0 && m >= 0) {