Merge "Add CarrierConfig for Invalid Call Forwarding number" into oc-mr1-dev
diff --git a/config/compiled-classes-phone b/config/compiled-classes-phone
index c1cbb64..0c40389d 100644
--- a/config/compiled-classes-phone
+++ b/config/compiled-classes-phone
@@ -3269,6 +3269,7 @@
 android.os.Parcel
 android.os.Parcel$1
 android.os.Parcel$2
+android.os.Parcel$ReadWriteHelper
 android.os.ParcelFileDescriptor
 android.os.ParcelFileDescriptor$1
 android.os.ParcelFileDescriptor$2
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index bf0a264..5785619 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -3054,71 +3054,104 @@
         final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(which);
         final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(which);
         final long powerDrainMaMs = counter.getPowerCounter().getCountLocked(which);
+        // Battery real time
+        final long totalControllerActivityTimeMs
+            = computeBatteryRealtime(SystemClock.elapsedRealtime() * 1000, which) / 1000;
         long totalTxTimeMs = 0;
         for (LongCounter txState : counter.getTxTimeCounters()) {
             totalTxTimeMs += txState.getCountLocked(which);
         }
-
-        final long totalTimeMs = idleTimeMs + rxTimeMs + totalTxTimeMs;
+        final long sleepTimeMs
+            = totalControllerActivityTimeMs - (idleTimeMs + rxTimeMs + totalTxTimeMs);
 
         sb.setLength(0);
         sb.append(prefix);
-        sb.append("  ");
+        sb.append("     ");
+        sb.append(controllerName);
+        sb.append(" Sleep time:  ");
+        formatTimeMs(sb, sleepTimeMs);
+        sb.append("(");
+        sb.append(formatRatioLocked(sleepTimeMs, totalControllerActivityTimeMs));
+        sb.append(")");
+        pw.println(sb.toString());
+
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("     ");
         sb.append(controllerName);
         sb.append(" Idle time:   ");
         formatTimeMs(sb, idleTimeMs);
         sb.append("(");
-        sb.append(formatRatioLocked(idleTimeMs, totalTimeMs));
+        sb.append(formatRatioLocked(idleTimeMs, totalControllerActivityTimeMs));
         sb.append(")");
         pw.println(sb.toString());
 
         sb.setLength(0);
         sb.append(prefix);
-        sb.append("  ");
+        sb.append("     ");
         sb.append(controllerName);
         sb.append(" Rx time:     ");
         formatTimeMs(sb, rxTimeMs);
         sb.append("(");
-        sb.append(formatRatioLocked(rxTimeMs, totalTimeMs));
+        sb.append(formatRatioLocked(rxTimeMs, totalControllerActivityTimeMs));
         sb.append(")");
         pw.println(sb.toString());
 
         sb.setLength(0);
         sb.append(prefix);
-        sb.append("  ");
+        sb.append("     ");
         sb.append(controllerName);
         sb.append(" Tx time:     ");
-        formatTimeMs(sb, totalTxTimeMs);
-        sb.append("(");
-        sb.append(formatRatioLocked(totalTxTimeMs, totalTimeMs));
-        sb.append(")");
-        pw.println(sb.toString());
 
-        final int numTxLvls = counter.getTxTimeCounters().length;
+        String [] powerLevel;
+        switch(controllerName) {
+            case "Cellular":
+                powerLevel = new String[] {
+                    "   less than 0dBm: ",
+                    "   0dBm to 8dBm: ",
+                    "   8dBm to 15dBm: ",
+                    "   15dBm to 20dBm: ",
+                    "   above 20dBm: "};
+                break;
+            default:
+                powerLevel = new String[] {"[0]", "[1]", "[2]", "[3]", "[4]"};
+                break;
+        }
+        final int numTxLvls = Math.min(counter.getTxTimeCounters().length, powerLevel.length);
         if (numTxLvls > 1) {
+            pw.println(sb.toString());
             for (int lvl = 0; lvl < numTxLvls; lvl++) {
                 final long txLvlTimeMs = counter.getTxTimeCounters()[lvl].getCountLocked(which);
                 sb.setLength(0);
                 sb.append(prefix);
-                sb.append("    [");
-                sb.append(lvl);
-                sb.append("] ");
+                sb.append("    ");
+                sb.append(powerLevel[lvl]);
+                sb.append(" ");
                 formatTimeMs(sb, txLvlTimeMs);
                 sb.append("(");
-                sb.append(formatRatioLocked(txLvlTimeMs, totalTxTimeMs));
+                sb.append(formatRatioLocked(txLvlTimeMs, totalControllerActivityTimeMs));
                 sb.append(")");
                 pw.println(sb.toString());
             }
+        } else {
+            final long txLvlTimeMs = counter.getTxTimeCounters()[0].getCountLocked(which);
+            formatTimeMs(sb, txLvlTimeMs);
+            sb.append("(");
+            sb.append(formatRatioLocked(txLvlTimeMs, totalControllerActivityTimeMs));
+            sb.append(")");
+            pw.println(sb.toString());
         }
 
-        sb.setLength(0);
-        sb.append(prefix);
-        sb.append("  ");
-        sb.append(controllerName);
-        sb.append(" Power drain: ").append(
+        if (powerDrainMaMs > 0) {
+            sb.setLength(0);
+            sb.append(prefix);
+            sb.append("     ");
+            sb.append(controllerName);
+            sb.append(" Battery drain: ").append(
                 BatteryStatsHelper.makemAh(powerDrainMaMs / (double) (1000*60*60)));
-        sb.append("mAh");
-        pw.println(sb.toString());
+            sb.append("mAh");
+            pw.println(sb.toString());
+        }
     }
 
     /**
@@ -4186,51 +4219,50 @@
             pw.println(sb.toString());
         }
 
+        pw.println("");
         pw.print(prefix);
-                pw.print("  Mobile total received: "); pw.print(formatBytesLocked(mobileRxTotalBytes));
-                pw.print(", sent: "); pw.print(formatBytesLocked(mobileTxTotalBytes));
-                pw.print(" (packets received "); pw.print(mobileRxTotalPackets);
-                pw.print(", sent "); pw.print(mobileTxTotalPackets); pw.println(")");
         sb.setLength(0);
         sb.append(prefix);
-        sb.append("  Phone signal levels:");
-        didOne = false;
-        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
-            final long time = getPhoneSignalStrengthTime(i, rawRealtime, which);
-            if (time == 0) {
-                continue;
-            }
-            sb.append("\n    ");
-            sb.append(prefix);
-            didOne = true;
-            sb.append(SignalStrength.SIGNAL_STRENGTH_NAMES[i]);
-            sb.append(" ");
-            formatTimeMs(sb, time/1000);
-            sb.append("(");
-            sb.append(formatRatioLocked(time, whichBatteryRealtime));
-            sb.append(") ");
-            sb.append(getPhoneSignalStrengthCount(i, which));
-            sb.append("x");
-        }
-        if (!didOne) sb.append(" (no activity)");
+        sb.append("  CONNECTIVITY POWER SUMMARY START");
+        pw.println(sb.toString());
+
+        pw.print(prefix);
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("  Logging duration for connectivity statistics: ");
+        formatTimeMs(sb, whichBatteryRealtime / 1000);
         pw.println(sb.toString());
 
         sb.setLength(0);
         sb.append(prefix);
-        sb.append("  Signal scanning time: ");
-        formatTimeMsNoSpace(sb, getPhoneSignalScanningTime(rawRealtime, which) / 1000);
+        sb.append("  Cellular Statistics:");
         pw.println(sb.toString());
 
+        pw.print(prefix);
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("     Cellular kernel active time: ");
+        final long mobileActiveTime = getMobileRadioActiveTime(rawRealtime, which);
+        formatTimeMs(sb, mobileActiveTime / 1000);
+        sb.append("("); sb.append(formatRatioLocked(mobileActiveTime, whichBatteryRealtime));
+        sb.append(")");
+        pw.println(sb.toString());
+
+        pw.print("     Cellular data received: "); pw.println(formatBytesLocked(mobileRxTotalBytes));
+        pw.print("     Cellular data sent: "); pw.println(formatBytesLocked(mobileTxTotalBytes));
+        pw.print("     Cellular packets received: "); pw.println(mobileRxTotalPackets);
+        pw.print("     Cellular packets sent: "); pw.println(mobileTxTotalPackets);
+
         sb.setLength(0);
         sb.append(prefix);
-        sb.append("  Radio types:");
+        sb.append("     Cellular Radio Access Technology:");
         didOne = false;
         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
             final long time = getPhoneDataConnectionTime(i, rawRealtime, which);
             if (time == 0) {
                 continue;
             }
-            sb.append("\n    ");
+            sb.append("\n       ");
             sb.append(prefix);
             didOne = true;
             sb.append(DATA_CONNECTION_NAMES[i]);
@@ -4239,73 +4271,64 @@
             sb.append("(");
             sb.append(formatRatioLocked(time, whichBatteryRealtime));
             sb.append(") ");
-            sb.append(getPhoneDataConnectionCount(i, which));
-            sb.append("x");
         }
         if (!didOne) sb.append(" (no activity)");
         pw.println(sb.toString());
 
         sb.setLength(0);
         sb.append(prefix);
-        sb.append("  Mobile radio active time: ");
-        final long mobileActiveTime = getMobileRadioActiveTime(rawRealtime, which);
-        formatTimeMs(sb, mobileActiveTime / 1000);
-        sb.append("("); sb.append(formatRatioLocked(mobileActiveTime, whichBatteryRealtime));
-        sb.append(") "); sb.append(getMobileRadioActiveCount(which));
-        sb.append("x");
+        sb.append("     Cellular Rx signal strength (RSRP):");
+        final String[] cellularRxSignalStrengthDescription = new String[]{
+            "very poor (less than -128dBm): ",
+            "poor (-128dBm to -118dBm): ",
+            "moderate (-118dBm to -108dBm): ",
+            "good (-108dBm to -98dBm): ",
+            "great (greater than -98dBm): "};
+        didOne = false;
+        final int numCellularRxBins = Math.min(SignalStrength.NUM_SIGNAL_STRENGTH_BINS,
+            cellularRxSignalStrengthDescription.length);
+        for (int i=0; i<numCellularRxBins; i++) {
+            final long time = getPhoneSignalStrengthTime(i, rawRealtime, which);
+            if (time == 0) {
+                continue;
+            }
+            sb.append("\n       ");
+            sb.append(prefix);
+            didOne = true;
+            sb.append(cellularRxSignalStrengthDescription[i]);
+            sb.append(" ");
+            formatTimeMs(sb, time/1000);
+            sb.append("(");
+            sb.append(formatRatioLocked(time, whichBatteryRealtime));
+            sb.append(") ");
+        }
+        if (!didOne) sb.append(" (no activity)");
         pw.println(sb.toString());
 
-        final long mobileActiveUnknownTime = getMobileRadioActiveUnknownTime(which);
-        if (mobileActiveUnknownTime != 0) {
-            sb.setLength(0);
-            sb.append(prefix);
-            sb.append("  Mobile radio active unknown time: ");
-            formatTimeMs(sb, mobileActiveUnknownTime / 1000);
-            sb.append("(");
-            sb.append(formatRatioLocked(mobileActiveUnknownTime, whichBatteryRealtime));
-            sb.append(") "); sb.append(getMobileRadioActiveUnknownCount(which));
-            sb.append("x");
-            pw.println(sb.toString());
-        }
-
-        final long mobileActiveAdjustedTime = getMobileRadioActiveAdjustedTime(which);
-        if (mobileActiveAdjustedTime != 0) {
-            sb.setLength(0);
-            sb.append(prefix);
-            sb.append("  Mobile radio active adjusted time: ");
-            formatTimeMs(sb, mobileActiveAdjustedTime / 1000);
-            sb.append("(");
-            sb.append(formatRatioLocked(mobileActiveAdjustedTime, whichBatteryRealtime));
-            sb.append(")");
-            pw.println(sb.toString());
-        }
-
-        printControllerActivity(pw, sb, prefix, "Radio", getModemControllerActivity(), which);
+        printControllerActivity(pw, sb, prefix, "Cellular",
+            getModemControllerActivity(), which);
 
         pw.print(prefix);
-                pw.print("  Wi-Fi total received: "); pw.print(formatBytesLocked(wifiRxTotalBytes));
-                pw.print(", sent: "); pw.print(formatBytesLocked(wifiTxTotalBytes));
-                pw.print(" (packets received "); pw.print(wifiRxTotalPackets);
-                pw.print(", sent "); pw.print(wifiTxTotalPackets); pw.println(")");
         sb.setLength(0);
         sb.append(prefix);
-                sb.append("  Wifi on: "); formatTimeMs(sb, wifiOnTime / 1000);
-                sb.append("("); sb.append(formatRatioLocked(wifiOnTime, whichBatteryRealtime));
-                sb.append("), Wifi running: "); formatTimeMs(sb, wifiRunningTime / 1000);
-                sb.append("("); sb.append(formatRatioLocked(wifiRunningTime, whichBatteryRealtime));
-                sb.append(")");
+        sb.append("  Wifi Statistics:");
         pw.println(sb.toString());
 
+        pw.print("     Wifi data received: "); pw.println(formatBytesLocked(wifiRxTotalBytes));
+        pw.print("     Wifi data sent: "); pw.println(formatBytesLocked(wifiTxTotalBytes));
+        pw.print("     Wifi packets received: "); pw.println(wifiRxTotalPackets);
+        pw.print("     Wifi packets sent: "); pw.println(wifiTxTotalPackets);
+
         sb.setLength(0);
         sb.append(prefix);
-        sb.append("  Wifi states:");
+        sb.append("     Wifi states:");
         didOne = false;
         for (int i=0; i<NUM_WIFI_STATES; i++) {
             final long time = getWifiStateTime(i, rawRealtime, which);
             if (time == 0) {
                 continue;
             }
-            sb.append("\n    ");
+            sb.append("\n       ");
             didOne = true;
             sb.append(WIFI_STATE_NAMES[i]);
             sb.append(" ");
@@ -4313,22 +4336,20 @@
             sb.append("(");
             sb.append(formatRatioLocked(time, whichBatteryRealtime));
             sb.append(") ");
-            sb.append(getWifiStateCount(i, which));
-            sb.append("x");
         }
         if (!didOne) sb.append(" (no activity)");
         pw.println(sb.toString());
 
         sb.setLength(0);
         sb.append(prefix);
-        sb.append("  Wifi supplicant states:");
+        sb.append("     Wifi supplicant states:");
         didOne = false;
         for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
             final long time = getWifiSupplStateTime(i, rawRealtime, which);
             if (time == 0) {
                 continue;
             }
-            sb.append("\n    ");
+            sb.append("\n       ");
             didOne = true;
             sb.append(WIFI_SUPPL_STATE_NAMES[i]);
             sb.append(" ");
@@ -4336,17 +4357,23 @@
             sb.append("(");
             sb.append(formatRatioLocked(time, whichBatteryRealtime));
             sb.append(") ");
-            sb.append(getWifiSupplStateCount(i, which));
-            sb.append("x");
         }
         if (!didOne) sb.append(" (no activity)");
         pw.println(sb.toString());
 
         sb.setLength(0);
         sb.append(prefix);
-        sb.append("  Wifi signal levels:");
+        sb.append("     Wifi Rx signal strength (RSSI):");
+        final String[] wifiRxSignalStrengthDescription = new String[]{
+            "very poor (less than -88.75dBm): ",
+            "poor (-88.75 to -77.5dBm): ",
+            "moderate (-77.5dBm to -66.25dBm): ",
+            "good (-66.25dBm to -55dBm): ",
+            "great (greater than -55dBm): "};
         didOne = false;
-        for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
+        final int numWifiRxBins = Math.min(NUM_WIFI_SIGNAL_STRENGTH_BINS,
+            wifiRxSignalStrengthDescription.length);
+        for (int i=0; i<numWifiRxBins; i++) {
             final long time = getWifiSignalStrengthTime(i, rawRealtime, which);
             if (time == 0) {
                 continue;
@@ -4354,15 +4381,12 @@
             sb.append("\n    ");
             sb.append(prefix);
             didOne = true;
-            sb.append("level(");
-            sb.append(i);
-            sb.append(") ");
+            sb.append("     ");
+            sb.append(wifiRxSignalStrengthDescription[i]);
             formatTimeMs(sb, time/1000);
             sb.append("(");
             sb.append(formatRatioLocked(time, whichBatteryRealtime));
             sb.append(") ");
-            sb.append(getWifiSignalStrengthCount(i, which));
-            sb.append("x");
         }
         if (!didOne) sb.append(" (no activity)");
         pw.println(sb.toString());
@@ -4370,6 +4394,13 @@
         printControllerActivity(pw, sb, prefix, "WiFi", getWifiControllerActivity(), which);
 
         pw.print(prefix);
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("  CONNECTIVITY POWER SUMMARY END");
+        pw.println(sb.toString());
+        pw.println("");
+
+        pw.print(prefix);
         pw.print("  Bluetooth total received: "); pw.print(formatBytesLocked(btRxTotalBytes));
         pw.print(", sent: "); pw.println(formatBytesLocked(btTxTotalBytes));
 
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index b46c6b1..017c213 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -1748,22 +1748,26 @@
     public static final int MEMINFO_SHMEM = 4;
     /** @hide */
     public static final int MEMINFO_SLAB = 5;
+     /** @hide */
+    public static final int MEMINFO_SLAB_RECLAIMABLE = 6;
+     /** @hide */
+    public static final int MEMINFO_SLAB_UNRECLAIMABLE = 7;
     /** @hide */
-    public static final int MEMINFO_SWAP_TOTAL = 6;
+    public static final int MEMINFO_SWAP_TOTAL = 8;
     /** @hide */
-    public static final int MEMINFO_SWAP_FREE = 7;
+    public static final int MEMINFO_SWAP_FREE = 9;
     /** @hide */
-    public static final int MEMINFO_ZRAM_TOTAL = 8;
+    public static final int MEMINFO_ZRAM_TOTAL = 10;
     /** @hide */
-    public static final int MEMINFO_MAPPED = 9;
+    public static final int MEMINFO_MAPPED = 11;
     /** @hide */
-    public static final int MEMINFO_VM_ALLOC_USED = 10;
+    public static final int MEMINFO_VM_ALLOC_USED = 12;
     /** @hide */
-    public static final int MEMINFO_PAGE_TABLES = 11;
+    public static final int MEMINFO_PAGE_TABLES = 13;
     /** @hide */
-    public static final int MEMINFO_KERNEL_STACK = 12;
+    public static final int MEMINFO_KERNEL_STACK = 14;
     /** @hide */
-    public static final int MEMINFO_COUNT = 13;
+    public static final int MEMINFO_COUNT = 15;
 
     /**
      * Retrieves /proc/meminfo.  outSizes is filled with fields
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c04e016..a248bf7 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9530,6 +9530,22 @@
         public static final String DEVICE_POLICY_CONSTANTS = "device_policy_constants";
 
         /**
+         * TextClassifier specific settings.
+         * This is encoded as a key=value list, separated by commas. Ex:
+         *
+         * <pre>
+         * smart_selection_dark_launch              (boolean)
+         * smart_selection_enabled_for_edit_text    (boolean)
+         * </pre>
+         *
+         * <p>
+         * Type: string
+         * @hide
+         * see also android.view.textclassifier.TextClassifierConstants
+         */
+        public static final String TEXT_CLASSIFIER_CONSTANTS = "text_classifier_constants";
+
+        /**
          * Get the key that retrieves a bluetooth headset's priority.
          * @hide
          */
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index bb1e693..c3601d9 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -152,4 +152,12 @@
      */
     @WorkerThread
     default void logEvent(String source, String event) {}
+
+    /**
+     * Returns this TextClassifier's settings.
+     * @hide
+     */
+    default TextClassifierConstants getSettings() {
+        return TextClassifierConstants.DEFAULT;
+    }
 }
diff --git a/core/java/android/view/textclassifier/TextClassifierConstants.java b/core/java/android/view/textclassifier/TextClassifierConstants.java
new file mode 100644
index 0000000..51e6168
--- /dev/null
+++ b/core/java/android/view/textclassifier/TextClassifierConstants.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2017 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 android.view.textclassifier;
+
+import android.annotation.Nullable;
+import android.util.KeyValueListParser;
+import android.util.Slog;
+
+/**
+ * TextClassifier specific settings.
+ * This is encoded as a key=value list, separated by commas. Ex:
+ *
+ * <pre>
+ * smart_selection_dark_launch              (boolean)
+ * smart_selection_enabled_for_edit_text    (boolean)
+ * </pre>
+ *
+ * <p>
+ * Type: string
+ * see also android.provider.Settings.Global.TEXT_CLASSIFIER_CONSTANTS
+ *
+ * Example of setting the values for testing.
+ * adb shell settings put global text_classifier_constants smart_selection_dark_launch=true,smart_selection_enabled_for_edit_text=true
+ * @hide
+ */
+public final class TextClassifierConstants {
+
+    private static final String LOG_TAG = "TextClassifierConstants";
+
+    private static final String SMART_SELECTION_DARK_LAUNCH =
+            "smart_selection_dark_launch";
+    private static final String SMART_SELECTION_ENABLED_FOR_EDIT_TEXT =
+            "smart_selection_enabled_for_edit_text";
+
+    private static final boolean SMART_SELECTION_DARK_LAUNCH_DEFAULT = false;
+    private static final boolean SMART_SELECTION_ENABLED_FOR_EDIT_TEXT_DEFAULT = true;
+
+    /** Default settings. */
+    static final TextClassifierConstants DEFAULT = new TextClassifierConstants();
+
+    private final boolean mDarkLaunch;
+    private final boolean mSuggestSelectionEnabledForEditableText;
+
+    private TextClassifierConstants() {
+        mDarkLaunch = SMART_SELECTION_DARK_LAUNCH_DEFAULT;
+        mSuggestSelectionEnabledForEditableText = SMART_SELECTION_ENABLED_FOR_EDIT_TEXT_DEFAULT;
+    }
+
+    private TextClassifierConstants(@Nullable String settings) {
+        final KeyValueListParser parser = new KeyValueListParser(',');
+        try {
+            parser.setString(settings);
+        } catch (IllegalArgumentException e) {
+            // Failed to parse the settings string, log this and move on with defaults.
+            Slog.e(LOG_TAG, "Bad TextClassifier settings: " + settings);
+        }
+        mDarkLaunch = parser.getBoolean(
+                SMART_SELECTION_DARK_LAUNCH,
+                SMART_SELECTION_DARK_LAUNCH_DEFAULT);
+        mSuggestSelectionEnabledForEditableText = parser.getBoolean(
+                SMART_SELECTION_ENABLED_FOR_EDIT_TEXT,
+                SMART_SELECTION_ENABLED_FOR_EDIT_TEXT_DEFAULT);
+    }
+
+    static TextClassifierConstants loadFromString(String settings) {
+        return new TextClassifierConstants(settings);
+    }
+
+    public boolean isDarkLaunch() {
+        return mDarkLaunch;
+    }
+
+    public boolean isSuggestSelectionEnabledForEditableText() {
+        return mSuggestSelectionEnabledForEditableText;
+    }
+}
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 7e93b78..2e41404 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -24,11 +24,11 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.graphics.drawable.Drawable;
-import android.icu.text.BreakIterator;
 import android.net.Uri;
 import android.os.LocaleList;
 import android.os.ParcelFileDescriptor;
 import android.provider.Browser;
+import android.provider.Settings;
 import android.text.Spannable;
 import android.text.TextUtils;
 import android.text.method.WordIterator;
@@ -46,6 +46,7 @@
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.text.BreakIterator;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -90,6 +91,8 @@
     @GuardedBy("mSmartSelectionLock") // Do not access outside this lock.
     private SmartSelection mSmartSelection;
 
+    private TextClassifierConstants mSettings;
+
     TextClassifierImpl(Context context) {
         mContext = Preconditions.checkNotNull(context);
     }
@@ -188,6 +191,15 @@
         }
     }
 
+    @Override
+    public TextClassifierConstants getSettings() {
+        if (mSettings == null) {
+            mSettings = TextClassifierConstants.loadFromString(Settings.Global.getString(
+                    mContext.getContentResolver(), Settings.Global.TEXT_CLASSIFIER_CONSTANTS));
+        }
+        return mSettings;
+    }
+
     private SmartSelection getSmartSelection(LocaleList localeList) throws FileNotFoundException {
         synchronized (mSmartSelectionLock) {
             localeList = localeList == null ? LocaleList.getEmptyLocaleList() : localeList;
diff --git a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
index aa172f9..fb870bd 100644
--- a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
+++ b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
@@ -43,7 +43,7 @@
 public final class SmartSelectionEventTracker {
 
     private static final String LOG_TAG = "SmartSelectEventTracker";
-    private static final boolean DEBUG_LOG_ENABLED = true;
+    private static final boolean DEBUG_LOG_ENABLED = false;
 
     private static final int START_EVENT_DELTA = MetricsEvent.FIELD_SELECTION_SINCE_START;
     private static final int PREV_EVENT_DELTA = MetricsEvent.FIELD_SELECTION_SINCE_PREVIOUS;
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 513a18c..384e254 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -71,11 +71,15 @@
     }
 
     public void startActionModeAsync(boolean adjustSelection) {
+        // Check if the smart selection should run for editable text.
+        adjustSelection &= !mTextView.isTextEditable()
+                || mTextView.getTextClassifier().getSettings()
+                        .isSuggestSelectionEnabledForEditableText();
+
         mSelectionTracker.onOriginalSelection(
                 getText(mTextView),
                 mTextView.getSelectionStart(),
-                mTextView.getSelectionEnd(),
-                mTextView.isTextEditable());
+                mTextView.getSelectionEnd());
         cancelAsyncTask();
         if (skipTextClassification()) {
             startActionMode(null);
@@ -163,7 +167,10 @@
     private void startActionMode(@Nullable SelectionResult result) {
         final CharSequence text = getText(mTextView);
         if (result != null && text instanceof Spannable) {
-            Selection.setSelection((Spannable) text, result.mStart, result.mEnd);
+            // Do not change the selection if TextClassifier should be dark launched.
+            if (!mTextView.getTextClassifier().getSettings().isDarkLaunch()) {
+                Selection.setSelection((Spannable) text, result.mStart, result.mEnd);
+            }
             mTextClassification = result.mClassification;
         } else {
             mTextClassification = null;
@@ -193,7 +200,7 @@
     }
 
     private void resetTextClassificationHelper() {
-        mTextClassificationHelper.reset(
+        mTextClassificationHelper.init(
                 mTextView.getTextClassifier(),
                 getText(mTextView),
                 mTextView.getSelectionStart(), mTextView.getSelectionEnd(),
@@ -225,8 +232,7 @@
         /**
          * Called when the original selection happens, before smart selection is triggered.
          */
-        public void onOriginalSelection(
-                CharSequence text, int selectionStart, int selectionEnd, boolean editableText) {
+        public void onOriginalSelection(CharSequence text, int selectionStart, int selectionEnd) {
             // If we abandoned a selection and created a new one very shortly after, we may still
             // have a pending request to log ABANDON, which we flush here.
             mDelayedLogAbandon.flush();
@@ -622,11 +628,11 @@
 
         TextClassificationHelper(TextClassifier textClassifier,
                 CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
-            reset(textClassifier, text, selectionStart, selectionEnd, locales);
+            init(textClassifier, text, selectionStart, selectionEnd, locales);
         }
 
         @UiThread
-        public void reset(TextClassifier textClassifier,
+        public void init(TextClassifier textClassifier,
                 CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
             mTextClassifier = Preconditions.checkNotNull(textClassifier);
             mText = Preconditions.checkNotNull(text).toString();
@@ -649,8 +655,12 @@
             trimText();
             final TextSelection selection = mTextClassifier.suggestSelection(
                     mTrimmedText, mRelativeStart, mRelativeEnd, mLocales);
-            mSelectionStart = Math.max(0, selection.getSelectionStartIndex() + mTrimStart);
-            mSelectionEnd = Math.min(mText.length(), selection.getSelectionEndIndex() + mTrimStart);
+            // Do not classify new selection boundaries if TextClassifier should be dark launched.
+            if (!mTextClassifier.getSettings().isDarkLaunch()) {
+                mSelectionStart = Math.max(0, selection.getSelectionStartIndex() + mTrimStart);
+                mSelectionEnd = Math.min(
+                        mText.length(), selection.getSelectionEndIndex() + mTrimStart);
+            }
             return performClassification(selection);
         }
 
diff --git a/core/java/com/android/internal/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java
index b71fa06..8d71666 100644
--- a/core/java/com/android/internal/util/MemInfoReader.java
+++ b/core/java/com/android/internal/util/MemInfoReader.java
@@ -82,7 +82,7 @@
      * that are mapped in to processes.
      */
     public long getCachedSizeKb() {
-        return mInfos[Debug.MEMINFO_BUFFERS]
+        return mInfos[Debug.MEMINFO_BUFFERS] + mInfos[Debug.MEMINFO_SLAB_RECLAIMABLE]
                 + mInfos[Debug.MEMINFO_CACHED] - mInfos[Debug.MEMINFO_MAPPED];
     }
 
@@ -90,7 +90,7 @@
      * Amount of RAM that is in use by the kernel for actual allocations.
      */
     public long getKernelUsedSizeKb() {
-        return mInfos[Debug.MEMINFO_SHMEM] + mInfos[Debug.MEMINFO_SLAB]
+        return mInfos[Debug.MEMINFO_SHMEM] + mInfos[Debug.MEMINFO_SLAB_UNRECLAIMABLE]
                 + mInfos[Debug.MEMINFO_VM_ALLOC_USED] + mInfos[Debug.MEMINFO_PAGE_TABLES]
                 + mInfos[Debug.MEMINFO_KERNEL_STACK];
     }
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 5afd067..c522bc4 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -615,6 +615,7 @@
     char jitprithreadweightOptBuf[sizeof("-Xjitprithreadweight:")-1 + PROPERTY_VALUE_MAX];
     char jittransitionweightOptBuf[sizeof("-Xjittransitionweight:")-1 + PROPERTY_VALUE_MAX];
     char hotstartupsamplesOptsBuf[sizeof("-Xps-hot-startup-method-samples:")-1 + PROPERTY_VALUE_MAX];
+    char madviseRandomOptsBuf[sizeof("-XX:MadviseRandomAccess:")-1 + PROPERTY_VALUE_MAX];
     char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];
     char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX];
     char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
@@ -742,6 +743,11 @@
                        "-Xjittransitionweight:");
 
     /*
+     * Madvise related options.
+     */
+    parseRuntimeOption("dalvik.vm.madvise-random", madviseRandomOptsBuf, "-XX:MadviseRandomAccess:");
+
+    /*
      * Profile related options.
      */
     parseRuntimeOption("dalvik.vm.hot-startup-method-samples", hotstartupsamplesOptsBuf,
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 4d32c05..4370747 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -705,6 +705,8 @@
     MEMINFO_CACHED,
     MEMINFO_SHMEM,
     MEMINFO_SLAB,
+    MEMINFO_SLAB_RECLAIMABLE,
+    MEMINFO_SLAB_UNRECLAIMABLE,
     MEMINFO_SWAP_TOTAL,
     MEMINFO_SWAP_FREE,
     MEMINFO_ZRAM_TOTAL,
@@ -776,6 +778,8 @@
             "Cached:",
             "Shmem:",
             "Slab:",
+            "SReclaimable:",
+            "SUnreclaim:",
             "SwapTotal:",
             "SwapFree:",
             "ZRam:",
@@ -792,6 +796,8 @@
             7,
             6,
             5,
+            13,
+            11,
             10,
             9,
             5,
@@ -801,7 +807,7 @@
             12,
             0
     };
-    long mem[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+    long mem[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 
     char* p = buffer;
     while (*p && numFound < (sizeof(tagsLen) / sizeof(tagsLen[0]))) {
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 7d9c50d..662f20e 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -344,6 +344,7 @@
                     Settings.Global.TETHER_DUN_REQUIRED,
                     Settings.Global.TETHER_OFFLOAD_DISABLED,
                     Settings.Global.TETHER_SUPPORTED,
+                    Settings.Global.TEXT_CLASSIFIER_CONSTANTS,
                     Settings.Global.THEATER_MODE_ON,
                     Settings.Global.TRANSITION_ANIMATION_SCALE,
                     Settings.Global.TRUSTED_SOUND,
diff --git a/packages/CtsShim/build/Android.mk b/packages/CtsShim/build/Android.mk
index 21f0afe..ec14d50 100644
--- a/packages/CtsShim/build/Android.mk
+++ b/packages/CtsShim/build/Android.mk
@@ -32,6 +32,9 @@
 
 LOCAL_MANIFEST_FILE := shim_priv_upgrade/AndroidManifest.xml
 
+LOCAL_MULTILIB := both
+LOCAL_JNI_SHARED_LIBRARIES := libshim_jni
+
 include $(BUILD_PACKAGE)
 my_shim_priv_upgrade_apk := $(LOCAL_BUILT_MODULE)
 
@@ -60,6 +63,9 @@
 
 LOCAL_FULL_MANIFEST_FILE := $(gen)
 
+LOCAL_MULTILIB := both
+LOCAL_JNI_SHARED_LIBRARIES := libshim_jni
+
 include $(BUILD_PACKAGE)
 
 ###########################################################
@@ -80,6 +86,9 @@
 
 LOCAL_MANIFEST_FILE := shim_priv_upgrade/AndroidManifest.xml
 
+LOCAL_MULTILIB := both
+LOCAL_JNI_SHARED_LIBRARIES := libshim_jni
+
 include $(BUILD_PACKAGE)
 
 
@@ -99,3 +108,5 @@
 
 include $(BUILD_PACKAGE)
 
+###########################################################
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/CtsShim/build/jni/Android.mk b/packages/CtsShim/build/jni/Android.mk
new file mode 100644
index 0000000..968fc0b
--- /dev/null
+++ b/packages/CtsShim/build/jni/Android.mk
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2017 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)
+
+LOCAL_MODULE := libshim_jni
+
+LOCAL_SRC_FILES := Shim.c
+
+LOCAL_SDK_VERSION := 24
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/packages/CtsShim/build/jni/Shim.c b/packages/CtsShim/build/jni/Shim.c
new file mode 100644
index 0000000..44eb316
--- /dev/null
+++ b/packages/CtsShim/build/jni/Shim.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include <jni.h>
\ No newline at end of file
diff --git a/packages/CtsShim/build/shim_priv/AndroidManifest.xml b/packages/CtsShim/build/shim_priv/AndroidManifest.xml
index 5195ef7..9bf454c 100644
--- a/packages/CtsShim/build/shim_priv/AndroidManifest.xml
+++ b/packages/CtsShim/build/shim_priv/AndroidManifest.xml
@@ -27,6 +27,7 @@
 
     <application
         android:hasCode="false"
+        android:multiArch="true"
         tools:ignore="AllowBackup,MissingApplicationIcon" >
 
         <!-- These activities don't actually exist; define them just to test the filters !-->
diff --git a/packages/CtsShim/build/shim_priv_upgrade/AndroidManifest.xml b/packages/CtsShim/build/shim_priv_upgrade/AndroidManifest.xml
index b938e3e..023e93e 100644
--- a/packages/CtsShim/build/shim_priv_upgrade/AndroidManifest.xml
+++ b/packages/CtsShim/build/shim_priv_upgrade/AndroidManifest.xml
@@ -24,6 +24,7 @@
 
     <application
         android:hasCode="false"
+        android:multiArch="true"
         tools:ignore="AllowBackup,MissingApplicationIcon" >
 
         <!-- These activities don't actually exist; define them just to test the filters !-->
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b4741d1..a95b7f3 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5459,7 +5459,7 @@
             boolean doLowMem = app.instr == null;
             boolean doOomAdj = doLowMem;
             if (!app.killedByAm) {
-                maybeNotifyTopAppKilled(app);
+                maybeNotifyTopAppKilledLocked(app);
                 Slog.i(TAG, "Process " + app.processName + " (pid " + pid + ") has died: "
                         + ProcessList.makeOomAdjString(app.setAdj)
                         + ProcessList.makeProcStateString(app.setProcState));
@@ -5494,8 +5494,8 @@
     }
 
     /** Show system error dialog when a top app is killed by LMK */
-    void maybeNotifyTopAppKilled(ProcessRecord app) {
-        if (!shouldNotifyTopAppKilled(app)) {
+    void maybeNotifyTopAppKilledLocked(ProcessRecord app) {
+        if (!shouldNotifyTopAppKilledLocked(app)) {
             return;
         }
 
@@ -5505,8 +5505,10 @@
     }
 
     /** Only show notification when the top app is killed on low ram devices */
-    private boolean shouldNotifyTopAppKilled(ProcessRecord app) {
-        return app.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP &&
+    private boolean shouldNotifyTopAppKilledLocked(ProcessRecord app) {
+        final ActivityRecord TOP_ACT = resumedAppLocked();
+        final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
+        return app == TOP_APP &&
             ActivityManager.isLowRamDeviceStatic();
     }