Merge "Hide RTL related APIs - DO NOT MERGE" into jb-dev
diff --git a/api/current.txt b/api/current.txt
index 5804c0f..a3c4901 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3762,12 +3762,18 @@
     ctor public Notification.BigPictureStyle();
     ctor public Notification.BigPictureStyle(android.app.Notification.Builder);
     method public android.app.Notification.BigPictureStyle bigPicture(android.graphics.Bitmap);
+    method public android.app.Notification build();
+    method public android.app.Notification.BigPictureStyle setBigContentTitle(java.lang.CharSequence);
+    method public android.app.Notification.BigPictureStyle setSummaryText(java.lang.CharSequence);
   }
 
   public static class Notification.BigTextStyle extends android.app.Notification.Style {
     ctor public Notification.BigTextStyle();
     ctor public Notification.BigTextStyle(android.app.Notification.Builder);
     method public android.app.Notification.BigTextStyle bigText(java.lang.CharSequence);
+    method public android.app.Notification build();
+    method public android.app.Notification.BigTextStyle setBigContentTitle(java.lang.CharSequence);
+    method public android.app.Notification.BigTextStyle setSummaryText(java.lang.CharSequence);
   }
 
   public static class Notification.Builder {
@@ -3809,11 +3815,18 @@
     ctor public Notification.InboxStyle();
     ctor public Notification.InboxStyle(android.app.Notification.Builder);
     method public android.app.Notification.InboxStyle addLine(java.lang.CharSequence);
+    method public android.app.Notification build();
+    method public android.app.Notification.InboxStyle setBigContentTitle(java.lang.CharSequence);
+    method public android.app.Notification.InboxStyle setSummaryText(java.lang.CharSequence);
   }
 
-  public static class Notification.Style {
+  public static abstract class Notification.Style {
     ctor public Notification.Style();
-    method public android.app.Notification build();
+    method public abstract android.app.Notification build();
+    method protected void checkBuilder();
+    method protected android.widget.RemoteViews getStandardView(int);
+    method protected void internalSetBigContentTitle(java.lang.CharSequence);
+    method protected void internalSetSummaryText(java.lang.CharSequence);
     method public void setBuilder(android.app.Notification.Builder);
     field protected android.app.Notification.Builder mBuilder;
   }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 8f4efab..b60eed9 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1397,7 +1397,8 @@
 
             if (mSubText != null) {
                 contentView.setTextViewText(R.id.text, mSubText);
-                contentView.setViewVisibility(R.id.text2, View.VISIBLE);
+                contentView.setViewVisibility(R.id.text2,
+                        mContentText != null ? View.VISIBLE : View.GONE);
             } else {
                 contentView.setViewVisibility(R.id.text2, View.GONE);
                 if (mProgressMax != 0 || mProgressIndeterminate) {
@@ -1428,12 +1429,12 @@
 
             int N = mActions.size();
             if (N > 0) {
-                Log.d("Notification", "has actions: " + mContentText);
+                // Log.d("Notification", "has actions: " + mContentText);
                 big.setViewVisibility(R.id.actions, View.VISIBLE);
                 if (N>3) N=3;
                 for (int i=0; i<N; i++) {
                     final RemoteViews button = generateActionButton(mActions.get(i));
-                    Log.d("Notification", "adding action " + i + ": " + mActions.get(i).title);
+                    //Log.d("Notification", "adding action " + i + ": " + mActions.get(i).title);
                     big.addView(R.id.actions, button);
                 }
             }
@@ -1549,9 +1550,28 @@
      * An object that can apply a rich notification style to a {@link Notification.Builder}
      * object.
      */
-    public static class Style {
+    public static abstract class Style
+    {
+        private CharSequence mBigContentTitle;
+        private CharSequence mSummaryText = null;
+
         protected Builder mBuilder;
 
+        /**
+         * Overrides ContentTitle in the big form of the template.
+         * This defaults to the value passed to setContentTitle().
+         */
+        protected void internalSetBigContentTitle(CharSequence title) {
+            mBigContentTitle = title;
+        }
+
+        /**
+         * Set the first line of text after the detail section in the big form of the template.
+         */
+        protected void internalSetSummaryText(CharSequence cs) {
+            mSummaryText = cs;
+        }
+
         public void setBuilder(Builder builder) {
             if (mBuilder != builder) {
                 mBuilder = builder;
@@ -1559,12 +1579,42 @@
             }
         }
 
-        public Notification build() {
+        protected void checkBuilder() {
             if (mBuilder == null) {
                 throw new IllegalArgumentException("Style requires a valid Builder object");
             }
-            return mBuilder.buildUnstyled();
         }
+
+        protected RemoteViews getStandardView(int layoutId) {
+            checkBuilder();
+
+            if (mBigContentTitle != null) {
+                mBuilder.setContentTitle(mBigContentTitle);
+            }
+
+            if (mBuilder.mSubText == null) {
+                mBuilder.setContentText(null);
+            }
+
+            RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(layoutId);
+
+            if (mBuilder.mSubText == null) {
+                contentView.setViewVisibility(R.id.line3, View.GONE);
+            }
+
+            if (mBigContentTitle != null && mBigContentTitle.equals("")) {
+                contentView.setViewVisibility(R.id.line1, View.GONE);
+            }
+
+            if (mSummaryText != null && !mSummaryText.equals("")) {
+                contentView.setViewVisibility(R.id.overflow_title, View.VISIBLE);
+                contentView.setTextViewText(R.id.overflow_title, mSummaryText);
+            }
+
+            return contentView;
+        }
+
+        public abstract Notification build();
     }
 
     /**
@@ -1594,13 +1644,30 @@
             setBuilder(builder);
         }
 
+        /**
+         * Overrides ContentTitle in the big form of the template.
+         * This defaults to the value passed to setContentTitle().
+         */
+        public BigPictureStyle setBigContentTitle(CharSequence title) {
+            internalSetBigContentTitle(title);
+            return this;
+        }
+
+        /**
+         * Set the first line of text after the detail section in the big form of the template.
+         */
+        public BigPictureStyle setSummaryText(CharSequence cs) {
+            internalSetSummaryText(cs);
+            return this;
+        }
+
         public BigPictureStyle bigPicture(Bitmap b) {
             mPicture = b;
             return this;
         }
 
         private RemoteViews makeBigContentView() {
-            RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(R.layout.notification_template_big_picture);
+            RemoteViews contentView = getStandardView(R.layout.notification_template_big_picture);
 
             contentView.setImageViewBitmap(R.id.big_picture, mPicture);
 
@@ -1609,9 +1676,7 @@
 
         @Override
         public Notification build() {
-            if (mBuilder == null) {
-                throw new IllegalArgumentException("Style requires a valid Builder object");
-            }
+            checkBuilder();
             Notification wip = mBuilder.buildUnstyled();
             wip.bigContentView = makeBigContentView();
             return wip;
@@ -1645,26 +1710,39 @@
             setBuilder(builder);
         }
 
+        /**
+         * Overrides ContentTitle in the big form of the template.
+         * This defaults to the value passed to setContentTitle().
+         */
+        public BigTextStyle setBigContentTitle(CharSequence title) {
+            internalSetBigContentTitle(title);
+            return this;
+        }
+
+        /**
+         * Set the first line of text after the detail section in the big form of the template.
+         */
+        public BigTextStyle setSummaryText(CharSequence cs) {
+            internalSetSummaryText(cs);
+            return this;
+        }
+
         public BigTextStyle bigText(CharSequence cs) {
             mBigText = cs;
             return this;
         }
 
         private RemoteViews makeBigContentView() {
-            int bigTextId = R.layout.notification_template_big_text;
-            RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(bigTextId);
+            RemoteViews contentView = getStandardView(R.layout.notification_template_big_text);
             contentView.setTextViewText(R.id.big_text, mBigText);
             contentView.setViewVisibility(R.id.big_text, View.VISIBLE);
-            contentView.setViewVisibility(R.id.text2, View.GONE);
 
             return contentView;
         }
 
         @Override
         public Notification build() {
-            if (mBuilder == null) {
-                throw new IllegalArgumentException("Style requires a valid Builder object");
-            }
+            checkBuilder();
             Notification wip = mBuilder.buildUnstyled();
             wip.bigContentView = makeBigContentView();
             return wip;
@@ -1678,12 +1756,14 @@
      * <pre class="prettyprint">
      * Notification noti = new Notification.InboxStyle(
      *      new Notification.Builder()
-     *         .setContentTitle(&quot;New mail from &quot; + sender.toString())
+     *         .setContentTitle(&quot;5 New mails from &quot; + sender.toString())
      *         .setContentText(subject)
      *         .setSmallIcon(R.drawable.new_mail)
      *         .setLargeIcon(aBitmap))
      *      .addLine(str1)
      *      .addLine(str2)
+     *      .setContentTitle("")
+     *      .setSummaryText(&quot;+3 more&quot;)
      *      .build();
      * </pre>
      * 
@@ -1699,16 +1779,35 @@
             setBuilder(builder);
         }
 
+        /**
+         * Overrides ContentTitle in the big form of the template.
+         * This defaults to the value passed to setContentTitle().
+         */
+        public InboxStyle setBigContentTitle(CharSequence title) {
+            internalSetBigContentTitle(title);
+            return this;
+        }
+
+        /**
+         * Set the first line of text after the detail section in the big form of the template.
+         */
+        public InboxStyle setSummaryText(CharSequence cs) {
+            internalSetSummaryText(cs);
+            return this;
+        }
+
         public InboxStyle addLine(CharSequence cs) {
             mTexts.add(cs);
             return this;
         }
 
         private RemoteViews makeBigContentView() {
-            RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(R.layout.notification_template_inbox);
+            RemoteViews contentView = getStandardView(R.layout.notification_template_inbox);
+            contentView.setViewVisibility(R.id.text2, View.GONE);
 
-            int[] rowIds = {R.id.inbox_text0, R.id.inbox_text1, R.id.inbox_text2, R.id.inbox_text3, R.id.inbox_text4};
-            
+            int[] rowIds = {R.id.inbox_text0, R.id.inbox_text1, R.id.inbox_text2, R.id.inbox_text3,
+                    R.id.inbox_text4};
+
             int i=0;
             while (i < mTexts.size() && i < rowIds.length) {
                 CharSequence str = mTexts.get(i);
@@ -1724,9 +1823,7 @@
 
         @Override
         public Notification build() {
-            if (mBuilder == null) {
-                throw new IllegalArgumentException("Style requires a valid Builder object");
-            }
+            checkBuilder();
             Notification wip = mBuilder.buildUnstyled();
             wip.bigContentView = makeBigContentView();
             return wip;
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index 08d4c6c..b7b8731 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -42,5 +42,7 @@
     void setUidForeground(int uid, boolean uidForeground);
     /** Force update of statistics. */
     void forceUpdate();
+    /** Advise persistance threshold; may be overridden internally. */
+    void advisePersistThreshold(long thresholdBytes);
 
 }
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index 4ac5e76..3c67bf9 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -158,9 +158,14 @@
             }
 
         } else if (type == TYPE_WIFI) {
-            final WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
-            final WifiInfo info = wifi.getConnectionInfo();
-            networkId = info != null ? info.getSSID() : null;
+            if (state.networkId != null) {
+                networkId = state.networkId;
+            } else {
+                final WifiManager wifi = (WifiManager) context.getSystemService(
+                        Context.WIFI_SERVICE);
+                final WifiInfo info = wifi.getConnectionInfo();
+                networkId = info != null ? info.getSSID() : null;
+            }
         }
 
         return new NetworkIdentity(type, subType, subscriberId, networkId, roaming);
diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java
index 2fc69ad..fbe1f82 100644
--- a/core/java/android/net/NetworkState.java
+++ b/core/java/android/net/NetworkState.java
@@ -31,18 +31,20 @@
     public final LinkCapabilities linkCapabilities;
     /** Currently only used by testing. */
     public final String subscriberId;
+    public final String networkId;
 
     public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties,
             LinkCapabilities linkCapabilities) {
-        this(networkInfo, linkProperties, linkCapabilities, null);
+        this(networkInfo, linkProperties, linkCapabilities, null, null);
     }
 
     public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties,
-            LinkCapabilities linkCapabilities, String subscriberId) {
+            LinkCapabilities linkCapabilities, String subscriberId, String networkId) {
         this.networkInfo = networkInfo;
         this.linkProperties = linkProperties;
         this.linkCapabilities = linkCapabilities;
         this.subscriberId = subscriberId;
+        this.networkId = networkId;
     }
 
     public NetworkState(Parcel in) {
@@ -50,6 +52,7 @@
         linkProperties = in.readParcelable(null);
         linkCapabilities = in.readParcelable(null);
         subscriberId = in.readString();
+        networkId = in.readString();
     }
 
     @Override
@@ -63,6 +66,7 @@
         out.writeParcelable(linkProperties, flags);
         out.writeParcelable(linkCapabilities, flags);
         out.writeString(subscriberId);
+        out.writeString(networkId);
     }
 
     public static final Creator<NetworkState> CREATOR = new Creator<NetworkState>() {
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 6ecc640..e7ea355 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -238,7 +238,8 @@
      * Return global network statistics summarized at an interface level,
      * without any UID-level granularity.
      */
-    NetworkStats getNetworkStatsSummary();
+    NetworkStats getNetworkStatsSummaryDev();
+    NetworkStats getNetworkStatsSummaryXt();
 
     /**
      * Return detailed network statistics with UID-level granularity,
diff --git a/core/java/android/util/MathUtils.java b/core/java/android/util/MathUtils.java
index b35dd1e..13a692e 100644
--- a/core/java/android/util/MathUtils.java
+++ b/core/java/android/util/MathUtils.java
@@ -39,6 +39,10 @@
         return amount < low ? low : (amount > high ? high : amount);
     }
 
+    public static long constrain(long amount, long low, long high) {
+        return amount < low ? low : (amount > high ? high : amount);
+    }
+
     public static float constrain(float amount, float low, float high) {
         return amount < low ? low : (amount > high ? high : amount);
     }
diff --git a/core/java/android/webkit/AutoCompletePopup.java b/core/java/android/webkit/AutoCompletePopup.java
index 21d5e02..87e878b 100644
--- a/core/java/android/webkit/AutoCompletePopup.java
+++ b/core/java/android/webkit/AutoCompletePopup.java
@@ -28,12 +28,15 @@
 import android.widget.Filterable;
 import android.widget.ListAdapter;
 import android.widget.ListPopupWindow;
+import android.widget.PopupWindow.OnDismissListener;
 
-class AutoCompletePopup implements OnItemClickListener, Filter.FilterListener {
+class AutoCompletePopup implements OnItemClickListener, Filter.FilterListener,
+        OnDismissListener{
     private static class AnchorView extends View {
         AnchorView(Context context) {
             super(context);
             setFocusable(false);
+            setVisibility(INVISIBLE);
         }
     }
     private static final int AUTOFILL_FORM = 100;
@@ -48,17 +51,10 @@
     private WebViewClassic.WebViewInputConnection mInputConnection;
     private WebViewClassic mWebView;
 
-    public AutoCompletePopup(Context context,
-            WebViewClassic webView,
+    public AutoCompletePopup(WebViewClassic webView,
             WebViewClassic.WebViewInputConnection inputConnection) {
         mInputConnection = inputConnection;
         mWebView = webView;
-        mPopup = new ListPopupWindow(context);
-        mAnchor = new AnchorView(context);
-        mWebView.getWebView().addView(mAnchor);
-        mPopup.setOnItemClickListener(this);
-        mPopup.setAnchorView(mAnchor);
-        mPopup.setPromptPosition(ListPopupWindow.POSITION_PROMPT_BELOW);
         mHandler = new Handler() {
             @Override
             public void handleMessage(Message msg) {
@@ -72,6 +68,9 @@
     }
 
     public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+        if (mPopup == null) {
+            return false;
+        }
         if (keyCode == KeyEvent.KEYCODE_BACK && mPopup.isShowing()) {
             // special case for the back key, we do not even try to send it
             // to the drop down list but instead, consume it immediately
@@ -112,11 +111,14 @@
     public void clearAdapter() {
         mAdapter = null;
         mFilter = null;
-        mPopup.dismiss();
-        mPopup.setAdapter(null);
+        if (mPopup != null) {
+            mPopup.dismiss();
+            mPopup.setAdapter(null);
+        }
     }
 
     public <T extends ListAdapter & Filterable> void setAdapter(T adapter) {
+        ensurePopup();
         mPopup.setAdapter(adapter);
         mAdapter = adapter;
         if (adapter != null) {
@@ -129,6 +131,7 @@
     }
 
     public void resetRect() {
+        ensurePopup();
         int left = mWebView.contentToViewX(mWebView.mEditTextContentBounds.left);
         int right = mWebView.contentToViewX(mWebView.mEditTextContentBounds.right);
         int width = right - left;
@@ -164,6 +167,9 @@
     // AdapterView.OnItemClickListener implementation
     @Override
     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+        if (mPopup == null) {
+            return;
+        }
         if (id == 0 && position == 0 && mInputConnection.getIsAutoFillable()) {
             mText = "";
             pushTextToInputConnection();
@@ -206,6 +212,7 @@
 
     @Override
     public void onFilterComplete(int count) {
+        ensurePopup();
         boolean showDropDown = (count > 0) &&
                 (mInputConnection.getIsAutoFillable() || mText.length() > 0);
         if (showDropDown) {
@@ -219,5 +226,23 @@
             mPopup.dismiss();
         }
     }
+
+    @Override
+    public void onDismiss() {
+        mWebView.getWebView().removeView(mAnchor);
+    }
+
+    private void ensurePopup() {
+        if (mPopup == null) {
+            mPopup = new ListPopupWindow(mWebView.getContext());
+            mAnchor = new AnchorView(mWebView.getContext());
+            mWebView.getWebView().addView(mAnchor);
+            mPopup.setOnItemClickListener(this);
+            mPopup.setAnchorView(mAnchor);
+            mPopup.setPromptPosition(ListPopupWindow.POSITION_PROMPT_BELOW);
+        } else if (mWebView.getWebView().indexOfChild(mAnchor) < 0) {
+            mWebView.getWebView().addView(mAnchor);
+        }
+    }
 }
 
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index 75e7b57..1bab91f 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -4696,8 +4696,7 @@
     public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
         if (mInputConnection == null) {
             mInputConnection = new WebViewInputConnection();
-            mAutoCompletePopup = new AutoCompletePopup(mContext, this,
-                    mInputConnection);
+            mAutoCompletePopup = new AutoCompletePopup(this, mInputConnection);
         }
         mInputConnection.setupEditorInfo(outAttrs);
         return mInputConnection;
diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java
index d59585f..8b222f0 100644
--- a/core/java/com/android/internal/net/NetworkStatsFactory.java
+++ b/core/java/com/android/internal/net/NetworkStatsFactory.java
@@ -24,20 +24,12 @@
 import android.net.NetworkStats;
 import android.os.StrictMode;
 import android.os.SystemClock;
-import android.util.Slog;
 
 import com.android.internal.util.ProcFileReader;
-import com.google.android.collect.Lists;
-import com.google.android.collect.Sets;
 
-import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileReader;
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.StringTokenizer;
 
 import libcore.io.IoUtils;
 
@@ -50,14 +42,10 @@
 
     // TODO: consider moving parsing to native code
 
-    /** Path to {@code /proc/net/dev}. */
-    @Deprecated
-    private final File mStatsIface;
-    /** Path to {@code /proc/net/xt_qtaguid/iface_stat}. */
-    @Deprecated
-    private final File mStatsXtIface;
     /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */
     private final File mStatsXtIfaceAll;
+    /** Path to {@code /proc/net/xt_qtaguid/iface_stat_fmt}. */
+    private final File mStatsXtIfaceFmt;
     /** Path to {@code /proc/net/xt_qtaguid/stats}. */
     private final File mStatsXtUid;
 
@@ -67,28 +55,20 @@
 
     // @VisibleForTesting
     public NetworkStatsFactory(File procRoot) {
-        mStatsIface = new File(procRoot, "net/dev");
-        mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
-        mStatsXtIface = new File(procRoot, "net/xt_qtaguid/iface_stat");
         mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all");
+        mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt");
+        mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
     }
 
     /**
-     * Parse and return interface-level summary {@link NetworkStats}. Values
-     * monotonically increase since device boot, and may include details about
-     * inactive interfaces.
+     * Parse and return interface-level summary {@link NetworkStats} measured
+     * using {@code /proc/net/dev} style hooks, which may include non IP layer
+     * traffic. Values monotonically increase since device boot, and may include
+     * details about inactive interfaces.
      *
      * @throws IllegalStateException when problem parsing stats.
      */
-    public NetworkStats readNetworkStatsSummary() throws IllegalStateException {
-        if (mStatsXtIfaceAll.exists()) {
-            return readNetworkStatsSummarySingleFile();
-        } else {
-            return readNetworkStatsSummaryMultipleFiles();
-        }
-    }
-
-    private NetworkStats readNetworkStatsSummarySingleFile() {
+    public NetworkStats readNetworkStatsSummaryDev() throws IllegalStateException {
         final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
 
         final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
@@ -137,79 +117,40 @@
     }
 
     /**
-     * @deprecated remove once {@code iface_stat_all} is merged to all kernels.
+     * Parse and return interface-level summary {@link NetworkStats}. Designed
+     * to return only IP layer traffic. Values monotonically increase since
+     * device boot, and may include details about inactive interfaces.
+     *
+     * @throws IllegalStateException when problem parsing stats.
      */
-    @Deprecated
-    private NetworkStats readNetworkStatsSummaryMultipleFiles() {
+    public NetworkStats readNetworkStatsSummaryXt() throws IllegalStateException {
         final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
 
+        // return null when kernel doesn't support
+        if (!mStatsXtIfaceFmt.exists()) return null;
+
         final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
         final NetworkStats.Entry entry = new NetworkStats.Entry();
 
-        final HashSet<String> knownIfaces = Sets.newHashSet();
-        final HashSet<String> activeIfaces = Sets.newHashSet();
-
-        // collect any historical stats and active state
-        for (String iface : fileListWithoutNull(mStatsXtIface)) {
-            final File ifacePath = new File(mStatsXtIface, iface);
-
-            final long active = readSingleLongFromFile(new File(ifacePath, "active"));
-            if (active == 1) {
-                knownIfaces.add(iface);
-                activeIfaces.add(iface);
-            } else if (active == 0) {
-                knownIfaces.add(iface);
-            } else {
-                continue;
-            }
-
-            entry.iface = iface;
-            entry.uid = UID_ALL;
-            entry.set = SET_ALL;
-            entry.tag = TAG_NONE;
-            entry.rxBytes = readSingleLongFromFile(new File(ifacePath, "rx_bytes"));
-            entry.rxPackets = readSingleLongFromFile(new File(ifacePath, "rx_packets"));
-            entry.txBytes = readSingleLongFromFile(new File(ifacePath, "tx_bytes"));
-            entry.txPackets = readSingleLongFromFile(new File(ifacePath, "tx_packets"));
-
-            stats.addValues(entry);
-        }
-
-        final ArrayList<String> values = Lists.newArrayList();
-
-        BufferedReader reader = null;
+        ProcFileReader reader = null;
         try {
-            reader = new BufferedReader(new FileReader(mStatsIface));
+            // open and consume header line
+            reader = new ProcFileReader(new FileInputStream(mStatsXtIfaceFmt));
+            reader.finishLine();
 
-            // skip first two header lines
-            reader.readLine();
-            reader.readLine();
+            while (reader.hasMoreData()) {
+                entry.iface = reader.nextString();
+                entry.uid = UID_ALL;
+                entry.set = SET_ALL;
+                entry.tag = TAG_NONE;
 
-            // parse remaining lines
-            String line;
-            while ((line = reader.readLine()) != null) {
-                splitLine(line, values);
+                entry.rxBytes = reader.nextLong();
+                entry.rxPackets = reader.nextLong();
+                entry.txBytes = reader.nextLong();
+                entry.txPackets = reader.nextLong();
 
-                try {
-                    entry.iface = values.get(0);
-                    entry.uid = UID_ALL;
-                    entry.set = SET_ALL;
-                    entry.tag = TAG_NONE;
-                    entry.rxBytes = Long.parseLong(values.get(1));
-                    entry.rxPackets = Long.parseLong(values.get(2));
-                    entry.txBytes = Long.parseLong(values.get(9));
-                    entry.txPackets = Long.parseLong(values.get(10));
-
-                    if (activeIfaces.contains(entry.iface)) {
-                        // combine stats when iface is active
-                        stats.combineValues(entry);
-                    } else if (!knownIfaces.contains(entry.iface)) {
-                        // add stats when iface is unknown
-                        stats.addValues(entry);
-                    }
-                } catch (NumberFormatException e) {
-                    Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
-                }
+                stats.addValues(entry);
+                reader.finishLine();
             }
         } catch (NullPointerException e) {
             throw new IllegalStateException("problem parsing stats: " + e);
@@ -221,7 +162,6 @@
             IoUtils.closeQuietly(reader);
             StrictMode.setThreadPolicy(savedPolicy);
         }
-
         return stats;
     }
 
@@ -286,41 +226,4 @@
 
         return stats;
     }
-
-    /**
-     * Split given line into {@link ArrayList}.
-     */
-    @Deprecated
-    private static void splitLine(String line, ArrayList<String> outSplit) {
-        outSplit.clear();
-
-        final StringTokenizer t = new StringTokenizer(line, " \t\n\r\f:");
-        while (t.hasMoreTokens()) {
-            outSplit.add(t.nextToken());
-        }
-    }
-
-    /**
-     * Utility method to read a single plain-text {@link Long} from the given
-     * {@link File}, usually from a {@code /proc/} filesystem.
-     */
-    private static long readSingleLongFromFile(File file) {
-        try {
-            final byte[] buffer = IoUtils.readFileAsByteArray(file.toString());
-            return Long.parseLong(new String(buffer).trim());
-        } catch (NumberFormatException e) {
-            return -1;
-        } catch (IOException e) {
-            return -1;
-        }
-    }
-
-    /**
-     * Wrapper for {@link File#list()} that returns empty array instead of
-     * {@code null}.
-     */
-    private static String[] fileListWithoutNull(File file) {
-        final String[] list = file.list();
-        return list != null ? list : new String[0];
-    }
 }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 86118b1..5157385 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -5719,7 +5719,7 @@
 
                 if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) {
                     try {
-                        mNetworkSummaryCache = mNetworkStatsFactory.readNetworkStatsSummary();
+                        mNetworkSummaryCache = mNetworkStatsFactory.readNetworkStatsSummaryDev();
                     } catch (IllegalStateException e) {
                         Log.wtf(TAG, "problem reading network stats", e);
                     }
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index a33b46a..2bd36c3 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -739,18 +739,18 @@
 #endif
 }
 
-
-size_t TextLayoutShaper::shapeFontRun(const SkPaint* paint, bool isRTL) {
-    // Reset kerning
-    mShaperItem.kerning_applied = false;
-
-    // Update Harfbuzz Shaper
-    mShaperItem.item.bidiLevel = isRTL;
-
-    SkTypeface* typeface = paint->getTypeface();
-
+/**
+ * Return the first typeface in the logical change, starting with this typeface,
+ * that contains the specified unichar, or NULL if none is found.
+ * 
+ * Note that this function does _not_ increment the reference count on the typeface, as the
+ * assumption is that its lifetime is managed elsewhere - in particular, the fallback typefaces
+ * for the default font live in a global cache.
+ */
+SkTypeface* TextLayoutShaper::typefaceForUnichar(const SkPaint* paint, SkTypeface* typeface,
+        SkUnichar unichar, HB_Script script) {
     // Set the correct Typeface depending on the script
-    switch (mShaperItem.item.script) {
+    switch (script) {
     case HB_Script_Arabic:
         typeface = getCachedTypeface(&mArabicTypeface, TYPEFACE_ARABIC);
 #if DEBUG_GLYPHS
@@ -815,32 +815,31 @@
         break;
 
     default:
-        if (!typeface) {
-            typeface = mDefaultTypeface;
 #if DEBUG_GLYPHS
-            ALOGD("Using Default Typeface");
-#endif
-        } else {
-#if DEBUG_GLYPHS
+        if (typeface) {
             ALOGD("Using Paint Typeface");
-#endif
         }
+#endif
         break;
     }
+    return typeface;
+}
 
-    mShapingPaint.setTypeface(typeface);
-    mShaperItem.face = getCachedHBFace(typeface);
+size_t TextLayoutShaper::shapeFontRun(const SkPaint* paint, bool isRTL) {
+    // Reset kerning
+    mShaperItem.kerning_applied = false;
 
-#if DEBUG_GLYPHS
-    ALOGD("Run typeface = %p, uniqueID = %d, hb_face = %p",
-            typeface, typeface->uniqueID(), mShaperItem.face);
-#endif
+    // Update Harfbuzz Shaper
+    mShaperItem.item.bidiLevel = isRTL;
+
+    SkTypeface* typeface = paint->getTypeface();
 
     // Get the glyphs base count for offsetting the glyphIDs returned by Harfbuzz
     // This is needed as the Typeface used for shaping can be not the default one
     // when we are shaping any script that needs to use a fallback Font.
     // If we are a "common" script we dont need to shift
     size_t baseGlyphCount = 0;
+    SkUnichar firstUnichar = 0;
     switch (mShaperItem.item.script) {
     case HB_Script_Arabic:
     case HB_Script_Hebrew:
@@ -849,7 +848,11 @@
     case HB_Script_Tamil:
     case HB_Script_Thai:{
         const uint16_t* text16 = (const uint16_t*)(mShaperItem.string + mShaperItem.item.pos);
-        SkUnichar firstUnichar = SkUTF16_NextUnichar(&text16);
+        const uint16_t* text16End = text16 + mShaperItem.item.length;
+        firstUnichar = SkUTF16_NextUnichar(&text16);
+        while (firstUnichar == ' ' && text16 < text16End) {
+            firstUnichar = SkUTF16_NextUnichar(&text16);
+        }
         baseGlyphCount = paint->getBaseGlyphCount(firstUnichar);
         break;
     }
@@ -857,6 +860,25 @@
         break;
     }
 
+    // We test the baseGlyphCount to see if the typeface supports the requested script
+    if (baseGlyphCount != 0) {
+        typeface = typefaceForUnichar(paint, typeface, firstUnichar, mShaperItem.item.script);
+    }
+
+    if (!typeface) {
+        typeface = mDefaultTypeface;
+#if DEBUG_GLYPHS
+        ALOGD("Using Default Typeface");
+#endif
+    }
+    mShapingPaint.setTypeface(typeface);
+    mShaperItem.face = getCachedHBFace(typeface);
+
+#if DEBUG_GLYPHS
+    ALOGD("Run typeface = %p, uniqueID = %d, hb_face = %p",
+            typeface, typeface->uniqueID(), mShaperItem.face);
+#endif
+
     // Shape
     assert(mShaperItem.item.length > 0); // Harfbuzz will overwrite other memory if length is 0.
     ensureShaperItemGlyphArrays(mShaperItem.item.length * 3 / 2);
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index 3c834a4..7d7caac 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -217,6 +217,9 @@
      */
     UnicodeString mBuffer;
 
+    SkTypeface* typefaceForUnichar(const SkPaint* paint, SkTypeface* typeface,
+        SkUnichar unichar, HB_Script script);
+
     size_t shapeFontRun(const SkPaint* paint, bool isRTL);
 
     void computeValues(const SkPaint* paint, const UChar* chars,
diff --git a/core/res/res/layout/notification_template_base.xml b/core/res/res/layout/notification_template_base.xml
index ae29537..63d20e4 100644
--- a/core/res/res/layout/notification_template_base.xml
+++ b/core/res/res/layout/notification_template_base.xml
@@ -85,6 +85,16 @@
             android:ellipsize="marquee"
             android:visibility="gone"
             />
+        <TextView android:id="@+id/overflow_title"
+            android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal"
+            android:visibility="gone"
+            android:layout_weight="1"
+            />
         <LinearLayout
             android:id="@+id/line3"
             android:layout_width="match_parent"
@@ -129,14 +139,5 @@
             android:visibility="gone"
             style="?android:attr/progressBarStyleHorizontal"
             />
-        <LinearLayout
-                android:id="@+id/actions"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="vertical"
-            android:visibility="gone"
-                >
-                <!-- actions will be added here -->
-        </LinearLayout>
     </LinearLayout>
 </FrameLayout>
diff --git a/core/res/res/layout/notification_template_big_base.xml b/core/res/res/layout/notification_template_big_base.xml
index 5de584d..097d15d 100644
--- a/core/res/res/layout/notification_template_big_base.xml
+++ b/core/res/res/layout/notification_template_big_base.xml
@@ -137,12 +137,13 @@
             style="?android:attr/progressBarStyleHorizontal"
             />
         <LinearLayout
-        	android:id="@+id/actions"
+            android:id="@+id/actions"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:orientation="vertical"
             android:visibility="gone"
-	        >
-	        <!-- actions will be added here -->
+                >
+                <!-- actions will be added here -->
         </LinearLayout>
     </LinearLayout>
 </FrameLayout>
diff --git a/core/res/res/layout/notification_template_big_text.xml b/core/res/res/layout/notification_template_big_text.xml
index ee6adc6..a225ab1 100644
--- a/core/res/res/layout/notification_template_big_text.xml
+++ b/core/res/res/layout/notification_template_big_text.xml
@@ -100,7 +100,7 @@
                 />
         </LinearLayout>
         <LinearLayout
-                android:id="@+id/actions"
+            android:id="@+id/actions"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:orientation="vertical"
@@ -108,6 +108,16 @@
                 >
                 <!-- actions will be added here -->
         </LinearLayout>
+        <TextView android:id="@+id/overflow_title"
+            android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal"
+            android:visibility="gone"
+            android:layout_weight="1"
+            />
         <LinearLayout
             android:id="@+id/line3"
             android:layout_width="match_parent"
diff --git a/core/res/res/layout/notification_template_inbox.xml b/core/res/res/layout/notification_template_inbox.xml
index 82342d4..05a3d62 100644
--- a/core/res/res/layout/notification_template_inbox.xml
+++ b/core/res/res/layout/notification_template_inbox.xml
@@ -87,6 +87,8 @@
             android:layout_height="wrap_content"
             android:singleLine="true"
             android:ellipsize="end"
+            android:paddingTop="4dp"
+            android:paddingBottom="4dp"
             android:visibility="gone"
             />
         <TextView android:id="@+id/inbox_text1"
@@ -95,6 +97,8 @@
             android:layout_height="wrap_content"
             android:singleLine="true"
             android:ellipsize="end"
+            android:paddingTop="4dp"
+            android:paddingBottom="4dp"
             android:visibility="gone"
             />
         <TextView android:id="@+id/inbox_text2"
@@ -103,6 +107,8 @@
             android:layout_height="wrap_content"
             android:singleLine="true"
             android:ellipsize="end"
+            android:paddingTop="4dp"
+            android:paddingBottom="4dp"
             android:visibility="gone"
             />
         <TextView android:id="@+id/inbox_text3"
@@ -111,6 +117,8 @@
             android:layout_height="wrap_content"
             android:singleLine="true"
             android:ellipsize="end"
+            android:paddingTop="4dp"
+            android:paddingBottom="4dp"
             android:visibility="gone"
             />
         <TextView android:id="@+id/inbox_text4"
@@ -119,9 +127,30 @@
             android:layout_height="wrap_content"
             android:singleLine="true"
             android:ellipsize="end"
+            android:paddingTop="4dp"
+            android:paddingBottom="4dp"
             android:visibility="gone"
             />
         <LinearLayout
+            android:id="@+id/actions"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:visibility="gone"
+           >
+          <!-- actions will be added here -->
+        </LinearLayout>
+        <TextView android:id="@+id/overflow_title"
+            android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal"
+            android:visibility="gone"
+            android:layout_weight="1"
+            />
+        <LinearLayout
             android:id="@+id/line3"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
@@ -165,13 +194,5 @@
             android:visibility="gone"
             style="?android:attr/progressBarStyleHorizontal"
             />
-        <LinearLayout
-        	android:id="@+id/actions"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:visibility="gone"
-	        >
-	        <!-- actions will be added here -->
-        </LinearLayout>
     </LinearLayout>
 </FrameLayout>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index a05ecdd..f06e30f 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -99,6 +99,7 @@
   <java-symbol type="id" name="issued_on" />
   <java-symbol type="id" name="left_icon" />
   <java-symbol type="id" name="leftSpacer" />
+  <java-symbol type="id" name="line1" />
   <java-symbol type="id" name="line3" />
   <java-symbol type="id" name="list_footer" />
   <java-symbol type="id" name="list_item" />
@@ -121,6 +122,7 @@
   <java-symbol type="id" name="old_app_action" />
   <java-symbol type="id" name="old_app_description" />
   <java-symbol type="id" name="old_app_icon" />
+  <java-symbol type="id" name="overflow_title" />
   <java-symbol type="id" name="package_label" />
   <java-symbol type="id" name="packages_list" />
   <java-symbol type="id" name="pause" />
diff --git a/core/tests/coretests/res/raw/net_dev_typical b/core/tests/coretests/res/raw/net_dev_typical
deleted file mode 100644
index 290bf03..0000000
--- a/core/tests/coretests/res/raw/net_dev_typical
+++ /dev/null
@@ -1,8 +0,0 @@
-Inter-|   Receive                                                |  Transmit
- face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
-    lo:    8308     116    0    0    0     0          0         0     8308     116    0    0    0     0       0          0
-rmnet0: 1507570    2205    0    0    0     0          0         0   489339    2237    0    0    0     0       0          0
-  ifb0:   52454     151    0  151    0     0          0         0        0       0    0    0    0     0       0          0
-  ifb1:   52454     151    0  151    0     0          0         0        0       0    0    0    0     0       0          0
-  sit0:       0       0    0    0    0     0          0         0        0       0  148    0    0     0       0          0
-ip6tnl0:       0       0    0    0    0     0          0         0        0       0  151  151    0     0       0          0
diff --git a/core/tests/coretests/res/raw/xt_qtaguid_iface_fmt_typical b/core/tests/coretests/res/raw/xt_qtaguid_iface_fmt_typical
new file mode 100644
index 0000000..656d5bb
--- /dev/null
+++ b/core/tests/coretests/res/raw/xt_qtaguid_iface_fmt_typical
@@ -0,0 +1,4 @@
+ifname total_skb_rx_bytes total_skb_rx_packets total_skb_tx_bytes total_skb_tx_packets
+rmnet2 4968 35 3081 39
+rmnet1 11153922 8051 190226 2468
+rmnet0 6824 16 5692 10
diff --git a/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java b/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java
index b994483..d3dd01a 100644
--- a/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java
+++ b/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java
@@ -81,58 +81,6 @@
         assertStatsEntry(stats, "rmnet2", 10001, SET_DEFAULT, 0x0, 1125899906842624L, 984L);
     }
 
-    public void testNetworkStatsSummary() throws Exception {
-        stageFile(R.raw.net_dev_typical, new File(mTestProc, "net/dev"));
-
-        final NetworkStats stats = mFactory.readNetworkStatsSummary();
-        assertEquals(6, stats.size());
-        assertStatsEntry(stats, "lo", UID_ALL, SET_ALL, TAG_NONE, 8308L, 8308L);
-        assertStatsEntry(stats, "rmnet0", UID_ALL, SET_ALL, TAG_NONE, 1507570L, 489339L);
-        assertStatsEntry(stats, "ifb0", UID_ALL, SET_ALL, TAG_NONE, 52454L, 0L);
-        assertStatsEntry(stats, "ifb1", UID_ALL, SET_ALL, TAG_NONE, 52454L, 0L);
-        assertStatsEntry(stats, "sit0", UID_ALL, SET_ALL, TAG_NONE, 0L, 0L);
-        assertStatsEntry(stats, "ip6tnl0", UID_ALL, SET_ALL, TAG_NONE, 0L, 0L);
-    }
-
-    public void testNetworkStatsSummaryDown() throws Exception {
-        stageFile(R.raw.net_dev_typical, new File(mTestProc, "net/dev"));
-        stageLong(1L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/active"));
-        stageLong(1024L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/rx_bytes"));
-        stageLong(128L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/rx_packets"));
-        stageLong(2048L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/tx_bytes"));
-        stageLong(256L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/tx_packets"));
-
-        final NetworkStats stats = mFactory.readNetworkStatsSummary();
-        assertEquals(7, stats.size());
-        assertStatsEntry(stats, "rmnet0", UID_ALL, SET_ALL, TAG_NONE, 1507570L, 489339L);
-        assertStatsEntry(stats, "wlan0", UID_ALL, SET_ALL, TAG_NONE, 1024L, 2048L);
-    }
-
-    public void testNetworkStatsCombined() throws Exception {
-        stageFile(R.raw.net_dev_typical, new File(mTestProc, "net/dev"));
-        stageLong(1L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/active"));
-        stageLong(10L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/rx_bytes"));
-        stageLong(20L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/rx_packets"));
-        stageLong(30L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/tx_bytes"));
-        stageLong(40L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/tx_packets"));
-
-        final NetworkStats stats = mFactory.readNetworkStatsSummary();
-        assertStatsEntry(stats, "rmnet0", UID_ALL, SET_ALL, TAG_NONE, 1507570L + 10L,
-                2205L + 20L, 489339L + 30L, 2237L + 40L);
-    }
-
-    public void testNetworkStatsCombinedInactive() throws Exception {
-        stageFile(R.raw.net_dev_typical, new File(mTestProc, "net/dev"));
-        stageLong(0L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/active"));
-        stageLong(10L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/rx_bytes"));
-        stageLong(20L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/rx_packets"));
-        stageLong(30L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/tx_bytes"));
-        stageLong(40L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/tx_packets"));
-
-        final NetworkStats stats = mFactory.readNetworkStatsSummary();
-        assertStatsEntry(stats, "rmnet0", UID_ALL, SET_ALL, TAG_NONE, 10L, 20L, 30L, 40L);
-    }
-
     public void testKernelTags() throws Exception {
         assertEquals(0, kernelToTag("0x0000000000000000"));
         assertEquals(0x32, kernelToTag("0x0000003200000000"));
@@ -159,13 +107,24 @@
     public void testNetworkStatsSingle() throws Exception {
         stageFile(R.raw.xt_qtaguid_iface_typical, new File(mTestProc, "net/xt_qtaguid/iface_stat_all"));
 
-        final NetworkStats stats = mFactory.readNetworkStatsSummary();
+        final NetworkStats stats = mFactory.readNetworkStatsSummaryDev();
         assertEquals(6, stats.size());
         assertStatsEntry(stats, "rmnet0", UID_ALL, SET_ALL, TAG_NONE, 2112L, 24L, 700L, 10L);
         assertStatsEntry(stats, "test1", UID_ALL, SET_ALL, TAG_NONE, 6L, 8L, 10L, 12L);
         assertStatsEntry(stats, "test2", UID_ALL, SET_ALL, TAG_NONE, 1L, 2L, 3L, 4L);
     }
 
+    public void testNetworkStatsXt() throws Exception {
+        stageFile(R.raw.xt_qtaguid_iface_fmt_typical,
+                new File(mTestProc, "net/xt_qtaguid/iface_stat_fmt"));
+
+        final NetworkStats stats = mFactory.readNetworkStatsSummaryXt();
+        assertEquals(3, stats.size());
+        assertStatsEntry(stats, "rmnet0", UID_ALL, SET_ALL, TAG_NONE, 6824L, 16L, 5692L, 10L);
+        assertStatsEntry(stats, "rmnet1", UID_ALL, SET_ALL, TAG_NONE, 11153922L, 8051L, 190226L, 2468L);
+        assertStatsEntry(stats, "rmnet2", UID_ALL, SET_ALL, TAG_NONE, 4968L, 35L, 3081L, 39L);
+    }
+
     /**
      * Copy a {@link Resources#openRawResource(int)} into {@link File} for
      * testing purposes.
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index dd650bf..e396a69 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -884,22 +884,25 @@
     @Override
     public boolean isActiveNetworkMetered() {
         enforceAccessPermission();
-
         final long token = Binder.clearCallingIdentity();
         try {
-            final NetworkState state = getNetworkStateUnchecked(mActiveDefaultNetwork);
-            if (state != null) {
-                try {
-                    return mPolicyManager.isNetworkMetered(state);
-                } catch (RemoteException e) {
-                }
-            }
-            return false;
+            return isNetworkMeteredUnchecked(mActiveDefaultNetwork);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
     }
 
+    private boolean isNetworkMeteredUnchecked(int networkType) {
+        final NetworkState state = getNetworkStateUnchecked(networkType);
+        if (state != null) {
+            try {
+                return mPolicyManager.isNetworkMetered(state);
+            } catch (RemoteException e) {
+            }
+        }
+        return false;
+    }
+
     public boolean setRadios(boolean turnOn) {
         boolean result = true;
         enforceChangePermission();
@@ -993,7 +996,8 @@
     public int startUsingNetworkFeature(int networkType, String feature,
             IBinder binder) {
         if (VDBG) {
-            log("startUsingNetworkFeature for net " + networkType + ": " + feature);
+            log("startUsingNetworkFeature for net " + networkType + ": " + feature + ", uid="
+                    + Binder.getCallingUid());
         }
         enforceChangePermission();
         if (!ConnectivityManager.isNetworkTypeValid(networkType) ||
@@ -1010,6 +1014,16 @@
             enforceConnectivityInternalPermission();
         }
 
+        // if UID is restricted, don't allow them to bring up metered APNs
+        final boolean networkMetered = isNetworkMeteredUnchecked(usedNetworkType);
+        final int uidRules;
+        synchronized (mRulesLock) {
+            uidRules = mUidRules.get(Binder.getCallingUid(), RULE_ALLOW_ALL);
+        }
+        if (networkMetered && (uidRules & RULE_REJECT_METERED) != 0) {
+            return Phone.APN_REQUEST_FAILED;
+        }
+
         NetworkStateTracker network = mNetTrackers[usedNetworkType];
         if (network != null) {
             Integer currentPid = new Integer(getCallingPid());
@@ -1432,7 +1446,6 @@
                 mUidRules.put(uid, uidRules);
             }
 
-            // TODO: dispatch into NMS to push rules towards kernel module
             // TODO: notify UID when it has requested targeted updates
         }
 
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 817d04d..4536a6d 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -989,9 +989,15 @@
     }
 
     @Override
-    public NetworkStats getNetworkStatsSummary() {
+    public NetworkStats getNetworkStatsSummaryDev() {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        return mStatsFactory.readNetworkStatsSummary();
+        return mStatsFactory.readNetworkStatsSummaryDev();
+    }
+
+    @Override
+    public NetworkStats getNetworkStatsSummaryXt() {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        return mStatsFactory.readNetworkStatsSummaryXt();
     }
 
     @Override
diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java
index 2155147..f35a5af 100644
--- a/services/java/com/android/server/ThrottleService.java
+++ b/services/java/com/android/server/ThrottleService.java
@@ -511,7 +511,7 @@
             long incRead = 0;
             long incWrite = 0;
             try {
-                final NetworkStats stats = mNMService.getNetworkStatsSummary();
+                final NetworkStats stats = mNMService.getNetworkStatsSummaryDev();
                 final int index = stats.findIndex(mIface, NetworkStats.UID_ALL,
                         NetworkStats.SET_DEFAULT, NetworkStats.TAG_NONE);
 
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 8ebe224..961d042 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -118,6 +118,7 @@
 import android.text.format.Formatter;
 import android.text.format.Time;
 import android.util.Log;
+import android.util.MathUtils;
 import android.util.NtpTrustedTime;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -166,7 +167,7 @@
  */
 public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
     private static final String TAG = "NetworkPolicy";
-    private static final boolean LOGD = true;
+    private static final boolean LOGD = false;
     private static final boolean LOGV = false;
 
     private static final int VERSION_INIT = 1;
@@ -962,6 +963,7 @@
             }
         }
 
+        long lowestRule = Long.MAX_VALUE;
         final HashSet<String> newMeteredIfaces = Sets.newHashSet();
 
         // apply each policy that we found ifaces for; compute remaining data
@@ -985,6 +987,7 @@
                         + Arrays.toString(ifaces));
             }
 
+            final boolean hasWarning = policy.warningBytes != LIMIT_DISABLED;
             final boolean hasLimit = policy.limitBytes != LIMIT_DISABLED;
             if (hasLimit || policy.metered) {
                 final long quotaBytes;
@@ -1014,6 +1017,23 @@
                     newMeteredIfaces.add(iface);
                 }
             }
+
+            // keep track of lowest warning or limit of active policies
+            if (hasWarning && policy.warningBytes < lowestRule) {
+                lowestRule = policy.warningBytes;
+            }
+            if (hasLimit && policy.limitBytes < lowestRule) {
+                lowestRule = policy.limitBytes;
+            }
+        }
+
+        try {
+            // make sure stats are recorded frequently enough; we aim for 2MB
+            // threshold for 2GB/month rules.
+            final long persistThreshold = lowestRule / 1000;
+            mNetworkStats.advisePersistThreshold(persistThreshold);
+        } catch (RemoteException e) {
+            // ignored; service lives in system_server
         }
 
         // remove quota on any trailing interfaces
diff --git a/services/java/com/android/server/net/NetworkStatsCollection.java b/services/java/com/android/server/net/NetworkStatsCollection.java
index 2892a74..c2e475a 100644
--- a/services/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/java/com/android/server/net/NetworkStatsCollection.java
@@ -186,12 +186,12 @@
         if (history.size() == 0) return;
         noteRecordedHistory(history.getStart(), history.getEnd(), history.getTotalBytes());
 
-        final NetworkStatsHistory existing = mStats.get(key);
-        if (existing != null) {
-            existing.recordEntireHistory(history);
-        } else {
-            mStats.put(key, history);
+        NetworkStatsHistory target = mStats.get(key);
+        if (target == null) {
+            target = new NetworkStatsHistory(history.getBucketDuration());
+            mStats.put(key, target);
         }
+        target.recordEntireHistory(history);
     }
 
     /**
diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/java/com/android/server/net/NetworkStatsRecorder.java
index 57ad158..2ce7771 100644
--- a/services/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/java/com/android/server/net/NetworkStatsRecorder.java
@@ -17,6 +17,8 @@
 package com.android.server.net;
 
 import static android.net.NetworkStats.TAG_NONE;
+import static android.net.TrafficStats.KB_IN_BYTES;
+import static android.net.TrafficStats.MB_IN_BYTES;
 import static com.android.internal.util.Preconditions.checkNotNull;
 
 import android.net.NetworkStats;
@@ -25,6 +27,7 @@
 import android.net.NetworkTemplate;
 import android.net.TrafficStats;
 import android.util.Log;
+import android.util.MathUtils;
 import android.util.Slog;
 
 import com.android.internal.util.FileRotator;
@@ -58,9 +61,9 @@
     private final String mCookie;
 
     private final long mBucketDuration;
-    private final long mPersistThresholdBytes;
     private final boolean mOnlyTags;
 
+    private long mPersistThresholdBytes = 2 * MB_IN_BYTES;
     private NetworkStats mLastSnapshot;
 
     private final NetworkStatsCollection mPending;
@@ -71,13 +74,12 @@
     private WeakReference<NetworkStatsCollection> mComplete;
 
     public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver<String> observer,
-            String cookie, long bucketDuration, long persistThresholdBytes, boolean onlyTags) {
+            String cookie, long bucketDuration, boolean onlyTags) {
         mRotator = checkNotNull(rotator, "missing FileRotator");
         mObserver = checkNotNull(observer, "missing NonMonotonicObserver");
         mCookie = cookie;
 
         mBucketDuration = bucketDuration;
-        mPersistThresholdBytes = persistThresholdBytes;
         mOnlyTags = onlyTags;
 
         mPending = new NetworkStatsCollection(bucketDuration);
@@ -86,6 +88,12 @@
         mPendingRewriter = new CombiningRewriter(mPending);
     }
 
+    public void setPersistThreshold(long thresholdBytes) {
+        if (LOGV) Slog.v(TAG, "setPersistThreshold() with " + thresholdBytes);
+        mPersistThresholdBytes = MathUtils.constrain(
+                thresholdBytes, 1 * KB_IN_BYTES, 100 * MB_IN_BYTES);
+    }
+
     public void resetLocked() {
         mLastSnapshot = null;
         mPending.reset();
@@ -128,6 +136,9 @@
             Map<String, NetworkIdentitySet> ifaceIdent, long currentTimeMillis) {
         final HashSet<String> unknownIfaces = Sets.newHashSet();
 
+        // skip recording when snapshot missing
+        if (snapshot == null) return;
+
         // assume first snapshot is bootstrap and don't record
         if (mLastSnapshot == null) {
             mLastSnapshot = snapshot;
@@ -150,7 +161,7 @@
                 continue;
             }
 
-            // skip when no delta occured
+            // skip when no delta occurred
             if (entry.isEmpty()) continue;
 
             // only record tag data when requested
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 1c3e24f..a9d4b59 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -36,6 +36,7 @@
 import static android.net.NetworkStats.UID_ALL;
 import static android.net.NetworkTemplate.buildTemplateMobileWildcard;
 import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
+import static android.net.TrafficStats.KB_IN_BYTES;
 import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.provider.Settings.Secure.NETSTATS_DEV_BUCKET_DURATION;
 import static android.provider.Settings.Secure.NETSTATS_DEV_DELETE_AGE;
@@ -49,6 +50,10 @@
 import static android.provider.Settings.Secure.NETSTATS_UID_DELETE_AGE;
 import static android.provider.Settings.Secure.NETSTATS_UID_PERSIST_BYTES;
 import static android.provider.Settings.Secure.NETSTATS_UID_ROTATE_AGE;
+import static android.provider.Settings.Secure.NETSTATS_UID_TAG_BUCKET_DURATION;
+import static android.provider.Settings.Secure.NETSTATS_UID_TAG_DELETE_AGE;
+import static android.provider.Settings.Secure.NETSTATS_UID_TAG_PERSIST_BYTES;
+import static android.provider.Settings.Secure.NETSTATS_UID_TAG_ROTATE_AGE;
 import static android.telephony.PhoneStateListener.LISTEN_DATA_CONNECTION_STATE;
 import static android.telephony.PhoneStateListener.LISTEN_NONE;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
@@ -94,10 +99,12 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.provider.Settings;
+import android.provider.Settings.Secure;
 import android.telephony.PhoneStateListener;
 import android.telephony.TelephonyManager;
 import android.util.EventLog;
 import android.util.Log;
+import android.util.MathUtils;
 import android.util.NtpTrustedTime;
 import android.util.Slog;
 import android.util.SparseIntArray;
@@ -159,6 +166,7 @@
     private PendingIntent mPollIntent;
 
     private static final String PREFIX_DEV = "dev";
+    private static final String PREFIX_XT = "xt";
     private static final String PREFIX_UID = "uid";
     private static final String PREFIX_UID_TAG = "uid_tag";
 
@@ -168,27 +176,30 @@
     public interface NetworkStatsSettings {
         public long getPollInterval();
         public long getTimeCacheMaxAge();
-        public long getGlobalAlertBytes();
         public boolean getSampleEnabled();
 
         public static class Config {
             public final long bucketDuration;
-            public final long persistBytes;
             public final long rotateAgeMillis;
             public final long deleteAgeMillis;
 
-            public Config(long bucketDuration, long persistBytes, long rotateAgeMillis,
-                    long deleteAgeMillis) {
+            public Config(long bucketDuration, long rotateAgeMillis, long deleteAgeMillis) {
                 this.bucketDuration = bucketDuration;
-                this.persistBytes = persistBytes;
                 this.rotateAgeMillis = rotateAgeMillis;
                 this.deleteAgeMillis = deleteAgeMillis;
             }
         }
 
         public Config getDevConfig();
+        public Config getXtConfig();
         public Config getUidConfig();
         public Config getUidTagConfig();
+
+        public long getGlobalAlertBytes(long def);
+        public long getDevPersistBytes(long def);
+        public long getXtPersistBytes(long def);
+        public long getUidPersistBytes(long def);
+        public long getUidTagPersistBytes(long def);
     }
 
     private final Object mStatsLock = new Object();
@@ -204,6 +215,7 @@
             new DropBoxNonMonotonicObserver();
 
     private NetworkStatsRecorder mDevRecorder;
+    private NetworkStatsRecorder mXtRecorder;
     private NetworkStatsRecorder mUidRecorder;
     private NetworkStatsRecorder mUidTagRecorder;
 
@@ -220,6 +232,8 @@
     private final Handler mHandler;
 
     private boolean mSystemReady;
+    private long mPersistThreshold = 2 * MB_IN_BYTES;
+    private long mGlobalAlertBytes;
 
     public NetworkStatsService(
             Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) {
@@ -268,9 +282,12 @@
 
         // create data recorders along with historical rotators
         mDevRecorder = buildRecorder(PREFIX_DEV, mSettings.getDevConfig(), false);
+        mXtRecorder = buildRecorder(PREFIX_XT, mSettings.getXtConfig(), false);
         mUidRecorder = buildRecorder(PREFIX_UID, mSettings.getUidConfig(), false);
         mUidTagRecorder = buildRecorder(PREFIX_UID_TAG, mSettings.getUidTagConfig(), true);
 
+        updatePersistThresholds();
+
         synchronized (mStatsLock) {
             // upgrade any legacy stats, migrating them to rotated files
             maybeUpgradeLegacyStatsLocked();
@@ -321,10 +338,9 @@
 
     private NetworkStatsRecorder buildRecorder(
             String prefix, NetworkStatsSettings.Config config, boolean includeTags) {
-        return new NetworkStatsRecorder(
-                new FileRotator(mBaseDir, prefix, config.rotateAgeMillis, config.deleteAgeMillis),
-                mNonMonotonicObserver, prefix, config.bucketDuration, config.persistBytes,
-                includeTags);
+        return new NetworkStatsRecorder(new FileRotator(
+                mBaseDir, prefix, config.rotateAgeMillis, config.deleteAgeMillis),
+                mNonMonotonicObserver, prefix, config.bucketDuration, includeTags);
     }
 
     private void shutdownLocked() {
@@ -343,10 +359,12 @@
 
         // persist any pending stats
         mDevRecorder.forcePersistLocked(currentTime);
+        mXtRecorder.forcePersistLocked(currentTime);
         mUidRecorder.forcePersistLocked(currentTime);
         mUidTagRecorder.forcePersistLocked(currentTime);
 
         mDevRecorder = null;
+        mXtRecorder = null;
         mUidRecorder = null;
         mUidTagRecorder = null;
 
@@ -408,8 +426,7 @@
      */
     private void registerGlobalAlert() {
         try {
-            final long alertBytes = mSettings.getGlobalAlertBytes();
-            mNetworkManager.setGlobalAlert(alertBytes);
+            mNetworkManager.setGlobalAlert(mGlobalAlertBytes);
         } catch (IllegalStateException e) {
             Slog.w(TAG, "problem registering for global alert: " + e);
         } catch (RemoteException e) {
@@ -431,14 +448,18 @@
 
             private NetworkStatsCollection getUidComplete() {
                 if (mUidComplete == null) {
-                    mUidComplete = mUidRecorder.getOrLoadCompleteLocked();
+                    synchronized (mStatsLock) {
+                        mUidComplete = mUidRecorder.getOrLoadCompleteLocked();
+                    }
                 }
                 return mUidComplete;
             }
 
             private NetworkStatsCollection getUidTagComplete() {
                 if (mUidTagComplete == null) {
-                    mUidTagComplete = mUidTagRecorder.getOrLoadCompleteLocked();
+                    synchronized (mStatsLock) {
+                        mUidTagComplete = mUidTagRecorder.getOrLoadCompleteLocked();
+                    }
                 }
                 return mUidTagComplete;
             }
@@ -578,6 +599,45 @@
         }
     }
 
+    @Override
+    public void advisePersistThreshold(long thresholdBytes) {
+        mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG);
+        assertBandwidthControlEnabled();
+
+        // clamp threshold into safe range
+        mPersistThreshold = MathUtils.constrain(thresholdBytes, 128 * KB_IN_BYTES, 2 * MB_IN_BYTES);
+        updatePersistThresholds();
+
+        if (LOGV) {
+            Slog.v(TAG, "advisePersistThreshold() given " + thresholdBytes + ", clamped to "
+                    + mPersistThreshold);
+        }
+
+        // persist if beyond new thresholds
+        final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
+                : System.currentTimeMillis();
+        mDevRecorder.maybePersistLocked(currentTime);
+        mXtRecorder.maybePersistLocked(currentTime);
+        mUidRecorder.maybePersistLocked(currentTime);
+        mUidTagRecorder.maybePersistLocked(currentTime);
+
+        // re-arm global alert
+        registerGlobalAlert();
+    }
+
+    /**
+     * Update {@link NetworkStatsRecorder} and {@link #mGlobalAlertBytes} to
+     * reflect current {@link #mPersistThreshold} value. Always defers to
+     * {@link Secure} values when defined.
+     */
+    private void updatePersistThresholds() {
+        mDevRecorder.setPersistThreshold(mSettings.getDevPersistBytes(mPersistThreshold));
+        mXtRecorder.setPersistThreshold(mSettings.getXtPersistBytes(mPersistThreshold));
+        mUidRecorder.setPersistThreshold(mSettings.getUidPersistBytes(mPersistThreshold));
+        mUidTagRecorder.setPersistThreshold(mSettings.getUidTagPersistBytes(mPersistThreshold));
+        mGlobalAlertBytes = mSettings.getGlobalAlertBytes(mPersistThreshold);
+    }
+
     /**
      * Receiver that watches for {@link IConnectivityManager} to claim network
      * interfaces. Used to associate {@link TelephonyManager#getSubscriberId()}
@@ -772,9 +832,11 @@
             // snapshot and record current counters; read UID stats first to
             // avoid overcounting dev stats.
             final NetworkStats uidSnapshot = getNetworkStatsUidDetail();
-            final NetworkStats devSnapshot = getNetworkStatsSummary();
+            final NetworkStats xtSnapshot = mNetworkManager.getNetworkStatsSummaryXt();
+            final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev();
 
             mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime);
+            mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, currentTime);
             mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime);
             mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime);
 
@@ -824,9 +886,11 @@
             // snapshot and record current counters; read UID stats first to
             // avoid overcounting dev stats.
             final NetworkStats uidSnapshot = getNetworkStatsUidDetail();
-            final NetworkStats devSnapshot = getNetworkStatsSummary();
+            final NetworkStats xtSnapshot = mNetworkManager.getNetworkStatsSummaryXt();
+            final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev();
 
             mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime);
+            mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, currentTime);
             mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime);
             mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime);
 
@@ -841,11 +905,13 @@
         // persist any pending data depending on requested flags
         if (persistForce) {
             mDevRecorder.forcePersistLocked(currentTime);
+            mXtRecorder.forcePersistLocked(currentTime);
             mUidRecorder.forcePersistLocked(currentTime);
             mUidTagRecorder.forcePersistLocked(currentTime);
         } else {
             if (persistNetwork) {
                 mDevRecorder.maybePersistLocked(currentTime);
+                mXtRecorder.maybePersistLocked(currentTime);
             }
             if (persistUid) {
                 mUidRecorder.maybePersistLocked(currentTime);
@@ -884,7 +950,7 @@
         // collect mobile sample
         template = buildTemplateMobileWildcard();
         devTotal = mDevRecorder.getTotalSinceBootLocked(template);
-        xtTotal = new NetworkStats.Entry();
+        xtTotal = mXtRecorder.getTotalSinceBootLocked(template);
         uidTotal = mUidRecorder.getTotalSinceBootLocked(template);
 
         EventLogTags.writeNetstatsMobileSample(
@@ -896,7 +962,7 @@
         // collect wifi sample
         template = buildTemplateWifiWildcard();
         devTotal = mDevRecorder.getTotalSinceBootLocked(template);
-        xtTotal = new NetworkStats.Entry();
+        xtTotal = mXtRecorder.getTotalSinceBootLocked(template);
         uidTotal = mUidRecorder.getTotalSinceBootLocked(template);
 
         EventLogTags.writeNetstatsWifiSample(
@@ -970,6 +1036,11 @@
             mDevRecorder.dumpLocked(pw, fullHistory);
             pw.decreaseIndent();
 
+            pw.println("Xt stats:");
+            pw.increaseIndent();
+            mXtRecorder.dumpLocked(pw, fullHistory);
+            pw.decreaseIndent();
+
             if (includeUid) {
                 pw.println("UID stats:");
                 pw.increaseIndent();
@@ -986,10 +1057,6 @@
         }
     }
 
-    private NetworkStats getNetworkStatsSummary() throws RemoteException {
-        return mNetworkManager.getNetworkStatsSummary();
-    }
-
     /**
      * Return snapshot of current UID statistics, including any
      * {@link TrafficStats#UID_TETHERING} and {@link #mUidOperations} values.
@@ -1109,36 +1176,50 @@
             return getSecureLong(NETSTATS_TIME_CACHE_MAX_AGE, DAY_IN_MILLIS);
         }
         @Override
-        public long getGlobalAlertBytes() {
-            return getSecureLong(NETSTATS_GLOBAL_ALERT_BYTES, 2 * MB_IN_BYTES);
+        public long getGlobalAlertBytes(long def) {
+            return getSecureLong(NETSTATS_GLOBAL_ALERT_BYTES, def);
         }
         @Override
         public boolean getSampleEnabled() {
             return getSecureBoolean(NETSTATS_SAMPLE_ENABLED, true);
         }
-
         @Override
         public Config getDevConfig() {
             return new Config(getSecureLong(NETSTATS_DEV_BUCKET_DURATION, HOUR_IN_MILLIS),
-                    getSecureLong(NETSTATS_DEV_PERSIST_BYTES, 2 * MB_IN_BYTES),
                     getSecureLong(NETSTATS_DEV_ROTATE_AGE, 15 * DAY_IN_MILLIS),
                     getSecureLong(NETSTATS_DEV_DELETE_AGE, 90 * DAY_IN_MILLIS));
         }
-
+        @Override
+        public Config getXtConfig() {
+            return getDevConfig();
+        }
         @Override
         public Config getUidConfig() {
             return new Config(getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS),
-                    getSecureLong(NETSTATS_UID_PERSIST_BYTES, 2 * MB_IN_BYTES),
                     getSecureLong(NETSTATS_UID_ROTATE_AGE, 15 * DAY_IN_MILLIS),
                     getSecureLong(NETSTATS_UID_DELETE_AGE, 90 * DAY_IN_MILLIS));
         }
-
         @Override
         public Config getUidTagConfig() {
-            return new Config(getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS),
-                    getSecureLong(NETSTATS_UID_PERSIST_BYTES, 2 * MB_IN_BYTES),
-                    getSecureLong(NETSTATS_UID_ROTATE_AGE, 5 * DAY_IN_MILLIS),
-                    getSecureLong(NETSTATS_UID_DELETE_AGE, 15 * DAY_IN_MILLIS));
+            return new Config(getSecureLong(NETSTATS_UID_TAG_BUCKET_DURATION, 2 * HOUR_IN_MILLIS),
+                    getSecureLong(NETSTATS_UID_TAG_ROTATE_AGE, 5 * DAY_IN_MILLIS),
+                    getSecureLong(NETSTATS_UID_TAG_DELETE_AGE, 15 * DAY_IN_MILLIS));
+        }
+        @Override
+        public long getDevPersistBytes(long def) {
+            return getSecureLong(NETSTATS_DEV_PERSIST_BYTES, def);
+        }
+        @Override
+        public long getXtPersistBytes(long def) {
+            return getDevPersistBytes(def);
+        }
+        @Override
+        public long getUidPersistBytes(long def) {
+            return getSecureLong(NETSTATS_UID_PERSIST_BYTES, def);
+        }
+        @Override
+        public long getUidTagPersistBytes(long def) {
+            return getSecureLong(NETSTATS_UID_TAG_PERSIST_BYTES, def);
         }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index ba3fd3c..9b371ac 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -106,8 +106,9 @@
 
     private static final long TEST_START = 1194220800000L;
     private static final String TEST_IFACE = "test0";
+    private static final String TEST_SSID = "AndroidAP";
 
-    private static NetworkTemplate sTemplateWifi = NetworkTemplate.buildTemplateWifi();
+    private static NetworkTemplate sTemplateWifi = NetworkTemplate.buildTemplateWifi(TEST_SSID);
 
     private BroadcastInterceptingContext mServiceContext;
     private File mPolicyDir;
@@ -860,7 +861,7 @@
         info.setDetailedState(DetailedState.CONNECTED, null, null);
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(TEST_IFACE);
-        return new NetworkState(info, prop, null);
+        return new NetworkState(info, prop, null, null, TEST_SSID);
     }
 
     private void expectCurrentTime() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index 6d9bb29..332d198 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -30,7 +30,7 @@
 import static android.net.NetworkStats.UID_ALL;
 import static android.net.NetworkStatsHistory.FIELD_ALL;
 import static android.net.NetworkTemplate.buildTemplateMobileAll;
-import static android.net.NetworkTemplate.buildTemplateWifi;
+import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
 import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.net.TrafficStats.UID_REMOVED;
 import static android.net.TrafficStats.UID_TETHERING;
@@ -93,8 +93,9 @@
 
     private static final String IMSI_1 = "310004";
     private static final String IMSI_2 = "310260";
+    private static final String TEST_SSID = "AndroidAP";
 
-    private static NetworkTemplate sTemplateWifi = buildTemplateWifi();
+    private static NetworkTemplate sTemplateWifi = buildTemplateWifiWildcard();
     private static NetworkTemplate sTemplateImsi1 = buildTemplateMobileAll(IMSI_1);
     private static NetworkTemplate sTemplateImsi2 = buildTemplateMobileAll(IMSI_2);
 
@@ -136,7 +137,6 @@
         mService = new NetworkStatsService(
                 mServiceContext, mNetManager, mAlarmManager, mTime, mStatsDir, mSettings);
         mService.bindConnectivityManager(mConnManager);
-        mSession = mService.openSession();
 
         mElapsedRealtime = 0L;
 
@@ -154,6 +154,7 @@
 
         replay();
         mService.systemReady();
+        mSession = mService.openSession();
         verifyAndReset();
 
         mNetworkObserver = networkObserver.getValue();
@@ -162,9 +163,7 @@
 
     @Override
     public void tearDown() throws Exception {
-        for (File file : mStatsDir.listFiles()) {
-            file.delete();
-        }
+        IoUtils.deleteContents(mStatsDir);
 
         mServiceContext = null;
         mStatsDir = null;
@@ -820,7 +819,8 @@
     }
 
     private void expectNetworkStatsSummary(NetworkStats summary) throws Exception {
-        expect(mNetManager.getNetworkStatsSummary()).andReturn(summary).atLeastOnce();
+        expect(mNetManager.getNetworkStatsSummaryDev()).andReturn(summary).atLeastOnce();
+        expect(mNetManager.getNetworkStatsSummaryXt()).andReturn(summary).atLeastOnce();
     }
 
     private void expectNetworkStatsUidDetail(NetworkStats detail) throws Exception {
@@ -846,13 +846,19 @@
             throws Exception {
         expect(mSettings.getPollInterval()).andReturn(HOUR_IN_MILLIS).anyTimes();
         expect(mSettings.getTimeCacheMaxAge()).andReturn(DAY_IN_MILLIS).anyTimes();
-        expect(mSettings.getGlobalAlertBytes()).andReturn(MB_IN_BYTES).anyTimes();
         expect(mSettings.getSampleEnabled()).andReturn(true).anyTimes();
 
-        final Config config = new Config(bucketDuration, persistBytes, deleteAge, deleteAge);
+        final Config config = new Config(bucketDuration, deleteAge, deleteAge);
         expect(mSettings.getDevConfig()).andReturn(config).anyTimes();
+        expect(mSettings.getXtConfig()).andReturn(config).anyTimes();
         expect(mSettings.getUidConfig()).andReturn(config).anyTimes();
         expect(mSettings.getUidTagConfig()).andReturn(config).anyTimes();
+
+        expect(mSettings.getGlobalAlertBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes();
+        expect(mSettings.getDevPersistBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes();
+        expect(mSettings.getXtPersistBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes();
+        expect(mSettings.getUidPersistBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes();
+        expect(mSettings.getUidTagPersistBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes();
     }
 
     private void expectCurrentTime() throws Exception {
@@ -903,7 +909,7 @@
         info.setDetailedState(DetailedState.CONNECTED, null, null);
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(TEST_IFACE);
-        return new NetworkState(info, prop, null);
+        return new NetworkState(info, prop, null, null, TEST_SSID);
     }
 
     private static NetworkState buildMobile3gState(String subscriberId) {
@@ -912,7 +918,7 @@
         info.setDetailedState(DetailedState.CONNECTED, null, null);
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(TEST_IFACE);
-        return new NetworkState(info, prop, null, subscriberId);
+        return new NetworkState(info, prop, null, subscriberId, null);
     }
 
     private static NetworkState buildMobile4gState(String iface) {
diff --git a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
index 6a9778e..afa0eec 100644
--- a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
@@ -232,7 +232,8 @@
         final INetworkManagementService nmService = INetworkManagementService.Stub.asInterface(b);
 
         // test is currently no-op, just exercises stats apis
-        Log.d(TAG, nmService.getNetworkStatsSummary().toString());
+        Log.d(TAG, nmService.getNetworkStatsSummaryDev().toString());
+        Log.d(TAG, nmService.getNetworkStatsSummaryXt().toString());
         Log.d(TAG, nmService.getNetworkStatsDetail().toString());
     }
 
@@ -286,7 +287,7 @@
     }
 
     /**
-     * Expect {@link NetworkManagementService#getNetworkStatsSummary()} mock
+     * Expect {@link NetworkManagementService#getNetworkStatsSummaryDev()} mock
      * calls, responding with the given counter values.
      */
     public void expectGetInterfaceCounter(long rx, long tx) throws Exception {
@@ -294,7 +295,7 @@
         final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
         stats.addValues(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, rx, 0L, tx, 0L, 0);
 
-        expect(mMockNMService.getNetworkStatsSummary()).andReturn(stats).atLeastOnce();
+        expect(mMockNMService.getNetworkStatsSummaryDev()).andReturn(stats).atLeastOnce();
     }
 
     /**
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index a90af15..70e2aac 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -715,20 +715,28 @@
         new Test("Ten Notifications") {
             public void run() {
                 for (int i = 0; i < 2; i++) {
-                    Notification n = new Notification(NotificationTestList.this,
+                    Notification n = new Notification(
                             kNumberedIconResIDs[i],
-                            null, System.currentTimeMillis(), "Persistent #" + i,
-                            "Notify me!!!" + i, null);
-                    n.flags |= Notification.FLAG_ONGOING_EVENT;
+                            null, System.currentTimeMillis());
                     n.number = i;
+                    n.setLatestEventInfo(
+                            NotificationTestList.this,
+                            "Persistent #" + i,
+                            "Notify me!!!" + i, 
+                            null);
+                    n.flags |= Notification.FLAG_ONGOING_EVENT;
                     mNM.notify((i+1)*10, n);
                 }
                 for (int i = 2; i < 10; i++) {
-                    Notification n = new Notification(NotificationTestList.this,
+                    Notification n = new Notification(
                             kNumberedIconResIDs[i],
-                            null, System.currentTimeMillis(), "Persistent #" + i,
-                            "Notify me!!!" + i, null);
+                            null, System.currentTimeMillis());
                     n.number = i;
+                    n.setLatestEventInfo(
+                            NotificationTestList.this,
+                            "Persistent #" + i,
+                            "Notify me!!!" + i, 
+                            null);
                     mNM.notify((i+1)*10, n);
                 }
             }