Merge "Make sure control points are in absolute coordinates"
diff --git a/api/current.txt b/api/current.txt
index 220a1ac..2eea8ac 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -35,6 +35,7 @@
     field public static final java.lang.String BLUETOOTH = "android.permission.BLUETOOTH";
     field public static final java.lang.String BLUETOOTH_ADMIN = "android.permission.BLUETOOTH_ADMIN";
     field public static final java.lang.String BLUETOOTH_PRIVILEGED = "android.permission.BLUETOOTH_PRIVILEGED";
+    field public static final java.lang.String BODY_SENSORS = "android.permission.BODY_SENSORS";
     field public static final java.lang.String BRICK = "android.permission.BRICK";
     field public static final java.lang.String BROADCAST_PACKAGE_REMOVED = "android.permission.BROADCAST_PACKAGE_REMOVED";
     field public static final java.lang.String BROADCAST_SMS = "android.permission.BROADCAST_SMS";
@@ -2456,6 +2457,7 @@
 
   public abstract class AccessibilityService extends android.app.Service {
     ctor public AccessibilityService();
+    method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
     method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
     method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
     method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
@@ -4755,6 +4757,7 @@
     method public void clearWindowAnimationFrameStats();
     method public boolean clearWindowContentFrameStats(int);
     method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
+    method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
     method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
     method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
     method public android.view.WindowAnimationFrameStats getWindowAnimationFrameStats();
@@ -7782,6 +7785,7 @@
     method public abstract java.lang.String getInstallerPackageName(java.lang.String);
     method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.Intent getLaunchIntentForPackage(java.lang.String);
+    method public abstract android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
     method public abstract java.lang.String getNameForUid(int);
     method public android.content.pm.PackageInfo getPackageArchiveInfo(java.lang.String, int);
     method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -11395,10 +11399,33 @@
     method public int getMinDelay();
     method public java.lang.String getName();
     method public float getPower();
+    method public java.lang.String getRequiredPermission();
     method public float getResolution();
+    method public java.lang.String getStringType();
     method public int getType();
     method public java.lang.String getVendor();
     method public int getVersion();
+    field public static final java.lang.String STRING_TYPE_ACCELEROMETER = "android.sensor.accelerometer";
+    field public static final java.lang.String STRING_TYPE_AMBIENT_TEMPERATURE = "android.sensor.ambient_temperature";
+    field public static final java.lang.String STRING_TYPE_GAME_ROTATION_VECTOR = "android.sensor.game_rotation_vector";
+    field public static final java.lang.String STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR = "android.sensor.geomagnetic_rotation_vector";
+    field public static final java.lang.String STRING_TYPE_GRAVITY = "android.sensor.gravity";
+    field public static final java.lang.String STRING_TYPE_GYROSCOPE = "android.sensor.gyroscope";
+    field public static final java.lang.String STRING_TYPE_GYROSCOPE_UNCALIBRATED = "android.sensor.gyroscope_uncalibrated";
+    field public static final java.lang.String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
+    field public static final java.lang.String STRING_TYPE_LIGHT = "android.sensor.light";
+    field public static final java.lang.String STRING_TYPE_LINEAR_ACCELERATION = "android.sensor.linear_acceleration";
+    field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD = "android.sensor.magnetic_field";
+    field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED = "android.sensor.magnetic_field_uncalibrated";
+    field public static final deprecated java.lang.String STRING_TYPE_ORIENTATION = "android.sensor.orientation";
+    field public static final java.lang.String STRING_TYPE_PRESSURE = "android.sensor.pressure";
+    field public static final java.lang.String STRING_TYPE_PROXIMITY = "android.sensor.proximity";
+    field public static final java.lang.String STRING_TYPE_RELATIVE_HUMIDITY = "android.sensor.relative_humidity";
+    field public static final java.lang.String STRING_TYPE_ROTATION_VECTOR = "android.sensor.rotation_vector";
+    field public static final java.lang.String STRING_TYPE_SIGNIFICANT_MOTION = "android.sensor.significant_motion";
+    field public static final java.lang.String STRING_TYPE_STEP_COUNTER = "android.sensor.step_counter";
+    field public static final java.lang.String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector";
+    field public static final deprecated java.lang.String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
     field public static final int TYPE_ACCELEROMETER = 1; // 0x1
     field public static final int TYPE_ALL = -1; // 0xffffffff
     field public static final int TYPE_AMBIENT_TEMPERATURE = 13; // 0xd
@@ -11407,6 +11434,7 @@
     field public static final int TYPE_GRAVITY = 9; // 0x9
     field public static final int TYPE_GYROSCOPE = 4; // 0x4
     field public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16; // 0x10
+    field public static final int TYPE_HEART_RATE = 21; // 0x15
     field public static final int TYPE_LIGHT = 5; // 0x5
     field public static final int TYPE_LINEAR_ACCELERATION = 10; // 0xa
     field public static final int TYPE_MAGNETIC_FIELD = 2; // 0x2
@@ -19950,6 +19978,7 @@
 
   public class UserManager {
     method public android.os.Bundle getApplicationRestrictions(java.lang.String);
+    method public android.graphics.drawable.Drawable getBadgedDrawableForUser(android.graphics.drawable.Drawable, android.os.UserHandle);
     method public long getSerialNumberForUser(android.os.UserHandle);
     method public int getUserCount();
     method public android.os.UserHandle getUserForSerialNumber(long);
@@ -26003,6 +26032,7 @@
     method public java.lang.String getInstallerPackageName(java.lang.String);
     method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
+    method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
     method public java.lang.String getNameForUid(int);
     method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index b01d92c..2620c44 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -526,6 +526,31 @@
     }
 
     /**
+     * Find the view that has the specified focus type. The search is performed
+     * across all windows.
+     * <p>
+     * <strong>Note:</strong> In order to access the windows your service has
+     * to declare the capability to retrieve window content by setting the
+     * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
+     * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
+     * Also the service has to opt-in to retrieve the interactive windows by
+     * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}
+     * flag.Otherwise, the search will be performed only in the active window.
+     * </p>
+     *
+     * @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
+     *         {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}.
+     * @return The node info of the focused view or null.
+     *
+     * @see AccessibilityNodeInfo#FOCUS_INPUT
+     * @see AccessibilityNodeInfo#FOCUS_ACCESSIBILITY
+     */
+    public AccessibilityNodeInfo findFocus(int focus) {
+        return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId,
+                AccessibilityNodeInfo.ANY_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, focus);
+    }
+
+    /**
      * Gets the an {@link AccessibilityServiceInfo} describing this
      * {@link AccessibilityService}. This method is useful if one wants
      * to change some of the dynamically configurable properties at
diff --git a/core/java/android/alsa/AlsaCardsParser.java b/core/java/android/alsa/AlsaCardsParser.java
new file mode 100644
index 0000000..f9af979
--- /dev/null
+++ b/core/java/android/alsa/AlsaCardsParser.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.alsascan;
+
+import android.util.Slog;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Vector;
+
+/**
+ * @hide Retrieves information from an ALSA "cards" file.
+ */
+public class AlsaCardsParser {
+    private static final String TAG = "AlsaCardsParser";
+
+    private static LineTokenizer tokenizer_ = new LineTokenizer(" :[]");
+
+    public class AlsaCardRecord {
+        public int mCardNum = -1;
+        public String mField1 = "";
+        public String mCardName = "";
+        public String mCardDescription = "";
+
+        public AlsaCardRecord() {}
+
+        public boolean parse(String line, int lineIndex) {
+            int tokenIndex = 0;
+            int delimIndex = 0;
+            if (lineIndex == 0) {
+                // line # (skip)
+                tokenIndex = tokenizer_.nextToken(line, tokenIndex);
+                delimIndex = tokenizer_.nextDelimiter(line, tokenIndex);
+
+                // mField1
+                tokenIndex = tokenizer_.nextToken(line, delimIndex);
+                delimIndex = tokenizer_.nextDelimiter(line, tokenIndex);
+                mField1 = line.substring(tokenIndex, delimIndex);
+
+                // mCardName
+                tokenIndex = tokenizer_.nextToken(line, delimIndex);
+                // delimIndex = tokenizer_.nextDelimiter(line, tokenIndex);
+                mCardName = line.substring(tokenIndex);
+                // done
+              } else if (lineIndex == 1) {
+                  tokenIndex = tokenizer_.nextToken(line, 0);
+                  if (tokenIndex != -1) {
+                      mCardDescription = line.substring(tokenIndex);
+                  }
+            }
+
+            return true;
+        }
+
+        public String textFormat() {
+          return mCardName + " : " + mCardDescription;
+        }
+    }
+
+    private Vector<AlsaCardRecord> cardRecords_ = new Vector<AlsaCardRecord>();
+
+    public void scan() {
+          cardRecords_.clear();
+          final String cardsFilePath = "/proc/asound/cards";
+          File cardsFile = new File(cardsFilePath);
+          try {
+              FileReader reader = new FileReader(cardsFile);
+              BufferedReader bufferedReader = new BufferedReader(reader);
+              String line = "";
+              while ((line = bufferedReader.readLine()) != null) {
+                  AlsaCardRecord cardRecord = new AlsaCardRecord();
+                  cardRecord.parse(line, 0);
+                  cardRecord.parse(line = bufferedReader.readLine(), 1);
+                  cardRecords_.add(cardRecord);
+              }
+              reader.close();
+          } catch (FileNotFoundException e) {
+              e.printStackTrace();
+          } catch (IOException e) {
+              e.printStackTrace();
+          }
+      }
+
+      public AlsaCardRecord getCardRecordAt(int index) {
+          return cardRecords_.get(index);
+      }
+
+      public int getNumCardRecords() {
+          return cardRecords_.size();
+      }
+
+    public void Log() {
+      int numCardRecs = getNumCardRecords();
+      for (int index = 0; index < numCardRecs; ++index) {
+          Slog.w(TAG, "usb:" + getCardRecordAt(index).textFormat());
+      }
+    }
+
+    public AlsaCardsParser() {}
+}
diff --git a/core/java/android/alsa/AlsaDevicesParser.java b/core/java/android/alsa/AlsaDevicesParser.java
new file mode 100644
index 0000000..094c8a2
--- /dev/null
+++ b/core/java/android/alsa/AlsaDevicesParser.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.alsascan;
+
+import android.util.Slog;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Vector;
+
+/**
+ * @hide
+ * Retrieves information from an ALSA "devices" file.
+ */
+public class AlsaDevicesParser {
+    private static final String TAG = "AlsaDevicesParser";
+
+    private static final int kIndex_CardDeviceField = 5;
+    private static final int kStartIndex_CardNum = 6;
+    private static final int kEndIndex_CardNum = 8; // one past
+    private static final int kStartIndex_DeviceNum = 9;
+    private static final int kEndIndex_DeviceNum = 11; // one past
+    private static final int kStartIndex_Type = 14;
+
+    private static LineTokenizer mTokenizer = new LineTokenizer(" :[]-");
+
+    private boolean mHasCaptureDevices = false;
+    private boolean mHasPlaybackDevices = false;
+    private boolean mHasMIDIDevices = false;
+
+    public class AlsaDeviceRecord {
+        public static final int kDeviceType_Unknown = -1;
+        public static final int kDeviceType_Audio = 0;
+        public static final int kDeviceType_Control = 1;
+        public static final int kDeviceType_MIDI = 2;
+
+        public static final int kDeviceDir_Unknown = -1;
+        public static final int kDeviceDir_Capture = 0;
+        public static final int kDeviceDir_Playback = 1;
+
+        int mCardNum = -1;
+        int mDeviceNum = -1;
+        int mDeviceType = kDeviceType_Unknown;
+        int mDeviceDir = kDeviceDir_Unknown;
+
+        public AlsaDeviceRecord() {
+        }
+
+        public boolean parse(String line) {
+            // "0123456789012345678901234567890"
+            // "  2: [ 0-31]: digital audio playback"
+            // "  3: [ 0-30]: digital audio capture"
+            // " 35: [ 1]   : control"
+            // " 36: [ 2- 0]: raw midi"
+
+            final int kToken_LineNum = 0;
+            final int kToken_CardNum = 1;
+            final int kToken_DeviceNum = 2;
+            final int kToken_Type0 = 3; // "digital", "control", "raw"
+            final int kToken_Type1 = 4; // "audio", "midi"
+            final int kToken_Type2 = 5; // "capture", "playback"
+
+            int tokenOffset = 0;
+            int delimOffset = 0;
+            int tokenIndex = kToken_LineNum;
+            while (true) {
+                tokenOffset = mTokenizer.nextToken(line, delimOffset);
+                if (tokenOffset == LineTokenizer.kTokenNotFound) {
+                    break; // bail
+                }
+                delimOffset = mTokenizer.nextDelimiter(line, tokenOffset);
+                if (delimOffset == LineTokenizer.kTokenNotFound) {
+                    delimOffset = line.length();
+                }
+                String token = line.substring(tokenOffset, delimOffset);
+
+                switch (tokenIndex) {
+                case kToken_LineNum:
+                    // ignore
+                    break;
+
+                case kToken_CardNum:
+                    mCardNum = Integer.parseInt(token);
+                    if (line.charAt(delimOffset) != '-') {
+                        tokenIndex++; // no device # in the token stream
+                    }
+                    break;
+
+                case kToken_DeviceNum:
+                    mDeviceNum = Integer.parseInt(token);
+                    break;
+
+                case kToken_Type0:
+                    if (token.equals("digital")) {
+                        // NOP
+                    } else if (token.equals("control")) {
+                        mDeviceType = kDeviceType_Control;
+                    } else if (token.equals("raw")) {
+                        // NOP
+                    }
+                    break;
+
+                case kToken_Type1:
+                    if (token.equals("audio")) {
+                        mDeviceType = kDeviceType_Audio;
+                    } else if (token.equals("midi")) {
+                        mDeviceType = kDeviceType_MIDI;
+                        mHasMIDIDevices = true;
+                    }
+                    break;
+
+                case kToken_Type2:
+                    if (token.equals("capture")) {
+                        mDeviceDir = kDeviceDir_Capture;
+                        mHasCaptureDevices = true;
+                    } else if (token.equals("playback")) {
+                        mDeviceDir = kDeviceDir_Playback;
+                        mHasPlaybackDevices = true;
+                    }
+                    break;
+                } // switch (tokenIndex)
+
+                tokenIndex++;
+            } // while (true)
+
+            return true;
+        } // parse()
+
+        public String textFormat() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("[" + mCardNum + ":" + mDeviceNum + "]");
+
+            switch (mDeviceType) {
+            case kDeviceType_Unknown:
+                sb.append(" N/A");
+                break;
+            case kDeviceType_Audio:
+                sb.append(" Audio");
+                break;
+            case kDeviceType_Control:
+                sb.append(" Control");
+                break;
+            case kDeviceType_MIDI:
+                sb.append(" MIDI");
+                break;
+            }
+
+            switch (mDeviceDir) {
+            case kDeviceDir_Unknown:
+                sb.append(" N/A");
+                break;
+            case kDeviceDir_Capture:
+                sb.append(" Capture");
+                break;
+            case kDeviceDir_Playback:
+                sb.append(" Playback");
+                break;
+            }
+
+            return sb.toString();
+        }
+    }
+
+    private Vector<AlsaDeviceRecord>
+            deviceRecords_ = new Vector<AlsaDeviceRecord>();
+
+    private boolean isLineDeviceRecord(String line) {
+        return line.charAt(kIndex_CardDeviceField) == '[';
+    }
+
+    public AlsaDevicesParser() {
+    }
+
+    public int getNumDeviceRecords() {
+        return deviceRecords_.size();
+    }
+
+    public AlsaDeviceRecord getDeviceRecordAt(int index) {
+        return deviceRecords_.get(index);
+    }
+
+    public void Log() {
+        int numDevRecs = getNumDeviceRecords();
+        for (int index = 0; index < numDevRecs; ++index) {
+            Slog.w(TAG, "usb:" + getDeviceRecordAt(index).textFormat());
+        }
+    }
+
+    public boolean hasPlaybackDevices() {
+        return mHasPlaybackDevices;
+    }
+
+    public boolean hasPlaybackDevices(int card) {
+        for (int index = 0; index < deviceRecords_.size(); index++) {
+            AlsaDeviceRecord deviceRecord = deviceRecords_.get(index);
+            if (deviceRecord.mCardNum == card &&
+                deviceRecord.mDeviceType == AlsaDeviceRecord.kDeviceType_Audio &&
+                deviceRecord.mDeviceDir == AlsaDeviceRecord.kDeviceDir_Playback) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean hasCaptureDevices() {
+        return mHasCaptureDevices;
+    }
+
+    public boolean hasCaptureDevices(int card) {
+        for (int index = 0; index < deviceRecords_.size(); index++) {
+            AlsaDeviceRecord deviceRecord = deviceRecords_.get(index);
+            if (deviceRecord.mCardNum == card &&
+                deviceRecord.mDeviceType == AlsaDeviceRecord.kDeviceType_Audio &&
+                deviceRecord.mDeviceDir == AlsaDeviceRecord.kDeviceDir_Capture) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean hasMIDIDevices() {
+        return mHasMIDIDevices;
+    }
+
+    public boolean hasMIDIDevices(int card) {
+        for (int index = 0; index < deviceRecords_.size(); index++) {
+            AlsaDeviceRecord deviceRecord = deviceRecords_.get(index);
+            if (deviceRecord.mCardNum == card &&
+                deviceRecord.mDeviceType == AlsaDeviceRecord.kDeviceType_MIDI) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void scan() {
+        deviceRecords_.clear();
+
+        final String devicesFilePath = "/proc/asound/devices";
+        File devicesFile = new File(devicesFilePath);
+        try {
+            FileReader reader = new FileReader(devicesFile);
+            BufferedReader bufferedReader = new BufferedReader(reader);
+            String line = "";
+            while ((line = bufferedReader.readLine()) != null) {
+                if (isLineDeviceRecord(line)) {
+                    AlsaDeviceRecord deviceRecord = new AlsaDeviceRecord();
+                    deviceRecord.parse(line);
+                    deviceRecords_.add(deviceRecord);
+                }
+            }
+            reader.close();
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+} // class AlsaDevicesParser
+
diff --git a/core/java/android/alsa/LineTokenizer.java b/core/java/android/alsa/LineTokenizer.java
new file mode 100644
index 0000000..c138fc5
--- /dev/null
+++ b/core/java/android/alsa/LineTokenizer.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.alsascan;
+
+/**
+ * @hide
+ * Breaks lines in an ALSA "cards" or "devices" file into tokens.
+ * TODO(pmclean) Look into replacing this with String.split().
+ */
+public class LineTokenizer {
+    public static final int kTokenNotFound = -1;
+
+    private String mDelimiters = "";
+
+    public LineTokenizer(String delimiters) {
+        mDelimiters = delimiters;
+    }
+
+    int nextToken(String line, int startIndex) {
+        int len = line.length();
+        int offset = startIndex;
+        for (; offset < len; offset++) {
+            if (mDelimiters.indexOf(line.charAt(offset)) == -1) {
+                // past a delimiter
+                break;
+            }
+      }
+
+      return offset < len ? offset : kTokenNotFound;
+    }
+
+    int nextDelimiter(String line, int startIndex) {
+        int len = line.length();
+        int offset = startIndex;
+        for (; offset < len; offset++) {
+            if (mDelimiters.indexOf(line.charAt(offset)) != -1) {
+                // past a delimiter
+                break;
+            }
+        }
+
+      return offset < len ? offset : kTokenNotFound;
+    }
+}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 6ca5244..ab62427 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -128,6 +128,24 @@
     }
 
     @Override
+    public Intent getLeanbackLaunchIntentForPackage(String packageName) {
+        // Try to find a main leanback_launcher activity.
+        Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
+        intentToResolve.addCategory(Intent.CATEGORY_LEANBACK_LAUNCHER);
+        intentToResolve.setPackage(packageName);
+        List<ResolveInfo> ris = queryIntentActivities(intentToResolve, 0);
+
+        if (ris == null || ris.size() <= 0) {
+            return null;
+        }
+        Intent intent = new Intent(intentToResolve);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.setClassName(ris.get(0).activityInfo.packageName,
+                ris.get(0).activityInfo.name);
+        return intent;
+    }
+
+    @Override
     public int[] getPackageGids(String packageName)
             throws NameNotFoundException {
         try {
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 8523d0c..9405325 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -297,6 +297,28 @@
     }
 
     /**
+     * Find the view that has the specified focus type. The search is performed
+     * across all windows.
+     * <p>
+     * <strong>Note:</strong> In order to access the windows you have to opt-in
+     * to retrieve the interactive windows by setting the
+     * {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS} flag.
+     * Otherwise, the search will be performed only in the active window.
+     * </p>
+     *
+     * @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
+     *         {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}.
+     * @return The node info of the focused view or null.
+     *
+     * @see AccessibilityNodeInfo#FOCUS_INPUT
+     * @see AccessibilityNodeInfo#FOCUS_ACCESSIBILITY
+     */
+    public AccessibilityNodeInfo findFocus(int focus) {
+        return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId,
+                AccessibilityNodeInfo.ANY_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, focus);
+    }
+
+    /**
      * Gets the an {@link AccessibilityServiceInfo} describing this UiAutomation.
      * This method is useful if one wants to change some of the dynamically
      * configurable properties at runtime.
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index d24a472..d981cc1 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1012,6 +1012,7 @@
      * @hide
      * @deprecated
      */
+    @Deprecated
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_NFC_HCE = "android.hardware.nfc.hce";
 
@@ -1308,6 +1309,7 @@
      * something like a DPAD, not through touch or mouse.
      * @deprecated use {@link #FEATURE_LEANBACK} instead.
      */
+    @Deprecated
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_TELEVISION = "android.hardware.type.television";
 
@@ -1522,17 +1524,33 @@
     public abstract Intent getLaunchIntentForPackage(String packageName);
 
     /**
-     * Return an array of all of the secondary group-ids that have been
-     * assigned to a package.
-     *
-     * <p>Throws {@link NameNotFoundException} if a package with the given
-     * name cannot be found on the system.
-     *
+     * Return a "good" intent to launch a front-door Leanback activity in a
+     * package, for use for example to implement an "open" button when browsing
+     * through packages. The current implementation will look for a main
+     * activity in the category {@link Intent#CATEGORY_LEANBACK_LAUNCHER}, or
+     * return null if no main leanback activities are found.
+     * <p>
+     * Throws {@link NameNotFoundException} if a package with the given name
+     * cannot be found on the system.
+     * 
+     * @param packageName The name of the package to inspect.
+     * @return Returns either a fully-qualified Intent that can be used to launch
+     *         the main Leanback activity in the package, or null if the package
+     *         does not contain such an activity.
+     */
+    public abstract Intent getLeanbackLaunchIntentForPackage(String packageName);
+
+    /**
+     * Return an array of all of the secondary group-ids that have been assigned
+     * to a package.
+     * <p>
+     * Throws {@link NameNotFoundException} if a package with the given name
+     * cannot be found on the system.
+     * 
      * @param packageName The full name (i.e. com.google.apps.contacts) of the
-     *                    desired package.
-     *
-     * @return Returns an int array of the assigned gids, or null if there
-     * are none.
+     *            desired package.
+     * @return Returns an int array of the assigned gids, or null if there are
+     *         none.
      */
     public abstract int[] getPackageGids(String packageName)
             throws NameNotFoundException;
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 89a5819..4bea9ee 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -38,6 +38,13 @@
     public static final int TYPE_ACCELEROMETER = 1;
 
     /**
+     * A constant string describing an accelerometer sensor type.
+     *
+     * @see #TYPE_ACCELEROMETER
+     */
+    public static final String STRING_TYPE_ACCELEROMETER = "android.sensor.accelerometer";
+
+    /**
      * A constant describing a magnetic field sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
@@ -45,6 +52,13 @@
     public static final int TYPE_MAGNETIC_FIELD = 2;
 
     /**
+     * A constant string describing a magnetic field sensor type.
+     *
+     * @see #TYPE_MAGNETIC_FIELD
+     */
+    public static final String STRING_TYPE_MAGNETIC_FIELD = "android.sensor.magnetic_field";
+
+    /**
      * A constant describing an orientation sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
@@ -55,24 +69,58 @@
     @Deprecated
     public static final int TYPE_ORIENTATION = 3;
 
-    /** A constant describing a gyroscope sensor type.
+    /**
+     * A constant string describing an orientation sensor type.
+     *
+     * @see #TYPE_ORIENTATION
+     * @deprecated use {@link android.hardware.SensorManager#getOrientation
+     *             SensorManager.getOrientation()} instead.
+     */
+    @Deprecated
+    public static final String STRING_TYPE_ORIENTATION = "android.sensor.orientation";
+
+    /**
+     * A constant describing a gyroscope sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details. */
     public static final int TYPE_GYROSCOPE = 4;
 
     /**
+     * A constant string describing a gyroscope sensor type.
+     *
+     * @see #TYPE_GYROSCOPE
+     */
+    public static final String STRING_TYPE_GYROSCOPE = "android.sensor.gyroscope";
+
+    /**
      * A constant describing a light sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
      */
     public static final int TYPE_LIGHT = 5;
 
-    /** A constant describing a pressure sensor type.
+    /**
+     * A constant string describing a light sensor type.
+     *
+     * @see #TYPE_LIGHT
+     */
+    public static final String STRING_TYPE_LIGHT = "android.sensor.light";
+
+    /**
+     * A constant describing a pressure sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
-     * for more details. */
+     * for more details.
+     */
     public static final int TYPE_PRESSURE = 6;
 
     /**
+     * A constant string describing a pressure sensor type.
+     *
+     * @see #TYPE_PRESSURE
+     */
+    public static final String STRING_TYPE_PRESSURE = "android.sensor.pressure";
+
+    /**
      * A constant describing a temperature sensor type
      *
      * @deprecated use
@@ -83,6 +131,17 @@
     public static final int TYPE_TEMPERATURE = 7;
 
     /**
+     * A constant string describing a temperature sensor type
+     *
+     * @see #TYPE_TEMPERATURE
+     * @deprecated use
+     *             {@link android.hardware.Sensor#STRING_TYPE_AMBIENT_TEMPERATURE
+     *             Sensor.STRING_TYPE_AMBIENT_TEMPERATURE} instead.
+     */
+    @Deprecated
+    public static final String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
+
+    /**
      * A constant describing a proximity sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
@@ -90,6 +149,13 @@
     public static final int TYPE_PROXIMITY = 8;
 
     /**
+     * A constant string describing a proximity sensor type.
+     *
+     * @see #TYPE_PROXIMITY
+     */
+    public static final String STRING_TYPE_PROXIMITY = "android.sensor.proximity";
+
+    /**
      * A constant describing a gravity sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
@@ -97,6 +163,13 @@
     public static final int TYPE_GRAVITY = 9;
 
     /**
+     * A constant string describing a gravity sensor type.
+     *
+     * @see #TYPE_GRAVITY
+     */
+    public static final String STRING_TYPE_GRAVITY = "android.sensor.gravity";
+
+    /**
      * A constant describing a linear acceleration sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
@@ -104,6 +177,14 @@
     public static final int TYPE_LINEAR_ACCELERATION = 10;
 
     /**
+     * A constant string describing a linear acceleration sensor type.
+     *
+     * @see #TYPE_LINEAR_ACCELERATION
+     */
+    public static final String STRING_TYPE_LINEAR_ACCELERATION =
+        "android.sensor.linear_acceleration";
+
+    /**
      * A constant describing a rotation vector sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
@@ -111,18 +192,42 @@
     public static final int TYPE_ROTATION_VECTOR = 11;
 
     /**
+     * A constant string describing a rotation vector sensor type.
+     *
+     * @see #TYPE_ROTATION_VECTOR
+     */
+    public static final String STRING_TYPE_ROTATION_VECTOR = "android.sensor.rotation_vector";
+
+    /**
      * A constant describing a relative humidity sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
      */
     public static final int TYPE_RELATIVE_HUMIDITY = 12;
 
-    /** A constant describing an ambient temperature sensor type.
+    /**
+     * A constant string describing a relative humidity sensor type
+     *
+     * @see #TYPE_RELATIVE_HUMIDITY
+     */
+    public static final String STRING_TYPE_RELATIVE_HUMIDITY = "android.sensor.relative_humidity";
+
+    /**
+     * A constant describing an ambient temperature sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
-     * for more details. */
+     * for more details.
+     */
     public static final int TYPE_AMBIENT_TEMPERATURE = 13;
 
     /**
+     * A constant string describing an ambient temperature sensor type.
+     *
+     * @see #TYPE_AMBIENT_TEMPERATURE
+     */
+    public static final String STRING_TYPE_AMBIENT_TEMPERATURE =
+        "android.sensor.ambient_temperature";
+
+    /**
      * A constant describing an uncalibrated magnetic field sensor type.
      * <p>
      * Similar to {@link #TYPE_MAGNETIC_FIELD} but the hard iron calibration (device calibration
@@ -139,6 +244,13 @@
      * details.
      */
     public static final int TYPE_MAGNETIC_FIELD_UNCALIBRATED = 14;
+    /**
+     * A constant string describing an uncalibrated magnetic field sensor type.
+     *
+     * @see #TYPE_MAGNETIC_FIELD_UNCALIBRATED
+     */
+    public static final String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED =
+        "android.sensor.magnetic_field_uncalibrated";
 
     /**
      * A constant describing an uncalibrated rotation vector sensor type.
@@ -156,10 +268,17 @@
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values} for more
      * details.
      */
-
     public static final int TYPE_GAME_ROTATION_VECTOR = 15;
 
     /**
+     * A constant string describing an uncalibrated rotation vector sensor type.
+     *
+     * @see #TYPE_GAME_ROTATION_VECTOR
+     */
+    public static final String STRING_TYPE_GAME_ROTATION_VECTOR =
+        "android.sensor.game_rotation_vector";
+
+    /**
      * A constant describing an uncalibrated gyroscope sensor type.
      * <p>Similar to {@link #TYPE_GYROSCOPE} but no gyro-drift compensation has been performed
      * to adjust the given sensor values. However, such gyro-drift bias values
@@ -174,6 +293,14 @@
     public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16;
 
     /**
+     * A constant string describing an uncalibrated gyroscope sensor type.
+     *
+     * @see #TYPE_GYROSCOPE_UNCALIBRATED
+     */
+    public static final String STRING_TYPE_GYROSCOPE_UNCALIBRATED =
+        "android.sensor.gyroscope_uncalibrated";
+
+    /**
      * A constant describing a significant motion trigger sensor.
      * <p>
      * It triggers when an event occurs and then automatically disables
@@ -186,6 +313,14 @@
     public static final int TYPE_SIGNIFICANT_MOTION = 17;
 
     /**
+     * A constant string describing a significant motion trigger sensor.
+     *
+     * @see #TYPE_SIGNIFICANT_MOTION
+     */
+    public static final String STRING_TYPE_SIGNIFICANT_MOTION =
+        "android.sensor.significant_motion";
+
+    /**
      * A constant describing a step detector sensor.
      * <p>
      * A sensor of this type triggers an event each time a step is taken by the user. The only
@@ -198,6 +333,13 @@
     public static final int TYPE_STEP_DETECTOR = 18;
 
     /**
+     * A constant string describing a step detector sensor.
+     *
+     * @see #TYPE_STEP_DETECTOR
+     */
+    public static final String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector";
+
+    /**
      * A constant describing a step counter sensor.
      * <p>
      * A sensor of this type returns the number of steps taken by the user since the last reboot
@@ -211,7 +353,14 @@
     public static final int TYPE_STEP_COUNTER = 19;
 
     /**
-     * A constant describing the geo-magnetic rotation vector.
+     * A constant string describing a step counter sensor.
+     *
+     * @see #TYPE_STEP_COUNTER
+     */
+    public static final String STRING_TYPE_STEP_COUNTER = "android.sensor.step_counter";
+
+    /**
+     * A constant describing a geo-magnetic rotation vector.
      * <p>
      * Similar to {@link #TYPE_ROTATION_VECTOR}, but using a magnetometer instead of using a
      * gyroscope. This sensor uses lower power than the other rotation vectors, because it doesn't
@@ -222,6 +371,32 @@
     public static final int TYPE_GEOMAGNETIC_ROTATION_VECTOR = 20;
 
     /**
+     * A constant string describing a geo-magnetic rotation vector.
+     *
+     * @see #TYPE_GEOMAGNETIC_ROTATION_VECTOR
+     */
+    public static final String STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR =
+        "android.sensor.geomagnetic_rotation_vector";
+
+    /**
+     * A constant describing a heart rate monitor.
+     * <p>
+     * A sensor that measures the heart rate in beats per minute.
+     * <p>
+     * value[0] represents the beats per minute when the measurement was taken.
+     * value[0] is 0 if the heart rate monitor could not measure the rate or the
+     * rate is 0 beat per minute.
+     */
+    public static final int TYPE_HEART_RATE = 21;
+
+    /**
+     * A constant string describing a heart rate monitor.
+     *
+     * @see #TYPE_HEART_RATE
+     */
+    public static final String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
+
+    /**
      * A constant describing all sensor types.
      */
     public static final int TYPE_ALL = -1;
@@ -265,7 +440,8 @@
             // added post 4.3
             REPORTING_MODE_ON_CHANGE,  1, // SENSOR_TYPE_STEP_DETECTOR
             REPORTING_MODE_ON_CHANGE,  1, // SENSOR_TYPE_STEP_COUNTER
-            REPORTING_MODE_CONTINUOUS, 5  // SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR
+            REPORTING_MODE_CONTINUOUS, 5, // SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR
+            REPORTING_MODE_ON_CHANGE, 1  // SENSOR_TYPE_HEART_RATE_MONITOR
     };
 
     static int getReportingMode(Sensor sensor) {
@@ -321,6 +497,8 @@
     private int     mMinDelay;
     private int     mFifoReservedEventCount;
     private int     mFifoMaxEventCount;
+    private String  mStringType;
+    private String  mRequiredPermission;
 
     Sensor() {
     }
@@ -401,6 +579,20 @@
         return mFifoMaxEventCount;
     }
 
+    /**
+     * @return The type of this sensor as a string.
+     */
+    public String getStringType() {
+        return mStringType;
+    }
+
+    /**
+     * @return The permission required to access this sensor. If empty, no permission is required.
+     */
+    public String getRequiredPermission() {
+        return mRequiredPermission;
+    }
+
     /** @hide */
     public int getHandle() {
         return mHandle;
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index c947eda..995e396 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -372,7 +372,7 @@
             for (int i = 0; i < tries; i++) {
                 if (i > 0) {
                     try {
-                        Log.i("Zygote", "Zygote not up yet, sleeping...");
+                        Log.i(LOG_TAG, "Zygote not up yet, sleeping...");
                         Thread.sleep(ZYGOTE_RETRY_MILLIS);
                     } catch (InterruptedException ex) {
                         throw new ZygoteStartFailedEx(ex);
@@ -707,6 +707,16 @@
             return primaryZygoteState;
         }
 
+        // TODO: Get rid of this. This is a temporary workaround until all the
+        // compilation related pieces for the dual zygote stack are ready.
+        // b/3647418.
+        if (System.getenv("ANDROID_SOCKET_" + SECONDARY_ZYGOTE_SOCKET) == null) {
+            Log.e(LOG_TAG, "Forcing app to primary zygote, secondary unavailable (ABI= " + abi + ")");
+            // Should be :
+            // throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
+            return primaryZygoteState;
+        }
+
         // The primary zygote didn't match. Try the secondary.
         if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
             secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET,
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 728c560..8aef9bd 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -492,7 +492,20 @@
         return profiles;
     }
 
-    /** @hide */
+    /**
+     * If the target user is a managed profile of the calling user or the caller
+     * is itself a managed profile, then this returns a badged copy of the given
+     * icon to be able to distinguish it from the original icon.
+     * <P>
+     * If the original drawable is not a BitmapDrawable, then the original
+     * drawable is returned.
+     * </P>
+     *
+     * @param icon The icon to badge.
+     * @param user The target user.
+     * @return A drawable that combines the original icon and a badge as
+     *         determined by the system.
+     */
     public Drawable getBadgedDrawableForUser(Drawable icon, UserHandle user) {
         int badgeResId = getBadgeResIdForUser(user.getIdentifier());
         if (badgeResId == 0) {
diff --git a/core/java/android/provider/SearchIndexableData.java b/core/java/android/provider/SearchIndexableData.java
index 05285a3..60bcc40 100644
--- a/core/java/android/provider/SearchIndexableData.java
+++ b/core/java/android/provider/SearchIndexableData.java
@@ -115,6 +115,7 @@
      * Default constructor.
      */
     public SearchIndexableData() {
+        locale = Locale.getDefault();
         enabled = true;
     }
 
@@ -124,8 +125,47 @@
      * @param ctx the Context
      */
     public SearchIndexableData(Context ctx) {
+        this();
         context = ctx;
-        locale = Locale.getDefault();
-        enabled = true;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("SearchIndexableData[context: ");
+        sb.append(context);
+        sb.append(", ");
+        sb.append("locale: ");
+        sb.append(locale);
+        sb.append(", ");
+        sb.append("enabled: ");
+        sb.append(enabled);
+        sb.append(", ");
+        sb.append("rank: ");
+        sb.append(rank);
+        sb.append(", ");
+        sb.append("key: ");
+        sb.append(key);
+        sb.append(", ");
+        sb.append("className: ");
+        sb.append(className);
+        sb.append(", ");
+        sb.append("packageName: ");
+        sb.append(packageName);
+        sb.append(", ");
+        sb.append("iconResId: ");
+        sb.append(iconResId);
+        sb.append(", ");
+        sb.append("intentAction: ");
+        sb.append(intentAction);
+        sb.append(", ");
+        sb.append("intentTargetPackage: ");
+        sb.append(intentTargetPackage);
+        sb.append(", ");
+        sb.append("intentTargetClass: ");
+        sb.append(intentTargetClass);
+        sb.append("]");
+
+        return sb.toString();
     }
 }
diff --git a/core/java/android/provider/SearchIndexableResource.java b/core/java/android/provider/SearchIndexableResource.java
index ba3bd4f..c807df2 100644
--- a/core/java/android/provider/SearchIndexableResource.java
+++ b/core/java/android/provider/SearchIndexableResource.java
@@ -48,6 +48,7 @@
      * @param iconResId the resource ID associated with the data.
      */
     public SearchIndexableResource(int rank, int xmlResId, String className, int iconResId) {
+        super();
         this.rank = rank;
         this.xmlResId = xmlResId;
         this.className = className;
@@ -62,4 +63,17 @@
     public SearchIndexableResource(Context context) {
         super(context);
     }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("SearchIndexableResource[");
+        sb.append(super.toString());
+        sb.append(", ");
+        sb.append("xmlResId: ");
+        sb.append(xmlResId);
+        sb.append("]");
+
+        return sb.toString();
+    }
 }
\ No newline at end of file
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9761f1a..3c0e6ef 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2968,12 +2968,6 @@
     private boolean mLastIsOpaque;
 
     /**
-     * Convenience value to check for float values that are close enough to zero to be considered
-     * zero.
-     */
-    private static final float NONZERO_EPSILON = .001f;
-
-    /**
      * The distance in pixels from the left edge of this view's parent
      * to the left edge of this view.
      * {@hide}
@@ -8790,11 +8784,6 @@
                             && !pointInView(event.getX(), event.getY()))) {
                 mSendingHoverAccessibilityEvents = false;
                 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
-                // If the window does not have input focus we take away accessibility
-                // focus as soon as the user stop hovering over the view.
-                if (mAttachInfo != null && !mAttachInfo.mHasWindowFocus) {
-                    getViewRootImpl().setAccessibilityFocus(null, null);
-                }
             }
         }
 
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index 8eae629..4730e59 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -27,8 +27,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
 import android.media.AudioService;
 import android.media.AudioSystem;
@@ -58,10 +56,8 @@
  *
  * @hide
  */
-public class VolumePanel extends Handler implements OnSeekBarChangeListener, View.OnClickListener,
-        VolumeController
-{
-    private static final String TAG = "VolumePanel";
+public class VolumePanel extends Handler implements VolumeController {
+    private static final String TAG = VolumePanel.class.getSimpleName();
     private static boolean LOGD = false;
 
     /**
@@ -189,7 +185,7 @@
             this.iconMuteRes = iconMuteRes;
             this.show = show;
         }
-    };
+    }
 
     // List of stream types and their order
     private static final StreamResources[] STREAMS = {
@@ -256,14 +252,14 @@
     }
 
 
-    public VolumePanel(final Context context, AudioService volumeService) {
+    public VolumePanel(Context context, AudioService volumeService) {
         mContext = context;
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
         mAudioService = volumeService;
 
         // For now, only show master volume if master volume is supported
-       final boolean useMasterVolume = context.getResources().getBoolean(
-               R.bool.config_useMasterVolume);
+        final Resources res = context.getResources();
+        final boolean useMasterVolume = res.getBoolean(R.bool.config_useMasterVolume);
         if (useMasterVolume) {
             for (int i = 0; i < STREAMS.length; i++) {
                 StreamResources streamRes = STREAMS[i];
@@ -271,29 +267,7 @@
             }
         }
 
-        final TypedArray a = context.obtainStyledAttributes(null,
-                com.android.internal.R.styleable.AlertDialog,
-                com.android.internal.R.attr.alertDialogStyle, 0);
-        final Drawable background = a.getDrawable(R.styleable.AlertDialog_fullBright);
-        a.recycle();
-
-        final LayoutInflater inflater = (LayoutInflater) context.getSystemService(
-                Context.LAYOUT_INFLATER_SERVICE);
-        mView = inflater.inflate(R.layout.volume_adjust, null);
-        mView.setBackground(background);
-        mView.setOnTouchListener(new View.OnTouchListener() {
-            @Override
-            public boolean onTouch(View v, MotionEvent event) {
-                resetTimeout();
-                return false;
-            }
-        });
-        mPanel = (ViewGroup) mView.findViewById(R.id.visible_panel);
-        mSliderGroup = (ViewGroup) mView.findViewById(R.id.slider_group);
-        mMoreButton = mView.findViewById(R.id.expand_button);
-        mDivider = mView.findViewById(R.id.expand_button_divider);
-
-        mDialog = new Dialog(context, R.style.Theme_Panel_Volume) {
+        mDialog = new Dialog(context) {
             @Override
             public boolean onTouchEvent(MotionEvent event) {
                 if (isShowing() && event.getAction() == MotionEvent.ACTION_OUTSIDE &&
@@ -304,9 +278,25 @@
                 return false;
             }
         };
-        
-        mDialog.setTitle("Volume control"); // No need to localize
-        mDialog.setContentView(mView);
+
+        // Change some window properties
+        final Window window = mDialog.getWindow();
+        final LayoutParams lp = window.getAttributes();
+        lp.token = null;
+        // Offset from the top
+        lp.y = res.getDimensionPixelOffset(R.dimen.volume_panel_top);
+        lp.type = LayoutParams.TYPE_VOLUME_OVERLAY;
+        lp.windowAnimations = R.style.Animation_VolumePanel;
+        window.setAttributes(lp);
+        window.setGravity(Gravity.TOP);
+        window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+        window.requestFeature(Window.FEATURE_NO_TITLE);
+        window.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE
+                | LayoutParams.FLAG_NOT_TOUCH_MODAL
+                | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
+
+        mDialog.setCanceledOnTouchOutside(true);
+        mDialog.setContentView(R.layout.volume_adjust);
         mDialog.setOnDismissListener(new OnDismissListener() {
             @Override
             public void onDismiss(DialogInterface dialog) {
@@ -315,40 +305,38 @@
             }
         });
 
-        // Change some window properties
-        final Window window = mDialog.getWindow();
-        window.setGravity(Gravity.TOP);
+        mDialog.create();
 
-        final LayoutParams lp = window.getAttributes();
-        lp.token = null;
-        // Offset from the top
-        lp.y = mContext.getResources().getDimensionPixelOffset(R.dimen.volume_panel_top);
-        lp.type = LayoutParams.TYPE_VOLUME_OVERLAY;
-        lp.width = LayoutParams.WRAP_CONTENT;
-        lp.height = LayoutParams.WRAP_CONTENT;
-        window.setAttributes(lp);
-        window.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCH_MODAL
-                | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
+        mView = window.findViewById(R.id.content);
+        mView.setOnTouchListener(new View.OnTouchListener() {
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+                resetTimeout();
+                return false;
+            }
+        });
+
+        mPanel = (ViewGroup) mView.findViewById(R.id.visible_panel);
+        mSliderGroup = (ViewGroup) mView.findViewById(R.id.slider_group);
+        mMoreButton = mView.findViewById(R.id.expand_button);
+        mDivider = mView.findViewById(R.id.expand_button_divider);
 
         mToneGenerators = new ToneGenerator[AudioSystem.getNumStreamTypes()];
-        mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
-
+        mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
         mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable);
+
+        // If we don't want to show multiple volumes, hide the settings button
+        // and divider.
         mShowCombinedVolumes = !mVoiceCapable && !useMasterVolume;
-        
-        // If we don't want to show multiple volumes, hide the settings button and divider
         if (!mShowCombinedVolumes) {
             mMoreButton.setVisibility(View.GONE);
             mDivider.setVisibility(View.GONE);
         } else {
-            mMoreButton.setOnClickListener(this);
+            mMoreButton.setOnClickListener(mClickListener);
         }
 
-        final boolean masterVolumeOnly = context.getResources().getBoolean(
-                R.bool.config_useMasterVolume);
-        final boolean masterVolumeKeySounds = mContext.getResources().getBoolean(
-                R.bool.config_useVolumeKeySounds);
-
+        final boolean masterVolumeOnly = res.getBoolean(R.bool.config_useMasterVolume);
+        final boolean masterVolumeKeySounds = res.getBoolean(R.bool.config_useVolumeKeySounds);
         mPlayMasterStreamTones = masterVolumeOnly && masterVolumeKeySounds;
 
         listenToRingerMode();
@@ -444,7 +432,7 @@
             final int plusOne = (streamType == AudioSystem.STREAM_BLUETOOTH_SCO ||
                     streamType == AudioSystem.STREAM_VOICE_CALL) ? 1 : 0;
             sc.seekbarView.setMax(getStreamMaxVolume(streamType) + plusOne);
-            sc.seekbarView.setOnSeekBarChangeListener(this);
+            sc.seekbarView.setOnSeekBarChangeListener(mSeekListener);
             sc.seekbarView.setTag(sc);
             mStreamControls.put(streamType, sc);
         }
@@ -506,10 +494,6 @@
         }
     }
 
-    private boolean isExpanded() {
-        return mMoreButton.getVisibility() != View.VISIBLE;
-    }
-
     private void expand() {
         final int count = mSliderGroup.getChildCount();
         for (int i = 0; i < count; i++) {
@@ -547,6 +531,7 @@
         obtainMessage(MSG_VOLUME_CHANGED, streamType, flags).sendToTarget();
     }
 
+    @Override
     public void postRemoteVolumeChanged(int streamType, int flags) {
         if (hasMessages(MSG_REMOTE_VOLUME_CHANGED)) return;
         synchronized (this) {
@@ -558,6 +543,7 @@
         obtainMessage(MSG_REMOTE_VOLUME_CHANGED, streamType, flags).sendToTarget();
     }
 
+    @Override
     public void postRemoteSliderVisibility(boolean visible) {
         obtainMessage(MSG_SLIDER_VISIBILITY_CHANGED,
                 AudioService.STREAM_REMOTE_MUSIC, visible ? 1 : 0).sendToTarget();
@@ -574,6 +560,7 @@
      * as a request to update the volume), the application will likely set a new volume. If the UI
      * is still up, we need to refresh the display to show this new value.
      */
+    @Override
     public void postHasNewRemotePlaybackInfo() {
         if (hasMessages(MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN)) return;
         // don't create or prevent resources to be freed, if they disappear, this update came too
@@ -753,7 +740,7 @@
             int stream = (streamType == AudioService.STREAM_REMOTE_MUSIC) ? -1 : streamType;
             // when the stream is for remote playback, use -1 to reset the stream type evaluation
             mAudioManager.forceVolumeControlStream(stream);
-            mDialog.setContentView(mView);
+
             // Showing dialog - use collapsed state
             if (mShowCombinedVolumes) {
                 collapse();
@@ -885,6 +872,7 @@
                         .setMessage(com.android.internal.R.string.safe_media_volume_warning)
                         .setPositiveButton(com.android.internal.R.string.yes,
                                             new DialogInterface.OnClickListener() {
+                            @Override
                             public void onClick(DialogInterface dialog, int which) {
                                 mAudioService.disableSafeMediaVolume();
                             }
@@ -1041,39 +1029,48 @@
         sendMessage(obtainMessage(MSG_TIMEOUT));
     }
 
-    public void onProgressChanged(SeekBar seekBar, int progress,
-            boolean fromUser) {
-        final Object tag = seekBar.getTag();
-        if (fromUser && tag instanceof StreamControl) {
-            StreamControl sc = (StreamControl) tag;
-            if (getStreamVolume(sc.streamType) != progress) {
-                setStreamVolume(sc.streamType, progress, 0);
+    private final OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
+        @Override
+        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+            final Object tag = seekBar.getTag();
+            if (fromUser && tag instanceof StreamControl) {
+                StreamControl sc = (StreamControl) tag;
+                if (getStreamVolume(sc.streamType) != progress) {
+                    setStreamVolume(sc.streamType, progress, 0);
+                }
+            }
+            resetTimeout();
+        }
+
+        @Override
+        public void onStartTrackingTouch(SeekBar seekBar) {
+        }
+
+        @Override
+        public void onStopTrackingTouch(SeekBar seekBar) {
+            final Object tag = seekBar.getTag();
+            if (tag instanceof StreamControl) {
+                StreamControl sc = (StreamControl) tag;
+                // Because remote volume updates are asynchronous, AudioService
+                // might have received a new remote volume value since the
+                // finger adjusted the slider. So when the progress of the
+                // slider isn't being tracked anymore, adjust the slider to the
+                // last "published" remote volume value, so the UI reflects the
+                // actual volume.
+                if (sc.streamType == AudioService.STREAM_REMOTE_MUSIC) {
+                    seekBar.setProgress(getStreamVolume(AudioService.STREAM_REMOTE_MUSIC));
+                }
             }
         }
-        resetTimeout();
-    }
+    };
 
-    public void onStartTrackingTouch(SeekBar seekBar) {
-    }
-
-    public void onStopTrackingTouch(SeekBar seekBar) {
-        final Object tag = seekBar.getTag();
-        if (tag instanceof StreamControl) {
-            StreamControl sc = (StreamControl) tag;
-            // because remote volume updates are asynchronous, AudioService might have received
-            // a new remote volume value since the finger adjusted the slider. So when the
-            // progress of the slider isn't being tracked anymore, adjust the slider to the last
-            // "published" remote volume value, so the UI reflects the actual volume.
-            if (sc.streamType == AudioService.STREAM_REMOTE_MUSIC) {
-                seekBar.setProgress(getStreamVolume(AudioService.STREAM_REMOTE_MUSIC));
+    private final View.OnClickListener mClickListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            if (v == mMoreButton) {
+                expand();
             }
+            resetTimeout();
         }
-    }
-
-    public void onClick(View v) {
-        if (v == mMoreButton) {
-            expand();
-        }
-        resetTimeout();
-    }
+    };
 }
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 4dd8dcb..5b9372d 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -163,6 +163,19 @@
     }
 
     /**
+     * Gets the root {@link AccessibilityNodeInfo} in a given window.
+     *
+     * @param connectionId The id of a connection for interacting with the system.
+     * @param windowId The window id.
+     * @return The root {@link AccessibilityNodeInfo} if found, null otherwise.
+     */
+    public AccessibilityNodeInfo getRootInWindow(int connectionId, int windowId) {
+        return findAccessibilityNodeInfoByAccessibilityId(connectionId, windowId,
+                AccessibilityNodeInfo.ROOT_NODE_ID, false,
+                AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS);
+    }
+
+    /**
      * Gets the info for a window.
      *
      * @param connectionId The id of a connection for interacting with the system.
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index a6904f7..9d10930 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -77,6 +77,9 @@
     public static final int ACTIVE_WINDOW_ID = UNDEFINED_ITEM_ID;
 
     /** @hide */
+    public static final int ANY_WINDOW_ID = -2;
+
+    /** @hide */
     public static final int FLAG_PREFETCH_PREDECESSORS = 0x00000001;
 
     /** @hide */
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 24e0b0a..7a4728d 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -49,6 +49,8 @@
     jfieldID    minDelay;
     jfieldID    fifoReservedEventCount;
     jfieldID    fifoMaxEventCount;
+    jfieldID    stringType;
+    jfieldID    requiredPermission;
 } gSensorOffsets;
 
 
@@ -73,6 +75,9 @@
     sensorOffsets.fifoReservedEventCount =
             _env->GetFieldID(sensorClass, "mFifoReservedEventCount",  "I");
     sensorOffsets.fifoMaxEventCount = _env->GetFieldID(sensorClass, "mFifoMaxEventCount",  "I");
+    sensorOffsets.stringType = _env->GetFieldID(sensorClass, "mStringType", "Ljava/lang/String;");
+    sensorOffsets.requiredPermission = _env->GetFieldID(sensorClass, "mRequiredPermission",
+                                                        "Ljava/lang/String;");
 }
 
 static jint
@@ -89,6 +94,8 @@
     const SensorOffsets& sensorOffsets(gSensorOffsets);
     jstring name = env->NewStringUTF(list->getName().string());
     jstring vendor = env->NewStringUTF(list->getVendor().string());
+    jstring stringType = env->NewStringUTF(list->getStringType().string());
+    jstring requiredPermission = env->NewStringUTF(list->getRequiredPermission().string());
     env->SetObjectField(sensor, sensorOffsets.name,      name);
     env->SetObjectField(sensor, sensorOffsets.vendor,    vendor);
     env->SetIntField(sensor, sensorOffsets.version,      list->getVersion());
@@ -100,7 +107,11 @@
     env->SetIntField(sensor, sensorOffsets.minDelay,     list->getMinDelay());
     env->SetIntField(sensor, sensorOffsets.fifoReservedEventCount,
                      list->getFifoReservedEventCount());
-    env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount, list->getFifoMaxEventCount());
+    env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount,
+                     list->getFifoMaxEventCount());
+    env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
+    env->SetObjectField(sensor, sensorOffsets.requiredPermission,
+                        requiredPermission);
     next++;
     return size_t(next) < count ? next : 0;
 }
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 31a1de6..8dacfeb 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -376,7 +376,8 @@
 static jboolean android_view_RenderNode_hasIdentityMatrix(JNIEnv* env,
         jobject clazz, jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
-    return renderNode->stagingProperties().getMatrixFlags() == 0;
+    renderNode->mutateStagingProperties().updateMatrix();
+    return !renderNode->stagingProperties().hasTransformMatrix();
 }
 
 // ----------------------------------------------------------------------------
@@ -391,10 +392,7 @@
     renderNode->mutateStagingProperties().updateMatrix();
     const SkMatrix* transformMatrix = renderNode->stagingProperties().getTransformMatrix();
 
-    if (renderNode->stagingProperties().getMatrixFlags() == TRANSLATION) {
-        outMatrix->setTranslate(renderNode->stagingProperties().getTranslationX(),
-                renderNode->stagingProperties().getTranslationY());
-    } else if (transformMatrix) {
+    if (transformMatrix) {
         *outMatrix = *transformMatrix;
     } else {
         outMatrix->setIdentity();
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a83942f..b2709af 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -483,6 +483,13 @@
         android:label="@string/permlab_writeProfile"
         android:description="@string/permdesc_writeProfile" />
 
+    <!-- Allows an application to access data from sensors that the user uses to
+         measure what is happening inside his/her body, such as heart rate. -->
+    <permission android:name="android.permission.BODY_SENSORS"
+        android:permissionGroup="android.permission-group.PERSONAL_INFO"
+        android:label="@string/permlab_bodySensors"
+        android:description="@string/permdesc_bodySensors" />
+
     <!-- =============================================================== -->
     <!-- Permissions for accessing the device calendar                   -->
     <!-- =============================================================== -->
diff --git a/core/res/res/layout/volume_adjust.xml b/core/res/res/layout/volume_adjust.xml
index 1cf7ca9..3ad1f23 100644
--- a/core/res/res/layout/volume_adjust.xml
+++ b/core/res/res/layout/volume_adjust.xml
@@ -14,42 +14,38 @@
      limitations under the License.
 -->
 
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="448dp"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/visible_panel"
+    android:orientation="horizontal"
+    android:layout_width="300dp"
     android:layout_height="wrap_content">
+
     <LinearLayout
-        android:id="@+id/visible_panel"
-        android:layout_width="match_parent"
+        android:id="@+id/slider_group"
+        android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:orientation="horizontal">
-
-        <LinearLayout
-            android:id="@+id/slider_group"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:orientation="vertical">
-            <!-- Sliders go here -->
-        </LinearLayout>
-
-        <ImageView
-            android:id="@+id/expand_button_divider"
-            android:src="?attr/dividerVertical"
-            android:layout_width="wrap_content"
-            android:layout_height="32dip"
-            android:scaleType="fitXY"
-            android:layout_gravity="top"
-            android:layout_marginTop="16dip"
-            android:layout_marginBottom="16dip" />
-
-        <ImageView
-            android:id="@+id/expand_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="top"
-            android:padding="16dip"
-            android:background="?attr/selectableItemBackground"
-            android:src="@drawable/ic_sysbar_quicksettings" />
-
+        android:layout_weight="1"
+        android:orientation="vertical">
+        <!-- Sliders go here -->
     </LinearLayout>
-</FrameLayout>
\ No newline at end of file
+
+    <ImageView
+        android:id="@+id/expand_button_divider"
+        android:src="?attr/dividerVertical"
+        android:layout_width="wrap_content"
+        android:layout_height="32dip"
+        android:scaleType="fitXY"
+        android:layout_gravity="top"
+        android:layout_marginTop="16dip"
+        android:layout_marginBottom="16dip" />
+
+    <ImageView
+        android:id="@+id/expand_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="top"
+        android:padding="16dip"
+        android:background="?attr/selectableItemBackground"
+        android:src="@drawable/ic_sysbar_quicksettings" />
+
+</LinearLayout>
diff --git a/core/res/res/layout/volume_adjust_item.xml b/core/res/res/layout/volume_adjust_item.xml
index 746cf91..57cecf4 100644
--- a/core/res/res/layout/volume_adjust_item.xml
+++ b/core/res/res/layout/volume_adjust_item.xml
@@ -33,8 +33,9 @@
     <SeekBar
         style="?android:attr/seekBarStyle"
         android:id="@+id/seekbar"
-        android:layout_width="252dp"
+        android:layout_width="0dp"
         android:layout_height="wrap_content"
+        android:layout_weight="1"
         android:padding="16dip"
         android:layout_marginEnd="16dip" />
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6266393..fde5e3f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1343,6 +1343,14 @@
       as your name and contact information.  This means the app can identify you
       and may send your profile information to others.</string>
 
+    <!-- Title of the body sensors permission, listed so the user can decide whether to allow the application to access body sensor data. [CHAR LIMIT=30] -->
+    <string name="permlab_bodySensors">body sensors (like heart rate monitors)
+    </string>
+    <!-- Description of the body sensors permission, listed so the user can decide whether to allow the application to access data from body sensors. [CHAR LIMIT=NONE] -->
+    <string name="permdesc_bodySensors" product="default">Allows the app to
+      access data from sensors you use to measure what’s happening inside your
+      body, such as heart rate.</string>
+
     <!-- Title of the read social stream permission, listed so the user can decide whether to allow the application to read information from the user's social stream. [CHAR LIMIT=30] -->
     <string name="permlab_readSocialStream" product="default">read your social stream</string>
     <string name="permdesc_readSocialStream" product="default">Allows the app
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ac6c15d..7a11ce8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1254,7 +1254,6 @@
   <java-symbol type="style" name="TextAppearance.SlidingTabNormal" />
   <java-symbol type="style" name="Theme.DeviceDefault.Dialog.NoFrame" />
   <java-symbol type="style" name="Theme.IconMenu" />
-  <java-symbol type="style" name="Theme.Panel.Volume" />
 
   <java-symbol type="attr" name="mediaRouteButtonStyle" />
   <java-symbol type="attr" name="externalRouteEnabledDrawable" />
@@ -1836,5 +1835,6 @@
   <java-symbol type="attr" name="subtitleTextAppearance" />
   <java-symbol type="drawable" name="ic_lock_bugreport" />
   <java-symbol type="id" name="icon_frame" />
+  <java-symbol type="style" name="Animation.VolumePanel" />
 
 </resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 6f9e55b..7b3d5e3 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -892,11 +892,6 @@
         <item name="android:windowCloseOnTouchOutside">false</item>
     </style>
 
-    <style name="Theme.Panel.Volume">
-        <item name="android:windowAnimationStyle">@android:style/Animation.VolumePanel</item>
-        <item name="android:windowCloseOnTouchOutside">true</item>
-    </style>
-
     <!-- Default theme with an Action Bar. -->
     <style name="Theme.WithActionBar">
         <item name="android:windowActionBar">true</item>
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 140a07a..6c73d68 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -258,11 +258,11 @@
 
 status_t DisplayListRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
         const float* vertices, const int* colors, const SkPaint* paint) {
-    int count = (meshWidth + 1) * (meshHeight + 1) * 2;
+    int vertexCount = (meshWidth + 1) * (meshHeight + 1);
     bitmap = refBitmap(bitmap);
-    vertices = refBuffer<float>(vertices, count);
+    vertices = refBuffer<float>(vertices, vertexCount * 2); // 2 floats per vertex
     paint = refPaint(paint);
-    colors = refBuffer<int>(colors, count);
+    colors = refBuffer<int>(colors, vertexCount); // 1 color per vertex
 
     addDrawOp(new (alloc()) DrawBitmapMeshOp(bitmap, meshWidth, meshHeight,
                     vertices, colors, paint));
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 823ae7b..c55ebd6 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -50,17 +50,13 @@
 }
 
 RenderNode::RenderNode()
-        : mDestroyed(false)
-        , mNeedsPropertiesSync(false)
+        : mNeedsPropertiesSync(false)
         , mNeedsDisplayListDataSync(false)
         , mDisplayListData(0)
         , mStagingDisplayListData(0) {
 }
 
 RenderNode::~RenderNode() {
-    LOG_ALWAYS_FATAL_IF(mDestroyed, "Double destroyed DisplayList %p", this);
-
-    mDestroyed = true;
     delete mDisplayListData;
     delete mStagingDisplayListData;
 }
@@ -154,8 +150,8 @@
     } else if (properties().getAnimationMatrix()) {
         renderer.concatMatrix(properties().getAnimationMatrix());
     }
-    if (properties().getMatrixFlags() != 0) {
-        if (properties().getMatrixFlags() == TRANSLATION) {
+    if (properties().hasTransformMatrix()) {
+        if (properties().isTransformTranslateOnly()) {
             renderer.translate(properties().getTranslationX(), properties().getTranslationY());
         } else {
             renderer.concatMatrix(*properties().getTransformMatrix());
@@ -214,8 +210,8 @@
         mat4 anim(*properties().getAnimationMatrix());
         matrix.multiply(anim);
     }
-    if (properties().getMatrixFlags() != 0) {
-        if (properties().getMatrixFlags() == TRANSLATION) {
+    if (properties().hasTransformMatrix()) {
+        if (properties().isTransformTranslateOnly()) {
             matrix.translate(properties().getTranslationX(), properties().getTranslationY(),
                     true3dTransform ? properties().getTranslationZ() : 0.0f);
         } else {
@@ -525,10 +521,6 @@
 template <class T>
 void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
     const int level = handler.level();
-    if (CC_UNLIKELY(mDestroyed)) { // temporary debug logging
-        ALOGW("Error: %s is drawing after destruction", mName.string());
-        CRASH();
-    }
     if (mDisplayListData->isEmpty() || properties().getAlpha() <= 0) {
         DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, mName.string());
         return;
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 7853701..9e6ee3f 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -210,7 +210,6 @@
     void prepareSubTree(TreeInfo& info, DisplayListData* subtree);
 
     String8 mName;
-    bool mDestroyed; // used for debugging crash, TODO: remove once invalid state crash fixed
 
     bool mNeedsPropertiesSync;
     RenderProperties mProperties;
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index e7e7768..08829ef 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -27,6 +27,16 @@
 
 #include "Matrix.h"
 
+/**
+ * Convenience value to check for float values that are close enough to zero to be considered
+ * zero.
+ */
+#define NONZERO_EPSILON .001f
+
+static inline bool is_zero(float value) {
+    return (value >= -NONZERO_EPSILON) || (value <= NONZERO_EPSILON);
+}
+
 namespace android {
 namespace uirenderer {
 
@@ -42,22 +52,18 @@
         , mPivotX(0), mPivotY(0)
         , mLeft(0), mTop(0), mRight(0), mBottom(0)
         , mWidth(0), mHeight(0)
-        , mPrevWidth(-1), mPrevHeight(-1)
         , mPivotExplicitlySet(false)
-        , mMatrixDirty(false)
-        , mMatrixFlags(0)
+        , mMatrixOrPivotDirty(false)
         , mCaching(false) {
 }
 
 RenderProperties::ComputedFields::ComputedFields()
         : mTransformMatrix(NULL)
-        , mTransformMatrix3D(NULL)
         , mClipPath(NULL) {
 }
 
 RenderProperties::ComputedFields::~ComputedFields() {
     delete mTransformMatrix;
-    delete mTransformMatrix3D;
     delete mClipPath;
 }
 
@@ -82,7 +88,7 @@
         updateClipPath();
 
         // Force recalculation of the matrix, since other's dirty bit may be clear
-        mPrimitiveFields.mMatrixDirty = true;
+        mPrimitiveFields.mMatrixOrPivotDirty = true;
         updateMatrix();
     }
     return *this;
@@ -100,8 +106,8 @@
         ALOGD("%*sConcatMatrix (animation) %p: " SK_MATRIX_STRING,
                 level * 2, "", mAnimationMatrix, SK_MATRIX_ARGS(mAnimationMatrix));
     }
-    if (mPrimitiveFields.mMatrixFlags != 0) {
-        if (mPrimitiveFields.mMatrixFlags == TRANSLATION) {
+    if (hasTransformMatrix()) {
+        if (isTransformTranslateOnly()) {
             ALOGD("%*sTranslate %.2f, %.2f, %.2f",
                     level * 2, "", mPrimitiveFields.mTranslationX, mPrimitiveFields.mTranslationY, mPrimitiveFields.mTranslationZ);
         } else {
@@ -134,52 +140,36 @@
 }
 
 void RenderProperties::updateMatrix() {
-    if (mPrimitiveFields.mMatrixDirty) {
-        // NOTE: mComputedFields.mTransformMatrix won't be up to date if a DisplayList goes from a complex transform
-        // to a pure translate. This is safe because the mPrimitiveFields.matrix isn't read in pure translate cases.
-        if (mPrimitiveFields.mMatrixFlags && mPrimitiveFields.mMatrixFlags != TRANSLATION) {
-            if (!mComputedFields.mTransformMatrix) {
-                // only allocate a mPrimitiveFields.matrix if we have a complex transform
-                mComputedFields.mTransformMatrix = new SkMatrix();
-            }
-            if (!mPrimitiveFields.mPivotExplicitlySet) {
-                if (mPrimitiveFields.mWidth != mPrimitiveFields.mPrevWidth || mPrimitiveFields.mHeight != mPrimitiveFields.mPrevHeight) {
-                    mPrimitiveFields.mPrevWidth = mPrimitiveFields.mWidth;
-                    mPrimitiveFields.mPrevHeight = mPrimitiveFields.mHeight;
-                    mPrimitiveFields.mPivotX = mPrimitiveFields.mPrevWidth / 2.0f;
-                    mPrimitiveFields.mPivotY = mPrimitiveFields.mPrevHeight / 2.0f;
-                }
-            }
-
-            if ((mPrimitiveFields.mMatrixFlags & ROTATION_3D) == 0) {
-                mComputedFields.mTransformMatrix->setTranslate(
-                        mPrimitiveFields.mTranslationX, mPrimitiveFields.mTranslationY);
-                mComputedFields.mTransformMatrix->preRotate(mPrimitiveFields.mRotation,
-                        mPrimitiveFields.mPivotX, mPrimitiveFields.mPivotY);
-                mComputedFields.mTransformMatrix->preScale(
-                        mPrimitiveFields.mScaleX, mPrimitiveFields.mScaleY,
-                        mPrimitiveFields.mPivotX, mPrimitiveFields.mPivotY);
-            } else {
-                if (!mComputedFields.mTransformMatrix3D) {
-                    mComputedFields.mTransformMatrix3D = new SkMatrix();
-                }
-                mComputedFields.mTransformMatrix->reset();
-                mComputedFields.mTransformCamera.save();
-                mComputedFields.mTransformMatrix->preScale(
-                        mPrimitiveFields.mScaleX, mPrimitiveFields.mScaleY,
-                        mPrimitiveFields.mPivotX, mPrimitiveFields.mPivotY);
-                mComputedFields.mTransformCamera.rotateX(mPrimitiveFields.mRotationX);
-                mComputedFields.mTransformCamera.rotateY(mPrimitiveFields.mRotationY);
-                mComputedFields.mTransformCamera.rotateZ(-mPrimitiveFields.mRotation);
-                mComputedFields.mTransformCamera.getMatrix(mComputedFields.mTransformMatrix3D);
-                mComputedFields.mTransformMatrix3D->preTranslate(-mPrimitiveFields.mPivotX, -mPrimitiveFields.mPivotY);
-                mComputedFields.mTransformMatrix3D->postTranslate(mPrimitiveFields.mPivotX + mPrimitiveFields.mTranslationX,
-                        mPrimitiveFields.mPivotY + mPrimitiveFields.mTranslationY);
-                mComputedFields.mTransformMatrix->postConcat(*mComputedFields.mTransformMatrix3D);
-                mComputedFields.mTransformCamera.restore();
-            }
+    if (mPrimitiveFields.mMatrixOrPivotDirty) {
+        if (!mComputedFields.mTransformMatrix) {
+            // only allocate a mPrimitiveFields.matrix if we have a complex transform
+            mComputedFields.mTransformMatrix = new SkMatrix();
         }
-        mPrimitiveFields.mMatrixDirty = false;
+        if (!mPrimitiveFields.mPivotExplicitlySet) {
+            mPrimitiveFields.mPivotX = mPrimitiveFields.mWidth / 2.0f;
+            mPrimitiveFields.mPivotY = mPrimitiveFields.mHeight / 2.0f;
+        }
+        SkMatrix* transform = mComputedFields.mTransformMatrix;
+        transform->reset();
+        if (is_zero(getRotationX()) && is_zero(getRotationY())) {
+            transform->setTranslate(getTranslationX(), getTranslationY());
+            transform->preRotate(getRotation(), getPivotX(), getPivotY());
+            transform->preScale(getScaleX(), getScaleY(), getPivotX(), getPivotY());
+        } else {
+            SkMatrix transform3D;
+            mComputedFields.mTransformCamera.save();
+            transform->preScale(getScaleX(), getScaleY(), getPivotX(), getPivotY());
+            mComputedFields.mTransformCamera.rotateX(mPrimitiveFields.mRotationX);
+            mComputedFields.mTransformCamera.rotateY(mPrimitiveFields.mRotationY);
+            mComputedFields.mTransformCamera.rotateZ(-mPrimitiveFields.mRotation);
+            mComputedFields.mTransformCamera.getMatrix(&transform3D);
+            transform3D.preTranslate(-getPivotX(), -getPivotY());
+            transform3D.postTranslate(getPivotX() + getTranslationX(),
+                    getPivotY() + getTranslationY());
+            transform->postConcat(transform3D);
+            mComputedFields.mTransformCamera.restore();
+        }
+        mPrimitiveFields.mMatrixOrPivotDirty = false;
     }
 }
 
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index dd68210..4270da2 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -28,12 +28,6 @@
 #include "RevealClip.h"
 #include "Outline.h"
 
-#define TRANSLATION 0x0001
-#define ROTATION    0x0002
-#define ROTATION_3D 0x0004
-#define SCALE       0x0008
-#define PIVOT       0x0010
-
 class SkBitmap;
 class SkPaint;
 
@@ -114,7 +108,7 @@
     void setTranslationX(float translationX) {
         if (translationX != mPrimitiveFields.mTranslationX) {
             mPrimitiveFields.mTranslationX = translationX;
-            onTranslationUpdate();
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
         }
     }
 
@@ -125,7 +119,7 @@
     void setTranslationY(float translationY) {
         if (translationY != mPrimitiveFields.mTranslationY) {
             mPrimitiveFields.mTranslationY = translationY;
-            onTranslationUpdate();
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
         }
     }
 
@@ -136,7 +130,7 @@
     void setTranslationZ(float translationZ) {
         if (translationZ != mPrimitiveFields.mTranslationZ) {
             mPrimitiveFields.mTranslationZ = translationZ;
-            onTranslationUpdate();
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
         }
     }
 
@@ -147,12 +141,7 @@
     void setRotation(float rotation) {
         if (rotation != mPrimitiveFields.mRotation) {
             mPrimitiveFields.mRotation = rotation;
-            mPrimitiveFields.mMatrixDirty = true;
-            if (mPrimitiveFields.mRotation == 0.0f) {
-                mPrimitiveFields.mMatrixFlags &= ~ROTATION;
-            } else {
-                mPrimitiveFields.mMatrixFlags |= ROTATION;
-            }
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
         }
     }
 
@@ -163,12 +152,7 @@
     void setRotationX(float rotationX) {
         if (rotationX != mPrimitiveFields.mRotationX) {
             mPrimitiveFields.mRotationX = rotationX;
-            mPrimitiveFields.mMatrixDirty = true;
-            if (mPrimitiveFields.mRotationX == 0.0f && mPrimitiveFields.mRotationY == 0.0f) {
-                mPrimitiveFields.mMatrixFlags &= ~ROTATION_3D;
-            } else {
-                mPrimitiveFields.mMatrixFlags |= ROTATION_3D;
-            }
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
         }
     }
 
@@ -179,12 +163,7 @@
     void setRotationY(float rotationY) {
         if (rotationY != mPrimitiveFields.mRotationY) {
             mPrimitiveFields.mRotationY = rotationY;
-            mPrimitiveFields.mMatrixDirty = true;
-            if (mPrimitiveFields.mRotationX == 0.0f && mPrimitiveFields.mRotationY == 0.0f) {
-                mPrimitiveFields.mMatrixFlags &= ~ROTATION_3D;
-            } else {
-                mPrimitiveFields.mMatrixFlags |= ROTATION_3D;
-            }
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
         }
     }
 
@@ -195,12 +174,7 @@
     void setScaleX(float scaleX) {
         if (scaleX != mPrimitiveFields.mScaleX) {
             mPrimitiveFields.mScaleX = scaleX;
-            mPrimitiveFields.mMatrixDirty = true;
-            if (mPrimitiveFields.mScaleX == 1.0f && mPrimitiveFields.mScaleY == 1.0f) {
-                mPrimitiveFields.mMatrixFlags &= ~SCALE;
-            } else {
-                mPrimitiveFields.mMatrixFlags |= SCALE;
-            }
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
         }
     }
 
@@ -211,12 +185,7 @@
     void setScaleY(float scaleY) {
         if (scaleY != mPrimitiveFields.mScaleY) {
             mPrimitiveFields.mScaleY = scaleY;
-            mPrimitiveFields.mMatrixDirty = true;
-            if (mPrimitiveFields.mScaleX == 1.0f && mPrimitiveFields.mScaleY == 1.0f) {
-                mPrimitiveFields.mMatrixFlags &= ~SCALE;
-            } else {
-                mPrimitiveFields.mMatrixFlags |= SCALE;
-            }
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
         }
     }
 
@@ -226,12 +195,7 @@
 
     void setPivotX(float pivotX) {
         mPrimitiveFields.mPivotX = pivotX;
-        mPrimitiveFields.mMatrixDirty = true;
-        if (mPrimitiveFields.mPivotX == 0.0f && mPrimitiveFields.mPivotY == 0.0f) {
-            mPrimitiveFields.mMatrixFlags &= ~PIVOT;
-        } else {
-            mPrimitiveFields.mMatrixFlags |= PIVOT;
-        }
+        mPrimitiveFields.mMatrixOrPivotDirty = true;
         mPrimitiveFields.mPivotExplicitlySet = true;
     }
 
@@ -245,12 +209,7 @@
 
     void setPivotY(float pivotY) {
         mPrimitiveFields.mPivotY = pivotY;
-        mPrimitiveFields.mMatrixDirty = true;
-        if (mPrimitiveFields.mPivotX == 0.0f && mPrimitiveFields.mPivotY == 0.0f) {
-            mPrimitiveFields.mMatrixFlags &= ~PIVOT;
-        } else {
-            mPrimitiveFields.mMatrixFlags |= PIVOT;
-        }
+        mPrimitiveFields.mMatrixOrPivotDirty = true;
         mPrimitiveFields.mPivotExplicitlySet = true;
     }
 
@@ -264,7 +223,7 @@
 
     void setCameraDistance(float distance) {
         if (distance != getCameraDistance()) {
-            mPrimitiveFields.mMatrixDirty = true;
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
             mComputedFields.mTransformCamera.setCameraLocation(0, 0, distance);
         }
     }
@@ -278,8 +237,8 @@
         if (left != mPrimitiveFields.mLeft) {
             mPrimitiveFields.mLeft = left;
             mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
-            if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
-                mPrimitiveFields.mMatrixDirty = true;
+            if (!mPrimitiveFields.mPivotExplicitlySet) {
+                mPrimitiveFields.mMatrixOrPivotDirty = true;
             }
         }
     }
@@ -292,8 +251,8 @@
         if (top != mPrimitiveFields.mTop) {
             mPrimitiveFields.mTop = top;
             mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
-            if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
-                mPrimitiveFields.mMatrixDirty = true;
+            if (!mPrimitiveFields.mPivotExplicitlySet) {
+                mPrimitiveFields.mMatrixOrPivotDirty = true;
             }
         }
     }
@@ -306,8 +265,8 @@
         if (right != mPrimitiveFields.mRight) {
             mPrimitiveFields.mRight = right;
             mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
-            if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
-                mPrimitiveFields.mMatrixDirty = true;
+            if (!mPrimitiveFields.mPivotExplicitlySet) {
+                mPrimitiveFields.mMatrixOrPivotDirty = true;
             }
         }
     }
@@ -320,8 +279,8 @@
         if (bottom != mPrimitiveFields.mBottom) {
             mPrimitiveFields.mBottom = bottom;
             mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
-            if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
-                mPrimitiveFields.mMatrixDirty = true;
+            if (!mPrimitiveFields.mPivotExplicitlySet) {
+                mPrimitiveFields.mMatrixOrPivotDirty = true;
             }
         }
     }
@@ -336,8 +295,8 @@
             mPrimitiveFields.mTop = top;
             mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
             mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
-            if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
-                mPrimitiveFields.mMatrixDirty = true;
+            if (!mPrimitiveFields.mPivotExplicitlySet) {
+                mPrimitiveFields.mMatrixOrPivotDirty = true;
             }
         }
     }
@@ -350,8 +309,8 @@
             mPrimitiveFields.mBottom = bottom;
             mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
             mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
-            if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
-                mPrimitiveFields.mMatrixDirty = true;
+            if (!mPrimitiveFields.mPivotExplicitlySet) {
+                mPrimitiveFields.mMatrixOrPivotDirty = true;
             }
         }
     }
@@ -360,8 +319,8 @@
         if (offset != 0) {
             mPrimitiveFields.mLeft += offset;
             mPrimitiveFields.mRight += offset;
-            if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
-                mPrimitiveFields.mMatrixDirty = true;
+            if (!mPrimitiveFields.mPivotExplicitlySet) {
+                mPrimitiveFields.mMatrixOrPivotDirty = true;
             }
         }
     }
@@ -370,8 +329,8 @@
         if (offset != 0) {
             mPrimitiveFields.mTop += offset;
             mPrimitiveFields.mBottom += offset;
-            if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
-                mPrimitiveFields.mMatrixDirty = true;
+            if (!mPrimitiveFields.mPivotExplicitlySet) {
+                mPrimitiveFields.mMatrixOrPivotDirty = true;
             }
         }
     }
@@ -392,11 +351,17 @@
         return mAnimationMatrix;
     }
 
-    uint32_t getMatrixFlags() const {
-        return mPrimitiveFields.mMatrixFlags;
+    bool hasTransformMatrix() const {
+        return getTransformMatrix() && !getTransformMatrix()->isIdentity();
+    }
+
+    // May only call this if hasTransformMatrix() is true
+    bool isTransformTranslateOnly() const {
+        return getTransformMatrix()->getType() == SkMatrix::kTranslate_Mask;
     }
 
     const SkMatrix* getTransformMatrix() const {
+        LOG_ALWAYS_FATAL_IF(mPrimitiveFields.mMatrixOrPivotDirty, "Cannot get a dirty matrix!");
         return mComputedFields.mTransformMatrix;
     }
 
@@ -452,14 +417,6 @@
     }
 
 private:
-    void onTranslationUpdate() {
-        mPrimitiveFields.mMatrixDirty = true;
-        if (mPrimitiveFields.mTranslationX == 0.0f && mPrimitiveFields.mTranslationY == 0.0f && mPrimitiveFields.mTranslationZ == 0.0f) {
-            mPrimitiveFields.mMatrixFlags &= ~TRANSLATION;
-        } else {
-            mPrimitiveFields.mMatrixFlags |= TRANSLATION;
-        }
-    }
 
     // Rendering properties
     struct PrimitiveFields {
@@ -478,10 +435,8 @@
         float mPivotX, mPivotY;
         int mLeft, mTop, mRight, mBottom;
         int mWidth, mHeight;
-        int mPrevWidth, mPrevHeight;
         bool mPivotExplicitlySet;
-        bool mMatrixDirty;
-        uint32_t mMatrixFlags;
+        bool mMatrixOrPivotDirty;
         bool mCaching;
     } mPrimitiveFields;
 
@@ -506,7 +461,6 @@
         SkMatrix* mTransformMatrix;
 
         Sk3DView mTransformCamera;
-        SkMatrix* mTransformMatrix3D;
         SkPath* mClipPath; // TODO: remove this, create new ops for efficient/special case clipping
         SkRegion::Op mClipPathOp;
     } mComputedFields;
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 7f1c5c7..4513ead 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -43,6 +43,7 @@
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.database.ContentObserver;
+import android.hardware.usb.UsbManager;
 import android.media.MediaPlayer.OnCompletionListener;
 import android.media.MediaPlayer.OnErrorListener;
 import android.os.Binder;
@@ -528,6 +529,7 @@
         intentFilter.addAction(Intent.ACTION_SCREEN_ON);
         intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
         intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
+        intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
 
         intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
         // TODO merge orientation and rotation
@@ -3975,7 +3977,8 @@
                     (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) {
                 setBluetoothA2dpOnInt(true);
             }
-            boolean isUsb = ((device & AudioSystem.DEVICE_OUT_ALL_USB) != 0);
+            boolean isUsb = ((device & AudioSystem.DEVICE_OUT_ALL_USB) != 0) ||
+                            ((device & AudioSystem.DEVICE_IN_ALL_USB) != 0);
             handleDeviceConnection((state == 1), device, (isUsb ? name : ""));
             if (state != 0) {
                 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
@@ -4080,20 +4083,41 @@
                         }
                     }
                 }
-            } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ||
-                           action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) {
+            } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG)) {
                 state = intent.getIntExtra("state", 0);
+
                 int alsaCard = intent.getIntExtra("card", -1);
                 int alsaDevice = intent.getIntExtra("device", -1);
+
                 String params = (alsaCard == -1 && alsaDevice == -1 ? ""
                                     : "card=" + alsaCard + ";device=" + alsaDevice);
-                device = action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
-                        AudioSystem.DEVICE_OUT_USB_ACCESSORY : AudioSystem.DEVICE_OUT_USB_DEVICE;
-                Log.v(TAG, "Broadcast Receiver: Got "
-                        + (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
-                              "ACTION_USB_AUDIO_ACCESSORY_PLUG" : "ACTION_USB_AUDIO_DEVICE_PLUG")
-                        + ", state = " + state + ", card: " + alsaCard + ", device: " + alsaDevice);
+
+                // Playback Device
+                device = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
                 setWiredDeviceConnectionState(device, state, params);
+            } else if (action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) {
+                state = intent.getIntExtra("state", 0);
+
+                int alsaCard = intent.getIntExtra("card", -1);
+                int alsaDevice = intent.getIntExtra("device", -1);
+                boolean hasPlayback = intent.getBooleanExtra("hasPlayback", false);
+                boolean hasCapture = intent.getBooleanExtra("hasCapture", false);
+                boolean hasMIDI = intent.getBooleanExtra("hasMIDI", false);
+
+                String params = (alsaCard == -1 && alsaDevice == -1 ? ""
+                                    : "card=" + alsaCard + ";device=" + alsaDevice);
+
+                // Playback Device
+                if (hasPlayback) {
+                    device = AudioSystem.DEVICE_OUT_USB_DEVICE;
+                    setWiredDeviceConnectionState(device, state, params);
+                }
+
+                // Capture Device
+                if (hasCapture) {
+                    device = AudioSystem.DEVICE_IN_USB_DEVICE;
+                    setWiredDeviceConnectionState(device, state, params);
+                }
             } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
                 boolean broadcast = false;
                 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
@@ -4199,7 +4223,7 @@
                         mStreamStates[AudioSystem.STREAM_MUSIC], 0);
             }
         }
-    }
+    } // end class AudioServiceBroadcastReceiver
 
     //==========================================================================================
     // RemoteControlDisplay / RemoteControlClient / Remote info
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 9c67bae..327c10c 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -288,6 +288,8 @@
                                              DEVICE_IN_USB_DEVICE |
                                              DEVICE_IN_DEFAULT);
     public static final int DEVICE_IN_ALL_SCO = DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+    public static final int DEVICE_IN_ALL_USB = (DEVICE_IN_USB_ACCESSORY |
+                                                 DEVICE_IN_USB_DEVICE);
 
     // device states, must match AudioSystem::device_connection_state
     public static final int DEVICE_STATE_UNAVAILABLE = 0;
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index 76c6eda..fb4de9e 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -153,3 +153,23 @@
 {
     return static_cast<Sensor const*>(sensor)->getMinDelay();
 }
+
+int ASensor_getFifoMaxEventCount(ASensor const* sensor)
+{
+    return static_cast<Sensor const*>(sensor)->getFifoMaxEventCount();
+}
+
+int ASensor_getFifoReservedEventCount(ASensor const* sensor)
+{
+    return static_cast<Sensor const*>(sensor)->getFifoReservedEventCount();
+}
+
+const char* ASensor_getStringType(ASensor const* sensor)
+{
+    return static_cast<Sensor const*>(sensor)->getStringType().string();
+}
+
+const char* ASensor_getRequiredPermission(ASensor const* sensor)
+{
+    return static_cast<Sensor const*>(sensor)->getRequiredPermission().string();
+}
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index 4738049..d20b269 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -18,6 +18,8 @@
 */
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- App label in the manifest  -->
+    <string name="app_name">Keyguard</string>
     <!-- Instructions telling the user to enter their SIM PIN to unlock the keyguard.
          Displayed in one line in a large font.  -->
     <string name="keyguard_password_enter_pin_code">Type PIN code</string>
diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
index 46fbaff..b7df51d 100644
--- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
+++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
@@ -22,7 +22,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
-        android:paddingEnd="10dp"
+        android:layout_marginEnd="8dp"
         android:src="@drawable/ic_qs_brightness_auto_off"
         android:contentDescription="@null" />
 
@@ -31,7 +31,6 @@
         android:layout_width="0dp"
         android:layout_height="40dp"
         android:layout_gravity="center_vertical"
-        android:layout_marginEnd="2dp"
         android:layout_weight="1"
         systemui:text="@string/status_bar_settings_auto_brightness_label" />
 
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 76cadd7..0ece8e0 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -137,10 +137,9 @@
     <style name="BaseBrightnessDialogContainer">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">wrap_content</item>
-        <item name="android:layout_marginLeft">8dp</item>
-        <item name="android:layout_marginRight">8dp</item>
         <item name="android:padding">16dp</item>
     </style>
+
     <style name="BrightnessDialogContainer" parent="@style/BaseBrightnessDialogContainer" />
 
     <style name="Animation" />
diff --git a/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java b/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java
index b085211..95ab8e8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java
@@ -24,9 +24,6 @@
      * P3 (1.0, 1.0)
      *
      * Values sampled with x at regular intervals between 0 and 1.
-     *
-     * These values were generated using:
-     *   ./scripts/bezier_interpolator_values_gen.py 0.4 0.2
      */
     private static final float[] VALUES = new float[] {
         0.0f, 0.0002f, 0.0009f, 0.0019f, 0.0036f, 0.0059f, 0.0086f, 0.0119f, 0.0157f, 0.0209f,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 21460bb..8949663 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -83,6 +83,7 @@
                 res.getInteger(R.integer.recents_animate_task_bar_enter_duration);
     }
 
+    /** Updates the system insets */
     public void updateSystemInsets(Rect insets) {
         systemInsets.set(insets);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 21e2c1d..d2de185 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -134,9 +134,9 @@
         /* Notifies when a task has been removed from the stack */
         public void onStackTaskRemoved(TaskStack stack, Task t);
         /** Notifies when the stack was filtered */
-        public void onStackFiltered(TaskStack newStack, ArrayList<Task> curStack, Task t);
+        public void onStackFiltered(TaskStack newStack, ArrayList<Task> curTasks, Task t);
         /** Notifies when the stack was un-filtered */
-        public void onStackUnfiltered(TaskStack newStack, ArrayList<Task> curStack);
+        public void onStackUnfiltered(TaskStack newStack, ArrayList<Task> curTasks);
     }
 
     Context mContext;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 728aaad..88fb972 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -26,6 +26,7 @@
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.Region;
+import android.util.Pair;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
@@ -45,6 +46,7 @@
 import com.android.systemui.recents.model.TaskStack;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 
 
 /* The visual representation of a task stack view */
@@ -76,9 +78,6 @@
     OverScroller mScroller;
     ObjectAnimator mScrollAnimator;
 
-    // Filtering
-    AnimatorSet mFilterChildrenAnimator;
-
     // Optimizations
     int mHwLayersRefCount;
     int mStackViewsAnimationDuration;
@@ -645,163 +644,22 @@
         requestSynchronizeStackViewsWithModel(Utilities.calculateTranslationAnimationDuration(movement));
     }
 
-    @Override
-    public void onStackFiltered(TaskStack newStack, final ArrayList<Task> curStack,
-                                Task filteredTask) {
-        // NOTE: This code assumes that the current (unfiltered) stack is a superset of the new
-        // (filtered) stack
-        // XXX: Use HW Layers
 
-        // Stash the scroll and filtered task for us to restore to when we unfilter
-        mStashedScroll = getStackScroll();
-
-        // Compute the transforms of the items in the current stack
-        final ArrayList<TaskViewTransform> curTaskTransforms =
-                getStackTransforms(curStack, mStashedScroll, null, true);
-
-        // Scroll the item to the top of the stack (sans-peek) rect so that we can see it better
-        updateMinMaxScroll(false);
-        float overlapHeight = Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height();
-        setStackScrollRaw((int) (newStack.indexOfTask(filteredTask) * overlapHeight));
-        boundScrollRaw();
-
-        // Compute the transforms of the items in the new stack after setting the new scroll
-        final ArrayList<TaskViewTransform> taskTransforms =
-                getStackTransforms(mStack.getTasks(), getStackScroll(), null, true);
-
-        // Animate all of the existing views on screen either out of view (if they are not visible
-        // in the new stack) or to their final positions in the new stack
-        final ArrayList<TaskView> childrenToReturnToPool = new ArrayList<TaskView>();
-        final ArrayList<Task> tasks = mStack.getTasks();
-        ArrayList<Animator> childViewAnims = new ArrayList<Animator>();
-        int childCount = getChildCount();
-        int movement = 0;
-        for (int i = 0; i < childCount; i++) {
-            TaskView tv = (TaskView) getChildAt(i);
-            Task task = tv.getTask();
-            TaskViewTransform toTransform;
-            int taskIndex = tasks.indexOf(task);
-
-            boolean willBeInvisible = (taskIndex < 0) || !taskTransforms.get(taskIndex).visible;
-            if (willBeInvisible) {
-                // Compose a new transform that fades and slides the task out of view
-                TaskViewTransform fromTransform = curTaskTransforms.get(curStack.indexOf(task));
-                toTransform = new TaskViewTransform(fromTransform);
-                tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0);
-                tv.prepareTaskTransformForFilterTaskHidden(toTransform);
-
-                childrenToReturnToPool.add(tv);
-            } else {
-                toTransform = taskTransforms.get(taskIndex);
-
-                // Use the movement of the visible views to calculate the duration of the animation
-                movement = Math.max(movement,
-                        Math.abs(toTransform.translationY - (int) tv.getTranslationY()));
-            }
-            childViewAnims.add(tv.getAnimatorToTaskTransform(toTransform));
-        }
-
-        // Cancel the previous animation
-        if (mFilterChildrenAnimator != null) {
-            mFilterChildrenAnimator.cancel();
-            mFilterChildrenAnimator.removeAllListeners();
-        }
-
-        // Create a new animation for the existing children
-        final RecentsConfiguration config = RecentsConfiguration.getInstance();
-        mFilterChildrenAnimator = new AnimatorSet();
-        mFilterChildrenAnimator.setDuration(
-                Utilities.calculateTranslationAnimationDuration(movement,
-                        config.filteringCurrentViewsMinAnimDuration));
-        mFilterChildrenAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE);
-        mFilterChildrenAnimator.addListener(new AnimatorListenerAdapter() {
-            boolean isCancelled;
-
-            @Override
-            public void onAnimationCancel(Animator animation) {
-                isCancelled = true;
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                if (isCancelled) return;
-
-                // Return all the removed children to the view pool
-                for (TaskView tv : childrenToReturnToPool) {
-                    mViewPool.returnViewToPool(tv);
-                }
-
-                // For views that are not already visible, animate them in
-                ArrayList<Animator> newViewsAnims = new ArrayList<Animator>();
-                int taskCount = tasks.size();
-                int movement = 0;
-                int offset = 0;
-                for (int i = 0; i < taskCount; i++) {
-                    Task task = tasks.get(i);
-                    TaskViewTransform toTransform = taskTransforms.get(i);
-                    if (toTransform.visible) {
-                        TaskViewTransform fromTransform =
-                                curTaskTransforms.get(curStack.indexOf(task));
-                        TaskView tv = getChildViewForTask(task);
-                        if (tv == null) {
-                            tv = mViewPool.pickUpViewFromPool(task, task);
-                            // Compose a new transform that fades and slides the new task in
-                            fromTransform = new TaskViewTransform(toTransform);
-                            tv.prepareTaskTransformForFilterTaskHidden(fromTransform);
-                            tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0);
-
-                            Animator anim = tv.getAnimatorToTaskTransform(toTransform);
-                            anim.setStartDelay(offset *
-                                    Constants.Values.TaskStackView.FilterStartDelay);
-                            newViewsAnims.add(anim);
-
-                            // Use the movement of the newly visible views to calculate the duration
-                            // of the animation
-                            movement = Math.max(movement, Math.abs(toTransform.translationY -
-                                    fromTransform.translationY));
-                            offset++;
-                        }
-                    }
-
-                    // Animate the new views in
-                    mFilterChildrenAnimator = new AnimatorSet();
-                    mFilterChildrenAnimator.setDuration(
-                            Utilities.calculateTranslationAnimationDuration(movement,
-                                    config.filteringNewViewsMinAnimDuration));
-                    mFilterChildrenAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE);
-                    mFilterChildrenAnimator.playTogether(newViewsAnims);
-                    mFilterChildrenAnimator.start();
-                }
-                invalidate();
-            }
-        });
-        mFilterChildrenAnimator.playTogether(childViewAnims);
-        mFilterChildrenAnimator.start();
-    }
-
-    @Override
-    public void onStackUnfiltered(TaskStack newStack, final ArrayList<Task> curStack) {
-        // Compute the transforms of the items in the current stack
-        final int curScroll = getStackScroll();
-        final ArrayList<TaskViewTransform> curTaskTransforms =
-                getStackTransforms(curStack, curScroll, null, true);
-
-        // Restore the stashed scroll
-        updateMinMaxScroll(false);
-        setStackScrollRaw(mStashedScroll);
-        boundScrollRaw();
-
-        // Compute the transforms of the items in the new stack after restoring the stashed scroll
-        final ArrayList<TaskViewTransform> taskTransforms =
-                getStackTransforms(mStack.getTasks(), getStackScroll(), null, true);
-
+    /**
+     * Creates the animations for all the children views that need to be removed or to move views
+     * to their un/filtered position when we are un/filtering a stack, and returns the duration
+     * for these animations.
+     */
+    int getExitTransformsForFilterAnimation(ArrayList<Task> curTasks,
+                        ArrayList<TaskViewTransform> curTaskTransforms,
+                        ArrayList<Task> tasks, ArrayList<TaskViewTransform> taskTransforms,
+                        HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransformsOut,
+                        ArrayList<TaskView> childrenToRemoveOut,
+                        RecentsConfiguration config) {
         // Animate all of the existing views out of view (if they are not in the visible range in
         // the new stack) or to their final positions in the new stack
-        final ArrayList<TaskView> childrenToRemove = new ArrayList<TaskView>();
-        final ArrayList<Task> tasks = mStack.getTasks();
-        ArrayList<Animator> childViewAnims = new ArrayList<Animator>();
-        int childCount = getChildCount();
         int movement = 0;
+        int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             TaskView tv = (TaskView) getChildAt(i);
             Task task = tv.getTask();
@@ -811,104 +669,166 @@
             // If the view is no longer visible, then we should just animate it out
             boolean willBeInvisible = taskIndex < 0 || !taskTransforms.get(taskIndex).visible;
             if (willBeInvisible) {
-                toTransform = new TaskViewTransform(taskTransforms.get(taskIndex));
+                if (taskIndex < 0) {
+                    toTransform = curTaskTransforms.get(curTasks.indexOf(task));
+                } else {
+                    toTransform = new TaskViewTransform(taskTransforms.get(taskIndex));
+                }
                 tv.prepareTaskTransformForFilterTaskVisible(toTransform);
-                childrenToRemove.add(tv);
+                childrenToRemoveOut.add(tv);
             } else {
                 toTransform = taskTransforms.get(taskIndex);
                 // Use the movement of the visible views to calculate the duration of the animation
                 movement = Math.max(movement, Math.abs(toTransform.translationY -
                         (int) tv.getTranslationY()));
             }
-
-            Animator anim = tv.getAnimatorToTaskTransform(toTransform);
-            childViewAnims.add(anim);
+            childViewTransformsOut.put(tv, new Pair(0, toTransform));
         }
+        return Utilities.calculateTranslationAnimationDuration(movement,
+                config.filteringCurrentViewsMinAnimDuration);
+    }
 
-        // Cancel the previous animation
-        if (mFilterChildrenAnimator != null) {
-            mFilterChildrenAnimator.cancel();
-            mFilterChildrenAnimator.removeAllListeners();
+    /**
+     * Creates the animations for all the children views that need to be animated in when we are
+     * un/filtering a stack, and returns the duration for these animations.
+     */
+    int getEnterTransformsForFilterAnimation(ArrayList<Task> tasks,
+                         ArrayList<TaskViewTransform> taskTransforms,
+                         HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransformsOut,
+                         RecentsConfiguration config) {
+        int offset = 0;
+        int movement = 0;
+        int taskCount = tasks.size();
+        for (int i = taskCount - 1; i >= 0; i--) {
+            Task task = tasks.get(i);
+            TaskViewTransform toTransform = taskTransforms.get(i);
+            if (toTransform.visible) {
+                TaskView tv = getChildViewForTask(task);
+                if (tv == null) {
+                    // For views that are not already visible, animate them in
+                    tv = mViewPool.pickUpViewFromPool(task, task);
+
+                    // Compose a new transform to fade and slide the new task in
+                    TaskViewTransform fromTransform = new TaskViewTransform(toTransform);
+                    tv.prepareTaskTransformForFilterTaskHidden(fromTransform);
+                    tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0);
+
+                    int startDelay = offset *
+                            Constants.Values.TaskStackView.FilterStartDelay;
+                    childViewTransformsOut.put(tv, new Pair(startDelay, toTransform));
+
+                    // Use the movement of the new views to calculate the duration of the animation
+                    movement = Math.max(movement,
+                            Math.abs(toTransform.translationY - fromTransform.translationY));
+                    offset++;
+                }
+            }
         }
+        return Utilities.calculateTranslationAnimationDuration(movement,
+                config.filteringNewViewsMinAnimDuration);
+    }
 
-        // Create a new animation for the existing children
+    /** Orchestrates the animations of the current child views and any new views. */
+    void doFilteringAnimation(ArrayList<Task> curTasks,
+                              ArrayList<TaskViewTransform> curTaskTransforms,
+                              final ArrayList<Task> tasks,
+                              final ArrayList<TaskViewTransform> taskTransforms) {
         final RecentsConfiguration config = RecentsConfiguration.getInstance();
-        mFilterChildrenAnimator = new AnimatorSet();
-        mFilterChildrenAnimator.setDuration(
-                Utilities.calculateTranslationAnimationDuration(movement,
-                        config.filteringCurrentViewsMinAnimDuration));
-        mFilterChildrenAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE);
-        mFilterChildrenAnimator.addListener(new AnimatorListenerAdapter() {
-            boolean isCancelled;
 
-            @Override
-            public void onAnimationCancel(Animator animation) {
-                isCancelled = true;
-            }
+        // Calculate the transforms to animate out all the existing views if they are not in the
+        // new visible range (or to their final positions in the stack if they are)
+        final ArrayList<TaskView> childrenToRemove = new ArrayList<TaskView>();
+        final HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransforms =
+                new HashMap<TaskView, Pair<Integer, TaskViewTransform>>();
+        int duration = getExitTransformsForFilterAnimation(curTasks, curTaskTransforms, tasks,
+                taskTransforms, childViewTransforms, childrenToRemove, config);
 
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                if (isCancelled) return;
+        // If all the current views are in the visible range of the new stack, then don't wait for
+        // views to animate out and animate all the new views into their place
+        final boolean unifyNewViewAnimation = childrenToRemove.isEmpty();
+        if (unifyNewViewAnimation) {
+            int inDuration = getEnterTransformsForFilterAnimation(tasks, taskTransforms,
+                    childViewTransforms, config);
+            duration = Math.max(duration, inDuration);
+        }
 
-                // Return all the removed children to the view pool
-                for (TaskView tv : childrenToRemove) {
-                    mViewPool.returnViewToPool(tv);
-                }
+        // Animate all the views to their final transforms
+        for (final TaskView tv : childViewTransforms.keySet()) {
+            Pair<Integer, TaskViewTransform> t = childViewTransforms.get(tv);
+            tv.animate().cancel();
+            tv.animate()
+                    .setStartDelay(t.first)
+                    .withEndAction(new Runnable() {
+                        @Override
+                        public void run() {
+                            childViewTransforms.remove(tv);
+                            if (childViewTransforms.isEmpty()) {
+                                // Return all the removed children to the view pool
+                                for (TaskView tv : childrenToRemove) {
+                                    mViewPool.returnViewToPool(tv);
+                                }
 
-                // Increment the hw layers ref count
-                addHwLayersRefCount("unfilteredNewViews");
-
-                // For views that are not already visible, animate them in
-                ArrayList<Animator> newViewAnims = new ArrayList<Animator>();
-                int taskCount = tasks.size();
-                int movement = 0;
-                int offset = 0;
-                for (int i = 0; i < taskCount; i++) {
-                    Task task = tasks.get(i);
-                    TaskViewTransform toTransform = taskTransforms.get(i);
-                    if (toTransform.visible) {
-                        TaskView tv = getChildViewForTask(task);
-                        if (tv == null) {
-                            // For views that are not already visible, animate them in
-                            tv = mViewPool.pickUpViewFromPool(task, task);
-
-                            // Compose a new transform to fade and slide the new task in
-                            TaskViewTransform fromTransform = new TaskViewTransform(toTransform);
-                            tv.prepareTaskTransformForFilterTaskHidden(fromTransform);
-                            tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0);
-
-                            Animator anim = tv.getAnimatorToTaskTransform(toTransform);
-                            anim.setStartDelay(offset *
-                                    Constants.Values.TaskStackView.FilterStartDelay);
-                            newViewAnims.add(anim);
-                            // Use the movement of the newly visible views to calculate the duration
-                            // of the animation
-                            movement = Math.max(movement,
-                                    Math.abs(toTransform.translationY - fromTransform.translationY));
-                            offset++;
+                                if (!unifyNewViewAnimation) {
+                                    // For views that are not already visible, animate them in
+                                    childViewTransforms.clear();
+                                    int duration = getEnterTransformsForFilterAnimation(tasks,
+                                            taskTransforms, childViewTransforms, config);
+                                    for (final TaskView tv : childViewTransforms.keySet()) {
+                                        Pair<Integer, TaskViewTransform> t = childViewTransforms.get(tv);
+                                        tv.animate().setStartDelay(t.first);
+                                        tv.updateViewPropertiesToTaskTransform(null, t.second, duration);
+                                    }
+                                }
+                            }
                         }
-                    }
-                }
+                    });
+            tv.updateViewPropertiesToTaskTransform(null, t.second, duration);
+        }
+    }
 
-                // Run the animation
-                mFilterChildrenAnimator = new AnimatorSet();
-                mFilterChildrenAnimator.setDuration(
-                        Utilities.calculateTranslationAnimationDuration(movement,
-                                config.filteringNewViewsMinAnimDuration));
-                mFilterChildrenAnimator.playTogether(newViewAnims);
-                mFilterChildrenAnimator.addListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        // Decrement the hw layers ref count
-                        decHwLayersRefCount("unfilteredNewViews");
-                    }
-                });
-                mFilterChildrenAnimator.start();
-                invalidate();
-            }
-        });
-        mFilterChildrenAnimator.playTogether(childViewAnims);
-        mFilterChildrenAnimator.start();
+    @Override
+    public void onStackFiltered(TaskStack newStack, final ArrayList<Task> curTasks,
+                                Task filteredTask) {
+        // Stash the scroll and filtered task for us to restore to when we unfilter
+        mStashedScroll = getStackScroll();
+
+        // Calculate the current task transforms
+        ArrayList<TaskViewTransform> curTaskTransforms =
+                getStackTransforms(curTasks, getStackScroll(), null, true);
+
+        // Scroll the item to the top of the stack (sans-peek) rect so that we can see it better
+        updateMinMaxScroll(false);
+        float overlapHeight = Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height();
+        setStackScrollRaw((int) (newStack.indexOfTask(filteredTask) * overlapHeight));
+        boundScrollRaw();
+
+        // Compute the transforms of the items in the new stack after setting the new scroll
+        final ArrayList<Task> tasks = mStack.getTasks();
+        final ArrayList<TaskViewTransform> taskTransforms =
+                getStackTransforms(mStack.getTasks(), getStackScroll(), null, true);
+
+        // Animate
+        doFilteringAnimation(curTasks, curTaskTransforms, tasks, taskTransforms);
+    }
+
+    @Override
+    public void onStackUnfiltered(TaskStack newStack, final ArrayList<Task> curTasks) {
+        // Calculate the current task transforms
+        final ArrayList<TaskViewTransform> curTaskTransforms =
+                getStackTransforms(curTasks, getStackScroll(), null, true);
+
+        // Restore the stashed scroll
+        updateMinMaxScroll(false);
+        setStackScrollRaw(mStashedScroll);
+        boundScrollRaw();
+
+        // Compute the transforms of the items in the new stack after restoring the stashed scroll
+        final ArrayList<Task> tasks = mStack.getTasks();
+        final ArrayList<TaskViewTransform> taskTransforms =
+                getStackTransforms(tasks, getStackScroll(), null, true);
+
+        // Animate
+        doFilteringAnimation(curTasks, curTaskTransforms, tasks, taskTransforms);
 
         // Clear the saved vars
         mStashedScroll = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index a3056ec..b4100127 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -16,21 +16,13 @@
 
 package com.android.systemui.recents.views;
 
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
 import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Outline;
-import android.graphics.Path;
 import android.graphics.Rect;
-import android.graphics.RectF;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.FrameLayout;
 import com.android.systemui.R;
 import com.android.systemui.recents.BakedBezierInterpolator;
-import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.Utilities;
 import com.android.systemui.recents.model.Task;
@@ -115,18 +107,6 @@
         }
     }
 
-    /** Returns an animator to animate this task to the specified transform */
-    Animator getAnimatorToTaskTransform(TaskViewTransform toTransform) {
-        AnimatorSet anims = new AnimatorSet();
-        anims.playTogether(
-                ObjectAnimator.ofFloat(this, "translationY", toTransform.translationY),
-                ObjectAnimator.ofFloat(this, "scaleX", toTransform.scale),
-                ObjectAnimator.ofFloat(this, "scaleY", toTransform.scale),
-                ObjectAnimator.ofFloat(this, "alpha", toTransform.alpha)
-        );
-        return anims;
-    }
-
     /** Resets this view's properties */
     void resetViewProperties() {
         setTranslationX(0f);
@@ -136,12 +116,20 @@
         setAlpha(1f);
     }
 
+    /**
+     * When we are un/filtering, this method will set up the transform that we are animating to,
+     * in order to hide the task.
+     */
     void prepareTaskTransformForFilterTaskHidden(TaskViewTransform toTransform) {
         // Fade the view out and slide it away
         toTransform.alpha = 0f;
         toTransform.translationY += 200;
     }
 
+    /**
+     * When we are un/filtering, this method will setup the transform that we are animating from,
+     * in order to show the task.
+     */
     void prepareTaskTransformForFilterTaskVisible(TaskViewTransform fromTransform) {
         // Fade the view in
         fromTransform.alpha = 0f;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 53ac063..038686b 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -166,8 +166,6 @@
 
     private final Point mTempPoint = new Point();
 
-    private final Display mDefaultDisplay;
-
     private final PackageManager mPackageManager;
 
     private final WindowManagerInternal mWindowManagerService;
@@ -176,7 +174,7 @@
 
     private final MainHandler mMainHandler;
 
-    private Service mQueryBridge;
+    private InteractionBridge mInteractionBridge;
 
     private AlertDialog mEnableTouchExplorationDialog;
 
@@ -232,10 +230,6 @@
         mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
         mSecurityPolicy = new SecurityPolicy();
         mMainHandler = new MainHandler(mContext.getMainLooper());
-        //TODO: (multi-display) We need to support multiple displays.
-        DisplayManager displayManager = (DisplayManager)
-                mContext.getSystemService(Context.DISPLAY_SERVICE);
-        mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
         registerBroadcastReceivers();
         new AccessibilityContentObserver(mMainHandler).register(
                 context.getContentResolver());
@@ -401,7 +395,8 @@
                 return true; // yes, recycle the event
             }
             if (mSecurityPolicy.canDispatchAccessibilityEventLocked(event)) {
-                mSecurityPolicy.updateActiveWindowLocked(event.getWindowId(), event.getEventType());
+                mSecurityPolicy.updateActiveAndAccessibilityFocusedWindowLocked(event.getWindowId(),
+                        event.getSourceNodeId(), event.getEventType());
                 mSecurityPolicy.updateEventSourceLocked(event);
                 notifyAccessibilityServicesDelayedLocked(event, false);
                 notifyAccessibilityServicesDelayedLocked(event, true);
@@ -725,46 +720,8 @@
      * @return Whether accessibility focus was found and the bounds are populated.
      */
     // TODO: (multi-display) Make sure this works for multiple displays.
-    boolean getAccessibilityFocusBoundsInActiveWindow(Rect outBounds) {
-        // Instead of keeping track of accessibility focus events per
-        // window to be able to find the focus in the active window,
-        // we take a stateless approach and look it up. This is fine
-        // since we do this only when the user clicks/long presses.
-        Service service = getQueryBridge();
-        final int connectionId = service.mId;
-        AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
-        client.addConnection(connectionId, service);
-        try {
-            AccessibilityNodeInfo root = AccessibilityInteractionClient.getInstance()
-                    .getRootInActiveWindow(connectionId);
-            if (root == null) {
-                return false;
-            }
-            AccessibilityNodeInfo focus = root.findFocus(
-                    AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
-            if (focus == null) {
-                return false;
-            }
-            focus.getBoundsInScreen(outBounds);
-
-            MagnificationSpec spec = service.getCompatibleMagnificationSpec(focus.getWindowId());
-            if (spec != null && !spec.isNop()) {
-                outBounds.offset((int) -spec.offsetX, (int) -spec.offsetY);
-                outBounds.scale(1 / spec.scale);
-            }
-
-            // Clip to the window rectangle.
-            Rect windowBounds = mTempRect;
-            getActiveWindowBounds(windowBounds);
-            outBounds.intersect(windowBounds);
-            // Clip to the screen rectangle.
-            mDefaultDisplay.getRealSize(mTempPoint);
-            outBounds.intersect(0,  0,  mTempPoint.x, mTempPoint.y);
-
-            return true;
-        } finally {
-            client.removeConnection(connectionId);
-        }
+    boolean getAccessibilityFocusBounds(Rect outBounds) {
+        return getInteractionBridgeLocked().getAccessibilityFocusBoundsNotLocked(outBounds);
     }
 
     /**
@@ -855,14 +812,11 @@
         }
     }
 
-    private Service getQueryBridge() {
-        if (mQueryBridge == null) {
-            AccessibilityServiceInfo info = new AccessibilityServiceInfo();
-            info.setCapabilities(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT);
-            mQueryBridge = new Service(UserHandle.USER_NULL,
-                    sFakeAccessibilityServiceComponentName, info);
+    private InteractionBridge getInteractionBridgeLocked() {
+        if (mInteractionBridge == null) {
+            mInteractionBridge = new InteractionBridge();
         }
-        return mQueryBridge;
+        return mInteractionBridge;
     }
 
     private boolean notifyGestureLocked(int gestureId, boolean isDefault) {
@@ -1333,9 +1287,10 @@
     private void onUserStateChangedLocked(UserState userState) {
         // TODO: Remove this hack
         mInitialized = true;
-        updateLegacyCapabilities(userState);
+        updateLegacyCapabilitiesLocked(userState);
         updateServicesLocked(userState);
-        updateWindowsForAccessibilityCallback(userState);
+        updateWindowsForAccessibilityCallbackLocked(userState);
+        updateAccessibilityFocusBehaviorLocked(userState);
         updateFilterKeyEventsLocked(userState);
         updateTouchExplorationLocked(userState);
         updateEnhancedWebAccessibilityLocked(userState);
@@ -1344,7 +1299,29 @@
         scheduleUpdateClientsIfNeededLocked(userState);
     }
 
-    private void updateWindowsForAccessibilityCallback(UserState userState) {
+    private void updateAccessibilityFocusBehaviorLocked(UserState userState) {
+        // If there is no service that can operate with interactive windows
+        // then we keep the old behavior where a window loses accessibility
+        // focus if it is no longer active. This still changes the behavior
+        // for services that do not operate with interactive windows and run
+        // at the same time as the one(s) which does. In practice however,
+        // there is only one service that uses accessibility focus and it
+        // is typically the one that operates with interactive windows, So,
+        // this is fine. Note that to allow a service to work across windows
+        // we have to allow accessibility focus stay in any of them. Sigh...
+        List<Service> boundServices = userState.mBoundServices;
+        final int boundServiceCount = boundServices.size();
+        for (int i = 0; i < boundServiceCount; i++) {
+            Service boundService = boundServices.get(i);
+            if (boundService.canRetrieveInteractiveWindowsLocked()) {
+                userState.mAccessibilityFocusOnlyInActiveWindow = false;
+                return;
+            }
+        }
+        userState.mAccessibilityFocusOnlyInActiveWindow = true;
+    }
+
+    private void updateWindowsForAccessibilityCallbackLocked(UserState userState) {
         if (userState.mIsAccessibilityEnabled) {
             // We observe windows for accessibility only if there is at least
             // one bound service that can retrieve window content that specified
@@ -1357,8 +1334,7 @@
             final int boundServiceCount = boundServices.size();
             for (int i = 0; i < boundServiceCount; i++) {
                 Service boundService = boundServices.get(i);
-                if (mSecurityPolicy.canRetrieveWindowContentLocked(boundService)
-                        && boundService.mRetrieveInteractiveWindows) {
+                if (boundService.canRetrieveInteractiveWindowsLocked()) {
                     boundServiceCanRetrieveInteractiveWindows = true;
                     break;
                 }
@@ -1381,7 +1357,7 @@
         }
     }
 
-    private void updateLegacyCapabilities(UserState userState) {
+    private void updateLegacyCapabilitiesLocked(UserState userState) {
         // Up to JB-MR1 we had a white list with services that can enable touch
         // exploration. When a service is first started we show a dialog to the
         // use to get a permission to white list the service.
@@ -1582,6 +1558,18 @@
         DisplayAdjustmentUtils.applyAdjustments(mContext, userState.mUserId);
     }
 
+    private MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId) {
+        IBinder windowToken = mGlobalWindowTokens.get(windowId);
+        if (windowToken == null) {
+            windowToken = getCurrentUserStateLocked().mWindowTokens.get(windowId);
+        }
+        if (windowToken != null) {
+            return mWindowManagerService.getCompatibleMagnificationSpecForWindow(
+                    windowToken);
+        }
+        return null;
+    }
+
     @Override
     public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
         mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP);
@@ -1658,6 +1646,7 @@
         public static final int MSG_UPDATE_INPUT_FILTER = 6;
         public static final int MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG = 7;
         public static final int MSG_SEND_KEY_EVENT_TO_INPUT_FILTER = 8;
+        public static final int MSG_CLEAR_ACCESSIBILITY_FOCUS = 9;
 
         public MainHandler(Looper looper) {
             super(looper);
@@ -1713,6 +1702,15 @@
                     Service service = (Service) msg.obj;
                     showEnableTouchExplorationDialog(service);
                 } break;
+
+                case MSG_CLEAR_ACCESSIBILITY_FOCUS: {
+                    final int windowId = msg.arg1;
+                    InteractionBridge bridge;
+                    synchronized (mLock) {
+                        bridge = getInteractionBridgeLocked();
+                    }
+                    bridge.clearAccessibilityFocusNotLocked(windowId);
+                } break;
             }
         }
 
@@ -1981,6 +1979,11 @@
             }
         }
 
+        public boolean canRetrieveInteractiveWindowsLocked() {
+            return mSecurityPolicy.canRetrieveWindowContentLocked(this)
+                    && mRetrieveInteractiveWindows;
+        }
+
         @Override
         public void setServiceInfo(AccessibilityServiceInfo info) {
             final long identity = Binder.clearCallingIdentity();
@@ -2109,7 +2112,7 @@
             }
             final int interrogatingPid = Binder.getCallingPid();
             final long identityToken = Binder.clearCallingIdentity();
-            MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
+            MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
             try {
                 connection.findAccessibilityNodeInfosByViewId(accessibilityNodeId,
                         viewIdResName, interactionId, callback, mFetchFlags, interrogatingPid,
@@ -2153,7 +2156,7 @@
             }
             final int interrogatingPid = Binder.getCallingPid();
             final long identityToken = Binder.clearCallingIdentity();
-            MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
+            MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
             try {
                 connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text,
                         interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid,
@@ -2197,7 +2200,7 @@
             }
             final int interrogatingPid = Binder.getCallingPid();
             final long identityToken = Binder.clearCallingIdentity();
-            MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
+            MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
             try {
                 connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId,
                         interactionId, callback, mFetchFlags | flags, interrogatingPid,
@@ -2227,7 +2230,8 @@
                 if (resolvedUserId != mCurrentUserId) {
                     return false;
                 }
-                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
+                resolvedWindowId = resolveAccessibilityWindowIdForFindFocusLocked(
+                        accessibilityWindowId, focusType);
                 final boolean permissionGranted =
                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
                 if (!permissionGranted) {
@@ -2241,14 +2245,14 @@
             }
             final int interrogatingPid = Binder.getCallingPid();
             final long identityToken = Binder.clearCallingIdentity();
-            MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
+            MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
             try {
                 connection.findFocus(accessibilityNodeId, focusType, interactionId, callback,
                         mFetchFlags, interrogatingPid, interrogatingTid, spec);
                 return true;
             } catch (RemoteException re) {
                 if (DEBUG) {
-                    Slog.e(LOG_TAG, "Error calling findAccessibilityFocus()");
+                    Slog.e(LOG_TAG, "Error calling findFocus()");
                 }
             } finally {
                 Binder.restoreCallingIdentity(identityToken);
@@ -2284,7 +2288,7 @@
             }
             final int interrogatingPid = Binder.getCallingPid();
             final long identityToken = Binder.clearCallingIdentity();
-            MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
+            MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
             try {
                 connection.focusSearch(accessibilityNodeId, direction, interactionId, callback,
                         mFetchFlags, interrogatingPid, interrogatingTid, spec);
@@ -2729,16 +2733,18 @@
             return accessibilityWindowId;
         }
 
-        private MagnificationSpec getCompatibleMagnificationSpec(int windowId) {
-            IBinder windowToken = mGlobalWindowTokens.get(windowId);
-            if (windowToken == null) {
-                windowToken = getCurrentUserStateLocked().mWindowTokens.get(windowId);
+        private int resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType) {
+            if (windowId == AccessibilityNodeInfo.ACTIVE_WINDOW_ID) {
+                return mSecurityPolicy.mActiveWindowId;
             }
-            if (windowToken != null) {
-                return mWindowManagerService.getCompatibleMagnificationSpecForWindow(
-                        windowToken);
+            if (windowId == AccessibilityNodeInfo.ANY_WINDOW_ID) {
+                if (focusType == AccessibilityNodeInfo.FOCUS_INPUT) {
+                    return mSecurityPolicy.mFocusedWindowId;
+                } else if (focusType == AccessibilityNodeInfo.FOCUS_ACCESSIBILITY) {
+                    return mSecurityPolicy.mAccessibilityFocusedWindowId;
+                }
             }
-            return null;
+            return windowId;
         }
 
         private final class InvocationHandler extends Handler {
@@ -3031,7 +3037,86 @@
         }
     }
 
+    private final class InteractionBridge {
+        private final Display mDefaultDisplay;
+        private final int mConnectionId;
+        private final AccessibilityInteractionClient mClient;
+
+        public InteractionBridge() {
+            AccessibilityServiceInfo info = new AccessibilityServiceInfo();
+            info.setCapabilities(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT);
+            info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
+            info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
+            Service service = new Service(UserHandle.USER_NULL,
+                    sFakeAccessibilityServiceComponentName, info);
+
+            mConnectionId = service.mId;
+
+            mClient = AccessibilityInteractionClient.getInstance();
+            mClient.addConnection(mConnectionId, service);
+
+            //TODO: (multi-display) We need to support multiple displays.
+            DisplayManager displayManager = (DisplayManager)
+                    mContext.getSystemService(Context.DISPLAY_SERVICE);
+            mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
+        }
+
+        public void clearAccessibilityFocusNotLocked(int windowId) {
+            AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked(windowId);
+            if (focus != null) {
+                focus.performAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
+            }
+        }
+
+        public boolean getAccessibilityFocusBoundsNotLocked(Rect outBounds) {
+            AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked();
+            if (focus == null) {
+                return false;
+            }
+
+            synchronized (mLock) {
+                focus.getBoundsInScreen(outBounds);
+
+                MagnificationSpec spec = getCompatibleMagnificationSpecLocked(focus.getWindowId());
+                if (spec != null && !spec.isNop()) {
+                    outBounds.offset((int) -spec.offsetX, (int) -spec.offsetY);
+                    outBounds.scale(1 / spec.scale);
+                }
+
+                // Clip to the window rectangle.
+                Rect windowBounds = mTempRect;
+                getActiveWindowBounds(windowBounds);
+                outBounds.intersect(windowBounds);
+
+                // Clip to the screen rectangle.
+                mDefaultDisplay.getRealSize(mTempPoint);
+                outBounds.intersect(0, 0, mTempPoint.x, mTempPoint.y);
+
+                return true;
+            }
+        }
+
+        private AccessibilityNodeInfo getAccessibilityFocusNotLocked() {
+            final int focusedWindowId;
+            synchronized (mLock) {
+                focusedWindowId = mSecurityPolicy.mAccessibilityFocusedWindowId;
+                if (focusedWindowId == SecurityPolicy.INVALID_WINDOW_ID) {
+                    return null;
+                }
+            }
+            return getAccessibilityFocusNotLocked(focusedWindowId);
+        }
+
+        private AccessibilityNodeInfo getAccessibilityFocusNotLocked(int windowId) {
+            return mClient.findFocus(mConnectionId,
+                    windowId, AccessibilityNodeInfo.ROOT_NODE_ID,
+                    AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
+        }
+    }
+
     final class SecurityPolicy {
+        public static final int INVALID_WINDOW_ID = -1;
+
         private static final int VALID_ACTIONS =
             AccessibilityNodeInfo.ACTION_CLICK
             | AccessibilityNodeInfo.ACTION_LONG_CLICK
@@ -3075,8 +3160,11 @@
         public final List<AccessibilityWindowInfo> mWindows =
                 new ArrayList<AccessibilityWindowInfo>();
 
-        public int mActiveWindowId;
-        public int mFocusedWindowId;
+        public int mActiveWindowId = INVALID_WINDOW_ID;
+        public int mFocusedWindowId = INVALID_WINDOW_ID;
+        public int mAccessibilityFocusedWindowId = INVALID_WINDOW_ID;
+        public long mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+
         public AccessibilityEvent mShowingFocusedWindowEvent;
 
         private boolean mTouchInteractionInProgress;
@@ -3129,9 +3217,9 @@
                 mWindows.remove(i).recycle();
             }
 
-            mFocusedWindowId = -1;
+            mFocusedWindowId = INVALID_WINDOW_ID;
             if (!mTouchInteractionInProgress) {
-                mActiveWindowId = -1;
+                mActiveWindowId = INVALID_WINDOW_ID;
             }
 
             // If the active window goes away while the user is touch exploring we
@@ -3159,7 +3247,7 @@
                 }
 
                 if (mTouchInteractionInProgress && activeWindowGone) {
-                    mActiveWindowId = -1;
+                    mActiveWindowId = INVALID_WINDOW_ID;
                 }
 
                 // Focused window may change the active one, so set the
@@ -3193,7 +3281,8 @@
             }
         }
 
-        public void updateActiveWindowLocked(int windowId, int eventType) {
+        public void updateActiveAndAccessibilityFocusedWindowLocked(int windowId, long nodeId,
+                int eventType) {
             // The active window is either the window that has input focus or
             // the window that the user is currently touching. If the user is
             // touching a window that does not have input focus as soon as the
@@ -3228,6 +3317,29 @@
                         }
                     }
                 } break;
+
+                case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
+                    synchronized (mLock) {
+                        if (mAccessibilityFocusedWindowId != windowId) {
+                            mMainHandler.obtainMessage(MainHandler.MSG_CLEAR_ACCESSIBILITY_FOCUS,
+                                    mAccessibilityFocusedWindowId, 0).sendToTarget();
+                            mAccessibilityFocusedWindowId = windowId;
+                            mAccessibilityFocusNodeId = nodeId;
+                        }
+                    }
+                } break;
+
+                case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
+                    synchronized (mLock) {
+                        if (mAccessibilityFocusNodeId == nodeId) {
+                            mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+                        }
+                        if (mAccessibilityFocusNodeId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID
+                                && mAccessibilityFocusedWindowId == windowId) {
+                            mAccessibilityFocusedWindowId = INVALID_WINDOW_ID;
+                        }
+                    }
+                } break;
             }
         }
 
@@ -3248,7 +3360,19 @@
                 // (they are a result of user touching the screen) so change of
                 // the active window before all hover accessibility events from
                 // the touched window are delivered is fine.
+                final int oldActiveWindow = mSecurityPolicy.mActiveWindowId;
                 setActiveWindowLocked(mFocusedWindowId);
+
+                // If there is no service that can operate with active windows
+                // we keep accessibility focus behavior to constrain it only in
+                // the active window. Look at updateAccessibilityFocusBehaviorLocked
+                // for details.
+                if (oldActiveWindow != mSecurityPolicy.mActiveWindowId
+                        && mAccessibilityFocusedWindowId == oldActiveWindow
+                        && getCurrentUserStateLocked().mAccessibilityFocusOnlyInActiveWindow) {
+                    mMainHandler.obtainMessage(MainHandler.MSG_CLEAR_ACCESSIBILITY_FOCUS,
+                            oldActiveWindow, 0).sendToTarget();
+                }
             }
         }
 
@@ -3403,6 +3527,7 @@
         public boolean mIsDisplayMagnificationEnabled;
         public boolean mIsFilterKeyEventsEnabled;
         public boolean mHasDisplayColorAdjustment;
+        public boolean mAccessibilityFocusOnlyInActiveWindow;
 
         private Service mUiAutomationService;
         private IAccessibilityServiceClient mUiAutomationServiceClient;
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index 43f12eb..ac0ca0a 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -1159,7 +1159,7 @@
                 // No last touch explored event but there is accessibility focus in
                 // the active window. We click in the middle of the focus bounds.
                 Rect focusBounds = mTempRect;
-                if (mAms.getAccessibilityFocusBoundsInActiveWindow(focusBounds)) {
+                if (mAms.getAccessibilityFocusBounds(focusBounds)) {
                     clickLocationX = focusBounds.centerX();
                     clickLocationY = focusBounds.centerY();
                 } else {
@@ -1177,7 +1177,7 @@
                     mAms.getActiveWindowBounds(activeWindowBounds);
                     if (activeWindowBounds.contains(clickLocationX, clickLocationY)) {
                         Rect focusBounds = mTempRect;
-                        if (mAms.getAccessibilityFocusBoundsInActiveWindow(focusBounds)) {
+                        if (mAms.getAccessibilityFocusBounds(focusBounds)) {
                             if (!focusBounds.contains(clickLocationX, clickLocationY)) {
                                 clickLocationX = focusBounds.centerX();
                                 clickLocationY = focusBounds.centerY();
@@ -1332,7 +1332,7 @@
                 // No last touch explored event but there is accessibility focus in
                 // the active window. We click in the middle of the focus bounds.
                 Rect focusBounds = mTempRect;
-                if (mAms.getAccessibilityFocusBoundsInActiveWindow(focusBounds)) {
+                if (mAms.getAccessibilityFocusBounds(focusBounds)) {
                     clickLocationX = focusBounds.centerX();
                     clickLocationY = focusBounds.centerY();
                 } else {
@@ -1350,7 +1350,7 @@
                     mAms.getActiveWindowBounds(activeWindowBounds);
                     if (activeWindowBounds.contains(clickLocationX, clickLocationY)) {
                         Rect focusBounds = mTempRect;
-                        if (mAms.getAccessibilityFocusBoundsInActiveWindow(focusBounds)) {
+                        if (mAms.getAccessibilityFocusBounds(focusBounds)) {
                             if (!focusBounds.contains(clickLocationX, clickLocationY)) {
                                 clickLocationX = focusBounds.centerX();
                                 clickLocationY = focusBounds.centerY();
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 7ae5460..8b54264 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -17,6 +17,7 @@
 package com.android.server.usb;
 
 import android.content.Context;
+import android.content.Intent;
 import android.hardware.usb.UsbConfiguration;
 import android.hardware.usb.UsbConstants;
 import android.hardware.usb.UsbDevice;
@@ -25,11 +26,16 @@
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
+import android.os.UserHandle;
 import android.util.Slog;
 
+import com.android.alsascan.AlsaCardsParser;
+import com.android.alsascan.AlsaDevicesParser;
 import com.android.internal.annotations.GuardedBy;
 
+import java.io.File;
 import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -39,7 +45,7 @@
  */
 public class UsbHostManager {
     private static final String TAG = UsbHostManager.class.getSimpleName();
-    private static final boolean LOG = false;
+    private static final boolean DEBUG_AUDIO = false;
 
     // contains all connected USB devices
     private final HashMap<String, UsbDevice> mDevices = new HashMap<String, UsbDevice>();
@@ -57,6 +63,15 @@
     private ArrayList<UsbInterface> mNewInterfaces;
     private ArrayList<UsbEndpoint> mNewEndpoints;
 
+    // Attributes of any connected USB audio device.
+    //TODO(pmclean) When we extend to multiple, USB Audio devices, we will need to get
+    // more clever about this.
+    private int mConnectedUsbCard = -1;
+    private int mConnectedUsbDeviceNum = -1;
+    private boolean mConnectedHasPlayback = false;
+    private boolean mConnectedHasCapture = false;
+    private boolean mConnectedHasMIDI = false;
+
     @GuardedBy("mLock")
     private UsbSettingsManager mCurrentSettings;
 
@@ -102,6 +117,48 @@
         return false;
     }
 
+    // Broadcasts the arrival/departure of a USB audio interface
+    // card - the ALSA card number of the physical interface
+    // device - the ALSA device number of the physical interface
+    // enabled - if true, we're connecting a device (it's arrived), else disconnecting
+    private void sendDeviceNotification(int card, int device, boolean enabled,
+            boolean hasPlayback, boolean hasCapture, boolean hasMIDI) {
+        // send a sticky broadcast containing current USB state
+        Intent intent = new Intent(Intent.ACTION_USB_AUDIO_DEVICE_PLUG);
+        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+        intent.putExtra("state", enabled ? 1 : 0);
+        intent.putExtra("card", card);
+        intent.putExtra("device", device);
+        intent.putExtra("hasPlayback", hasPlayback);
+        intent.putExtra("hasCapture", hasCapture);
+        intent.putExtra("hasMIDI", hasMIDI);
+        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+    }
+
+    private boolean waitForAlsaFile(int card, int device, boolean capture) {
+        // These values were empirically determined.
+        final int kNumRetries = 5;
+        final int kSleepTime = 500; // ms
+        String alsaDevPath = "/dev/snd/pcmC" + card + "D" + device + (capture ? "c" : "p");
+        File alsaDevFile = new File(alsaDevPath);
+        boolean exists = false;
+        for (int retry = 0; !exists && retry < kNumRetries; retry++) {
+            exists = alsaDevFile.exists();
+            if (!exists) {
+                try {
+                    Thread.sleep(kSleepTime);
+                } catch (IllegalThreadStateException ex) {
+                    Slog.d(TAG, "usb: IllegalThreadStateException while waiting for ALSA file.");
+                } catch (java.lang.InterruptedException ex) {
+                    Slog.d(TAG, "usb: InterruptedException while waiting for ALSA file.");
+                }
+            }
+        }
+
+        return exists;
+    }
+
     /* Called from JNI in monitorUsbHostBus() to report new USB devices
        Returns true if successful, in which case the JNI code will continue adding configurations,
        interfaces and endpoints, and finally call endUsbDeviceAdded after all descriptors
@@ -111,6 +168,25 @@
             int deviceClass, int deviceSubclass, int deviceProtocol,
             String manufacturerName, String productName, String serialNumber) {
 
+        if (DEBUG_AUDIO) {
+            Slog.d(TAG, "usb:UsbHostManager.beginUsbDeviceAdded(" + deviceName + ")");
+            // Audio Class Codes:
+            // Audio: 0x01
+            // Audio Subclass Codes:
+            // undefined: 0x00
+            // audio control: 0x01
+            // audio streaming: 0x02
+            // midi streaming: 0x03
+
+            // some useful debugging info
+            Slog.d(TAG, "usb: nm:" + deviceName + " vnd:" + vendorID + " prd:" + productID + " cls:"
+                    + deviceClass + " sub:" + deviceSubclass + " proto:" + deviceProtocol);
+        }
+
+        // OK this is non-obvious, but true. One can't tell if the device being attached is even
+        // potentially an audio device without parsing the interface descriptors, so punt on any
+        // such test until endUsbDeviceAdded() when we have that info.
+
         if (isBlackListed(deviceName) ||
                 isBlackListed(deviceClass, deviceSubclass, deviceProtocol)) {
             return false;
@@ -135,6 +211,7 @@
             mNewInterfaces = new ArrayList<UsbInterface>();
             mNewEndpoints = new ArrayList<UsbEndpoint>();
         }
+
         return true;
     }
 
@@ -176,6 +253,9 @@
 
     /* Called from JNI in monitorUsbHostBus() to finish adding a new device */
     private void endUsbDeviceAdded() {
+        if (DEBUG_AUDIO) {
+            Slog.d(TAG, "usb:UsbHostManager.endUsbDeviceAdded()");
+        }
         if (mNewInterface != null) {
             mNewInterface.setEndpoints(
                     mNewEndpoints.toArray(new UsbEndpoint[mNewEndpoints.size()]));
@@ -185,6 +265,17 @@
                     mNewInterfaces.toArray(new UsbInterface[mNewInterfaces.size()]));
         }
 
+        // Is there an audio interface in there?
+        final int kUsbClassId_Audio = 0x01;
+        boolean isAudioDevice = false;
+        for (int ntrfaceIndex = 0; !isAudioDevice && ntrfaceIndex < mNewInterfaces.size();
+                ntrfaceIndex++) {
+            UsbInterface ntrface = mNewInterfaces.get(ntrfaceIndex);
+            if (ntrface.getInterfaceClass() == kUsbClassId_Audio) {
+                isAudioDevice = true;
+            }
+        }
+
         synchronized (mLock) {
             if (mNewDevice != null) {
                 mNewDevice.setConfigurations(
@@ -200,10 +291,70 @@
             mNewInterfaces = null;
             mNewEndpoints = null;
         }
+
+        if (!isAudioDevice) {
+            return; // bail
+        }
+
+        //TODO(pmclean) The "Parser" objects inspect files in "/proc/asound" which we presume is
+        // present, unlike the waitForAlsaFile() which waits on a file in /dev/snd. It is not
+        // clear why this works, or that it can be relied on going forward.  Needs further
+        // research.
+        AlsaCardsParser cardsParser = new AlsaCardsParser();
+        cardsParser.scan();
+        // cardsParser.Log();
+
+        // But we need to parse the device to determine its capabilities.
+        AlsaDevicesParser devicesParser = new AlsaDevicesParser();
+        devicesParser.scan();
+        // devicesParser.Log();
+
+        // The protocol for now will be to select the last-connected (highest-numbered)
+        // Alsa Card.
+        mConnectedUsbCard = cardsParser.getNumCardRecords() - 1;
+        mConnectedUsbDeviceNum = 0;
+
+        if (!waitForAlsaFile(mConnectedUsbCard, mConnectedUsbDeviceNum, false)) {
+            return;
+        }
+
+        mConnectedHasPlayback = devicesParser.hasPlaybackDevices(mConnectedUsbCard);
+        mConnectedHasCapture = devicesParser.hasCaptureDevices(mConnectedUsbCard);
+        mConnectedHasMIDI = devicesParser.hasMIDIDevices(mConnectedUsbCard);
+
+        if (DEBUG_AUDIO) {
+            Slog.d(TAG,
+                    "usb: hasPlayback:" + mConnectedHasPlayback + " hasCapture:" + mConnectedHasCapture);
+        }
+
+        sendDeviceNotification(mConnectedUsbCard,
+                mConnectedUsbDeviceNum,
+                true,
+                mConnectedHasPlayback,
+                mConnectedHasCapture,
+                mConnectedHasMIDI);
     }
 
     /* Called from JNI in monitorUsbHostBus to report USB device removal */
     private void usbDeviceRemoved(String deviceName) {
+        if (DEBUG_AUDIO) {
+          Slog.d(TAG, "usb:UsbHostManager.usbDeviceRemoved() nm:" + deviceName);
+        }
+
+        if (mConnectedUsbCard != -1 && mConnectedUsbDeviceNum != -1) {
+            sendDeviceNotification(mConnectedUsbCard,
+                    mConnectedUsbDeviceNum,
+                    false,
+                    mConnectedHasPlayback,
+                    mConnectedHasCapture,
+                    mConnectedHasMIDI);
+            mConnectedUsbCard = -1;
+            mConnectedUsbDeviceNum = -1;
+            mConnectedHasPlayback = false;
+            mConnectedHasCapture = false;
+            mConnectedHasMIDI = false;
+        }
+
         synchronized (mLock) {
             UsbDevice device = mDevices.remove(deviceName);
             if (device != null) {
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index daef37a..992ef4b 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -78,6 +78,12 @@
     }
 
     @Override
+    public Intent getLeanbackLaunchIntentForPackage(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+
     public int[] getPackageGids(String packageName) throws NameNotFoundException {
         throw new UnsupportedOperationException();
     }
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index c8eefe0..0ad3456 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -867,14 +867,5 @@
             </intent-filter>
         </activity>
 
-        <activity
-                android:name="IsolationVolumeActivity"
-                android:label="Reordering/IsolationVolume">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="com.android.test.hwui.TEST" />
-            </intent-filter>
-        </activity>
-
     </application>
 </manifest>
diff --git a/tests/HwAccelerationTest/res/layout/isolation.xml b/tests/HwAccelerationTest/res/layout/isolation.xml
deleted file mode 100644
index e66db19..0000000
--- a/tests/HwAccelerationTest/res/layout/isolation.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:background="#f55">
-    <!-- Left and right layouts are not isolated volumes, so the text views
-         will interleave since they share an isolated z volume-->
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal">
-        <LinearLayout
-            android:layout_width="0dp"
-            android:layout_height="200dp"
-            android:layout_weight="1"
-            android:orientation="vertical">
-            <TextView style="@style/TopLeftReorderTextView"/>
-            <TextView style="@style/BottomLeftReorderTextView"/>
-        </LinearLayout>
-        <LinearLayout
-            android:layout_width="0dp"
-            android:layout_height="200dp"
-            android:layout_weight="1"
-            android:translationY="50dp"
-            android:orientation="vertical">
-            <TextView style="@style/TopRightReorderTextView"/>
-            <TextView style="@style/BottomRightReorderTextView"/>
-        </LinearLayout>
-    </LinearLayout>
-
-    <!-- Left and right volumes are isolated by default, so no interleaving will be seen. -->
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal">
-        <LinearLayout
-            android:layout_width="0dp"
-            android:layout_height="200dp"
-            android:layout_weight="1"
-            android:orientation="vertical">
-            <TextView style="@style/TopLeftReorderTextView"/>
-            <TextView style="@style/BottomLeftReorderTextView"/>
-        </LinearLayout>
-        <LinearLayout
-            android:layout_width="0dp"
-            android:layout_height="200dp"
-            android:layout_weight="1"
-            android:translationY="50dp"
-            android:orientation="vertical">
-            <TextView style="@style/TopRightReorderTextView"/>
-            <TextView style="@style/BottomRightReorderTextView"/>
-        </LinearLayout>
-    </LinearLayout>
-</LinearLayout>
\ No newline at end of file
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/IsolationVolumeActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/IsolationVolumeActivity.java
deleted file mode 100644
index d5c93f2..0000000
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/IsolationVolumeActivity.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.android.test.hwui;
-
-import android.os.Bundle;
-import android.app.Activity;
-
-public class IsolationVolumeActivity extends Activity {
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.isolation);
-    }
-}