Merge "Fix PackageInstaller displays with multi-user" into jb-mr1-dev
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2a8cf21..3bbdf36 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -911,17 +911,20 @@
         }
 
         private static final HashSet<String> MOVED_TO_GLOBAL;
+        private static final HashSet<String> MOVED_TO_SECURE_THEN_GLOBAL;
         static {
             MOVED_TO_GLOBAL = new HashSet<String>();
+            MOVED_TO_SECURE_THEN_GLOBAL = new HashSet<String>();
+
             // these were originally in system but migrated to secure in the past,
             // so are duplicated in the Secure.* namespace
-            MOVED_TO_GLOBAL.add(Global.ADB_ENABLED);
-            MOVED_TO_GLOBAL.add(Global.BLUETOOTH_ON);
-            MOVED_TO_GLOBAL.add(Global.DATA_ROAMING);
-            MOVED_TO_GLOBAL.add(Global.DEVICE_PROVISIONED);
-            MOVED_TO_GLOBAL.add(Global.INSTALL_NON_MARKET_APPS);
-            MOVED_TO_GLOBAL.add(Global.USB_MASS_STORAGE_ENABLED);
-            MOVED_TO_GLOBAL.add(Global.HTTP_PROXY);
+            MOVED_TO_SECURE_THEN_GLOBAL.add(Global.ADB_ENABLED);
+            MOVED_TO_SECURE_THEN_GLOBAL.add(Global.BLUETOOTH_ON);
+            MOVED_TO_SECURE_THEN_GLOBAL.add(Global.DATA_ROAMING);
+            MOVED_TO_SECURE_THEN_GLOBAL.add(Global.DEVICE_PROVISIONED);
+            MOVED_TO_SECURE_THEN_GLOBAL.add(Global.INSTALL_NON_MARKET_APPS);
+            MOVED_TO_SECURE_THEN_GLOBAL.add(Global.USB_MASS_STORAGE_ENABLED);
+            MOVED_TO_SECURE_THEN_GLOBAL.add(Global.HTTP_PROXY);
 
             // these are moving directly from system to global
             MOVED_TO_GLOBAL.add(Settings.Global.AIRPLANE_MODE_ON);
@@ -954,6 +957,17 @@
             MOVED_TO_GLOBAL.add(Settings.Global.ALWAYS_FINISH_ACTIVITIES);
         }
 
+        /** @hide */
+        public static void getMovedKeys(HashSet<String> outKeySet) {
+            outKeySet.addAll(MOVED_TO_GLOBAL);
+            outKeySet.addAll(MOVED_TO_SECURE_THEN_GLOBAL);
+        }
+
+        /** @hide */
+        public static void getNonLegacyMovedKeys(HashSet<String> outKeySet) {
+            outKeySet.addAll(MOVED_TO_GLOBAL);
+        }
+
         /**
          * Look up a name in the database.
          * @param resolver to access the database with
@@ -972,7 +986,7 @@
                         + " to android.provider.Settings.Secure, returning read-only value.");
                 return Secure.getStringForUser(resolver, name, userHandle);
             }
-            if (MOVED_TO_GLOBAL.contains(name)) {
+            if (MOVED_TO_GLOBAL.contains(name) || MOVED_TO_SECURE_THEN_GLOBAL.contains(name)) {
                 Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
                         + " to android.provider.Settings.Global, returning read-only value.");
                 return Global.getStringForUser(resolver, name, userHandle);
@@ -999,7 +1013,7 @@
                         + " to android.provider.Settings.Secure, value is unchanged.");
                 return false;
             }
-            if (MOVED_TO_GLOBAL.contains(name)) {
+            if (MOVED_TO_GLOBAL.contains(name) || MOVED_TO_SECURE_THEN_GLOBAL.contains(name)) {
                 Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
                         + " to android.provider.Settings.Global, value is unchanged.");
                 return false;
@@ -1019,7 +1033,7 @@
                     + " to android.provider.Settings.Secure, returning Secure URI.");
                 return Secure.getUriFor(Secure.CONTENT_URI, name);
             }
-            if (MOVED_TO_GLOBAL.contains(name)) {
+            if (MOVED_TO_GLOBAL.contains(name) || MOVED_TO_SECURE_THEN_GLOBAL.contains(name)) {
                 Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
                         + " to android.provider.Settings.Global, returning read-only global URI.");
                 return Global.getUriFor(Global.CONTENT_URI, name);
@@ -2257,7 +2271,7 @@
          * @hide
          */
         public static final String[] SETTINGS_TO_BACKUP = {
-            STAY_ON_WHILE_PLUGGED_IN,
+            STAY_ON_WHILE_PLUGGED_IN,   // moved to global
             WIFI_USE_STATIC_IP,
             WIFI_STATIC_IP,
             WIFI_STATIC_GATEWAY,
@@ -2272,7 +2286,7 @@
             SCREEN_BRIGHTNESS_MODE,
             SCREEN_AUTO_BRIGHTNESS_ADJ,
             VIBRATE_INPUT_DEVICES,
-            MODE_RINGER,
+            MODE_RINGER,                // moved to global
             MODE_RINGER_STREAMS_AFFECTED,
             MUTE_STREAMS_AFFECTED,
             VOLUME_VOICE,
@@ -2293,20 +2307,18 @@
             TEXT_AUTO_CAPS,
             TEXT_AUTO_PUNCTUATE,
             TEXT_SHOW_PASSWORD,
-            AUTO_TIME,
-            AUTO_TIME_ZONE,
+            AUTO_TIME,                  // moved to global
+            AUTO_TIME_ZONE,             // moved to global
             TIME_12_24,
             DATE_FORMAT,
             DTMF_TONE_WHEN_DIALING,
             DTMF_TONE_TYPE_WHEN_DIALING,
-            Global.EMERGENCY_TONE,
-            Global.CALL_AUTO_RETRY,
             HEARING_AID,
             TTY_MODE,
             SOUND_EFFECTS_ENABLED,
             HAPTIC_FEEDBACK_ENABLED,
-            POWER_SOUNDS_ENABLED,
-            DOCK_SOUNDS_ENABLED,
+            POWER_SOUNDS_ENABLED,       // moved to global
+            DOCK_SOUNDS_ENABLED,        // moved to global
             LOCKSCREEN_SOUNDS_ENABLED,
             SHOW_WEB_SUGGESTIONS,
             NOTIFICATION_LIGHT_PULSE,
@@ -2702,6 +2714,11 @@
             MOVED_TO_GLOBAL.add(Settings.Global.PREFERRED_CDMA_SUBSCRIPTION);
         }
 
+        /** @hide */
+        public static void getMovedKeys(HashSet<String> outKeySet) {
+            outKeySet.addAll(MOVED_TO_GLOBAL);
+        }
+
         /**
          * Look up a name in the database.
          * @param resolver to access the database with
@@ -3993,12 +4010,11 @@
          * @hide
          */
         public static final String[] SETTINGS_TO_BACKUP = {
-            ADB_ENABLED,
             BUGREPORT_IN_POWER_MENU,
             ALLOW_MOCK_LOCATION,
             PARENTAL_CONTROL_ENABLED,
             PARENTAL_CONTROL_REDIRECT_URL,
-            USB_MASS_STORAGE_ENABLED,
+            USB_MASS_STORAGE_ENABLED,                           // moved to global
             ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
             ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
             ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE,
@@ -4017,9 +4033,9 @@
             TTS_DEFAULT_COUNTRY,
             TTS_ENABLED_PLUGINS,
             TTS_DEFAULT_LOCALE,
-            WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
-            WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
-            WIFI_NUM_OPEN_NETWORKS_KEPT,
+            WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,            // moved to global
+            WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,               // moved to global
+            WIFI_NUM_OPEN_NETWORKS_KEPT,                        // moved to global
             MOUNT_PLAY_NOTIFICATION_SND,
             MOUNT_UMS_AUTOSTART,
             MOUNT_UMS_PROMPT,
@@ -5251,6 +5267,38 @@
         public static final String ALWAYS_FINISH_ACTIVITIES =
                 "always_finish_activities";
 
+        /**
+         * Settings to backup. This is here so that it's in the same place as the settings
+         * keys and easy to update.
+         *
+         * These keys may be mentioned in the SETTINGS_TO_BACKUP arrays in System
+         * and Secure as well.  This is because those tables drive both backup and
+         * restore, and restore needs to properly whitelist keys that used to live
+         * in those namespaces.  The keys will only actually be backed up / restored
+         * if they are also mentioned in this table (Global.SETTINGS_TO_BACKUP).
+         *
+         * NOTE: Settings are backed up and restored in the order they appear
+         *       in this array. If you have one setting depending on another,
+         *       make sure that they are ordered appropriately.
+         *
+         * @hide
+         */
+        public static final String[] SETTINGS_TO_BACKUP = {
+            STAY_ON_WHILE_PLUGGED_IN,
+            MODE_RINGER,
+            AUTO_TIME,
+            AUTO_TIME_ZONE,
+            POWER_SOUNDS_ENABLED,
+            DOCK_SOUNDS_ENABLED,
+            USB_MASS_STORAGE_ENABLED,
+            ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED,
+            WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+            WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
+            WIFI_NUM_OPEN_NETWORKS_KEPT,
+            EMERGENCY_TONE,
+            CALL_AUTO_RETRY,
+        };
+
         // Populated lazily, guarded by class object:
         private static NameValueCache sNameValueCache = new NameValueCache(
                     SYS_PROP_SETTING_VERSION,
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index c67cae6..19b825c 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -122,6 +122,7 @@
     InputMethodState mInputMethodState;
 
     DisplayList[] mTextDisplayLists;
+    int mLastLayoutHeight;
 
     boolean mFrozenWithFocus;
     boolean mSelectionMoved;
@@ -1258,6 +1259,16 @@
                 mTextDisplayLists = new DisplayList[ArrayUtils.idealObjectArraySize(0)];
             }
 
+            // If the height of the layout changes (usually when inserting or deleting a line,
+            // but could be changes within a span), invalidate everything. We could optimize
+            // more aggressively (for example, adding offsets to blocks) but it would be more
+            // complex and we would only get the benefit in some cases.
+            int layoutHeight = layout.getHeight();
+            if (mLastLayoutHeight != layoutHeight) {
+                invalidateTextDisplayList();
+                mLastLayoutHeight = layoutHeight;
+            }
+
             DynamicLayout dynamicLayout = (DynamicLayout) layout;
             int[] blockEndLines = dynamicLayout.getBlockEndLines();
             int[] blockIndices = dynamicLayout.getBlockIndices();
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index 317baf1..925864c 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -30,8 +30,11 @@
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.PopupWindow.OnDismissListener;
 
 
 /**
@@ -978,6 +981,30 @@
             super.show();
             getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
             setSelection(Spinner.this.getSelectedItemPosition());
+
+            // Make sure we hide if our anchor goes away.
+            // TODO: This might be appropriate to push all the way down to PopupWindow,
+            // but it may have other side effects to investigate first. (Text editing handles, etc.)
+            final ViewTreeObserver vto = getViewTreeObserver();
+            if (vto != null) {
+                final OnGlobalLayoutListener layoutListener = new OnGlobalLayoutListener() {
+                    @Override
+                    public void onGlobalLayout() {
+                        if (!Spinner.this.isVisibleToUser()) {
+                            dismiss();
+                        }
+                    }
+                };
+                vto.addOnGlobalLayoutListener(layoutListener);
+                setOnDismissListener(new OnDismissListener() {
+                    @Override public void onDismiss() {
+                        final ViewTreeObserver vto = getViewTreeObserver();
+                        if (vto != null) {
+                            vto.removeOnGlobalLayoutListener(layoutListener);
+                        }
+                    }
+                });
+            }
         }
     }
 }
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 0d9cf9a..6c5ed7e 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -375,31 +375,31 @@
     }
 
     private void notifyCellAdded() {
+        sendAccessEvent(R.string.lockscreen_access_pattern_cell_added);
         if (mOnPatternListener != null) {
             mOnPatternListener.onPatternCellAdded(mPattern);
         }
-        sendAccessEvent(R.string.lockscreen_access_pattern_cell_added);
     }
 
     private void notifyPatternStarted() {
+        sendAccessEvent(R.string.lockscreen_access_pattern_start);
         if (mOnPatternListener != null) {
             mOnPatternListener.onPatternStart();
         }
-        sendAccessEvent(R.string.lockscreen_access_pattern_start);
     }
 
     private void notifyPatternDetected() {
+        sendAccessEvent(R.string.lockscreen_access_pattern_detected);
         if (mOnPatternListener != null) {
             mOnPatternListener.onPatternDetected(mPattern);
         }
-        sendAccessEvent(R.string.lockscreen_access_pattern_detected);
     }
 
     private void notifyPatternCleared() {
+        sendAccessEvent(R.string.lockscreen_access_pattern_cleared);
         if (mOnPatternListener != null) {
             mOnPatternListener.onPatternCleared();
         }
-        sendAccessEvent(R.string.lockscreen_access_pattern_cleared);
     }
 
     /**
@@ -799,9 +799,7 @@
     }
 
     private void sendAccessEvent(int resId) {
-        setContentDescription(mContext.getString(resId));
-        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
-        setContentDescription(null);
+        announceForAccessibility(mContext.getString(resId));
     }
 
     private void handleActionUp(MotionEvent event) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 1096540..ba7501b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -46,7 +46,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.io.Reader;
 import java.io.Writer;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -64,25 +63,35 @@
 
     private static final String KEY_SYSTEM = "system";
     private static final String KEY_SECURE = "secure";
+    private static final String KEY_GLOBAL = "global";
     private static final String KEY_LOCALE = "locale";
 
-    //Version 2 adds STATE_WIFI_CONFIG
-    private static final int STATE_VERSION_1       = 1;
-    private static final int STATE_VERSION_1_SIZE  = 4;
-
     // Versioning of the state file.  Increment this version
     // number any time the set of state items is altered.
-    private static final int STATE_VERSION = 2;
+    private static final int STATE_VERSION = 3;
 
+    // Slots in the checksum array.  Never insert new items in the middle
+    // of this array; new slots must be appended.
     private static final int STATE_SYSTEM          = 0;
     private static final int STATE_SECURE          = 1;
     private static final int STATE_LOCALE          = 2;
     private static final int STATE_WIFI_SUPPLICANT = 3;
     private static final int STATE_WIFI_CONFIG     = 4;
-    private static final int STATE_SIZE            = 5; // The number of state items
+    private static final int STATE_GLOBAL          = 5;
+
+    private static final int STATE_SIZE            = 6; // The current number of state items
+
+    // Number of entries in the checksum array at various version numbers
+    private static final int STATE_SIZES[] = {
+        0,
+        4,              // version 1
+        5,              // version 2 added STATE_WIFI_CONFIG
+        STATE_SIZE      // version 3 added STATE_GLOBAL
+    };
 
     // Versioning of the 'full backup' format
-    private static final int FULL_BACKUP_VERSION = 1;
+    private static final int FULL_BACKUP_VERSION = 2;
+    private static final int FULL_BACKUP_ADDED_GLOBAL = 2;  // added the "global" entry
 
     private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE;
 
@@ -257,6 +266,7 @@
 
         byte[] systemSettingsData = getSystemSettings();
         byte[] secureSettingsData = getSecureSettings();
+        byte[] globalSettingsData = getGlobalSettings();
         byte[] locale = mSettingsHelper.getLocaleData();
         byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
         byte[] wifiConfigData = getFileData(mWifiConfigFile);
@@ -267,6 +277,8 @@
             writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data);
         stateChecksums[STATE_SECURE] =
             writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
+        stateChecksums[STATE_GLOBAL] =
+            writeIfChanged(stateChecksums[STATE_GLOBAL], KEY_GLOBAL, secureSettingsData, data);
         stateChecksums[STATE_LOCALE] =
             writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
         stateChecksums[STATE_WIFI_SUPPLICANT] =
@@ -283,14 +295,18 @@
     public void onRestore(BackupDataInput data, int appVersionCode,
             ParcelFileDescriptor newState) throws IOException {
 
+        HashSet<String> movedToGlobal = new HashSet<String>();
+        Settings.System.getMovedKeys(movedToGlobal);
+        Settings.Secure.getMovedKeys(movedToGlobal);
+
         while (data.readNextHeader()) {
             final String key = data.getKey();
             final int size = data.getDataSize();
             if (KEY_SYSTEM.equals(key)) {
-                restoreSettings(data, Settings.System.CONTENT_URI);
+                restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal);
                 mSettingsHelper.applyAudioSettings();
             } else if (KEY_SECURE.equals(key)) {
-                restoreSettings(data, Settings.Secure.CONTENT_URI);
+                restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal);
             } else if (KEY_WIFI_SUPPLICANT.equals(key)) {
                 int retainedWifiState = enableWifi(false);
                 restoreWifiSupplicant(FILE_WIFI_SUPPLICANT, data);
@@ -317,6 +333,7 @@
     public void onFullBackup(FullBackupDataOutput data)  throws IOException {
         byte[] systemSettingsData = getSystemSettings();
         byte[] secureSettingsData = getSecureSettings();
+        byte[] globalSettingsData = getGlobalSettings();
         byte[] locale = mSettingsHelper.getLocaleData();
         byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
         byte[] wifiConfigData = getFileData(mWifiConfigFile);
@@ -339,6 +356,9 @@
             if (DEBUG_BACKUP) Log.d(TAG, secureSettingsData.length + " bytes of secure settings data");
             out.writeInt(secureSettingsData.length);
             out.write(secureSettingsData);
+            if (DEBUG_BACKUP) Log.d(TAG, globalSettingsData.length + " bytes of global settings data");
+            out.writeInt(globalSettingsData.length);
+            out.write(globalSettingsData);
             if (DEBUG_BACKUP) Log.d(TAG, locale.length + " bytes of locale data");
             out.writeInt(locale.length);
             out.write(locale);
@@ -371,20 +391,35 @@
 
         int version = in.readInt();
         if (DEBUG_BACKUP) Log.d(TAG, "Flattened data version " + version);
-        if (version == FULL_BACKUP_VERSION) {
+        if (version <= FULL_BACKUP_VERSION) {
+            // Generate the moved-to-global lookup table
+            HashSet<String> movedToGlobal = new HashSet<String>();
+            Settings.System.getMovedKeys(movedToGlobal);
+            Settings.Secure.getMovedKeys(movedToGlobal);
+
             // system settings data first
             int nBytes = in.readInt();
             if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of settings data");
             byte[] buffer = new byte[nBytes];
             in.readFully(buffer, 0, nBytes);
-            restoreSettings(buffer, nBytes, Settings.System.CONTENT_URI);
+            restoreSettings(buffer, nBytes, Settings.System.CONTENT_URI, movedToGlobal);
 
             // secure settings
             nBytes = in.readInt();
             if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of secure settings data");
             if (nBytes > buffer.length) buffer = new byte[nBytes];
             in.readFully(buffer, 0, nBytes);
-            restoreSettings(buffer, nBytes, Settings.Secure.CONTENT_URI);
+            restoreSettings(buffer, nBytes, Settings.Secure.CONTENT_URI, movedToGlobal);
+
+            // Global only if sufficiently new
+            if (version >= FULL_BACKUP_ADDED_GLOBAL) {
+                nBytes = in.readInt();
+                if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of global settings data");
+                if (nBytes > buffer.length) buffer = new byte[nBytes];
+                in.readFully(buffer, 0, nBytes);
+                movedToGlobal.clear();  // no redirection; this *is* the global namespace
+                restoreSettings(buffer, nBytes, Settings.Global.CONTENT_URI, movedToGlobal);
+            }
 
             // locale
             nBytes = in.readInt();
@@ -430,14 +465,8 @@
 
         try {
             int stateVersion = dataInput.readInt();
-            if (stateVersion == STATE_VERSION_1) {
-                for (int i = 0; i < STATE_VERSION_1_SIZE; i++) {
-                    stateChecksums[i] = dataInput.readLong();
-                }
-            } else if (stateVersion == STATE_VERSION) {
-                for (int i = 0; i < STATE_SIZE; i++) {
-                    stateChecksums[i] = dataInput.readLong();
-                }
+            for (int i = 0; i < STATE_SIZES[stateVersion]; i++) {
+                stateChecksums[i] = dataInput.readLong();
             }
         } catch (EOFException eof) {
             // With the default 0 checksum we'll wind up forcing a backup of
@@ -496,7 +525,18 @@
         }
     }
 
-    private void restoreSettings(BackupDataInput data, Uri contentUri) {
+    private byte[] getGlobalSettings() {
+        Cursor cursor = getContentResolver().query(Settings.Global.CONTENT_URI, PROJECTION, null,
+                null, null);
+        try {
+            return extractRelevantValues(cursor, Settings.Global.SETTINGS_TO_BACKUP);
+        } finally {
+            cursor.close();
+        }
+    }
+
+    private void restoreSettings(BackupDataInput data, Uri contentUri,
+            HashSet<String> movedToGlobal) {
         byte[] settings = new byte[data.getDataSize()];
         try {
             data.readEntityData(settings, 0, settings.length);
@@ -504,20 +544,23 @@
             Log.e(TAG, "Couldn't read entity data");
             return;
         }
-        restoreSettings(settings, settings.length, contentUri);
+        restoreSettings(settings, settings.length, contentUri, movedToGlobal);
     }
 
-    private void restoreSettings(byte[] settings, int bytes, Uri contentUri) {
+    private void restoreSettings(byte[] settings, int bytes, Uri contentUri,
+            HashSet<String> movedToGlobal) {
         if (DEBUG) {
             Log.i(TAG, "restoreSettings: " + contentUri);
         }
 
-        // Figure out the white list.
+        // Figure out the white list and redirects to the global table.
         String[] whitelist = null;
         if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
             whitelist = Settings.Secure.SETTINGS_TO_BACKUP;
         } else if (contentUri.equals(Settings.System.CONTENT_URI)) {
             whitelist = Settings.System.SETTINGS_TO_BACKUP;
+        } else if (contentUri.equals(Settings.Global.CONTENT_URI)) {
+            whitelist = Settings.Global.SETTINGS_TO_BACKUP;
         } else {
             throw new IllegalArgumentException("Unknown URI: " + contentUri);
         }
@@ -556,15 +599,20 @@
                 continue;
             }
 
+            final Uri destination = (movedToGlobal.contains(key))
+                    ? Settings.Global.CONTENT_URI
+                    : contentUri;
+
+            // The helper doesn't care what namespace the keys are in
             if (settingsHelper.restoreValue(key, value)) {
                 contentValues.clear();
                 contentValues.put(Settings.NameValueTable.NAME, key);
                 contentValues.put(Settings.NameValueTable.VALUE, value);
-                getContentResolver().insert(contentUri, contentValues);
+                getContentResolver().insert(destination, contentValues);
             }
 
             if (DEBUG || true) {
-                Log.d(TAG, "Restored setting: " + key + "=" + value);
+                Log.d(TAG, "Restored setting: " + destination + " : "+ key + "=" + value);
             }
         }
     }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index cc6656d..ad35f7f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -110,158 +110,12 @@
         // table, shared across all users
         // These must match Settings.Secure.MOVED_TO_GLOBAL
         sSecureGlobalKeys = new HashSet<String>();
-        sSecureGlobalKeys.add(Settings.Global.ADB_ENABLED);
-        sSecureGlobalKeys.add(Settings.Global.ASSISTED_GPS_ENABLED);
-        sSecureGlobalKeys.add(Settings.Global.BLUETOOTH_ON);
-        sSecureGlobalKeys.add(Settings.Global.CDMA_CELL_BROADCAST_SMS);
-        sSecureGlobalKeys.add(Settings.Global.CDMA_ROAMING_MODE);
-        sSecureGlobalKeys.add(Settings.Global.CDMA_SUBSCRIPTION_MODE);
-        sSecureGlobalKeys.add(Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE);
-        sSecureGlobalKeys.add(Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI);
-        sSecureGlobalKeys.add(Settings.Global.DATA_ROAMING);
-        sSecureGlobalKeys.add(Settings.Global.DEVELOPMENT_SETTINGS_ENABLED);
-        sSecureGlobalKeys.add(Settings.Global.DEVICE_PROVISIONED);
-        sSecureGlobalKeys.add(Settings.Global.DISPLAY_DENSITY_FORCED);
-        sSecureGlobalKeys.add(Settings.Global.DISPLAY_SIZE_FORCED);
-        sSecureGlobalKeys.add(Settings.Global.DOWNLOAD_MAX_BYTES_OVER_MOBILE);
-        sSecureGlobalKeys.add(Settings.Global.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE);
-        sSecureGlobalKeys.add(Settings.Global.INSTALL_NON_MARKET_APPS);
-        sSecureGlobalKeys.add(Settings.Global.MOBILE_DATA);
-        sSecureGlobalKeys.add(Settings.Global.NETSTATS_DEV_BUCKET_DURATION);
-        sSecureGlobalKeys.add(Settings.Global.NETSTATS_DEV_DELETE_AGE);
-        sSecureGlobalKeys.add(Settings.Global.NETSTATS_DEV_PERSIST_BYTES);
-        sSecureGlobalKeys.add(Settings.Global.NETSTATS_DEV_ROTATE_AGE);
-        sSecureGlobalKeys.add(Settings.Global.NETSTATS_ENABLED);
-        sSecureGlobalKeys.add(Settings.Global.NETSTATS_GLOBAL_ALERT_BYTES);
-        sSecureGlobalKeys.add(Settings.Global.NETSTATS_POLL_INTERVAL);
-        sSecureGlobalKeys.add(Settings.Global.NETSTATS_REPORT_XT_OVER_DEV);
-        sSecureGlobalKeys.add(Settings.Global.NETSTATS_SAMPLE_ENABLED);
-        sSecureGlobalKeys.add(Settings.Global.NETSTATS_TIME_CACHE_MAX_AGE);
-        sSecureGlobalKeys.add(Settings.Global.NETSTATS_UID_BUCKET_DURATION);
-        sSecureGlobalKeys.add(Settings.Global.NETSTATS_UID_DELETE_AGE);
-        sSecureGlobalKeys.add(Settings.Global.NETSTATS_UID_PERSIST_BYTES);
-        sSecureGlobalKeys.add(Settings.Global.NETSTATS_UID_ROTATE_AGE);
-        sSecureGlobalKeys.add(Settings.Global.NETSTATS_UID_TAG_BUCKET_DURATION);
-        sSecureGlobalKeys.add(Settings.Global.NETSTATS_UID_TAG_DELETE_AGE);
-        sSecureGlobalKeys.add(Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES);
-        sSecureGlobalKeys.add(Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE);
-        sSecureGlobalKeys.add(Settings.Global.NETWORK_PREFERENCE);
-        sSecureGlobalKeys.add(Settings.Global.NITZ_UPDATE_DIFF);
-        sSecureGlobalKeys.add(Settings.Global.NITZ_UPDATE_SPACING);
-        sSecureGlobalKeys.add(Settings.Global.NTP_SERVER);
-        sSecureGlobalKeys.add(Settings.Global.NTP_TIMEOUT);
-        sSecureGlobalKeys.add(Settings.Global.PDP_WATCHDOG_ERROR_POLL_COUNT);
-        sSecureGlobalKeys.add(Settings.Global.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS);
-        sSecureGlobalKeys.add(Settings.Global.PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT);
-        sSecureGlobalKeys.add(Settings.Global.PDP_WATCHDOG_POLL_INTERVAL_MS);
-        sSecureGlobalKeys.add(Settings.Global.PDP_WATCHDOG_TRIGGER_PACKET_COUNT);
-        sSecureGlobalKeys.add(Settings.Global.SAMPLING_PROFILER_MS);
-        sSecureGlobalKeys.add(Settings.Global.SETUP_PREPAID_DATA_SERVICE_URL);
-        sSecureGlobalKeys.add(Settings.Global.SETUP_PREPAID_DETECTION_REDIR_HOST);
-        sSecureGlobalKeys.add(Settings.Global.SETUP_PREPAID_DETECTION_TARGET_URL);
-        sSecureGlobalKeys.add(Settings.Global.TETHER_DUN_APN);
-        sSecureGlobalKeys.add(Settings.Global.TETHER_DUN_REQUIRED);
-        sSecureGlobalKeys.add(Settings.Global.TETHER_SUPPORTED);
-        sSecureGlobalKeys.add(Settings.Global.THROTTLE_HELP_URI);
-        sSecureGlobalKeys.add(Settings.Global.THROTTLE_MAX_NTP_CACHE_AGE_SEC);
-        sSecureGlobalKeys.add(Settings.Global.THROTTLE_NOTIFICATION_TYPE);
-        sSecureGlobalKeys.add(Settings.Global.THROTTLE_POLLING_SEC);
-        sSecureGlobalKeys.add(Settings.Global.THROTTLE_RESET_DAY);
-        sSecureGlobalKeys.add(Settings.Global.THROTTLE_THRESHOLD_BYTES);
-        sSecureGlobalKeys.add(Settings.Global.THROTTLE_VALUE_KBITSPS);
-        sSecureGlobalKeys.add(Settings.Global.USB_MASS_STORAGE_ENABLED);
-        sSecureGlobalKeys.add(Settings.Global.USE_GOOGLE_MAIL);
-        sSecureGlobalKeys.add(Settings.Global.WEB_AUTOFILL_QUERY_URL);
-        sSecureGlobalKeys.add(Settings.Global.WIFI_COUNTRY_CODE);
-        sSecureGlobalKeys.add(Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS);
-        sSecureGlobalKeys.add(Settings.Global.WIFI_FREQUENCY_BAND);
-        sSecureGlobalKeys.add(Settings.Global.WIFI_IDLE_MS);
-        sSecureGlobalKeys.add(Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT);
-        sSecureGlobalKeys.add(Settings.Global.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS);
-        sSecureGlobalKeys.add(Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON);
-        sSecureGlobalKeys.add(Settings.Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY);
-        sSecureGlobalKeys.add(Settings.Global.WIFI_NUM_OPEN_NETWORKS_KEPT);
-        sSecureGlobalKeys.add(Settings.Global.WIFI_ON);
-        sSecureGlobalKeys.add(Settings.Global.WIFI_P2P_DEVICE_NAME);
-        sSecureGlobalKeys.add(Settings.Global.WIFI_SAVED_STATE);
-        sSecureGlobalKeys.add(Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS);
-        sSecureGlobalKeys.add(Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED);
-        sSecureGlobalKeys.add(Settings.Global.WIFI_WATCHDOG_ON);
-        sSecureGlobalKeys.add(Settings.Global.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED);
-        sSecureGlobalKeys.add(Settings.Global.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON);
-        sSecureGlobalKeys.add(Settings.Global.PACKAGE_VERIFIER_ENABLE);
-        sSecureGlobalKeys.add(Settings.Global.PACKAGE_VERIFIER_TIMEOUT);
-        sSecureGlobalKeys.add(Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE);
-        sSecureGlobalKeys.add(Settings.Global.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS);
-        sSecureGlobalKeys.add(Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS);
-        sSecureGlobalKeys.add(Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS);
-        sSecureGlobalKeys.add(Settings.Global.WTF_IS_FATAL);
-        sSecureGlobalKeys.add(Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD);
-        sSecureGlobalKeys.add(Settings.Global.BATTERY_DISCHARGE_THRESHOLD);
-        sSecureGlobalKeys.add(Settings.Global.SEND_ACTION_APP_ERROR);
-        sSecureGlobalKeys.add(Settings.Global.DROPBOX_AGE_SECONDS);
-        sSecureGlobalKeys.add(Settings.Global.DROPBOX_MAX_FILES);
-        sSecureGlobalKeys.add(Settings.Global.DROPBOX_QUOTA_KB);
-        sSecureGlobalKeys.add(Settings.Global.DROPBOX_QUOTA_PERCENT);
-        sSecureGlobalKeys.add(Settings.Global.DROPBOX_RESERVE_PERCENT);
-        sSecureGlobalKeys.add(Settings.Global.DROPBOX_TAG_PREFIX);
-        sSecureGlobalKeys.add(Settings.Global.ERROR_LOGCAT_PREFIX);
-        sSecureGlobalKeys.add(Settings.Global.SYS_FREE_STORAGE_LOG_INTERVAL);
-        sSecureGlobalKeys.add(Settings.Global.DISK_FREE_CHANGE_REPORTING_THRESHOLD);
-        sSecureGlobalKeys.add(Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE);
-        sSecureGlobalKeys.add(Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES);
-        sSecureGlobalKeys.add(Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES);
-        sSecureGlobalKeys.add(Settings.Global.SYNC_MAX_RETRY_DELAY_IN_SECONDS);
-        sSecureGlobalKeys.add(Settings.Global.CONNECTIVITY_CHANGE_DELAY);
-        sSecureGlobalKeys.add(Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED);
-        sSecureGlobalKeys.add(Settings.Global.CAPTIVE_PORTAL_SERVER);
-        sSecureGlobalKeys.add(Settings.Global.NSD_ON);
-        sSecureGlobalKeys.add(Settings.Global.SET_INSTALL_LOCATION);
-        sSecureGlobalKeys.add(Settings.Global.DEFAULT_INSTALL_LOCATION);
-        sSecureGlobalKeys.add(Settings.Global.INET_CONDITION_DEBOUNCE_UP_DELAY);
-        sSecureGlobalKeys.add(Settings.Global.INET_CONDITION_DEBOUNCE_DOWN_DELAY);
-        sSecureGlobalKeys.add(Settings.Global.READ_EXTERNAL_STORAGE_ENFORCED_DEFAULT);
-        sSecureGlobalKeys.add(Settings.Global.HTTP_PROXY);
-        sSecureGlobalKeys.add(Settings.Global.GLOBAL_HTTP_PROXY_HOST);
-        sSecureGlobalKeys.add(Settings.Global.GLOBAL_HTTP_PROXY_PORT);
-        sSecureGlobalKeys.add(Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
-        sSecureGlobalKeys.add(Settings.Global.SET_GLOBAL_HTTP_PROXY);
-        sSecureGlobalKeys.add(Settings.Global.DEFAULT_DNS_SERVER);
-        sSecureGlobalKeys.add(Settings.Global.PREFERRED_NETWORK_MODE);
-        sSecureGlobalKeys.add(Settings.Global.PREFERRED_CDMA_SUBSCRIPTION);
+        Settings.Secure.getMovedKeys(sSecureGlobalKeys);
 
         // Keys from the 'system' table now moved to 'global'
         // These must match Settings.System.MOVED_TO_GLOBAL
         sSystemGlobalKeys = new HashSet<String>();
-
-        sSystemGlobalKeys.add(Settings.Global.AIRPLANE_MODE_ON);
-        sSystemGlobalKeys.add(Settings.Global.AIRPLANE_MODE_RADIOS);
-        sSystemGlobalKeys.add(Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
-        sSystemGlobalKeys.add(Settings.Global.AUTO_TIME);
-        sSystemGlobalKeys.add(Settings.Global.AUTO_TIME_ZONE);
-        sSystemGlobalKeys.add(Settings.Global.CAR_DOCK_SOUND);
-        sSystemGlobalKeys.add(Settings.Global.CAR_UNDOCK_SOUND);
-        sSystemGlobalKeys.add(Settings.Global.DESK_DOCK_SOUND);
-        sSystemGlobalKeys.add(Settings.Global.DESK_UNDOCK_SOUND);
-        sSystemGlobalKeys.add(Settings.Global.DOCK_SOUNDS_ENABLED);
-        sSystemGlobalKeys.add(Settings.Global.LOCK_SOUND);
-        sSystemGlobalKeys.add(Settings.Global.UNLOCK_SOUND);
-        sSystemGlobalKeys.add(Settings.Global.LOW_BATTERY_SOUND);
-        sSystemGlobalKeys.add(Settings.Global.POWER_SOUNDS_ENABLED);
-        sSystemGlobalKeys.add(Settings.Global.STAY_ON_WHILE_PLUGGED_IN);
-        sSystemGlobalKeys.add(Settings.Global.WIFI_SLEEP_POLICY);
-        sSystemGlobalKeys.add(Settings.Global.MODE_RINGER);
-        sSystemGlobalKeys.add(Settings.Global.WINDOW_ANIMATION_SCALE);
-        sSystemGlobalKeys.add(Settings.Global.TRANSITION_ANIMATION_SCALE);
-        sSystemGlobalKeys.add(Settings.Global.ANIMATOR_DURATION_SCALE);
-        sSystemGlobalKeys.add(Settings.Global.FANCY_IME_ANIMATIONS);
-        sSystemGlobalKeys.add(Settings.Global.COMPATIBILITY_MODE);
-        sSystemGlobalKeys.add(Settings.Global.EMERGENCY_TONE);
-        sSystemGlobalKeys.add(Settings.Global.CALL_AUTO_RETRY);
-        sSystemGlobalKeys.add(Settings.Global.DEBUG_APP);
-        sSystemGlobalKeys.add(Settings.Global.WAIT_FOR_DEBUGGER);
-        sSystemGlobalKeys.add(Settings.Global.SHOW_PROCESSES);
-        sSystemGlobalKeys.add(Settings.Global.ALWAYS_FINISH_ACTIVITIES);
+        Settings.System.getNonLegacyMovedKeys(sSystemGlobalKeys);
     }
 
     private boolean settingMovedToGlobal(final String name) {
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 5023d23..99036ef 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -103,16 +103,16 @@
     <!-- Initial velocity of the shade when collapsing on its own -->
     <dimen name="self_collapse_velocity">2000dp</dimen>
     <!-- Minimum final velocity of gestures interpreted as expand requests -->
-    <dimen name="fling_expand_min_velocity">200dp</dimen>
+    <dimen name="fling_expand_min_velocity">100dp</dimen>
     <!-- Minimum final velocity of gestures interpreted as collapse requests -->
-    <dimen name="fling_collapse_min_velocity">200dp</dimen>
+    <dimen name="fling_collapse_min_velocity">100dp</dimen>
     <!-- Cap on contribution of x dimension of gesture to overall velocity -->
     <dimen name="fling_gesture_max_x_velocity">200dp</dimen>
     <!-- Cap on overall resulting fling speed (s^-1) -->
     <dimen name="fling_gesture_max_output_velocity">3000dp</dimen>
 
     <!-- Minimum distance a fling must travel (anti-jitter) -->
-    <dimen name="fling_gesture_min_dist">10dp</dimen>
+    <dimen name="fling_gesture_min_dist">20dp</dimen>
 
     <!-- Minimum fraction of the display a gesture must travel, at any velocity, to qualify as a
          collapse request -->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index 6b9bc89..4962199 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -21,14 +21,16 @@
     public static final int STATE_OPENING = 1;
     public static final int STATE_OPEN = 2;
 
-    private PanelHolder mPanelHolder;
-    private ArrayList<PanelView> mPanels = new ArrayList<PanelView>();
-    protected PanelView mTouchingPanel;
+    PanelHolder mPanelHolder;
+    ArrayList<PanelView> mPanels = new ArrayList<PanelView>();
+    PanelView mTouchingPanel;
     private int mState = STATE_CLOSED;
     private boolean mTracking;
 
+    float mPanelExpandedFractionSum;
+
     public void go(int state) {
-        LOG("go state: %d -> %d", mState, state);
+        if (DEBUG) LOG("go state: %d -> %d", mState, state);
         mState = state;
     }
 
@@ -84,7 +86,7 @@
         if (event.getAction() == MotionEvent.ACTION_DOWN) {
             final PanelView panel = selectPanelForTouchX(event.getX());
             boolean enabled = panel.isEnabled();
-            LOG("PanelBar.onTouch: state=%d ACTION_DOWN: panel %s %s", mState, panel,
+            if (DEBUG) LOG("PanelBar.onTouch: state=%d ACTION_DOWN: panel %s %s", mState, panel,
                     (enabled ? "" : " (disabled)"));
             if (!enabled)
                 return false;
@@ -96,15 +98,21 @@
 
     // called from PanelView when self-expanding, too
     public void startOpeningPanel(PanelView panel) {
-        LOG("startOpeningPanel: " + panel);
+        if (DEBUG) LOG("startOpeningPanel: " + panel);
         mTouchingPanel = panel;
         mPanelHolder.setSelectedPanel(mTouchingPanel);
+        for (PanelView pv : mPanels) {
+            if (pv != panel) {
+                pv.collapse();
+            }
+        }
     }
 
     public void panelExpansionChanged(PanelView panel, float frac) {
         boolean fullyClosed = true;
         PanelView fullyOpenedPanel = null;
-        LOG("panelExpansionChanged: start state=%d panel=%s", mState, panel.getName());
+        if (DEBUG) LOG("panelExpansionChanged: start state=%d panel=%s", mState, panel.getName());
+        mPanelExpandedFractionSum = 0f;
         for (PanelView pv : mPanels) {
             final boolean visible = pv.getVisibility() == View.VISIBLE;
             // adjust any other panels that may be partially visible
@@ -115,11 +123,10 @@
                 }
                 fullyClosed = false;
                 final float thisFrac = pv.getExpandedFraction();
-                LOG("panelExpansionChanged:  -> %s: f=%.1f", pv.getName(), thisFrac);
+                mPanelExpandedFractionSum += (visible ? thisFrac : 0);
+                if (DEBUG) LOG("panelExpansionChanged:  -> %s: f=%.1f", pv.getName(), thisFrac);
                 if (panel == pv) {
                     if (thisFrac == 1f) fullyOpenedPanel = panel;
-                } else {
-                    pv.setExpandedFraction(1f-frac);
                 }
             }
             if (pv.getExpandedHeight() > 0f) {
@@ -128,6 +135,7 @@
                 if (visible) pv.setVisibility(View.GONE);
             }
         }
+        mPanelExpandedFractionSum /= mPanels.size();
         if (fullyOpenedPanel != null && !mTracking) {
             go(STATE_OPEN);
             onPanelFullyOpened(fullyOpenedPanel);
@@ -136,7 +144,7 @@
             onAllPanelsCollapsed();
         }
 
-        LOG("panelExpansionChanged: end state=%d [%s%s ]", mState,
+        if (DEBUG) LOG("panelExpansionChanged: end state=%d [%s%s ]", mState,
                 (fullyOpenedPanel!=null)?" fullyOpened":"", fullyClosed?" fullyClosed":"");
     }
 
@@ -148,9 +156,10 @@
                 waiting = true;
             } else {
                 pv.setExpandedFraction(0); // just in case
+                pv.setVisibility(View.GONE);
             }
-            pv.setVisibility(View.GONE);
         }
+        if (DEBUG) LOG("collapseAllPanels: animate=%s waiting=%s", animate, waiting);
         if (!waiting) {
             // it's possible that nothing animated, so we replicate the termination 
             // conditions of panelExpansionChanged here
@@ -160,20 +169,20 @@
     }
 
     public void onPanelPeeked() {
-        LOG("onPanelPeeked");
+        if (DEBUG) LOG("onPanelPeeked");
     }
 
     public void onAllPanelsCollapsed() {
-        LOG("onAllPanelsCollapsed");
+        if (DEBUG) LOG("onAllPanelsCollapsed");
     }
 
     public void onPanelFullyOpened(PanelView openPanel) {
-        LOG("onPanelFullyOpened");
+        if (DEBUG) LOG("onPanelFullyOpened");
     }
 
     public void onTrackingStarted(PanelView panel) {
         mTracking = true;
-        if (panel != mTouchingPanel) {
+        if (DEBUG && panel != mTouchingPanel) {
             LOG("shouldn't happen: onTrackingStarted(%s) != mTouchingPanel(%s)",
                     panel, mTouchingPanel);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java
index abd82bd..241ac3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java
@@ -7,7 +7,7 @@
 
 public class PanelHolder extends FrameLayout {
 
-    private int mSelectedPanelIndex;
+    private int mSelectedPanelIndex = -1;
     private PanelBar mBar;
 
     public PanelHolder(Context context, AttributeSet attrs) {
@@ -53,6 +53,7 @@
     public boolean onTouchEvent(MotionEvent event) {
         switch (event.getAction()) {
             case MotionEvent.ACTION_DOWN:
+                PanelBar.LOG("PanelHolder got touch in open air, closing panels");
                 mBar.collapseAllPanels(true);
                 break;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index d94dbe4..ca1f75c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -9,14 +9,9 @@
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
-import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
 import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BluetoothController;
-import com.android.systemui.statusbar.policy.LocationController;
-import com.android.systemui.statusbar.policy.NetworkController;
 
 public class PanelView extends FrameLayout {
     public static final boolean DEBUG = PanelBar.DEBUG;
@@ -70,12 +65,16 @@
         }
     };
 
-    private final Runnable mStopAnimator = new Runnable() { public void run() {
-        if (mTimeAnimator.isStarted()) {
-            mTimeAnimator.end();
-            mRubberbanding = false;
+    private final Runnable mStopAnimator = new Runnable() {
+        @Override
+        public void run() {
+            if (mTimeAnimator.isStarted()) {
+                mTimeAnimator.end();
+                mRubberbanding = false;
+                mClosing = false;
+            }
         }
-    }};
+    };
 
     private float mVel, mAccel;
     private int mFullHeight = 0;
@@ -90,20 +89,22 @@
             mTimeAnimator.setTimeListener(mAnimationCallback);
 
             mTimeAnimator.start();
-            
-            mRubberbanding = STRETCH_PAST_CONTENTS && mExpandedHeight > getFullHeight();
+
+            mRubberbanding = STRETCH_PAST_CONTENTS // is it enabled at all?
+                    && mExpandedHeight > getFullHeight() // are we past the end?
+                    && mVel >= -mFlingGestureMinDistPx; // was this not possibly a "close" gesture?
             if (mRubberbanding) {
                 mClosing = true;
             } else if (mVel == 0) {
-                // if the panel is less than halfway open, close it 
+                // if the panel is less than halfway open, close it
                 mClosing = (mFinalTouchY / getFullHeight()) < 0.5f;
             } else {
                 mClosing = mExpandedHeight > 0 && mVel < 0;
             }
         } else if (dtms > 0) {
             final float dt = dtms * 0.001f;                  // ms -> s
-            LOG("tick: v=%.2fpx/s dt=%.4fs", mVel, dt);
-            LOG("tick: before: h=%d", (int) mExpandedHeight);
+            if (DEBUG) LOG("tick: v=%.2fpx/s dt=%.4fs", mVel, dt);
+            if (DEBUG) LOG("tick: before: h=%d", (int) mExpandedHeight);
 
             final float fh = getFullHeight();
             boolean braking = false;
@@ -136,12 +137,12 @@
             }
 
             float h = mExpandedHeight + mVel * dt;
-            
+
             if (mRubberbanding && h < fh) {
                 h = fh;
             }
 
-            LOG("tick: new h=%d closing=%s", (int) h, mClosing?"true":"false");
+            if (DEBUG) LOG("tick: new h=%d closing=%s", (int) h, mClosing?"true":"false");
 
             setExpandedHeightInternal(h);
 
@@ -205,14 +206,14 @@
         loadDimens();
 
         mHandleView = findViewById(R.id.handle);
-        LOG("handle view: " + mHandleView);
+        if (DEBUG) LOG("handle view: " + mHandleView);
         if (mHandleView != null) {
             mHandleView.setOnTouchListener(new View.OnTouchListener() {
                 @Override
                 public boolean onTouch(View v, MotionEvent event) {
                     final float y = event.getY();
                     final float rawY = event.getRawY();
-                    LOG("handle.onTouch: a=%s y=%.1f rawY=%.1f off=%.1f",
+                    if (DEBUG) LOG("handle.onTouch: a=%s y=%.1f rawY=%.1f off=%.1f",
                             MotionEvent.actionToString(event.getAction()),
                             y, rawY, mTouchOffset);
                     PanelView.this.getLocationOnScreen(mAbsPos);
@@ -224,6 +225,7 @@
                             mInitialTouchY = y;
                             mVelocityTracker = VelocityTracker.obtain();
                             trackMovement(event);
+                            mTimeAnimator.cancel(); // end any outstanding animations
                             mBar.onTrackingStarted(PanelView.this);
                             mTouchOffset = (rawY - mAbsPos[1]) - PanelView.this.getExpandedHeight();
                             break;
@@ -263,9 +265,9 @@
 
                             // if you've barely moved your finger, we treat the velocity as 0
                             // preventing spurious flings due to touch screen jitter
-                            final float deltaY = (float)Math.abs(mFinalTouchY - mInitialTouchY);
+                            final float deltaY = Math.abs(mFinalTouchY - mInitialTouchY);
                             if (deltaY < mFlingGestureMinDistPx
-                                    || vel < mFlingGestureMinDistPx) {
+                                    || vel < mFlingExpandMinVelocityPx) {
                                 vel = 0;
                             }
 
@@ -273,7 +275,7 @@
                                 vel = -vel;
                             }
 
-                            LOG("gesture: dy=%f vraw=(%f,%f) vnorm=(%f,%f) vlinear=%f",
+                            if (DEBUG) LOG("gesture: dy=%f vraw=(%f,%f) vnorm=(%f,%f) vlinear=%f",
                                     deltaY,
                                     mVelocityTracker.getXVelocity(),
                                     mVelocityTracker.getYVelocity(),
@@ -312,7 +314,7 @@
 
     @Override
     protected void onViewAdded(View child) {
-        LOG("onViewAdded: " + child);
+        if (DEBUG) LOG("onViewAdded: " + child);
     }
 
     public View getHandle() {
@@ -324,7 +326,7 @@
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 
-        LOG("onMeasure(%d, %d) -> (%d, %d)",
+        if (DEBUG) LOG("onMeasure(%d, %d) -> (%d, %d)",
                 widthMeasureSpec, heightMeasureSpec, getMeasuredWidth(), getMeasuredHeight());
 
         // Did one of our children change size?
@@ -332,7 +334,7 @@
         if (newHeight != mFullHeight) {
             mFullHeight = newHeight;
             // If the user isn't actively poking us, let's rubberband to the content
-            if (!mTracking && !mRubberbanding && !mTimeAnimator.isStarted() 
+            if (!mTracking && !mRubberbanding && !mTimeAnimator.isStarted()
                     && mExpandedHeight > 0 && mExpandedHeight != mFullHeight) {
                 mExpandedHeight = mFullHeight;
             }
@@ -351,7 +353,7 @@
 
     @Override
     protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
-        LOG("onLayout: changed=%s, bottom=%d eh=%d fh=%d", changed?"T":"f", bottom, (int)mExpandedHeight, (int)mFullHeight);
+        if (DEBUG) LOG("onLayout: changed=%s, bottom=%d eh=%d fh=%d", changed?"T":"f", bottom, (int)mExpandedHeight, mFullHeight);
         super.onLayout(changed, left, top, right, bottom);
     }
 
@@ -365,7 +367,7 @@
         if (!(STRETCH_PAST_CONTENTS && (mTracking || mRubberbanding)) && h > fh) h = fh;
         mExpandedHeight = h;
 
-        LOG("setExpansion: height=%.1f fh=%.1f tracking=%s rubber=%s", h, fh, mTracking?"T":"f", mRubberbanding?"T":"f");
+        if (DEBUG) LOG("setExpansion: height=%.1f fh=%.1f tracking=%s rubber=%s", h, fh, mTracking?"T":"f", mRubberbanding?"T":"f");
 
         requestLayout();
 //        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
@@ -377,9 +379,9 @@
 
     private float getFullHeight() {
         if (mFullHeight <= 0) {
-            LOG("Forcing measure() since fullHeight=" + mFullHeight);
-            measure(MeasureSpec.makeMeasureSpec(LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY),
-                    MeasureSpec.makeMeasureSpec(LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY));
+            if (DEBUG) LOG("Forcing measure() since fullHeight=" + mFullHeight);
+            measure(MeasureSpec.makeMeasureSpec(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY),
+                    MeasureSpec.makeMeasureSpec(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY));
         }
         return mFullHeight;
     }
@@ -397,11 +399,15 @@
     }
 
     public boolean isFullyExpanded() {
-        return mExpandedHeight == getFullHeight();
+        return mExpandedHeight >= getFullHeight();
     }
 
     public boolean isFullyCollapsed() {
-        return mExpandedHeight == 0;
+        return mExpandedHeight <= 0;
+    }
+
+    public boolean isCollapsing() {
+        return mClosing;
     }
 
     public void setBar(PanelBar panelBar) {
@@ -411,6 +417,8 @@
     public void collapse() {
         // TODO: abort animation or ongoing touch
         if (!isFullyCollapsed()) {
+            // collapse() should never be a rubberband, even if an animation is already running
+            mRubberbanding = false;
             fling(-mSelfCollapseVelocityPx, /*always=*/ true);
         }
     }
@@ -418,10 +426,10 @@
     public void expand() {
         if (isFullyCollapsed()) {
             mBar.startOpeningPanel(this);
-            LOG("expand: calling fling(%s, true)", mSelfExpandVelocityPx);
+            if (DEBUG) LOG("expand: calling fling(%s, true)", mSelfExpandVelocityPx);
             fling (mSelfExpandVelocityPx, /*always=*/ true);
         } else if (DEBUG) {
-            LOG("skipping expansion: is expanded");
+            if (DEBUG) LOG("skipping expansion: is expanded");
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 6517e7c..15ac5c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -19,27 +19,14 @@
 import android.app.ActivityManager;
 import android.app.StatusBarManager;
 import android.content.Context;
-import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.os.SystemClock;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.util.Slog;
-import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
 import android.view.accessibility.AccessibilityEvent;
-import android.widget.FrameLayout;
-
 import com.android.systemui.R;
-import com.android.systemui.statusbar.BaseStatusBar;
-import com.android.systemui.statusbar.policy.FixedSizeDrawable;
 
 public class PhoneStatusBarView extends PanelBar {
     private static final String TAG = "PhoneStatusBarView";
@@ -53,6 +40,7 @@
     boolean mFullWidthNotifications;
     PanelView mFadingPanel = null;
     PanelView mNotificationPanel, mSettingsPanel;
+    private boolean mShouldFade;
 
     public PhoneStatusBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -112,7 +100,7 @@
             if (DEBUG) {
                 Slog.v(TAG, "notif frac=" + mNotificationPanel.getExpandedFraction());
             }
-            return (mNotificationPanel.getExpandedFraction() == 1.0f)
+            return (mNotificationPanel.getExpandedFraction() > 0f)
                 ? mSettingsPanel : mNotificationPanel;
         }
 
@@ -120,7 +108,7 @@
         // right 1/3 for quick settings. If you pull the status bar down a second time you'll
         // toggle panels no matter where you pull it down.
 
-        final float w = (float) getMeasuredWidth();
+        final float w = getMeasuredWidth();
         float region = (w * mSettingsPanelDragzoneFrac);
 
         if (DEBUG) {
@@ -138,9 +126,18 @@
     public void onPanelPeeked() {
         super.onPanelPeeked();
         mBar.makeExpandedVisible(true);
-        if (mFadingPanel == null) {
-            mFadingPanel = mTouchingPanel;
+    }
+
+    @Override
+    public void startOpeningPanel(PanelView panel) {
+        super.startOpeningPanel(panel);
+        // we only want to start fading if this is the "first" or "last" panel,
+        // which is kind of tricky to determine
+        mShouldFade = (mFadingPanel == null || mFadingPanel.isFullyExpanded());
+        if (DEBUG) {
+            Slog.v(TAG, "start opening: " + panel + " shouldfade=" + mShouldFade);
         }
+        mFadingPanel = panel;
     }
 
     @Override
@@ -153,6 +150,7 @@
     @Override
     public void onPanelFullyOpened(PanelView openPanel) {
         mFadingPanel = openPanel;
+        mShouldFade = true; // now you own the fade, mister
     }
 
     @Override
@@ -166,24 +164,24 @@
     }
 
     @Override
-    public void panelExpansionChanged(PanelView pv, float frac) {
-        super.panelExpansionChanged(pv, frac);
+    public void panelExpansionChanged(PanelView panel, float frac) {
+        super.panelExpansionChanged(panel, frac);
 
         if (DEBUG) {
             Slog.v(TAG, "panelExpansionChanged: f=" + frac);
         }
 
-        if (mFadingPanel == pv
-                && mScrimColor != 0 && ActivityManager.isHighEndGfx()) {
-            // woo, special effects
-            final float k = (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2.2f))));
-            // attenuate background color alpha by k
-            final int color = (int) ((float)(mScrimColor >>> 24) * k) << 24 | (mScrimColor & 0xFFFFFF);
-            mBar.mStatusBarWindow.setBackgroundColor(color);
+        if (panel == mFadingPanel && mScrimColor != 0 && ActivityManager.isHighEndGfx()) {
+            if (mShouldFade) {
+                frac = mPanelExpandedFractionSum; // don't judge me
+                // woo, special effects
+                final float k = (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2.2f))));
+                // attenuate background color alpha by k
+                final int color = (int) ((mScrimColor >>> 24) * k) << 24 | (mScrimColor & 0xFFFFFF);
+                mBar.mStatusBarWindow.setBackgroundColor(color);
+            }
         }
 
         mBar.updateCarrierLabelVisibility(false);
     }
-
-
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
index 4b2fee4..0e53617 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
@@ -357,7 +357,7 @@
             mWifiState.label = removeDoubleQuotes(enabledDesc);
         } else if (wifiNotConnected) {
             mWifiState.iconId = R.drawable.ic_qs_wifi_0;
-            mWifiState.label = r.getString(R.string.quick_settings_wifi_not_connected);
+            mWifiState.label = r.getString(R.string.quick_settings_wifi_label);
         } else {
             mWifiState.iconId = R.drawable.ic_qs_wifi_no_network;
             mWifiState.label = r.getString(R.string.quick_settings_wifi_off_label);
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
index fe1005f..9d9b043 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
@@ -117,14 +117,7 @@
             mOverScrollAmount = r;
             mForegroundGradient = left ? mLeftToRightGradient : mRightToLeftGradient;
             mForegroundAlpha = (int) Math.round((0.85f * r * 255));
-            if (getLayerType() != LAYER_TYPE_HARDWARE) {
-                setLayerType(LAYER_TYPE_HARDWARE, null);
-            }
             invalidate();
-        } else {
-            if (getLayerType() != LAYER_TYPE_NONE) {
-                setLayerType(LAYER_TYPE_NONE, null);
-            }
         }
     }
 }
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 a1603dc..9dfbba8 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
@@ -76,6 +76,25 @@
         }
     }
 
+    @Override
+    protected void onPageBeginMoving() {
+        // Enable hardware layers while pages are moving
+        // TODO: We should only do this for the two views that are actually moving
+        int children = getChildCount();
+        for (int i = 0; i < children; i++) {
+            getChildAt(i).setLayerType(LAYER_TYPE_HARDWARE, null);
+        }
+    }
+
+    @Override
+    protected void onPageEndMoving() {
+        // Disable hardware layers while pages are moving
+        int children = getChildCount();
+        for (int i = 0; i < children; i++) {
+            getChildAt(i).setLayerType(LAYER_TYPE_NONE, null);
+        }
+    }
+
     /*
      * This interpolator emulates the rate at which the perceived scale of an object changes
      * as its distance from a camera increases. When this interpolator is applied to a scale