Merge "Fix keyguard pin/simpin/simpuk RTL-ization" into jb-mr1.1-dev
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index cb61a71..24fd2e4 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -224,6 +224,22 @@
         }
     }
 
+    /**
+     * Gets a list of all the appWidgetIds that are bound to the current host
+     *
+     * @hide
+     */
+    public int[] getAppWidgetIds() {
+        try {
+            if (sService == null) {
+                bindService();
+            }
+            return sService.getAppWidgetIdsForHost(mHostId);
+        } catch (RemoteException e) {
+            throw new RuntimeException("system server dead?", e);
+        }
+    }
+
     private static void checkCallerIsSystem() {
         int uid = Process.myUid();
         if (UserHandle.getAppId(uid) == Process.SYSTEM_UID || uid == 0) {
diff --git a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
index cfb16fa..b63ad62 100644
--- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
+++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
@@ -38,6 +38,7 @@
     void deleteHost(int hostId);
     void deleteAllHosts();
     RemoteViews getAppWidgetViews(int appWidgetId);
+    int[] getAppWidgetIdsForHost(int hostId);
 
     //
     // for AppWidgetManager
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 13d1791..83ecdd9 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -134,6 +134,7 @@
     <assign-permission name="android.permission.ACCESS_NETWORK_STATE" uid="shell" />
     <assign-permission name="android.permission.ACCESS_WIFI_STATE" uid="shell" />
     <assign-permission name="android.permission.BLUETOOTH" uid="shell" />
+    <assign-permission name="android.permission.EXPAND_STATUS_BAR" uid="shell" />
     <!-- System tool permissions granted to the shell. -->
     <assign-permission name="android.permission.GET_TASKS" uid="shell" />
     <assign-permission name="android.permission.CHANGE_CONFIGURATION" uid="shell" />
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index 31b2f3b..23c102e 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -7,20 +7,20 @@
 sdk.win32_bundle_checksum=42d9a6c15113d405a97eed05e6d42e2b
 
 sdk.win64_bundle_download=adt-bundle-windows-x86_64.zip
-sdk.win64_bundle_bytes=417975502
-sdk.win64_bundle_checksum=9c8ef6855764ecc516ee9d1664405461
+sdk.win64_bundle_bytes=417851515
+sdk.win64_bundle_checksum=73bdd1168fce0e36a27255a4335c865d
 
 sdk.mac64_bundle_download=adt-bundle-mac-x86_64.zip
-sdk.mac64_bundle_bytes=383081781
-sdk.mac64_bundle_checksum=3e39d683361901226183730f717bc4ee
+sdk.mac64_bundle_bytes=382957959
+sdk.mac64_bundle_checksum=a320f8bbaee8572a36e68c434564bdd0
 
 sdk.linux32_bundle_download=adt-bundle-linux-x86.zip
 sdk.linux32_bundle_bytes=411065882
 sdk.linux32_bundle_checksum=39687b06fedfea7487ff0824a4d32ee8
 
 sdk.linux64_bundle_download=adt-bundle-linux-x86_64.zip
-sdk.linux64_bundle_bytes=411339954
-sdk.linux64_bundle_checksum=b92a799faf94ee445e34b12a50bf9d08
+sdk.linux64_bundle_bytes=411217430
+sdk.linux64_bundle_checksum=b0590fe9c1533da9b20ea65525b77677
 
 
 
diff --git a/docs/html/training/perf-anr.jd b/docs/html/training/articles/perf-anr.jd
similarity index 100%
rename from docs/html/training/perf-anr.jd
rename to docs/html/training/articles/perf-anr.jd
diff --git a/docs/html/training/perf-jni.jd b/docs/html/training/articles/perf-jni.jd
similarity index 100%
rename from docs/html/training/perf-jni.jd
rename to docs/html/training/articles/perf-jni.jd
diff --git a/docs/html/training/perf-tips.jd b/docs/html/training/articles/perf-tips.jd
similarity index 100%
rename from docs/html/training/perf-tips.jd
rename to docs/html/training/articles/perf-tips.jd
diff --git a/docs/html/training/security-tips.jd b/docs/html/training/articles/security-tips.jd
similarity index 100%
rename from docs/html/training/security-tips.jd
rename to docs/html/training/articles/security-tips.jd
diff --git a/docs/html/training/index.jd b/docs/html/training/index.jd
index 85fa19d..72ad018 100644
--- a/docs/html/training/index.jd
+++ b/docs/html/training/index.jd
@@ -5,8 +5,8 @@
 @jd:body
 
 
-<p>Welcome to Training. Each class provides a series of lessons that
-describe how to accomplish a specific task with code samples you can re-use in your app.
+<p>Welcome to Training for Android developers. Here you'll find sets of lessons within classes
+that describe how to accomplish a specific task with code samples you can re-use in your app.
 Classes are organized into several groups you can see at the top-level of the left navigation.</p>
 
 <p>This first group, <em>Getting Started</em>, teaches you the bare
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index ece5582..abce37a 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -775,7 +775,7 @@
     <ul>
       
       <li>
-        <a href="<?cs var:toroot ?>training/perf-tips.html"
+        <a href="<?cs var:toroot ?>training/articles/perf-tips.html"
            description=
            "How to optimize your app's performance in various ways to improve its
            responsiveness and battery efficiency."
@@ -851,7 +851,7 @@
       </li>
       
       <li>
-        <a href="<?cs var:toroot ?>training/perf-anr.html"
+        <a href="<?cs var:toroot ?>training/articles/perf-anr.html"
            description=
            "How to keep your app responsive to user interaction so the UI does not lock-up and
            display an &quot;Application Not Responding&quot; dialog."
@@ -859,7 +859,7 @@
       </li>
       
       <li>
-        <a href="<?cs var:toroot ?>training/perf-jni.html"
+        <a href="<?cs var:toroot ?>training/articles/perf-jni.html"
            description=
            "How to efficiently use the Java Native Interface with the Android NDK."
           >JNI Tips</a>
@@ -879,7 +879,7 @@
     <ul>
 
       <li>
-        <a href="<?cs var:toroot ?>training/security-tips.html"
+        <a href="<?cs var:toroot ?>training/articles/security-tips.html"
            description=
            "How to perform various tasks and keep your app's data and your user's data secure."
           >Security Tips</a>
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
index de19bd5..0e25c84 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -26,7 +26,6 @@
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
-import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -128,6 +127,8 @@
         mLockPatternUtils = new LockPatternUtils(context);
         mAppWidgetHost = new AppWidgetHost(
                 context, APPWIDGET_HOST_ID, mOnClickHandler, Looper.myLooper());
+        cleanupAppWidgetIds();
+
         mAppWidgetManager = AppWidgetManager.getInstance(mContext);
         mSecurityModel = new KeyguardSecurityModel(context);
 
@@ -153,6 +154,33 @@
         }
     }
 
+    private void cleanupAppWidgetIds() {
+        // Clean up appWidgetIds that are bound to lockscreen, but not actually used
+        // This is only to clean up after another bug: we used to not call
+        // deleteAppWidgetId when a user manually deleted a widget in keyguard. This code
+        // shouldn't have to run more than once per user. AppWidgetProviders rely on callbacks
+        // that are triggered by deleteAppWidgetId, which is why we're doing this
+        int[] appWidgetIdsInKeyguardSettings = mLockPatternUtils.getAppWidgets();
+        int[] appWidgetIdsBoundToHost = mAppWidgetHost.getAppWidgetIds();
+        for (int i = 0; i < appWidgetIdsBoundToHost.length; i++) {
+            int appWidgetId = appWidgetIdsBoundToHost[i];
+            if (!contains(appWidgetIdsInKeyguardSettings, appWidgetId)) {
+                Log.d(TAG, "Found a appWidgetId that's not being used by keyguard, deleting id "
+                        + appWidgetId);
+                mAppWidgetHost.deleteAppWidgetId(appWidgetId);
+            }
+        }
+    }
+
+    private static boolean contains(int[] array, int target) {
+        for (int value : array) {
+            if (value == target) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private KeyguardUpdateMonitorCallback mUpdateMonitorCallbacks =
             new KeyguardUpdateMonitorCallback() {
         @Override
@@ -331,10 +359,17 @@
         };
 
         @Override
-        public void onRemoveView(View v) {
+        public void onRemoveView(View v, boolean deletePermanently) {
             if (numWidgets() < MAX_WIDGETS) {
                 setAddWidgetEnabled(true);
             }
+            if (deletePermanently) {
+                final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
+                if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID &&
+                        appWidgetId != LockPatternUtils.ID_DEFAULT_STATUS_WIDGET) {
+                    mAppWidgetHost.deleteAppWidgetId(appWidgetId);
+                }
+            }
         }
     };
 
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
index 25e2781..85b5472 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
@@ -237,7 +237,7 @@
         public void userActivity();
         public void onUserActivityTimeoutChanged();
         public void onAddView(View v);
-        public void onRemoveView(View v);
+        public void onRemoveView(View v, boolean deletePermanently);
     }
 
     public void addWidget(View widget) {
@@ -245,10 +245,10 @@
     }
 
 
-    public void onRemoveView(View v) {
+    public void onRemoveView(View v, final boolean deletePermanently) {
         final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
         if (mCallbacks != null) {
-            mCallbacks.onRemoveView(v);
+            mCallbacks.onRemoveView(v, deletePermanently);
         }
         mBackgroundWorkerHandler.post(new Runnable() {
             @Override
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java b/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
index 3900ab4..0b06306 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
@@ -1457,7 +1457,7 @@
                                 }
 
                                 removeView(mDragView);
-                                onRemoveView(mDragView);
+                                onRemoveView(mDragView, false);
                                 addView(mDragView, pageUnderPointIndex);
                                 onAddView(mDragView, pageUnderPointIndex);
                                 mSidePageHoverIndex = -1;
@@ -1587,7 +1587,7 @@
     }
 
     //public abstract void onFlingToDelete(View v);
-    public abstract void onRemoveView(View v);
+    public abstract void onRemoveView(View v, boolean deletePermanently);
     public abstract void onAddView(View v, int index);
 
     private void resetTouchState() {
@@ -2391,7 +2391,7 @@
                 slideAnimations.start();
 
                 removeView(dragView);
-                onRemoveView(dragView);
+                onRemoveView(dragView, true);
             }
         };
     }
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 532b36a..9590712 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -146,6 +146,11 @@
         return getImplForUser(getCallingOrCurrentUserId()).allocateAppWidgetId(
                 packageName, hostId);
     }
+
+    @Override
+    public int[] getAppWidgetIdsForHost(int hostId) throws RemoteException {
+        return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetIdsForHost(hostId);
+    }
     
     @Override
     public void deleteAppWidgetId(int appWidgetId) throws RemoteException {
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index d2354a6..fe92b26 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -1358,6 +1358,28 @@
         }
     }
 
+    static int[] getAppWidgetIds(Host h) {
+        int instancesSize = h.instances.size();
+        int appWidgetIds[] = new int[instancesSize];
+        for (int i = 0; i < instancesSize; i++) {
+            appWidgetIds[i] = h.instances.get(i).appWidgetId;
+        }
+        return appWidgetIds;
+    }
+
+    public int[] getAppWidgetIdsForHost(int hostId) {
+        synchronized (mAppWidgetIds) {
+            ensureStateLoadedLocked();
+            int callingUid = Binder.getCallingUid();
+            Host host = lookupHostLocked(callingUid, hostId);
+            if (host != null) {
+                return getAppWidgetIds(host);
+            } else {
+                return new int[0];
+            }
+        }
+    }
+
     private Provider parseProviderInfoXml(ComponentName component, ResolveInfo ri) {
         Provider p = null;
 
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index 66c3ce9..dbfe34d 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -88,7 +88,7 @@
 
     private static final int MIN_USER_ID = 10;
 
-    private static final int USER_VERSION = 1;
+    private static final int USER_VERSION = 2;
 
     private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms
 
@@ -484,8 +484,7 @@
     }
 
     /**
-     * This fixes an incorrect initialization of user name for the owner.
-     * TODO: Remove in the next release.
+     * Upgrade steps between versions, either for fixing bugs or changing the data format.
      */
     private void upgradeIfNecessary() {
         int userVersion = mUserVersion;
@@ -499,6 +498,16 @@
             userVersion = 1;
         }
 
+        if (userVersion < 2) {
+            // Owner should be marked as initialized
+            UserInfo user = mUsers.get(UserHandle.USER_OWNER);
+            if ((user.flags & UserInfo.FLAG_INITIALIZED) == 0) {
+                user.flags |= UserInfo.FLAG_INITIALIZED;
+                writeUserLocked(user);
+            }
+            userVersion = 2;
+        }
+
         if (userVersion < USER_VERSION) {
             Slog.w(LOG_TAG, "User version " + mUserVersion + " didn't upgrade as expected to "
                     + USER_VERSION);