Merge "Fix crash while connecting channel."
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index fd60813f..4a9c5bd 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9995,6 +9995,7 @@
             }
 
             final HardwareCanvas canvas = mDisplayList.start();
+            int restoreCount = 0;
             try {
                 int width = mRight - mLeft;
                 int height = mBottom - mTop;
@@ -10004,6 +10005,8 @@
                 canvas.onPreDraw(null);
 
                 computeScroll();
+
+                restoreCount = canvas.save();
                 canvas.translate(-mScrollX, -mScrollY);
                 mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
                 mPrivateFlags &= ~DIRTY_MASK;
@@ -10015,6 +10018,7 @@
                     draw(canvas);
                 }
             } finally {
+                canvas.restoreToCount(restoreCount);
                 canvas.onPostDraw();
 
                 mDisplayList.end();
diff --git a/core/java/com/android/internal/widget/ScrollingTabContainerView.java b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
index 5baed75..b7bc366 100644
--- a/core/java/com/android/internal/widget/ScrollingTabContainerView.java
+++ b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
@@ -444,7 +444,9 @@
                     mTextView.setText(null);
                 }
 
-                setContentDescription(tab.getContentDescription());
+                if (mIconView != null) {
+                    mIconView.setContentDescription(tab.getContentDescription());
+                }
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 43905dd..10e7602 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -96,11 +96,13 @@
     /* package */ final class ActivityDescription {
         final ActivityManager.RecentTaskInfo recentTaskInfo;
         final ResolveInfo resolveInfo;
-        int taskId; // application task id for curating apps
-        Intent intent; // launch intent for application
+        final int taskId; // application task id for curating apps
+        final int persistentTaskId; // persistent id
+        final Intent intent; // launch intent for application
+        final String packageName; // used to override animations (see onClick())
+        final int position; // position in list
+
         Matrix matrix; // arbitrary rotation matrix to correct orientation
-        String packageName; // used to override animations (see onClick())
-        int position; // position in list
 
         private Bitmap mThumbnail; // generated by Activity.onCreateThumbnail()
         private Drawable mIcon; // application package icon
@@ -108,11 +110,12 @@
 
         public ActivityDescription(ActivityManager.RecentTaskInfo _recentInfo,
                 ResolveInfo _resolveInfo, Intent _intent,
-                int _id, int _pos, String _packageName) {
+                int _pos, String _packageName) {
             recentTaskInfo = _recentInfo;
             resolveInfo = _resolveInfo;
             intent = _intent;
-            taskId = _id;
+            taskId = _recentInfo.id;
+            persistentTaskId = _recentInfo.persistentId;
             position = _pos;
             packageName = _packageName;
         }
@@ -496,17 +499,17 @@
                 final String title = info.loadLabel(pm).toString();
                 // Drawable icon = info.loadIcon(pm);
                 Drawable icon = getFullResIcon(resolveInfo, pm);
-                int id = recentInfo.id;
                 if (title != null && title.length() > 0 && icon != null) {
-                    if (DEBUG) Log.v(TAG, "creating activity desc for id=" + id + ", label=" + title);
+                    if (DEBUG) Log.v(TAG, "creating activity desc for id="
+                            + recentInfo.id + ", label=" + title);
                     ActivityManager.TaskThumbnails thumbs = am.getTaskThumbnails(
                             recentInfo.persistentId);
                     ActivityDescription item = new ActivityDescription(recentInfo,
-                            resolveInfo, intent, id, index, info.packageName);
+                            resolveInfo, intent, index, info.packageName);
                     activityDescriptions.add(item);
                     ++index;
                 } else {
-                    if (DEBUG) Log.v(TAG, "SKIPPING item " + id);
+                    if (DEBUG) Log.v(TAG, "SKIPPING item " + recentInfo.id);
                 }
             }
         }
@@ -727,7 +730,7 @@
         // the task.
         final ActivityManager am = (ActivityManager)
                 mContext.getSystemService(Context.ACTIVITY_SERVICE);
-        am.removeTask(ad.taskId, ActivityManager.REMOVE_TASK_KILL_PROCESS);
+        am.removeTask(ad.persistentTaskId, ActivityManager.REMOVE_TASK_KILL_PROCESS);
     }
 
     private void startApplicationDetailsActivity(String packageName) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 57bfaed..d6d3b9d 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -5159,6 +5159,29 @@
                     cleanUpRemovedTaskLocked(r,
                             (flags&ActivityManager.REMOVE_TASK_KILL_PROCESS) != 0);
                     return true;
+                } else {
+                    TaskRecord tr = null;
+                    int i=0;
+                    while (i < mRecentTasks.size()) {
+                        TaskRecord t = mRecentTasks.get(i);
+                        if (t.taskId == taskId) {
+                            tr = t;
+                            break;
+                        }
+                        i++;
+                    }
+                    if (tr != null) {
+                        if (tr.numActivities <= 0) {
+                            // Caller is just removing a recent task that is
+                            // not actively running.  That is easy!
+                            mRecentTasks.remove(i);
+                        } else {
+                            Slog.w(TAG, "removeTask: task " + taskId
+                                    + " does not have activities to remove, "
+                                    + " but numActivities=" + tr.numActivities
+                                    + ": " + tr);
+                        }
+                    }
                 }
             } finally {
                 Binder.restoreCallingIdentity(ident);
diff --git a/tests/DataIdleTest/Android.mk b/tests/DataIdleTest/Android.mk
new file mode 100644
index 0000000..acb46c5
--- /dev/null
+++ b/tests/DataIdleTest/Android.mk
@@ -0,0 +1,29 @@
+#
+# 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.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_PACKAGE_NAME := DataIdleTest
+LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+# We need to sign it to get access to the network usage history.
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/tests/DataIdleTest/AndroidManifest.xml b/tests/DataIdleTest/AndroidManifest.xml
new file mode 100644
index 0000000..2792eec
--- /dev/null
+++ b/tests/DataIdleTest/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+  package="com.android.tests.dataidle"
+  android:sharedUserId="android.uid.system">
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
+    <application >
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation
+        android:name="android.test.InstrumentationTestRunner"
+        android:targetPackage="com.android.tests.dataidle"
+        android:label="Idle Bandwidth Tests" />
+
+</manifest>
diff --git a/tests/DataIdleTest/src/com/android/tests/dataidle/DataIdleTest.java b/tests/DataIdleTest/src/com/android/tests/dataidle/DataIdleTest.java
new file mode 100644
index 0000000..637f0d2
--- /dev/null
+++ b/tests/DataIdleTest/src/com/android/tests/dataidle/DataIdleTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.tests.dataidle;
+
+import android.content.Context;
+import android.net.INetworkStatsService;
+import android.net.NetworkStats.Entry;
+import android.net.NetworkTemplate;
+import android.net.NetworkStats;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.telephony.TelephonyManager;
+import android.test.InstrumentationTestCase;
+import android.test.InstrumentationTestRunner;
+import android.util.Log;
+
+/**
+ * A test that dumps data usage to instrumentation out, used for measuring data usage for idle
+ * devices.
+ */
+public class DataIdleTest extends InstrumentationTestCase {
+
+    private TelephonyManager mTelephonyManager;
+    private INetworkStatsService mStatsService;
+
+    private static final String LOG_TAG = "DataIdleTest";
+    private final static int INSTRUMENTATION_IN_PROGRESS = 2;
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        Context c = getInstrumentation().getTargetContext();
+        mStatsService = INetworkStatsService.Stub.asInterface(
+                ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
+        mTelephonyManager = (TelephonyManager) c.getSystemService(Context.TELEPHONY_SERVICE);
+    }
+
+    /**
+     * Test that dumps all the data usage metrics for wifi to instrumentation out.
+     */
+    public void testWifiIdle() {
+        NetworkTemplate template = NetworkTemplate.buildTemplateWifi();
+        fetchStats(template);
+    }
+
+    /**
+     * Test that dumps all the data usage metrics for all mobile to instrumentation out.
+     */
+    public void testMobile() {
+        String subscriberId = mTelephonyManager.getSubscriberId();
+        NetworkTemplate template = NetworkTemplate.buildTemplateMobileAll(subscriberId);
+        fetchStats(template);
+    }
+
+    /**
+     * Helper method that fetches all the network stats available and reports it
+     * to instrumentation out.
+     * @param template {link {@link NetworkTemplate} to match.
+     */
+    private void fetchStats(NetworkTemplate template) {
+        try {
+            NetworkStats stats = mStatsService.getSummaryForAllUid(template, Long.MIN_VALUE,
+                    Long.MAX_VALUE, false);
+            reportStats(stats);
+        } catch (RemoteException e) {
+            Log.w(LOG_TAG, "Failed to fetch network stats for wifi.");
+        }
+    }
+
+    /**
+     * Print network data usage stats to instrumentation out
+     * @param stats {@link NetworkorStats} to print
+     */
+    void reportStats(NetworkStats stats) {
+        for (int i = 0; i < stats.size(); ++i) {
+            Entry  statsEntry = stats.getValues(i, null);
+            Bundle result = new Bundle();
+            result.putInt("uid", statsEntry.uid);
+            result.putInt("tag", statsEntry.tag);
+            result.putInt("set", statsEntry.set);
+            result.putString("iface", statsEntry.iface);
+            result.putLong("rxBytes", statsEntry.rxBytes);
+            result.putLong("txBytes", statsEntry.txBytes);
+            getInstrumentation().sendStatus(INSTRUMENTATION_IN_PROGRESS, result);
+        }
+    }
+}
diff --git a/voip/jni/rtp/AmrCodec.cpp b/voip/jni/rtp/AmrCodec.cpp
index 84c7166..e2d820e 100644
--- a/voip/jni/rtp/AmrCodec.cpp
+++ b/voip/jni/rtp/AmrCodec.cpp
@@ -52,7 +52,7 @@
 
     int set(int sampleRate, const char *fmtp);
     int encode(void *payload, int16_t *samples);
-    int decode(int16_t *samples, void *payload, int length);
+    int decode(int16_t *samples, int count, void *payload, int length);
 
 private:
     void *mEncoder;
@@ -128,7 +128,7 @@
     return length;
 }
 
-int AmrCodec::decode(int16_t *samples, void *payload, int length)
+int AmrCodec::decode(int16_t *samples, int count, void *payload, int length)
 {
     unsigned char *bytes = (unsigned char *)payload;
     Frame_Type_3GPP type;
@@ -213,7 +213,7 @@
     }
 
     int encode(void *payload, int16_t *samples);
-    int decode(int16_t *samples, void *payload, int length);
+    int decode(int16_t *samples, int count, void *payload, int length);
 
 private:
     void *mEncoder;
@@ -239,20 +239,24 @@
     return -1;
 }
 
-int GsmEfrCodec::decode(int16_t *samples, void *payload, int length)
+int GsmEfrCodec::decode(int16_t *samples, int count, void *payload, int length)
 {
     unsigned char *bytes = (unsigned char *)payload;
-    if (length == 31 && (bytes[0] >> 4) == 0x0C) {
+    int n = 0;
+    while (n + 160 <= count && length >= 31 && (bytes[0] >> 4) == 0x0C) {
         for (int i = 0; i < 30; ++i) {
             bytes[i] = (bytes[i] << 4) | (bytes[i + 1] >> 4);
         }
         bytes[30] <<= 4;
 
-        if (AMRDecode(mDecoder, AMR_122, bytes, samples, MIME_IETF) == 31) {
-            return 160;
+        if (AMRDecode(mDecoder, AMR_122, bytes, &samples[n], MIME_IETF) != 31) {
+            break;
         }
+        n += 160;
+        length -= 31;
+        bytes += 31;
     }
-    return -1;
+    return n;
 }
 
 } // namespace
diff --git a/voip/jni/rtp/AudioCodec.h b/voip/jni/rtp/AudioCodec.h
index e389255..741730b 100644
--- a/voip/jni/rtp/AudioCodec.h
+++ b/voip/jni/rtp/AudioCodec.h
@@ -30,7 +30,7 @@
     // Returns the length of payload in bytes.
     virtual int encode(void *payload, int16_t *samples) = 0;
     // Returns the number of decoded samples.
-    virtual int decode(int16_t *samples, void *payload, int length) = 0;
+    virtual int decode(int16_t *samples, int count, void *payload, int length) = 0;
 };
 
 AudioCodec *newAudioCodec(const char *codecName);
diff --git a/voip/jni/rtp/AudioGroup.cpp b/voip/jni/rtp/AudioGroup.cpp
index 5f07bb5..93c809e 100644
--- a/voip/jni/rtp/AudioGroup.cpp
+++ b/voip/jni/rtp/AudioGroup.cpp
@@ -395,7 +395,8 @@
         mLatencyTimer = tick;
     }
 
-    if (mBufferTail - mBufferHead > BUFFER_SIZE - mInterval) {
+    int count = (BUFFER_SIZE - (mBufferTail - mBufferHead)) * mSampleRate;
+    if (count < mSampleCount) {
         // Buffer overflow. Drop the packet.
         LOGV("stream[%d] buffer overflow", mSocket);
         recv(mSocket, &c, 1, MSG_DONTWAIT);
@@ -403,19 +404,18 @@
     }
 
     // Receive the packet and decode it.
-    int16_t samples[mSampleCount];
-    int length = 0;
+    int16_t samples[count];
     if (!mCodec) {
         // Special case for device stream.
-        length = recv(mSocket, samples, sizeof(samples),
+        count = recv(mSocket, samples, sizeof(samples),
             MSG_TRUNC | MSG_DONTWAIT) >> 1;
     } else {
         __attribute__((aligned(4))) uint8_t buffer[2048];
         sockaddr_storage remote;
-        socklen_t len = sizeof(remote);
+        socklen_t addrlen = sizeof(remote);
 
-        length = recvfrom(mSocket, buffer, sizeof(buffer),
-            MSG_TRUNC | MSG_DONTWAIT, (sockaddr *)&remote, &len);
+        int length = recvfrom(mSocket, buffer, sizeof(buffer),
+            MSG_TRUNC | MSG_DONTWAIT, (sockaddr *)&remote, &addrlen);
 
         // Do we need to check SSRC, sequence, and timestamp? They are not
         // reliable but at least they can be used to identify duplicates?
@@ -433,14 +433,15 @@
         }
         length -= offset;
         if (length >= 0) {
-            length = mCodec->decode(samples, &buffer[offset], length);
+            length = mCodec->decode(samples, count, &buffer[offset], length);
         }
         if (length > 0 && mFixRemote) {
             mRemote = remote;
             mFixRemote = false;
         }
+        count = length;
     }
-    if (length <= 0) {
+    if (count <= 0) {
         LOGV("stream[%d] decoder error", mSocket);
         return;
     }
@@ -462,7 +463,7 @@
 
     // Append to the jitter buffer.
     int tail = mBufferTail * mSampleRate;
-    for (int i = 0; i < mSampleCount; ++i) {
+    for (int i = 0; i < count; ++i) {
         mBuffer[tail & mBufferMask] = samples[i];
         ++tail;
     }
diff --git a/voip/jni/rtp/G711Codec.cpp b/voip/jni/rtp/G711Codec.cpp
index a467acf..ef54863 100644
--- a/voip/jni/rtp/G711Codec.cpp
+++ b/voip/jni/rtp/G711Codec.cpp
@@ -39,7 +39,7 @@
         return mSampleCount;
     }
     int encode(void *payload, int16_t *samples);
-    int decode(int16_t *samples, void *payload, int length);
+    int decode(int16_t *samples, int count, void *payload, int length);
 private:
     int mSampleCount;
 };
@@ -64,9 +64,12 @@
     return mSampleCount;
 }
 
-int UlawCodec::decode(int16_t *samples, void *payload, int length)
+int UlawCodec::decode(int16_t *samples, int count, void *payload, int length)
 {
     int8_t *ulaws = (int8_t *)payload;
+    if (length > count) {
+        length = count;
+    }
     for (int i = 0; i < length; ++i) {
         int ulaw = ~ulaws[i];
         int exponent = (ulaw >> 4) & 0x07;
@@ -87,7 +90,7 @@
         return mSampleCount;
     }
     int encode(void *payload, int16_t *samples);
-    int decode(int16_t *samples, void *payload, int length);
+    int decode(int16_t *samples, int count, void *payload, int length);
 private:
     int mSampleCount;
 };
@@ -111,9 +114,12 @@
     return mSampleCount;
 }
 
-int AlawCodec::decode(int16_t *samples, void *payload, int length)
+int AlawCodec::decode(int16_t *samples, int count, void *payload, int length)
 {
     int8_t *alaws = (int8_t *)payload;
+    if (length > count) {
+        length = count;
+    }
     for (int i = 0; i < length; ++i) {
         int alaw = alaws[i] ^ 0x55;
         int exponent = (alaw >> 4) & 0x07;
diff --git a/voip/jni/rtp/GsmCodec.cpp b/voip/jni/rtp/GsmCodec.cpp
index 8d2286e..61dfdc9 100644
--- a/voip/jni/rtp/GsmCodec.cpp
+++ b/voip/jni/rtp/GsmCodec.cpp
@@ -44,7 +44,7 @@
     }
 
     int encode(void *payload, int16_t *samples);
-    int decode(int16_t *samples, void *payload, int length);
+    int decode(int16_t *samples, int count, void *payload, int length);
 
 private:
     gsm mEncode;
@@ -57,13 +57,17 @@
     return 33;
 }
 
-int GsmCodec::decode(int16_t *samples, void *payload, int length)
+int GsmCodec::decode(int16_t *samples, int count, void *payload, int length)
 {
-    if (length == 33 &&
-        gsm_decode(mDecode, (unsigned char *)payload, samples) == 0) {
-        return 160;
+    unsigned char *bytes = (unsigned char *)payload;
+    int n = 0;
+    while (n + 160 <= count && length >= 33 &&
+        gsm_decode(mDecode, bytes, &samples[n]) == 0) {
+        n += 160;
+        length -= 33;
+        bytes += 33;
     }
-    return -1;
+    return n;
 }
 
 } // namespace