Merge "Default to using hardware layer during fade transition." into lmp-dev
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 57c1505..5ba7d50 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -48,6 +48,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.text.TextUtils;
@@ -726,6 +727,7 @@
 
             IActivityManager.WaitResult result = null;
             int res;
+            final long startTime = SystemClock.uptimeMillis();
             if (mWaitOption) {
                 result = mAm.startActivityAndWait(null, null, intent, mimeType,
                             null, null, 0, mStartFlags, profilerInfo, null, mUserId);
@@ -734,6 +736,7 @@
                 res = mAm.startActivityAsUser(null, null, intent, mimeType,
                         null, null, 0, mStartFlags, profilerInfo, null, mUserId);
             }
+            final long endTime = SystemClock.uptimeMillis();
             PrintStream out = mWaitOption ? System.out : System.err;
             boolean launched = false;
             switch (res) {
@@ -811,6 +814,7 @@
                 if (result.totalTime >= 0) {
                     System.out.println("TotalTime: " + result.totalTime);
                 }
+                System.out.println("WaitTime: " + (endTime-startTime));
                 System.out.println("Complete");
             }
             mRepeat--;
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 7c69a7d..e3cbef5 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1402,6 +1402,20 @@
         return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
     }
 
+    /** {@hide */
+    public static final void enforceTetherChangePermission(Context context) {
+        if (context.getResources().getStringArray(
+                com.android.internal.R.array.config_mobile_hotspot_provision_app).length == 2) {
+            // Have a provisioning app - must only let system apps (which check this app)
+            // turn on tethering
+            context.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.CONNECTIVITY_INTERNAL, "ConnectivityService");
+        } else {
+            context.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.CHANGE_NETWORK_STATE, "ConnectivityService");
+        }
+    }
+
     /**
      * Get the set of tetherable, available interfaces.  This list is limited by
      * device configuration and current interface existence.
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index c25278f..82016c3 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -19,6 +19,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -430,7 +431,8 @@
      * @return whether the user making this call is a goat
      */
     public boolean isUserAGoat() {
-        return false;
+        return mContext.getPackageManager()
+                .isPackageAvailable("com.coffeestainstudios.goatsimulator");
     }
 
     /**
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 107e8c6..22600de 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -491,8 +491,7 @@
     }
 
     private boolean versionNumberAtLeastL(int versionNumber) {
-        // TODO: remove "|| true" once the build code for L is fixed.
-        return versionNumber >= Build.VERSION_CODES.L || true;
+        return versionNumber >= Build.VERSION_CODES.L;
     }
 
     private void setAlwaysButtonEnabled(boolean hasValidSelection, int checkedPos,
diff --git a/core/res/res/drawable/ic_corp_icon_badge.xml b/core/res/res/drawable/ic_corp_icon_badge.xml
index 0e1c63d..538dade 100644
--- a/core/res/res/drawable/ic_corp_icon_badge.xml
+++ b/core/res/res/drawable/ic_corp_icon_badge.xml
@@ -30,18 +30,15 @@
         android:pathData="M49.0,49.0m-14.0,0.0a14.0,14.0 0.0,1.0 1.0,28.0 0.0a14.0,14.0 0.0,1.0 1.0,-28.0 0.0"
         android:fillColor="#FF5722"/>
     <path
-        android:pathData="M55.25,44.264l-2.254,0.0l0.0,-1.531l-1.531,-1.531l-4.638,0.0l-1.531,1.531l0.0,1.531l-2.294,0.0c-0.846,0.0 -1.523,0.685 -1.523,1.531l-0.008,8.421c0.0,0.846 0.685,1.531 1.531,1.531L55.25,55.746994c0.846,0.0 1.531,-0.685 1.531,-1.531l0.0,-8.421C56.782,44.948 56.097,44.264 55.25,44.264zM51.465,44.264l-4.638,0.0l0.0,-1.531l4.638,0.0L51.465,44.264z"
+        android:pathData="M55.801,43.688l-2.837,-0.001l0.0,-1.137l-1.587,-1.588l-4.72,-0.001l-1.588,1.587l0.0,1.137l-2.867,-0.001c-0.94,0.0 -1.691,0.76 -1.691,1.699L40.5,48.654c0.0,0.94 0.76,1.7 1.699,1.7l5.255,0.001l0.0,-1.271l0.225,0.0l2.589,0.0l0.225,0.0l0.0,1.271l5.303,0.001c0.939,0.0 1.7,-0.76 1.7,-1.699l0.002,-3.269C57.5,44.449 56.74,43.689 55.801,43.688zM51.377,43.687l-4.72,-0.001l0.0,-1.137l4.72,0.001L51.377,43.687z"
         android:fillColor="#FFFFFF"/>
     <path
-        android:pathData="M57.359,45.373c0.0,-0.855 -0.738,-1.547 -1.651,-1.547L42.535,43.826c-0.913,0.0 -1.643,0.692 -1.643,1.547l0.004,3.232c0.0,0.911 0.737,1.648 1.648,1.648l13.162,0.0c0.911,0.0 1.648,-0.737 1.648,-1.648L57.359,45.373z"
+        android:pathData="M50.494,52.012l-3.04,0.0l0.0,-0.901l-6.417,0.0l0.0,3.172c0.0,0.94 0.741,1.7 1.68,1.7l12.464,0.003c0.939,0.0 1.702,-0.76 1.703,-1.699l0.0,-3.176l-6.39,0.0L50.494,52.012z"
         android:fillColor="#FFFFFF"/>
     <path
         android:pathData="M40.726,40.726 h16.13 v16.13 h-16.13z"
         android:fillColor="#00000000"/>
     <path
-        android:pathData="M40.0,49.0l17.0,0.0l0.0,2.0l-17.0,0.0z"
-        android:fillColor="#FF5722"/>
-    <path
-        android:pathData="M47.625,48.951l3.003,0.0l0.0,3.002l-3.003,0.0z"
-        android:fillColor="#FF5722"/>
-</vector>
\ No newline at end of file
+        android:pathData="M46.657,42.55 h4.72 v1.137 h-4.72z"
+        android:fillColor="#00000000"/>
+</vector>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index e95d735..ef3f47e 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -355,9 +355,9 @@
 
     <!-- Integer parameters of the wifi to cellular handover feature
          wifi should not stick to bad networks -->
-    <integer translatable="false" name="config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz">-60</integer>
+    <integer translatable="false" name="config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz">-82</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_low_rssi_threshold_5GHz">-72</integer>
-    <integer translatable="false" name="config_wifi_framework_wifi_score_good_rssi_threshold_5GHz">-82</integer>
+    <integer translatable="false" name="config_wifi_framework_wifi_score_good_rssi_threshold_5GHz">-60</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz">-87</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_low_rssi_threshold_24GHz">-77</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_good_rssi_threshold_24GHz">-65</integer>
@@ -1791,6 +1791,7 @@
         <item>SUPL_PORT=7275</item>
         <item>NTP_SERVER=north-america.pool.ntp.org</item>
         <item>SUPL_VER=0x20000</item>
+        <item>SUPL_MODE=0x01</item>
     </string-array>
 
     <!-- If there is no preload VM number in the sim card, carriers such as
diff --git a/data/keyboards/Vendor_0a5c_Product_8502.kl b/data/keyboards/Vendor_0a5c_Product_8502.kl
deleted file mode 100644
index 2f07328..0000000
--- a/data/keyboards/Vendor_0a5c_Product_8502.kl
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (C) 2013 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.
-
-# Rhodi
-
-key 304 BUTTON_A
-key 305 BUTTON_B
-key 307 BUTTON_X
-key 308 BUTTON_Y
-key 310 BUTTON_L1
-key 311 BUTTON_R1
-key 316 BUTTON_MODE
-key 317 BUTTON_THUMBL
-key 318 BUTTON_THUMBR
-
-key 158 BACK
-key 172 HOME
-
-axis 0x00 X
-axis 0x01 Y
-axis 0x02 Z
-axis 0x05 RZ
-axis 0x09 RTRIGGER
-axis 0x0a LTRIGGER
-axis 0x10 HAT_X
-axis 0x11 HAT_Y
-
-led 0x00 CONTROLLER_1
-led 0x01 CONTROLLER_2
-led 0x02 CONTROLLER_3
-led 0x03 CONTROLLER_4
diff --git a/docs/html/google/play/billing/index.jd b/docs/html/google/play/billing/index.jd
index e1326d7..bdbf5c7 100644
--- a/docs/html/google/play/billing/index.jd
+++ b/docs/html/google/play/billing/index.jd
@@ -14,6 +14,7 @@
 <div class="sidebox">
   <h2><strong>New in In-App Billing</strong></h2>
   <ul>
+  <li><strong>IAB v2 shutdown</strong>&mdash;In-app Billing v2 API is deprecated and will be shut down in January 2015. If your app is still using In-app Billing v2, please migrate to the v3 API as soon as possible.</li>
   <li><strong>Seasonal subscriptions</strong>&mdash;You can now set up a
     recurring <a href="billing_subscriptions.html#user-billing">seasonal
     subscription</a> that starts and ends on the same date each year (for
@@ -41,7 +42,7 @@
 
 <ul>
 <li>Standard in-app products (one-time billing), or</li>
-<li>Subscriptions, (recurring, automated billing)</li>
+<li>Subscriptions (recurring, automated billing)</li>
 </ul>
 
 <p>When you use the in-app billing service to sell an item,
diff --git a/docs/html/google/play/billing/v2/api.jd b/docs/html/google/play/billing/v2/api.jd
index 9501555..36a9017 100644
--- a/docs/html/google/play/billing/v2/api.jd
+++ b/docs/html/google/play/billing/v2/api.jd
@@ -2,7 +2,28 @@
 excludeFromSuggestions=true
 @jd:body
 
-<div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">In-app Billing Version 2 is superseded. Please <a href="{@docRoot}google/play/billing/billing_overview.html#migration">migrate to Version 3</a> at your earliest convenience.</div>
+<p class="caution" style=
+"background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">
+  The <strong>In-app Billing Version 2 API</strong> has been deprecated in
+  favor of the Version 3 API. If your app is using In-app Billing, please
+  <strong>make sure that it is using the Version 3 API</strong>. If your app is
+  still using the Version 2 API, you must <strong>migrate to the Version 3 API
+  as soon as possible</strong>.<br>
+  <br>
+  We plan to turn off the In-app Billing Version 2 service on <strong>January
+  27, 2015</strong>, after which time users will <strong>no longer be able to
+  purchase in-app items and subscriptions through the Version 2 API</strong>.
+  We strongly encourage and recommend you migrate your apps to use Version 3
+  API by November 2014, to provide ample time for users to update their apps to
+  the new version.<br>
+  <br>
+  For more information, please see the <a href=
+  "http://support.google.com/googleplay/android-developer/answer/6090268">Help Center
+  article</a>. For common questions about transitioning your implementation to
+  In-app Billing Version 3, please see <a href=
+  "{@docRoot}google/play/billing/billing_overview.html#migration">Migration
+  Considerations</a>.
+</p>
     <div id="qv-wrapper" style="margin-top:0;">
 <div id="qv">
 
diff --git a/docs/html/google/play/billing/v2/billing_integrate.jd b/docs/html/google/play/billing/v2/billing_integrate.jd
index 5eb17d5..c264271 100644
--- a/docs/html/google/play/billing/v2/billing_integrate.jd
+++ b/docs/html/google/play/billing/v2/billing_integrate.jd
@@ -2,7 +2,28 @@
 excludeFromSuggestions=true
 @jd:body
 
-<div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">In-app Billing Version 2 is superseded. Please <a href="{@docRoot}google/play/billing/billing_overview.html#migration">migrate to Version 3</a> at your earliest convenience.</div>
+<p class="caution" style=
+"background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">
+  The <strong>In-app Billing Version 2 API</strong> has been deprecated in
+  favor of the Version 3 API. If your app is using In-app Billing, please
+  <strong>make sure that it is using the Version 3 API</strong>. If your app is
+  still using the Version 2 API, you must <strong>migrate to the Version 3 API
+  as soon as possible</strong>.<br>
+  <br>
+  We plan to turn off the In-app Billing Version 2 service on <strong>January
+  27, 2015</strong>, after which time users will <strong>no longer be able to
+  purchase in-app items and subscriptions through the Version 2 API</strong>.
+  We strongly encourage and recommend you migrate your apps to use Version 3
+  API by November 2014, to provide ample time for users to update their apps to
+  the new version.<br>
+  <br>
+  For more information, please see the <a href=
+  "http://support.google.com/googleplay/android-developer/answer/6090268">Help Center
+  article</a>. For common questions about transitioning your implementation to
+  In-app Billing Version 3, please see <a href=
+  "{@docRoot}google/play/billing/billing_overview.html#migration">Migration
+  Considerations</a>.
+</p>
     <div id="qv-wrapper" style="margin-top:0;">
 <div id="qv">
   <h2>In this document</h2>
diff --git a/docs/html/google/play/billing/v2/billing_reference.jd b/docs/html/google/play/billing/v2/billing_reference.jd
index 4587dee..32e00cf 100644
--- a/docs/html/google/play/billing/v2/billing_reference.jd
+++ b/docs/html/google/play/billing/v2/billing_reference.jd
@@ -2,7 +2,28 @@
 excludeFromSuggestions=true
 @jd:body
 
-<div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">In-app Billing Version 2 is superseded. Please <a href="{@docRoot}google/play/billing/billing_overview.html#migration">migrate to Version 3</a> at your earliest convenience.</div>
+<p class="caution" style=
+"background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">
+  The <strong>In-app Billing Version 2 API</strong> has been deprecated in
+  favor of the Version 3 API. If your app is using In-app Billing, please
+  <strong>make sure that it is using the Version 3 API</strong>. If your app is
+  still using the Version 2 API, you must <strong>migrate to the Version 3 API
+  as soon as possible</strong>.<br>
+  <br>
+  We plan to turn off the In-app Billing Version 2 service on <strong>January
+  27, 2015</strong>, after which time users will <strong>no longer be able to
+  purchase in-app items and subscriptions through the Version 2 API</strong>.
+  We strongly encourage and recommend you migrate your apps to use Version 3
+  API by November 2014, to provide ample time for users to update their apps to
+  the new version.<br>
+  <br>
+  For more information, please see the <a href=
+  "http://support.google.com/googleplay/android-developer/answer/6090268">Help Center
+  article</a>. For common questions about transitioning your implementation to
+  In-app Billing Version 3, please see <a href=
+  "{@docRoot}google/play/billing/billing_overview.html#migration">Migration
+  Considerations</a>.
+</p>
     <div id="qv-wrapper" style="margin-top:0;">
 <div id="qv">
 <h2>In this document</h2>
diff --git a/docs/html/google/play/billing/v2/billing_subscriptions.jd b/docs/html/google/play/billing/v2/billing_subscriptions.jd
index f8051a9..01e39ac 100644
--- a/docs/html/google/play/billing/v2/billing_subscriptions.jd
+++ b/docs/html/google/play/billing/v2/billing_subscriptions.jd
@@ -2,7 +2,28 @@
 excludeFromSuggestions=true
 @jd:body
 
-<div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">In-app Billing Version 2 is superseded. Please <a href="{@docRoot}google/play/billing/billing_overview.html#migration">migrate to Version 3</a> at your earliest convenience.</div>
+<p class="caution" style=
+"background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">
+  The <strong>In-app Billing Version 2 API</strong> has been deprecated in
+  favor of the Version 3 API. If your app is using In-app Billing, please
+  <strong>make sure that it is using the Version 3 API</strong>. If your app is
+  still using the Version 2 API, you must <strong>migrate to the Version 3 API
+  as soon as possible</strong>.<br>
+  <br>
+  We plan to turn off the In-app Billing Version 2 service on <strong>January
+  27, 2015</strong>, after which time users will <strong>no longer be able to
+  purchase in-app items and subscriptions through the Version 2 API</strong>.
+  We strongly encourage and recommend you migrate your apps to use Version 3
+  API by November 2014, to provide ample time for users to update their apps to
+  the new version.<br>
+  <br>
+  For more information, please see the <a href=
+  "http://support.google.com/googleplay/android-developer/answer/6090268">Help Center
+  article</a>. For common questions about transitioning your implementation to
+  In-app Billing Version 3, please see <a href=
+  "{@docRoot}google/play/billing/billing_overview.html#migration">Migration
+  Considerations</a>.
+</p>
     <div id="qv-wrapper" style="margin-top:0;">
 <div id="qv">
   <h2>In this document</h2>
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index feaee8e..7eb9a32 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -227,7 +227,7 @@
 #define DEFAULT_PATCH_CACHE_SIZE 128 // in kB
 #define DEFAULT_GRADIENT_CACHE_SIZE 0.5f
 #define DEFAULT_DROP_SHADOW_CACHE_SIZE 2.0f
-#define DEFAULT_FBO_CACHE_SIZE 16
+#define DEFAULT_FBO_CACHE_SIZE 0
 
 #define DEFAULT_TEXTURE_CACHE_FLUSH_RATE 0.6f
 
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 5e6796c..832d170 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -91,7 +91,9 @@
 }
 
 void CanvasContext::swapBuffers() {
-    mEglManager.swapBuffers(mEglSurface);
+    if (CC_UNLIKELY(!mEglManager.swapBuffers(mEglSurface))) {
+        setSurface(NULL);
+    }
     mHaveNewSurface = false;
 }
 
@@ -102,8 +104,8 @@
 }
 
 bool CanvasContext::initialize(ANativeWindow* window) {
-    if (mCanvas) return false;
     setSurface(window);
+    if (mCanvas) return false;
     mCanvas = new OpenGLRenderer(mRenderThread.renderState());
     mCanvas->initProperties();
     return true;
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index e030cdb..a87834e 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -254,11 +254,23 @@
     eglBeginFrame(mEglDisplay, surface);
 }
 
-void EglManager::swapBuffers(EGLSurface surface) {
+bool EglManager::swapBuffers(EGLSurface surface) {
     eglSwapBuffers(mEglDisplay, surface);
     EGLint err = eglGetError();
-    LOG_ALWAYS_FATAL_IF(err != EGL_SUCCESS,
-            "Encountered EGL error %d %s during rendering", err, egl_error_str(err));
+    if (CC_LIKELY(err == EGL_SUCCESS)) {
+        return true;
+    }
+    if (err == EGL_BAD_SURFACE) {
+        // For some reason our surface was destroyed out from under us
+        // This really shouldn't happen, but if it does we can recover easily
+        // by just not trying to use the surface anymore
+        ALOGW("swapBuffers encountered EGL_BAD_SURFACE on %p, halting rendering...", surface);
+        return false;
+    }
+    LOG_ALWAYS_FATAL("Encountered EGL error %d %s during rendering",
+            err, egl_error_str(err));
+    // Impossible to hit this, but the compiler doesn't know that
+    return false;
 }
 
 bool EglManager::enableDirtyRegions(EGLSurface surface) {
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index a844cfc..71213fb 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -47,7 +47,7 @@
     // Returns true if the current surface changed, false if it was already current
     bool makeCurrent(EGLSurface surface);
     void beginFrame(EGLSurface surface, EGLint* width, EGLint* height);
-    void swapBuffers(EGLSurface surface);
+    bool swapBuffers(EGLSurface surface);
 
     bool enableDirtyRegions(EGLSurface surface);
 
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
index 0bec217..a4555f1 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
@@ -64,9 +64,6 @@
 
     private final CloseGuard mCloseGuard = CloseGuard.get();
 
-    private final ArrayMap<Integer, PageContentProvider> mPageContentProviders =
-            new ArrayMap<>();
-
     private final AsyncRenderer mRenderer;
 
     private RenderSpec mLastRenderSpec;
@@ -141,10 +138,6 @@
         return mRenderer.getPageCount();
     }
 
-    public PageContentProvider peekPageContentProvider(int pageIndex) {
-        return mPageContentProviders.get(pageIndex);
-    }
-
     public PageContentProvider acquirePageContentProvider(int pageIndex, View owner) {
         throwIfDestroyed();
 
@@ -152,15 +145,7 @@
             Log.i(LOG_TAG, "Acquiring provider for page: " + pageIndex);
         }
 
-        if (mPageContentProviders.get(pageIndex)!= null) {
-            throw new IllegalStateException("Already acquired for page: " + pageIndex);
-        }
-
-        PageContentProvider provider = new PageContentProvider(pageIndex, owner);
-
-        mPageContentProviders.put(pageIndex, provider);
-
-        return provider;
+        return new PageContentProvider(pageIndex, owner);
     }
 
     public void releasePageContentProvider(PageContentProvider provider) {
@@ -170,10 +155,6 @@
             Log.i(LOG_TAG, "Releasing provider for page: " + provider.mPageIndex);
         }
 
-        if (mPageContentProviders.remove(provider.mPageIndex) == null) {
-            throw new IllegalStateException("Not acquired");
-        }
-
         provider.cancelLoad();
     }
 
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
index 84bbc27..da8160a 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
@@ -274,8 +274,7 @@
     @Override
     public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
         View page = mLayoutInflater.inflate(R.layout.preview_page, parent, false);
-        ViewHolder holder = new MyViewHolder(page);
-        return holder;
+        return new MyViewHolder(page);
     }
 
     @Override
@@ -313,14 +312,8 @@
                         + ", pageIndexInFile: " + pageIndexInFile);
             }
 
-            // OK, there are bugs in recycler view which tries to bind views
-            // without recycling them which would give us a chance to clean up.
-            PageContentProvider boundProvider = mPageContentRepository
-                    .peekPageContentProvider(pageIndexInFile);
-            if (boundProvider != null) {
-                PageContentView owner = (PageContentView) boundProvider.getOwner();
-                owner.init(null, mEmptyState, mMediaSize, mMinMargins);
-                mPageContentRepository.releasePageContentProvider(boundProvider);
+            if (provider != null && provider.getPageIndex() != pageIndexInFile) {
+                mPageContentRepository.releasePageContentProvider(provider);
             }
 
             provider = mPageContentRepository.acquirePageContentProvider(
@@ -731,7 +724,7 @@
     private void recyclePageView(PageContentView page, int pageIndexInAdapter) {
         PageContentProvider provider = page.getPageContentProvider();
         if (provider != null) {
-            page.init(null, null, null, null);
+            page.init(null, mEmptyState, mMediaSize, mMinMargins);
             mPageContentRepository.releasePageContentProvider(provider);
         }
         mBoundPagesInAdapter.remove(pageIndexInAdapter);
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 3c2a776..bddd691 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -283,6 +283,21 @@
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".egg.LLandActivity"
+                  android:theme="@android:style/Theme.Material.Light.NoActionBar.TranslucentDecor"
+                  android:exported="true"
+                  android:label="@string/lland"
+                  android:hardwareAccelerated="true"
+                  android:launchMode="singleInstance"
+                  android:screenOrientation="locked"
+                  android:process=":sweetsweetdesserts"
+                  android:excludeFromRecents="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.DEFAULT" />
                 <category android:name="com.android.internal.category.PLATLOGO" />
             </intent-filter>
         </activity>
diff --git a/packages/SystemUI/res/drawable/android.xml b/packages/SystemUI/res/drawable/android.xml
new file mode 100644
index 0000000..750de05
--- /dev/null
+++ b/packages/SystemUI/res/drawable/android.xml
@@ -0,0 +1,37 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2 (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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48dp"
+        android:height="48dp"
+        android:viewportWidth="48"
+        android:viewportHeight="48">
+    <path
+        android:name="torso"
+        android:pathData="M12,36c0,1.1 0.9,2 2,2l2,0l0,7c0,1.7 1.3,3 3,3c1.7,0 3,-1.3 3,-3l0,-7l4,0l0,7c0,1.7 1.3,3 3,3c1.7,0 3,-1.3 3,-3l0,-7l2,0c1.1,0 2,-0.9 2,-2L36,16L12,16L12,36z"
+        android:fillColor="#FFFFFF"/>
+    <path
+        android:name="leftArm"
+        android:pathData="M7,16c-1.7,0 -3,1.3 -3,3l0,14c0,1.7 1.3,3 3,3c1.7,0 3,-1.3 3,-3L10,19C10,17.3 8.7,16 7,16z"
+        android:fillColor="#FFFFFF"/>
+    <path
+        android:name="rightArm"
+        android:pathData="M41,16c-1.7,0 -3,1.3 -3,3l0,14c0,1.7 1.3,3 3,3c1.7,0 3,-1.3 3,-3L44,19C44,17.3 42.7,16 41,16z"
+        android:fillColor="#FFFFFF"/>
+    <path
+        android:name="illFormTheHead"
+        android:pathData="M31.1,4.3l2.6,-2.6c0.4,-0.4 0.4,-1 0,-1.4c-0.4,-0.4 -1,-0.4 -1.4,0l-3,3C27.7,2.5 25.9,2 24,2c-1.9,0 -3.7,0.5 -5.3,1.3l-3,-3c-0.4,-0.4 -1,-0.4 -1.4,0c-0.4,0.4 -0.4,1 0,1.4l2.6,2.6C13.9,6.5 12,10 12,14l24,0C36,10 34.1,6.5 31.1,4.3zM20.31,9c0,0.72 -0.59,1.31 -1.31,1.31c-0.72,0 -1.31,-0.59 -1.31,-1.31c0,-0.72 0.59,-1.31 1.31,-1.31C19.72,7.69 20.31,8.28 20.31,9zM30.31,9c0,0.72 -0.59,1.31 -1.31,1.31c-0.73,0 -1.31,-0.59 -1.31,-1.31c0,-0.72 0.59,-1.31 1.31,-1.31C29.72,7.69 30.31,8.28 30.31,9z"
+        android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/cloud.xml b/packages/SystemUI/res/drawable/cloud.xml
new file mode 100644
index 0000000..17e4ad2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/cloud.xml
@@ -0,0 +1,24 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48.0dp"
+        android:height="48.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:pathData="M38.700001,20.100000C37.299999,13.200000 31.299999,8.000000 24.000000,8.000000c-5.800000,0.000000 -10.800000,3.300000 -13.300000,8.100000C4.700000,16.700001 0.000000,21.799999 0.000000,28.000000c0.000000,6.600000 5.400000,12.000000 12.000000,12.000000l26.000000,0.000000c5.500000,0.000000 10.000000,-4.500000 10.000000,-10.000000C48.000000,24.700001 43.900002,20.400000 38.700001,20.100000z"
+        android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/cloud_off.xml b/packages/SystemUI/res/drawable/cloud_off.xml
new file mode 100644
index 0000000..b15ea5f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/cloud_off.xml
@@ -0,0 +1,24 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:pathData="M19.400000,10.000000c-0.700000,-3.400000 -3.700000,-6.000000 -7.400000,-6.000000c-1.500000,0.000000 -2.900000,0.400000 -4.000000,1.200000l1.500000,1.500000C10.200000,6.200000 11.100000,6.000000 12.000000,6.000000c3.000000,0.000000 5.500000,2.500000 5.500000,5.500000L17.500000,12.000000L19.000000,12.000000c1.700000,0.000000 3.000000,1.300000 3.000000,3.000000c0.000000,1.100000 -0.600000,2.100000 -1.600000,2.600000l1.500000,1.500000c1.300000,-0.900000 2.100000,-2.400000 2.100000,-4.100000C24.000000,12.400000 21.900000,10.200000 19.400000,10.000000zM3.000000,5.300000L5.800000,8.000000C2.600000,8.200000 0.000000,10.800000 0.000000,14.000000c0.000000,3.300000 2.700000,6.000000 6.000000,6.000000l11.700000,0.000000l2.000000,2.000000l1.300000,-1.300000L4.300000,4.000000L3.000000,5.300000zM7.700000,10.000000l8.000000,8.000000L6.000000,18.000000c-2.200000,0.000000 -4.000000,-1.800000 -4.000000,-4.000000c0.000000,-2.200000 1.800000,-4.000000 4.000000,-4.000000L7.700000,10.000000z"
+        android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/moon.xml b/packages/SystemUI/res/drawable/moon.xml
new file mode 100644
index 0000000..4ee6286
--- /dev/null
+++ b/packages/SystemUI/res/drawable/moon.xml
@@ -0,0 +1,24 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48.0dp"
+        android:height="48.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:pathData="M18.000000,4.000000c-2.100000,0.000000 -4.100000,0.300000 -6.000000,0.900000C20.100000,7.500000 26.000000,15.000000 26.000000,24.000000s-5.900000,16.500000 -14.000000,19.100000c1.900000,0.600000 3.900000,0.900000 6.000000,0.900000c11.000000,0.000000 20.000000,-9.000000 20.000000,-20.000000S29.000000,4.000000 18.000000,4.000000z"
+        android:fillColor="#FFF2F2FF"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/placeholder.xml b/packages/SystemUI/res/drawable/placeholder.xml
new file mode 100644
index 0000000..1933145
--- /dev/null
+++ b/packages/SystemUI/res/drawable/placeholder.xml
@@ -0,0 +1,51 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="100dp"
+        android:height="400dp"
+        android:viewportWidth="100"
+        android:viewportHeight="400">
+
+    <!-- future site of real artwork -->
+
+    <path android:fillColor="#FFFFFF00"
+        android:pathData="M 0,0 L 100,0 L 100,400 L 0,400 z" />
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M 0,0 L 100,25 L 100,50 L 0,25 z" />
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M 0,50 L 100,75 L 100,100 L 0,75 z" />
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M 0,100 L 100,125 L 100,150 L 0,125 z" />
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M 0,150 L 100,175 L 100,200 L 0,175 z" />
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M 0,200 L 100,225 L 100,250 L 0,225 z" />
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M 0,250 L 100,275 L 100,300 L 0,275 z" />
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M 0,300 L 100,325 L 100,350 L 0,325 z" />
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M 0,350 L 100,375 L 100,400 L 0,375 z" />
+</vector>
+
diff --git a/packages/SystemUI/res/drawable/scorecard.xml b/packages/SystemUI/res/drawable/scorecard.xml
new file mode 100644
index 0000000..707449a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/scorecard.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle"
+    >
+    <corners
+        android:radius="8dp" />
+    <solid
+        android:color="#ffffffff" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/scorecard_gameover.xml b/packages/SystemUI/res/drawable/scorecard_gameover.xml
new file mode 100644
index 0000000..f663a66
--- /dev/null
+++ b/packages/SystemUI/res/drawable/scorecard_gameover.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle"
+    >
+    <corners
+        android:radius="8dp" />
+    <solid
+        android:color="#ffff0000" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/star.xml b/packages/SystemUI/res/drawable/star.xml
new file mode 100644
index 0000000..73ca04a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/star.xml
@@ -0,0 +1,24 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48.0dp"
+        android:height="48.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:pathData="M30.250000,17.750000L24.000000,4.000000l-6.250000,13.750000L4.000000,24.000000l13.750000,6.250000L24.000000,44.000000l6.250000,-13.750000L44.000000,24.000000L30.250000,17.750000z"
+        android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/sun.xml b/packages/SystemUI/res/drawable/sun.xml
new file mode 100644
index 0000000..3e4a233
--- /dev/null
+++ b/packages/SystemUI/res/drawable/sun.xml
@@ -0,0 +1,29 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48.0dp"
+        android:height="48.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <group>
+        <path
+            android:pathData="M 24,8 A 16,16 0 1,0 24.0001,8 z"
+            android:fillColor="#FFFFFFCC" />
+        <path
+            android:pathData="M40.0,30.6l6.6,-6.6L40.0,17.4L40.0,8.0l-9.4,0.0L24.0,1.4L17.4,8.0L8.0,8.0l0.0,9.4L1.4,24.0L8.0,30.6L8.0,40.0l9.4,0.0l6.6,6.6l6.6,-6.6L40.0,40.0L40.0,30.6zM24.0,36.0c-6.6,0.0 -12.0,-5.4 -12.0,-12.0s5.4,-12.0 12.0,-12.0c6.6,0.0 12.0,5.4 12.0,12.0S30.6,36.0 24.0,36.0z"
+            android:fillColor="#FFFFFF40"/>
+    </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/sun2.xml b/packages/SystemUI/res/drawable/sun2.xml
new file mode 100644
index 0000000..6d2d504
--- /dev/null
+++ b/packages/SystemUI/res/drawable/sun2.xml
@@ -0,0 +1,24 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48.0dp"
+        android:height="48.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:pathData="M40.000000,17.400000L40.000000,8.000000l-9.400000,0.000000L24.000000,1.400000L17.400000,8.000000L8.000000,8.000000l0.000000,9.400000L1.400000,24.000000L8.000000,30.600000L8.000000,40.000000l9.400000,0.000000l6.600000,6.600000l6.600000,-6.600000L40.000000,40.000000l0.000000,-9.400000l6.600000,-6.600000L40.000000,17.400000zM24.000000,36.000000c-6.600000,0.000000 -12.000000,-5.400000 -12.000000,-12.000000s5.400000,-12.000000 12.000000,-12.000000c6.600000,0.000000 12.000000,5.400000 12.000000,12.000000S30.600000,36.000000 24.000000,36.000000zM24.000000,16.000000c-4.400000,0.000000 -8.000000,3.600000 -8.000000,8.000000c0.000000,4.400000 3.600000,8.000000 8.000000,8.000000s8.000000,-3.600000 8.000000,-8.000000C32.000000,19.600000 28.400000,16.000000 24.000000,16.000000z"
+        android:fillColor="#FF000000"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/lland.xml b/packages/SystemUI/res/layout/lland.xml
new file mode 100644
index 0000000..053225d
--- /dev/null
+++ b/packages/SystemUI/res/layout/lland.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+        >
+    <com.android.systemui.egg.LLand
+            android:id="@+id/world"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+    </com.android.systemui.egg.LLand>
+    <TextView
+            android:id="@+id/score"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="32sp"
+            android:textColor="#FFAAAAAA"
+            android:layout_marginTop="32dp"
+            android:layout_marginLeft="16dp"
+            android:layout_gravity="top|left"
+            android:paddingLeft="16dp"
+            android:paddingRight="16dp"
+            android:paddingTop="8dp"
+            android:paddingBottom="8dp"
+            android:background="@drawable/scorecard"
+            />
+    <TextView
+            android:id="@+id/welcome"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="30sp"
+            android:textColor="#FFFFFFFF"
+            android:layout_gravity="center"
+            android:layout_marginTop="70dp"
+            android:visibility="gone"
+            />
+</FrameLayout>
+
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 37ee0aea..002a970 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -452,10 +452,14 @@
     <!-- How far the user needs to drag up to invoke search. -->
     <dimen name="search_panel_threshold">100dp</dimen>
 
-    <!-- The width/height of the phone/camera/unlock icon on keyguard. -->
+    <!-- The width/height of the phone/camera/unlock icon view on keyguard. -->
     <dimen name="keyguard_affordance_height">56dp</dimen>
     <dimen name="keyguard_affordance_width">56dp</dimen>
 
+    <!-- The width/height of the phone/camera/unlock icon drawable on keyguard. -->
+    <dimen name="keyguard_affordance_icon_height">24dp</dimen>
+    <dimen name="keyguard_affordance_icon_width">24dp</dimen>
+
     <dimen name="keyguard_indication_margin_bottom">65dp</dimen>
 
     <!-- The text size for battery level -->
diff --git a/packages/SystemUI/res/values/lland_config.xml b/packages/SystemUI/res/values/lland_config.xml
new file mode 100644
index 0000000..56125a5
--- /dev/null
+++ b/packages/SystemUI/res/values/lland_config.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<resources>
+    <dimen name="obstacle_spacing">380dp</dimen>
+    <dimen name="translation_per_sec">100dp</dimen>
+    <dimen name="boost_dv">600dp</dimen>
+    <dimen name="player_hit_size">40dp</dimen>
+    <dimen name="player_size">40dp</dimen>
+    <dimen name="obstacle_width">80dp</dimen>
+    <dimen name="obstacle_gap">170dp</dimen>
+    <dimen name="obstacle_height_min">40dp</dimen>
+    <dimen name="building_width_min">20dp</dimen>
+    <dimen name="building_width_max">250dp</dimen>
+    <dimen name="building_height_min">20dp</dimen>
+    <dimen name="cloud_size_min">10dp</dimen>
+    <dimen name="cloud_size_max">100dp</dimen>
+    <dimen name="sun_size">45dp</dimen>
+    <dimen name="moon_size">30dp</dimen>
+    <dimen name="star_size_min">3dp</dimen>
+    <dimen name="star_size_max">5dp</dimen>
+    <dimen name="G">30dp</dimen>
+    <dimen name="max_v">1000dp</dimen>
+    <dimen name="scenery_z">6dp</dimen>
+    <dimen name="obstacle_z">15dp</dimen>
+    <dimen name="player_z">15dp</dimen>
+    <dimen name="player_z_boost">18dp</dimen>
+    <dimen name="hud_z">35dp</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values/lland_strings.xml b/packages/SystemUI/res/values/lland_strings.xml
new file mode 100644
index 0000000..ce88157
--- /dev/null
+++ b/packages/SystemUI/res/values/lland_strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Name of the L Land easter egg. DO NOT TRANSLATE -->
+    <string name="lland">L Land</string>
+</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/egg/LLand.java b/packages/SystemUI/src/com/android/systemui/egg/LLand.java
new file mode 100644
index 0000000..d1c02dd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/egg/LLand.java
@@ -0,0 +1,748 @@
+/*
+ * 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.systemui.egg;
+
+import android.animation.TimeAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.*;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.*;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+
+import com.android.systemui.R;
+
+public class LLand extends FrameLayout {
+    public static final String TAG = "LLand";
+
+    public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    public static final boolean DEBUG_DRAW = false && DEBUG;
+
+    public static final void L(String s, Object ... objects) {
+        if (DEBUG) {
+            Log.d(TAG, String.format(s, objects));
+        }
+    }
+
+    public static final boolean AUTOSTART = true;
+    public static final boolean HAVE_STARS = true;
+
+    public static final float DEBUG_SPEED_MULTIPLIER = 1f; // 0.1f;
+    public static final boolean DEBUG_IDDQD = false;
+
+    private static class Params {
+        public float TRANSLATION_PER_SEC;
+        public int OBSTACLE_SPACING, OBSTACLE_PERIOD;
+        public int BOOST_DV;
+        public int PLAYER_HIT_SIZE;
+        public int PLAYER_SIZE;
+        public int OBSTACLE_WIDTH;
+        public int OBSTACLE_GAP;
+        public int OBSTACLE_MIN;
+        public int BUILDING_WIDTH_MIN, BUILDING_WIDTH_MAX;
+        public int BUILDING_HEIGHT_MIN;
+        public int CLOUD_SIZE_MIN, CLOUD_SIZE_MAX;
+        public int STAR_SIZE_MIN, STAR_SIZE_MAX;
+        public int G;
+        public int MAX_V;
+            public float SCENERY_Z, OBSTACLE_Z, PLAYER_Z, PLAYER_Z_BOOST, HUD_Z;
+        public Params(Resources res) {
+            TRANSLATION_PER_SEC = res.getDimension(R.dimen.translation_per_sec);
+            OBSTACLE_SPACING = res.getDimensionPixelSize(R.dimen.obstacle_spacing);
+            OBSTACLE_PERIOD = (int) (OBSTACLE_SPACING / TRANSLATION_PER_SEC);
+            BOOST_DV = res.getDimensionPixelSize(R.dimen.boost_dv);
+            PLAYER_HIT_SIZE = res.getDimensionPixelSize(R.dimen.player_hit_size);
+            PLAYER_SIZE = res.getDimensionPixelSize(R.dimen.player_size);
+            OBSTACLE_WIDTH = res.getDimensionPixelSize(R.dimen.obstacle_width);
+            OBSTACLE_GAP = res.getDimensionPixelSize(R.dimen.obstacle_gap);
+            OBSTACLE_MIN = res.getDimensionPixelSize(R.dimen.obstacle_height_min);
+            BUILDING_HEIGHT_MIN = res.getDimensionPixelSize(R.dimen.building_height_min);
+            BUILDING_WIDTH_MIN = res.getDimensionPixelSize(R.dimen.building_width_min);
+            BUILDING_WIDTH_MAX = res.getDimensionPixelSize(R.dimen.building_width_max);
+            CLOUD_SIZE_MIN = res.getDimensionPixelSize(R.dimen.cloud_size_min);
+            CLOUD_SIZE_MAX = res.getDimensionPixelSize(R.dimen.cloud_size_max);
+            STAR_SIZE_MIN = res.getDimensionPixelSize(R.dimen.star_size_min);
+            STAR_SIZE_MAX = res.getDimensionPixelSize(R.dimen.star_size_max);
+
+            G = res.getDimensionPixelSize(R.dimen.G);
+            MAX_V = res.getDimensionPixelSize(R.dimen.max_v);
+
+            SCENERY_Z = res.getDimensionPixelSize(R.dimen.scenery_z);
+            OBSTACLE_Z = res.getDimensionPixelSize(R.dimen.obstacle_z);
+            PLAYER_Z = res.getDimensionPixelSize(R.dimen.player_z);
+            PLAYER_Z_BOOST = res.getDimensionPixelSize(R.dimen.player_z_boost);
+            HUD_Z = res.getDimensionPixelSize(R.dimen.hud_z);
+        }
+    }
+
+    private TimeAnimator mAnim;
+
+    private TextView mScoreField;
+    private View mSplash;
+
+    private Player mDroid;
+    private ArrayList<Obstacle> mObstaclesInPlay = new ArrayList<Obstacle>();
+
+    private float t, dt;
+
+    private int mScore;
+    private float mLastPipeTime; // in sec
+    private int mWidth, mHeight;
+    private boolean mAnimating, mPlaying;
+    private boolean mFrozen; // after death, a short backoff
+
+    private int mTimeOfDay;
+    private static final int DAY = 0, NIGHT = 1, TWILIGHT = 2, SUNSET = 3;
+    private static final int[][] SKIES = {
+            { 0xFFc0c0FF, 0xFFa0a0FF }, // DAY
+            { 0xFF000010, 0xFF000000 }, // NIGHT
+            { 0xFF000040, 0xFF000010 }, // TWILIGHT
+            { 0xFF805010, 0xFF202080 }, // SUNSET
+    };
+
+    private static Params PARAMS;
+
+    public LLand(Context context) {
+        this(context, null);
+    }
+
+    public LLand(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public LLand(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        setFocusable(true);
+        PARAMS = new Params(getResources());
+        mTimeOfDay = irand(0, SKIES.length);
+    }
+
+    @Override
+    public boolean willNotDraw() {
+        return !DEBUG;
+    }
+
+    public int getGameWidth() { return mWidth; }
+    public int getGameHeight() { return mHeight; }
+    public float getGameTime() { return t; }
+    public float getLastTimeStep() { return dt; }
+
+    public void setScoreField(TextView tv) {
+        mScoreField = tv;
+        if (tv != null) {
+            tv.setTranslationZ(PARAMS.HUD_Z);
+            if (!(mAnimating && mPlaying)) {
+                tv.setTranslationY(-500);
+            }
+        }
+    }
+
+    public void setSplash(View v) {
+        mSplash = v;
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        stop();
+        reset();
+        if (AUTOSTART) {
+            start(false);
+        }
+    }
+
+    final float hsv[] = {0, 0, 0};
+
+    private void reset() {
+        L("reset");
+        final Drawable sky = new GradientDrawable(
+                GradientDrawable.Orientation.BOTTOM_TOP,
+                SKIES[mTimeOfDay]
+        );
+        sky.setDither(true);
+        setBackground(sky);
+
+        setScaleX(frand() > 0.5f ? 1 : -1);
+
+        setScore(0);
+
+        int i = getChildCount();
+        while (i-->0) {
+            final View v = getChildAt(i);
+            if (v instanceof GameView) {
+                removeViewAt(i);
+            }
+        }
+
+        mObstaclesInPlay.clear();
+
+        mWidth = getWidth();
+        mHeight = getHeight();
+
+        boolean showingSun = (mTimeOfDay == DAY || mTimeOfDay == SUNSET) && frand() > 0.25;
+        if (showingSun) {
+            final Star sun = new Star(getContext());
+            sun.setBackgroundResource(R.drawable.sun);
+            final int w = getResources().getDimensionPixelSize(R.dimen.sun_size);
+            sun.setTranslationX(frand(w, mWidth-w));
+            if (mTimeOfDay == DAY) {
+                sun.setTranslationY(frand(w, (mHeight * 0.66f)));
+                sun.getBackground().setTint(0);
+            } else {
+                sun.setTranslationY(frand(mHeight * 0.66f, mHeight - w));
+                sun.getBackground().setTintMode(PorterDuff.Mode.SRC_ATOP);
+                sun.getBackground().setTint(0xC0FF8000);
+
+            }
+            addView(sun, new LayoutParams(w, w));
+        }
+        if (!showingSun) {
+            final boolean dark = mTimeOfDay == NIGHT || mTimeOfDay == TWILIGHT;
+            final float ff = frand();
+            if ((dark && ff < 0.75f) || ff < 0.5f) {
+                final Star moon = new Star(getContext());
+                moon.setBackgroundResource(R.drawable.moon);
+                moon.getBackground().setAlpha(dark ? 255 : 128);
+                moon.setScaleX(frand() > 0.5 ? -1 : 1);
+                moon.setRotation(moon.getScaleX() * frand(5, 30));
+                final int w = getResources().getDimensionPixelSize(R.dimen.sun_size);
+                moon.setTranslationX(frand(w, mWidth - w));
+                moon.setTranslationY(frand(w, mHeight - w));
+                addView(moon, new LayoutParams(w, w));
+            }
+        }
+
+        final int mh = mHeight / 6;
+        final boolean cloudless = frand() < 0.25;
+        final int N = 20;
+        for (i=0; i<N; i++) {
+            final float r1 = frand();
+            final Scenery s;
+            if (HAVE_STARS && r1 < 0.3 && mTimeOfDay != DAY) {
+                s = new Star(getContext());
+            } else if (r1 < 0.6 && !cloudless) {
+                s = new Cloud(getContext());
+            } else {
+                s = new Building(getContext());
+
+                s.z = (float)i/N;
+                s.setTranslationZ(PARAMS.SCENERY_Z * (1+s.z));
+                s.v = 0.85f * s.z; // buildings move proportional to their distance
+                hsv[0] = 175;
+                hsv[1] = 0.25f;
+                hsv[2] = 1 * s.z;
+                s.setBackgroundColor(Color.HSVToColor(hsv));
+                s.h = irand(PARAMS.BUILDING_HEIGHT_MIN, mh);
+            }
+            final LayoutParams lp = new LayoutParams(s.w, s.h);
+            if (s instanceof Building) {
+                lp.gravity = Gravity.BOTTOM;
+            } else {
+                lp.gravity = Gravity.TOP;
+                final float r = frand();
+                if (s instanceof Star) {
+                    lp.topMargin = (int) (r * r * mHeight);
+                } else {
+                    lp.topMargin = (int) (1 - r*r * mHeight/2) + mHeight/2;
+                }
+            }
+
+            addView(s, lp);
+            s.setTranslationX(frand(-lp.width, mWidth + lp.width));
+        }
+
+        mDroid = new Player(getContext());
+        mDroid.setX(mWidth / 2);
+        mDroid.setY(mHeight / 2);
+        addView(mDroid, new LayoutParams(PARAMS.PLAYER_SIZE, PARAMS.PLAYER_SIZE));
+        if (mAnim != null) {
+            Log.wtf(TAG, "reseting while animating??!?");
+        }
+        mAnim = new TimeAnimator();
+        mAnim.setTimeListener(new TimeAnimator.TimeListener() {
+            @Override
+            public void onTimeUpdate(TimeAnimator timeAnimator, long t, long dt) {
+                step(t, dt);
+            }
+        });
+    }
+
+    private void setScore(int score) {
+        mScore = score;
+        if (mScoreField != null) mScoreField.setText(String.valueOf(score));
+    }
+
+    private void addScore(int incr) {
+        setScore(mScore + incr);
+    }
+
+    private void start(boolean startPlaying) {
+        L("start(startPlaying=%s)", startPlaying?"true":"false");
+        if (startPlaying) {
+            mPlaying = true;
+
+            t = 0;
+            mLastPipeTime = getGameTime() - PARAMS.OBSTACLE_PERIOD; // queue up a obstacle
+
+            if (mSplash != null && mSplash.getAlpha() > 0f) {
+                mSplash.setTranslationZ(PARAMS.HUD_Z);
+                mSplash.animate().alpha(0).translationZ(0).setDuration(400);
+
+                mScoreField.animate().translationY(0)
+                        .setInterpolator(new DecelerateInterpolator())
+                        .setDuration(1500);
+            }
+
+            mScoreField.setTextColor(0xFFAAAAAA);
+            mScoreField.setBackgroundResource(R.drawable.scorecard);
+            mDroid.setVisibility(View.VISIBLE);
+            mDroid.setX(mWidth / 2);
+            mDroid.setY(mHeight / 2);
+        } else {
+            mDroid.setVisibility(View.GONE);
+        }
+        if (!mAnimating) {
+            mAnim.start();
+            mAnimating = true;
+        }
+    }
+
+    private void stop() {
+        if (mAnimating) {
+            mAnim.cancel();
+            mAnim = null;
+            mAnimating = false;
+            mScoreField.setTextColor(0xFFFFFFFF);
+            mScoreField.setBackgroundResource(R.drawable.scorecard_gameover);
+            mTimeOfDay = irand(0, SKIES.length); // for next reset
+            mFrozen = true;
+            postDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        mFrozen = false;
+                    }
+                }, 250);
+        }
+    }
+
+    public static final float lerp(float x, float a, float b) {
+        return (b - a) * x + a;
+    }
+
+    public static final float rlerp(float v, float a, float b) {
+        return (v - a) / (b - a);
+    }
+
+    public static final float clamp(float f) {
+        return f < 0f ? 0f : f > 1f ? 1f : f;
+    }
+
+    public static final float frand() {
+        return (float) Math.random();
+    }
+
+    public static final float frand(float a, float b) {
+        return lerp(frand(), a, b);
+    }
+
+    public static final int irand(int a, int b) {
+        return (int) lerp(frand(), (float) a, (float) b);
+    }
+
+    private void step(long t_ms, long dt_ms) {
+        t = t_ms / 1000f; // seconds
+        dt = dt_ms / 1000f;
+
+        if (DEBUG) {
+            t *= DEBUG_SPEED_MULTIPLIER;
+            dt *= DEBUG_SPEED_MULTIPLIER;
+        }
+
+        // 1. Move all objects and update bounds
+        final int N = getChildCount();
+        int i = 0;
+        for (; i<N; i++) {
+            final View v = getChildAt(i);
+            if (v instanceof GameView) {
+                ((GameView) v).step(t_ms, dt_ms, t, dt);
+            }
+        }
+
+        // 2. Check for altitude
+        if (mPlaying && mDroid.below(mHeight)) {
+            if (DEBUG_IDDQD) {
+                poke();
+            } else {
+                L("player hit the floor");
+                stop();
+            }
+        }
+
+        // 3. Check for obstacles
+        boolean passedBarrier = false;
+        for (int j = mObstaclesInPlay.size(); j-->0;) {
+            final Obstacle ob = mObstaclesInPlay.get(j);
+            if (mPlaying && ob.intersects(mDroid) && !DEBUG_IDDQD) {
+                L("player hit an obstacle");
+                stop();
+            } else if (ob.cleared(mDroid)) {
+                passedBarrier = true;
+                mObstaclesInPlay.remove(j);
+            }
+        }
+
+        if (mPlaying && passedBarrier) {
+            addScore(1);
+        }
+
+        // 4. Handle edge of screen
+        // Walk backwards to make sure removal is safe
+        while (i-->0) {
+            final View v = getChildAt(i);
+            if (v instanceof Obstacle) {
+                if (v.getTranslationX() + v.getWidth() < 0) {
+                    removeViewAt(i);
+                }
+            } else if (v instanceof Scenery) {
+                final Scenery s = (Scenery) v;
+                if (v.getTranslationX() + s.w < 0) {
+                    v.setTranslationX(getWidth());
+                }
+            }
+        }
+
+        // 3. Time for more obstacles!
+        if (mPlaying && (t - mLastPipeTime) > PARAMS.OBSTACLE_PERIOD) {
+            mLastPipeTime = t;
+            final int obstacley = (int) (Math.random()
+                    * (mHeight - 2*PARAMS.OBSTACLE_MIN - PARAMS.OBSTACLE_GAP)) + PARAMS.OBSTACLE_MIN;
+
+            final Obstacle p1 = new Obstacle(getContext(), obstacley);
+            addView(p1, new LayoutParams(
+                    PARAMS.OBSTACLE_WIDTH,
+                    mHeight,
+                    Gravity.TOP|Gravity.LEFT));
+            p1.setTranslationX(mWidth);
+            p1.setTranslationY(-mHeight);
+            p1.setTranslationZ(0);
+            p1.animate()
+                    .translationY(-mHeight+p1.h)
+                    .translationZ(PARAMS.OBSTACLE_Z)
+                    .setStartDelay(irand(0,250))
+                    .setDuration(250);
+            mObstaclesInPlay.add(p1);
+
+            final Obstacle p2 = new Obstacle(getContext(),
+                    mHeight - obstacley - PARAMS.OBSTACLE_GAP);
+            addView(p2, new LayoutParams(
+                    PARAMS.OBSTACLE_WIDTH,
+                    mHeight,
+                    Gravity.TOP|Gravity.LEFT));
+            p2.setTranslationX(mWidth);
+            p2.setTranslationY(mHeight);
+            p2.setTranslationZ(0);
+            p2.animate()
+                    .translationY(mHeight-p2.h)
+                    .translationZ(PARAMS.OBSTACLE_Z)
+                    .setStartDelay(irand(0,100))
+                    .setDuration(400);
+            mObstaclesInPlay.add(p2);
+        }
+
+        if (DEBUG) {
+            final Rect r = new Rect();
+            mDroid.getHitRect(r);
+            r.inset(-4, -4);
+            invalidate(r);
+        }
+    }
+    
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (DEBUG) L("touch: %s", ev);
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            poke();
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onTrackballEvent(MotionEvent ev) {
+        if (DEBUG) L("trackball: %s", ev);
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            poke();
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent ev) {
+        if (DEBUG) L("keyDown: %d", keyCode);
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_CENTER:
+            case KeyEvent.KEYCODE_DPAD_UP:
+            case KeyEvent.KEYCODE_SPACE:
+            case KeyEvent.KEYCODE_ENTER:
+            case KeyEvent.KEYCODE_BUTTON_A:
+                poke();
+                return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onGenericMotionEvent (MotionEvent ev) {
+        if (DEBUG) L("generic: %s", ev);
+        return false;
+    }
+
+    private void poke() {
+        L("poke");
+        if (mFrozen) return;
+        if (!mAnimating) {
+            reset();
+            start(true);
+        } else if (!mPlaying) {
+            start(true);
+        }
+        mDroid.boost();
+        if (DEBUG) {
+            mDroid.dv *= DEBUG_SPEED_MULTIPLIER;
+            mDroid.animate().setDuration((long) (200/DEBUG_SPEED_MULTIPLIER));
+        }
+    }
+
+    @Override
+    public void onDraw(Canvas c) {
+        super.onDraw(c);
+
+        if (!DEBUG_DRAW) return;
+
+        final Paint pt = new Paint();
+        pt.setColor(0xFFFFFFFF);
+        final int L = mDroid.corners.length;
+        final int N = L/2;
+        for (int i=0; i<N; i++) {
+            final int x = (int) mDroid.corners[i*2];
+            final int y = (int) mDroid.corners[i*2+1];
+            c.drawCircle(x, y, 4, pt);
+            c.drawLine(x, y,
+                    mDroid.corners[(i*2+2)%L],
+                    mDroid.corners[(i*2+3)%L],
+                    pt);
+        }
+
+        final int M = getChildCount();
+        pt.setColor(0x6000FF00);
+        for (int i=0; i<M; i++) {
+            final View v = getChildAt(i);
+            if (v == mDroid) continue;
+            if (!(v instanceof GameView)) continue;
+            final Rect r = new Rect();
+            v.getHitRect(r);
+            c.drawRect(r, pt);
+        }
+
+        pt.setColor(Color.BLACK);
+        final StringBuilder sb = new StringBuilder("obstacles: ");
+        for (Obstacle ob : mObstaclesInPlay) {
+            sb.append(ob.hitRect.toShortString());
+            sb.append(" ");
+        }
+        pt.setTextSize(20f);
+        c.drawText(sb.toString(), 20, 100, pt);
+    }
+
+    static final Rect sTmpRect = new Rect();
+
+    private interface GameView {
+        public void step(long t_ms, long dt_ms, float t, float dt);
+    }
+
+    private class Player extends ImageView implements GameView {
+        public float dv;
+
+        private final float[] sHull = new float[] {
+                0.3f,  0f,    // left antenna
+                0.7f,  0f,    // right antenna
+                0.92f, 0.33f, // off the right shoulder of Orion
+                0.92f, 0.75f, // right hand (our right, not his right)
+                0.6f,  1f,    // right foot
+                0.4f,  1f,    // left foot BLUE!
+                0.08f, 0.75f, // sinistram
+                0.08f, 0.33f,  // cold shoulder
+        };
+        public final float[] corners = new float[sHull.length];
+
+        public Player(Context context) {
+            super(context);
+
+            setBackgroundResource(R.drawable.android);
+            getBackground().setTintMode(PorterDuff.Mode.SRC_ATOP);
+            getBackground().setTint(0xFF00FF00);
+            setOutlineProvider(new ViewOutlineProvider() {
+                @Override
+                public void getOutline(View view, Outline outline) {
+                    final int w = view.getWidth();
+                    final int h = view.getHeight();
+                    final int ix = (int) (w * 0.3f);
+                    final int iy = (int) (h * 0.2f);
+                    outline.setRect(ix, iy, w - ix, h - iy);
+                }
+            });
+        }
+
+        public void prepareCheckIntersections() {
+            final int inset = (PARAMS.PLAYER_SIZE - PARAMS.PLAYER_HIT_SIZE)/2;
+            final int scale = PARAMS.PLAYER_HIT_SIZE;
+            final int N = sHull.length/2;
+            for (int i=0; i<N; i++) {
+                corners[i*2]   = scale * sHull[i*2]   + inset;
+                corners[i*2+1] = scale * sHull[i*2+1] + inset;
+            }
+            final Matrix m = getMatrix();
+            m.mapPoints(corners);
+        }
+
+        public boolean below(int h) {
+            final int N = corners.length/2;
+            for (int i=0; i<N; i++) {
+                final int y = (int) corners[i*2+1];
+                if (y >= h) return true;
+            }
+            return false;
+        }
+
+        public void step(long t_ms, long dt_ms, float t, float dt) {
+            if (getVisibility() != View.VISIBLE) return; // not playing yet
+
+            dv += PARAMS.G;
+            if (dv < -PARAMS.MAX_V) dv = -PARAMS.MAX_V;
+            else if (dv > PARAMS.MAX_V) dv = PARAMS.MAX_V;
+
+            final float y = getTranslationY() + dv * dt;
+            setTranslationY(y < 0 ? 0 : y);
+            setRotation(
+                    90 + lerp(clamp(rlerp(dv, PARAMS.MAX_V, -1 * PARAMS.MAX_V)), 90, -90));
+
+            prepareCheckIntersections();
+        }
+
+        public void boost() {
+            dv = -PARAMS.BOOST_DV;
+            setTranslationZ(PARAMS.PLAYER_Z_BOOST);
+            setScaleX(1.25f);
+            setScaleY(1.25f);
+            animate()
+                .scaleX(1f)
+                .scaleY(1f)
+                .translationZ(PARAMS.PLAYER_Z)
+                .setDuration(200);
+        }
+    }
+
+    private class Obstacle extends View implements GameView {
+        public float h;
+
+        public final Rect hitRect = new Rect();
+
+        public Obstacle(Context context, float h) {
+            super(context);
+            setBackgroundResource(R.drawable.placeholder);
+            this.h = h;
+        }
+
+        public boolean intersects(Player p) {
+            final int N = p.corners.length/2;
+            for (int i=0; i<N; i++) {
+                final int x = (int) p.corners[i*2];
+                final int y = (int) p.corners[i*2+1];
+                if (hitRect.contains(x, y)) return true;
+            }
+            return false;
+        }
+
+        public boolean cleared(Player p) {
+            final int N = p.corners.length/2;
+            for (int i=0; i<N; i++) {
+                final int x = (int) p.corners[i*2];
+                if (hitRect.right >= x) return false;
+            }
+            return true;
+        }
+
+        @Override
+        public void step(long t_ms, long dt_ms, float t, float dt) {
+            setTranslationX(getTranslationX()-PARAMS.TRANSLATION_PER_SEC*dt);
+            getHitRect(hitRect);
+        }
+    }
+
+    private class Scenery extends FrameLayout implements GameView {
+        public float z;
+        public float v;
+        public int h, w;
+        public Scenery(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void step(long t_ms, long dt_ms, float t, float dt) {
+            setTranslationX(getTranslationX() - PARAMS.TRANSLATION_PER_SEC * dt * v);
+        }
+    }
+
+    private class Building extends Scenery {
+        public Building(Context context) {
+            super(context);
+
+            w = irand(PARAMS.BUILDING_WIDTH_MIN, PARAMS.BUILDING_WIDTH_MAX);
+            h = 0; // will be setup later, along with z
+
+            setTranslationZ(PARAMS.SCENERY_Z);
+        }
+    }
+
+    private class Cloud extends Scenery {
+        public Cloud(Context context) {
+            super(context);
+            setBackgroundResource(frand() < 0.01f ? R.drawable.cloud_off : R.drawable.cloud);
+            getBackground().setAlpha(0x40);
+            w = h = irand(PARAMS.CLOUD_SIZE_MIN, PARAMS.CLOUD_SIZE_MAX);
+            z = 0;
+            v = frand(0.15f,0.5f);
+        }
+    }
+
+    private class Star extends Scenery {
+        public Star(Context context) {
+            super(context);
+            setBackgroundResource(R.drawable.star);
+            w = h = irand(PARAMS.STAR_SIZE_MIN, PARAMS.STAR_SIZE_MAX);
+            v = z = 0;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/egg/LLandActivity.java b/packages/SystemUI/src/com/android/systemui/egg/LLandActivity.java
new file mode 100644
index 0000000..88fd952
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/egg/LLandActivity.java
@@ -0,0 +1,36 @@
+/*
+ * 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.systemui.egg;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+
+public class LLandActivity extends Activity {
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.lland);
+        LLand world = (LLand) findViewById(R.id.world);
+        world.setScoreField((TextView) findViewById(R.id.score));
+        world.setSplash(findViewById(R.id.welcome));
+        Log.v(LLand.TAG, "focus: " + world.requestFocus());
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 9af893d..4af8499 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -170,6 +170,8 @@
     private boolean mSwitchingUser;
 
     private boolean mSystemReady;
+    private boolean mBootCompleted;
+    private boolean mBootSendUserPresent;
 
     // Whether the next call to playSounds() should be skipped.  Defaults to
     // true because the first lock (on boot) should be silent.
@@ -1145,8 +1147,14 @@
     }
 
     private void sendUserPresentBroadcast() {
-        final UserHandle currentUser = new UserHandle(mLockPatternUtils.getCurrentUser());
-        mContext.sendBroadcastAsUser(USER_PRESENT_INTENT, currentUser);
+        synchronized (this) {
+            if (mBootCompleted) {
+                final UserHandle currentUser = new UserHandle(mLockPatternUtils.getCurrentUser());
+                mContext.sendBroadcastAsUser(USER_PRESENT_INTENT, currentUser);
+            } else {
+                mBootSendUserPresent = true;
+            }
+        }
     }
 
     /**
@@ -1406,6 +1414,12 @@
 
     public void onBootCompleted() {
         mUpdateMonitor.dispatchBootCompleted();
+        synchronized (this) {
+            mBootCompleted = true;
+            if (mBootSendUserPresent) {
+                sendUserPresentBroadcast();
+            }
+        }
     }
 
     public StatusBarKeyguardViewManager registerStatusBar(PhoneStatusBar phoneStatusBar,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index e323dd6..754fade 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -25,6 +25,8 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.RemoteException;
@@ -91,6 +93,8 @@
 
     private final TrustDrawable mTrustDrawable;
 
+    private int mLastUnlockIconRes = 0;
+
     public KeyguardBottomAreaView(Context context) {
         this(context, null);
     }
@@ -380,7 +384,17 @@
                 ? com.android.internal.R.drawable.ic_account_circle
                 : mUnlockMethodCache.isMethodInsecure() ? R.drawable.ic_lock_open_24dp
                 : R.drawable.ic_lock_24dp;
-        mLockIcon.setImageResource(iconRes);
+        if (mLastUnlockIconRes != iconRes) {
+            Drawable icon = mContext.getDrawable(iconRes);
+            int iconHeight = getResources().getDimensionPixelSize(
+                    R.dimen.keyguard_affordance_icon_height);
+            int iconWidth = getResources().getDimensionPixelSize(
+                    R.dimen.keyguard_affordance_icon_width);
+            if (icon.getIntrinsicHeight() != iconHeight || icon.getIntrinsicWidth() != iconWidth) {
+                icon = new IntrinsicSizeDrawable(icon, iconWidth, iconHeight);
+            }
+            mLockIcon.setImageDrawable(icon);
+        }
         boolean trustManaged = mUnlockMethodCache.isTrustManaged();
         mTrustDrawable.setTrustManaged(trustManaged);
         updateLockIconClickability();
@@ -469,4 +483,30 @@
             KeyguardIndicationController keyguardIndicationController) {
         mIndicationController = keyguardIndicationController;
     }
+
+
+    /**
+     * A wrapper around another Drawable that overrides the intrinsic size.
+     */
+    private static class IntrinsicSizeDrawable extends InsetDrawable {
+
+        private final int mIntrinsicWidth;
+        private final int mIntrinsicHeight;
+
+        public IntrinsicSizeDrawable(Drawable drawable, int intrinsicWidth, int intrinsicHeight) {
+            super(drawable, 0);
+            mIntrinsicWidth = intrinsicWidth;
+            mIntrinsicHeight = intrinsicHeight;
+        }
+
+        @Override
+        public int getIntrinsicWidth() {
+            return mIntrinsicWidth;
+        }
+
+        @Override
+        public int getIntrinsicHeight() {
+            return mIntrinsicHeight;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index e8f35fd..bbe6622 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -227,7 +227,14 @@
         int id;
         if (record.isGuest && record.info == null) {
             // No guest user. Create one.
-            id = mUserManager.createGuest(mContext, mContext.getString(R.string.guest_nickname)).id;
+            UserInfo guest = mUserManager.createGuest(
+                    mContext, mContext.getString(R.string.guest_nickname));
+            if (guest == null) {
+                // Couldn't create guest, most likely because there already exists one, we just
+                // haven't reloaded the user list yet.
+                return;
+            }
+            id = guest.id;
         } else if (record.isAddUser) {
             showAddUserDialog();
             return;
@@ -564,8 +571,14 @@
                 cancel();
             } else {
                 dismiss();
-                int id = mUserManager.createUser(
-                        mContext.getString(R.string.user_new_user_name), 0 /* flags */).id;
+                UserInfo user = mUserManager.createUser(
+                        mContext.getString(R.string.user_new_user_name), 0 /* flags */);
+                if (user == null) {
+                    // Couldn't create user, most likely because there are too many, but we haven't
+                    // been able to reload the list yet.
+                    return;
+                }
+                int id = user.id;
                 Bitmap icon = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(
                         id, /* light= */ false));
                 mUserManager.setUserIcon(id, icon);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index c516874..57ed619 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -2125,8 +2125,7 @@
         }
     }
 
-    private final class DecorView extends FrameLayout implements RootViewSurfaceTaker,
-            View.OnSystemUiVisibilityChangeListener {
+    private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
         /* package */int mDefaultOpacity = PixelFormat.OPAQUE;
 
         /** The feature ID of the panel, or -1 if this is the application's DecorView */
@@ -2163,8 +2162,6 @@
         private int mLastTopInset = 0;
         private int mLastBottomInset = 0;
         private int mLastRightInset = 0;
-        private int mLastSystemUiVisibility = 0;
-        private int mLastWindowSystemUiVisibility = 0;
 
 
         public DecorView(Context context, int featureId) {
@@ -2745,14 +2742,7 @@
         }
 
         @Override
-        public void onSystemUiVisibilityChange(int visible) {
-            mLastSystemUiVisibility = visible;
-            updateColorViews(null /* insets */);
-        }
-
-        @Override
         public void onWindowSystemUiVisibilityChanged(int visible) {
-            mLastWindowSystemUiVisibility = visible;
             updateColorViews(null /* insets */);
         }
 
@@ -2774,6 +2764,9 @@
         }
 
         private WindowInsets updateColorViews(WindowInsets insets) {
+            WindowManager.LayoutParams attrs = getAttributes();
+            int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility();
+
             if (!mIsFloating && ActivityManager.isHighEndGfx()) {
                 if (insets != null) {
                     mLastTopInset = Math.min(insets.getStableInsetTop(),
@@ -2783,13 +2776,13 @@
                     mLastRightInset = Math.min(insets.getStableInsetRight(),
                             insets.getSystemWindowInsetRight());
                 }
-                mStatusColorView = updateColorViewInt(mStatusColorView,
+                mStatusColorView = updateColorViewInt(mStatusColorView, sysUiVisibility,
                         SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
                         mStatusBarColor, mLastTopInset, Gravity.TOP,
                         STATUS_BAR_BACKGROUND_TRANSITION_NAME,
                         com.android.internal.R.id.statusBarBackground,
                         (getAttributes().flags & FLAG_FULLSCREEN) != 0);
-                mNavigationColorView = updateColorViewInt(mNavigationColorView,
+                mNavigationColorView = updateColorViewInt(mNavigationColorView, sysUiVisibility,
                         SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION,
                         mNavigationBarColor, mLastBottomInset, Gravity.BOTTOM,
                         NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME,
@@ -2797,9 +2790,6 @@
                         false /* hiddenByWindowFlag */);
             }
 
-            WindowManager.LayoutParams attrs = getAttributes();
-            int sysUiVisibility = attrs.systemUiVisibility | mLastWindowSystemUiVisibility;
-
             // When we expand the window with FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, we still need
             // to ensure that the rest of the view hierarchy doesn't notice it, unless they've
             // explicitly asked for it.
@@ -2807,7 +2797,7 @@
             boolean consumingNavBar =
                     (attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
                             && (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0
-                            && (mLastSystemUiVisibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
+                            && (sysUiVisibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
 
             int consumedRight = consumingNavBar ? mLastRightInset : 0;
             int consumedBottom = consumingNavBar ? mLastBottomInset : 0;
@@ -2841,10 +2831,10 @@
             return insets;
         }
 
-        private View updateColorViewInt(View view, int systemUiHideFlag, int translucentFlag,
-                int color, int height, int verticalGravity, String transitionName, int id,
-                boolean hiddenByWindowFlag) {
-            boolean show = height > 0 && (mLastSystemUiVisibility & systemUiHideFlag) == 0
+        private View updateColorViewInt(View view, int sysUiVis, int systemUiHideFlag,
+                int translucentFlag, int color, int height, int verticalGravity,
+                String transitionName, int id, boolean hiddenByWindowFlag) {
+            boolean show = height > 0 && (sysUiVis & systemUiHideFlag) == 0
                     && !hiddenByWindowFlag
                     && (getAttributes().flags & translucentFlag) == 0
                     && (color & Color.BLACK) != 0
@@ -3320,7 +3310,6 @@
                 setFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
                         FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS & ~getForcedWindowFlags());
             }
-            decor.setOnSystemUiVisibilityChangeListener(decor);
         }
         if (!mForcedStatusBarColor) {
             mStatusBarColor = a.getColor(R.styleable.Window_statusBarColor, 0xFF000000);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index ebe21ff..24bfba6 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -3277,7 +3277,7 @@
                         // But we still have not gotten the window state from the
                         // window manager, so delay the notification until then.
                         AccessibilityWindowInfo window = findWindowById(event.getWindowId());
-                        if (window == null || !window.isFocused()) {
+                        if (window == null) {
                             mShowingFocusedWindowEvent = AccessibilityEvent.obtain(event);
                             return false;
                         }
@@ -3377,7 +3377,7 @@
             if (mShowingFocusedWindowEvent != null) {
                 final int windowId = mShowingFocusedWindowEvent.getWindowId();
                 AccessibilityWindowInfo window = findWindowById(windowId);
-                if (window != null && window.isFocused()) {
+                if (window != null) {
                     // Sending does the recycle.
                     sendAccessibilityEvent(mShowingFocusedWindowEvent, mCurrentUserId);
                 }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index dfec307..967681b 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1357,13 +1357,6 @@
                 "ConnectivityService");
     }
 
-    // TODO Make this a special check when it goes public
-    private void enforceTetherChangePermission() {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.CHANGE_NETWORK_STATE,
-                "ConnectivityService");
-    }
-
     private void enforceTetherAccessPermission() {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.ACCESS_NETWORK_STATE,
@@ -2389,8 +2382,7 @@
 
     // javadoc from interface
     public int tether(String iface) {
-        enforceTetherChangePermission();
-
+        ConnectivityManager.enforceTetherChangePermission(mContext);
         if (isTetheringSupported()) {
             return mTethering.tether(iface);
         } else {
@@ -2400,7 +2392,7 @@
 
     // javadoc from interface
     public int untether(String iface) {
-        enforceTetherChangePermission();
+        ConnectivityManager.enforceTetherChangePermission(mContext);
 
         if (isTetheringSupported()) {
             return mTethering.untether(iface);
@@ -2449,7 +2441,7 @@
     }
 
     public int setUsbTethering(boolean enable) {
-        enforceTetherChangePermission();
+        ConnectivityManager.enforceTetherChangePermission(mContext);
         if (isTetheringSupported()) {
             return mTethering.setUsbTethering(enable);
         } else {
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index fdcb3b9..cf2a49f 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -50,19 +50,16 @@
 
     // These are the built-in uid -> permission mappings that were read from the
     // system configuration files.
-    final SparseArray<HashSet<String>> mSystemPermissions =
-            new SparseArray<HashSet<String>>();
+    final SparseArray<HashSet<String>> mSystemPermissions = new SparseArray<>();
 
     // These are the built-in shared libraries that were read from the
     // system configuration files.  Keys are the library names; strings are the
     // paths to the libraries.
-    final ArrayMap<String, String> mSharedLibraries
-            = new ArrayMap<String, String>();
+    final ArrayMap<String, String> mSharedLibraries  = new ArrayMap<>();
 
     // These are the features this devices supports that were read from the
     // system configuration files.
-    final HashMap<String, FeatureInfo> mAvailableFeatures =
-            new HashMap<String, FeatureInfo>();
+    final HashMap<String, FeatureInfo> mAvailableFeatures = new HashMap<>();
 
     public static final class PermissionEntry {
         public final String name;
@@ -75,12 +72,14 @@
 
     // These are the permission -> gid mappings that were read from the
     // system configuration files.
-    final ArrayMap<String, PermissionEntry> mPermissions =
-            new ArrayMap<String, PermissionEntry>();
+    final ArrayMap<String, PermissionEntry> mPermissions = new ArrayMap<>();
 
     // These are the packages that are white-listed to be able to run in the
     // background while in power save mode, as read from the configuration files.
-    final ArraySet<String> mAllowInPowerSave = new ArraySet<String>();
+    final ArraySet<String> mAllowInPowerSave = new ArraySet<>();
+
+    // These are the app package names that should not allow IME switching.
+    final ArraySet<String> mFixedImeApps = new ArraySet<>();
 
     public static SystemConfig getInstance() {
         synchronized (SystemConfig.class) {
@@ -115,6 +114,10 @@
         return mAllowInPowerSave;
     }
 
+    public ArraySet<String> getFixedImeApps() {
+        return mFixedImeApps;
+    }
+
     SystemConfig() {
         // Read configuration from system
         readPermissions(Environment.buildPath(
@@ -298,6 +301,17 @@
                     XmlUtils.skipCurrentTag(parser);
                     continue;
 
+                } else if ("fixed-ime-app".equals(name)) {
+                    String pkgname = parser.getAttributeValue(null, "package");
+                    if (pkgname == null) {
+                        Slog.w(TAG, "<fixed-ime-app> without package at "
+                                + parser.getPositionDescription());
+                    } else {
+                        mFixedImeApps.add(pkgname);
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+
                 } else {
                     XmlUtils.skipCurrentTag(parser);
                     continue;
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index e043f03..adea271 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -917,6 +917,7 @@
             if (displayStartTime != 0) {
                 reportLaunchTimeLocked(SystemClock.uptimeMillis());
             }
+            mStackSupervisor.sendWaitingVisibleReportLocked(this);
             startTime = 0;
             finishLaunchTickingLocked();
             if (task != null) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 4940493..ebd0d4e9 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -650,31 +650,47 @@
     }
 
     void reportActivityVisibleLocked(ActivityRecord r) {
+        sendWaitingVisibleReportLocked(r);
+        notifyActivityDrawnForKeyguard();
+    }
+
+    void sendWaitingVisibleReportLocked(ActivityRecord r) {
+        boolean changed = false;
         for (int i = mWaitingActivityVisible.size()-1; i >= 0; i--) {
             WaitResult w = mWaitingActivityVisible.get(i);
-            w.timeout = false;
-            if (r != null) {
-                w.who = new ComponentName(r.info.packageName, r.info.name);
+            if (w.who == null) {
+                changed = true;
+                w.timeout = false;
+                if (r != null) {
+                    w.who = new ComponentName(r.info.packageName, r.info.name);
+                }
+                w.totalTime = SystemClock.uptimeMillis() - w.thisTime;
+                w.thisTime = w.totalTime;
             }
-            w.totalTime = SystemClock.uptimeMillis() - w.thisTime;
-            w.thisTime = w.totalTime;
         }
-        mService.notifyAll();
-        notifyActivityDrawnForKeyguard();
+        if (changed) {
+            mService.notifyAll();
+        }
     }
 
     void reportActivityLaunchedLocked(boolean timeout, ActivityRecord r,
             long thisTime, long totalTime) {
+        boolean changed = false;
         for (int i = mWaitingActivityLaunched.size() - 1; i >= 0; i--) {
             WaitResult w = mWaitingActivityLaunched.remove(i);
-            w.timeout = timeout;
-            if (r != null) {
-                w.who = new ComponentName(r.info.packageName, r.info.name);
+            if (w.who == null) {
+                changed = true;
+                w.timeout = timeout;
+                if (r != null) {
+                    w.who = new ComponentName(r.info.packageName, r.info.name);
+                }
+                w.thisTime = thisTime;
+                w.totalTime = totalTime;
             }
-            w.thisTime = thisTime;
-            w.totalTime = totalTime;
         }
-        mService.notifyAll();
+        if (changed) {
+            mService.notifyAll();
+        }
     }
 
     ActivityRecord topRunningActivityLocked() {
@@ -936,7 +952,7 @@
                     } while (!outResult.timeout && outResult.who == null);
                 } else if (res == ActivityManager.START_TASK_TO_FRONT) {
                     ActivityRecord r = stack.topRunningActivityLocked(null);
-                    if (r.nowVisible) {
+                    if (r.nowVisible && r.state == ActivityState.RESUMED) {
                         outResult.timeout = false;
                         outResult.who = new ComponentName(r.info.packageName, r.info.name);
                         outResult.totalTime = 0;
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 4de7367..f74b795 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -327,8 +327,8 @@
             }
         }
 
-        if (intent != null &&
-                (intent.getFlags()&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
+        final int intentFlags = intent == null ? 0 : intent.getFlags();
+        if ((intentFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
             // Once we are set to an Intent with this flag, we count this
             // task as having a true root activity.
             rootWasReset = true;
@@ -338,8 +338,8 @@
         if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
             // If the activity itself has requested auto-remove, then just always do it.
             autoRemoveRecents = true;
-        } else if ((intent.getFlags()&(Intent.FLAG_ACTIVITY_NEW_DOCUMENT
-                |Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS)) == Intent.FLAG_ACTIVITY_NEW_DOCUMENT) {
+        } else if ((intentFlags & (Intent.FLAG_ACTIVITY_NEW_DOCUMENT
+                | Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS)) == Intent.FLAG_ACTIVITY_NEW_DOCUMENT) {
             // If the caller has not asked for the document to be retained, then we may
             // want to turn on auto-remove, depending on whether the target has set its
             // own document launch mode.
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index df846a8..f1c5a6c 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -162,6 +162,10 @@
     private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008;
     private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010;
 
+    // The AGPS SUPL mode
+    private static final int AGPS_SUPL_MODE_MSA = 0x02;
+    private static final int AGPS_SUPL_MODE_MSB = 0x01;
+
     // these need to match AGpsType enum in gps.h
     private static final int AGPS_TYPE_SUPL = 1;
     private static final int AGPS_TYPE_C2K = 2;
@@ -486,12 +490,9 @@
             } else if (action.equals(SIM_STATE_CHANGED)) {
                 TelephonyManager phone = (TelephonyManager)
                         mContext.getSystemService(Context.TELEPHONY_SERVICE);
-                int simState = phone.getSimState();
-                Log.d(TAG, "SIM STATE CHANGED to " + simState);
                 String mccMnc = phone.getSimOperator();
-                if (simState == TelephonyManager.SIM_STATE_READY &&
-                    !TextUtils.isEmpty(mccMnc)) {
-                    Log.d(TAG, "SIM STATE is ready, SIM MCC/MNC is " + mccMnc);
+                if (!TextUtils.isEmpty(mccMnc)) {
+                    Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc);
                     synchronized (mLock) {
                         reloadGpsProperties(context, mProperties);
                         mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
@@ -922,6 +923,39 @@
         }
     }
 
+    /**
+     * Checks what SUPL mode to use, according to the AGPS mode as well as the
+     * allowed mode from properties.
+     *
+     * @param properties GPS properties
+     * @param agpsEnabled whether AGPS is enabled by settings value
+     * @param singleShot whether "singleshot" is needed
+     * @return SUPL mode (MSA vs MSB vs STANDALONE)
+     */
+    private int getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot) {
+        if (agpsEnabled) {
+            String modeString = properties.getProperty("SUPL_MODE");
+            int suplMode = 0;
+            if (!TextUtils.isEmpty(modeString)) {
+                try {
+                    suplMode = Integer.parseInt(modeString);
+                } catch (NumberFormatException e) {
+                    Log.e(TAG, "unable to parse SUPL_MODE: " + modeString);
+                    return GPS_POSITION_MODE_STANDALONE;
+                }
+            }
+            if (singleShot
+                    && hasCapability(GPS_CAPABILITY_MSA)
+                    && (suplMode & AGPS_SUPL_MODE_MSA) != 0) {
+                return GPS_POSITION_MODE_MS_ASSISTED;
+            } else if (hasCapability(GPS_CAPABILITY_MSB)
+                    && (suplMode & AGPS_SUPL_MODE_MSB) != 0) {
+                return GPS_POSITION_MODE_MS_BASED;
+            }
+        }
+        return GPS_POSITION_MODE_STANDALONE;
+    }
+
     private void handleEnable() {
         if (DEBUG) Log.d(TAG, "handleEnable");
 
@@ -1199,14 +1233,10 @@
             mSingleShot = singleShot;
             mPositionMode = GPS_POSITION_MODE_STANDALONE;
 
-             if (Settings.Global.getInt(mContext.getContentResolver(),
-                    Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0) {
-                if (singleShot && hasCapability(GPS_CAPABILITY_MSA)) {
-                    mPositionMode = GPS_POSITION_MODE_MS_ASSISTED;
-                } else if (hasCapability(GPS_CAPABILITY_MSB)) {
-                    mPositionMode = GPS_POSITION_MODE_MS_BASED;
-                }
-            }
+            boolean agpsEnabled =
+                    (Settings.Global.getInt(mContext.getContentResolver(),
+                                            Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0);
+            mPositionMode = getSuplMode(mProperties, agpsEnabled, singleShot);
 
             if (DEBUG) {
                 String mode;