Merge "Make sure we send a cancel event on system bar keys."
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index 898c642..8204e3c 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -112,6 +112,12 @@
             throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
         }
         MessageQueue queue = me.mQueue;
+        
+        // Make sure the identity of this thread is that of the local process,
+        // and keep track of what that identity token actually is.
+        Binder.clearCallingIdentity();
+        final long ident = Binder.clearCallingIdentity();
+        
         while (true) {
             Message msg = queue.next(); // might block
             if (msg != null) {
@@ -127,6 +133,17 @@
                 if (me.mLogging != null) me.mLogging.println(
                         "<<<<< Finished to    " + msg.target + " "
                         + msg.callback);
+                
+                // Make sure that during the course of dispatching the
+                // identity of the thread wasn't corrupted.
+                final long newIdent = Binder.clearCallingIdentity();
+                if (ident != newIdent) {
+                    Log.wtf("Looper", "Thread identity changed from 0x"
+                            + Long.toHexString(ident) + " to 0x"
+                            + Long.toHexString(newIdent) + " while dispatching to "
+                            + msg.target + " " + msg.callback + " what=" + msg.what);
+                }
+                
                 msg.recycle();
             }
         }
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index d95c5b0..739758c 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -74,11 +74,16 @@
     private static final int PRESSED_STATE_DURATION = 125;
     
     /**
-     * Defines the duration in milliseconds before a press turns into
+     * Defines the default duration in milliseconds before a press turns into
      * a long press
      */
-    private static final int DEFAULTLONG_PRESS_TIMEOUT = 500;
-    
+    private static final int DEFAULT_LONG_PRESS_TIMEOUT = 500;
+
+    /**
+     * Defines the time between successive key repeats in milliseconds.
+     */
+    private static final int KEY_REPEAT_DELAY = 50;
+
     /**
      * Defines the duration in milliseconds a user needs to hold down the
      * appropriate button to bring up the global actions dialog (power off,
@@ -330,7 +335,21 @@
      */
     public static int getLongPressTimeout() {
         return AppGlobals.getIntCoreSetting(Settings.Secure.LONG_PRESS_TIMEOUT,
-                DEFAULTLONG_PRESS_TIMEOUT);
+                DEFAULT_LONG_PRESS_TIMEOUT);
+    }
+
+    /**
+     * @return the time before the first key repeat in milliseconds.
+     */
+    public static int getKeyRepeatTimeout() {
+        return getLongPressTimeout();
+    }
+
+    /**
+     * @return the time between successive key repeats in milliseconds.
+     */
+    public static int getKeyRepeatDelay() {
+        return KEY_REPEAT_DELAY;
     }
 
     /**
diff --git a/core/res/res/drawable-hdpi/stat_sys_adb.png b/core/res/res/drawable-hdpi/stat_sys_adb.png
index 58c1746..af713e8 100755
--- a/core/res/res/drawable-hdpi/stat_sys_adb.png
+++ b/core/res/res/drawable-hdpi/stat_sys_adb.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/stat_sys_adb.png b/core/res/res/drawable-ldpi/stat_sys_adb.png
index cdead24..86b945b 100644
--- a/core/res/res/drawable-ldpi/stat_sys_adb.png
+++ b/core/res/res/drawable-ldpi/stat_sys_adb.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_adb.png b/core/res/res/drawable-mdpi/stat_sys_adb.png
index 255ce94..2c4d2b5 100644
--- a/core/res/res/drawable-mdpi/stat_sys_adb.png
+++ b/core/res/res/drawable-mdpi/stat_sys_adb.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/notify_panel_clock_bg.9.png b/packages/SystemUI/res/drawable-mdpi/notify_panel_clock_bg.9.png
deleted file mode 100644
index 85d9795..0000000
--- a/packages/SystemUI/res/drawable-mdpi/notify_panel_clock_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/notify_panel_clock_bg_normal.9.png b/packages/SystemUI/res/drawable-mdpi/notify_panel_clock_bg_normal.9.png
new file mode 100644
index 0000000..2266d15
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/notify_panel_clock_bg_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/notify_panel_clock_bg_pressed.9.png b/packages/SystemUI/res/drawable-mdpi/notify_panel_clock_bg_pressed.9.png
new file mode 100644
index 0000000..4fc6b46
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/notify_panel_clock_bg_pressed.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_veto_pressed.png b/packages/SystemUI/res/drawable-mdpi/status_bar_veto_pressed.png
index 3b7c9c7..653acbb 100644
--- a/packages/SystemUI/res/drawable-mdpi/status_bar_veto_pressed.png
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_veto_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/notify_panel_clock_bg.xml b/packages/SystemUI/res/drawable/notify_panel_clock_bg.xml
new file mode 100644
index 0000000..c83d878
--- /dev/null
+++ b/packages/SystemUI/res/drawable/notify_panel_clock_bg.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true"
+        android:drawable="@drawable/notify_panel_clock_bg_pressed" />
+    <item android:drawable="@drawable/notify_panel_clock_bg_normal" />
+</selector>
+
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_notification_panel_title.xml b/packages/SystemUI/res/layout-xlarge/status_bar_notification_panel_title.xml
index 0cf28a7..1afb2e3 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar_notification_panel_title.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar_notification_panel_title.xml
@@ -22,6 +22,7 @@
     android:layout_height="0dp"
     android:orientation="vertical"
     android:background="@drawable/notify_panel_clock_bg"
+    android:clickable="true"
     >
     <LinearLayout
         android:id="@+id/icons"
@@ -171,10 +172,12 @@
         android:layout_marginLeft="32dp"
         />
 
-    <Button
+    <view
+        class="com.android.systemui.statusbar.tablet.NotificationPanel$ModeToggle"
         android:id="@+id/mode_toggle"
         android:background="@null"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
+        android:clickable="true"
         />
 </RelativeLayout>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
index 8a88792..64a4f16 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
@@ -28,7 +28,10 @@
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.Slog;
+import android.view.accessibility.AccessibilityEvent;
 import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.SoundEffectConstants;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.AccelerateInterpolator;
@@ -51,7 +54,7 @@
     boolean mShowing;
     int mNotificationCount = 0;
     View mTitleArea;
-    View mModeToggle;
+    ModeToggle mModeToggle;
     View mSettingsButton;
     View mNotificationButton;
     View mNotificationScroller;
@@ -65,6 +68,48 @@
 
     Choreographer mChoreo = new Choreographer();
 
+    static class ModeToggle extends View {
+        NotificationPanel mPanel;
+        View mTitle;
+        public ModeToggle(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+        public void setPanel(NotificationPanel p) {
+            mPanel = p;
+        }
+        public void setTitleArea(View v) {
+            mTitle = v;
+        }
+        @Override
+        public boolean onTouchEvent(MotionEvent e) {
+            final int x = (int)e.getX();
+            final int y = (int)e.getY();
+            switch (e.getAction()) {
+                case MotionEvent.ACTION_DOWN:
+                    mTitle.setPressed(true);
+                    break;
+                case MotionEvent.ACTION_MOVE:
+                    mTitle.setPressed(x >= 0
+                            && x < getWidth()
+                            && y >= 0
+                            && y < getHeight());
+                    break;
+                case MotionEvent.ACTION_CANCEL:
+                    mTitle.setPressed(false);
+                    break;
+                case MotionEvent.ACTION_UP:
+                    if (mTitle.isPressed()) {
+                        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
+                        playSoundEffect(SoundEffectConstants.CLICK);
+                        mPanel.swapPanels();
+                        mTitle.setPressed(false);
+                    }
+                    break;
+            }
+            return true;
+        }
+    }
+
     public NotificationPanel(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
@@ -82,8 +127,10 @@
         mContentParent = (ViewGroup)findViewById(R.id.content_parent);
         mContentParent.bringToFront();
         mTitleArea = findViewById(R.id.title_area);
-        mModeToggle = findViewById(R.id.mode_toggle);
+        mModeToggle = (ModeToggle) findViewById(R.id.mode_toggle);
         mModeToggle.setOnClickListener(this);
+        mModeToggle.setPanel(this);
+        mModeToggle.setTitleArea(mTitleArea);
 
         mSettingsButton = (ImageView)findViewById(R.id.settings_button);
         mNotificationButton = (ImageView)findViewById(R.id.notification_button);
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 655b672..0606307 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -699,10 +699,6 @@
     // mKeyRepeatState.lastKeyEntry in addition to the one we return.
     entry->refCount += 1;
 
-    if (entry->repeatCount == 1) {
-        entry->flags |= AKEY_EVENT_FLAG_LONG_PRESS;
-    }
-
     mKeyRepeatState.nextRepeatTime = currentTime + keyRepeatDelay;
     return entry;
 }
@@ -752,6 +748,12 @@
             resetKeyRepeatLocked();
         }
 
+        if (entry->repeatCount == 1) {
+            entry->flags |= AKEY_EVENT_FLAG_LONG_PRESS;
+        } else {
+            entry->flags &= ~AKEY_EVENT_FLAG_LONG_PRESS;
+        }
+
         entry->dispatchInProgress = true;
         resetTargetsLocked();
 
diff --git a/services/java/com/android/server/usb/UsbDeviceSettingsManager.java b/services/java/com/android/server/usb/UsbDeviceSettingsManager.java
index 9a96e7f..2f22fe1 100644
--- a/services/java/com/android/server/usb/UsbDeviceSettingsManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceSettingsManager.java
@@ -615,8 +615,11 @@
             defaultPackage = mDevicePreferenceMap.get(new DeviceFilter(device));
         }
 
+        int count = matches.size();
+        // don't show the resolver activity if there are no choices available
+        if (count == 0) return;
+
         if (defaultPackage != null) {
-            int count = matches.size();
             for (int i = 0; i < count; i++) {
                 ResolveInfo rInfo = matches.get(i);
                 if (rInfo.activityInfo != null &&
@@ -666,8 +669,11 @@
             defaultPackage = mAccessoryPreferenceMap.get(new AccessoryFilter(accessory));
         }
 
+        int count = matches.size();
+        // don't show the resolver activity if there are no choices available
+        if (count == 0) return;
+
         if (defaultPackage != null) {
-            int count = matches.size();
             for (int i = 0; i < count; i++) {
                 ResolveInfo rInfo = matches.get(i);
                 if (rInfo.activityInfo != null &&
diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/wm/InputManager.java
index 77cec5d..fc32d5a 100644
--- a/services/java/com/android/server/wm/InputManager.java
+++ b/services/java/com/android/server/wm/InputManager.java
@@ -40,6 +40,7 @@
 import android.view.InputEvent;
 import android.view.KeyEvent;
 import android.view.Surface;
+import android.view.ViewConfiguration;
 import android.view.WindowManager;
 
 import java.io.File;
@@ -529,7 +530,17 @@
             
             return names.toArray(new String[names.size()]);
         }
-        
+
+        @SuppressWarnings("unused")
+        public int getKeyRepeatTimeout() {
+            return ViewConfiguration.getKeyRepeatTimeout();
+        }
+
+        @SuppressWarnings("unused")
+        public int getKeyRepeatDelay() {
+            return ViewConfiguration.getKeyRepeatDelay();
+        }
+
         @SuppressWarnings("unused")
         public int getMaxEventsPerSecond() {
             int result = 0;
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 00d0af1..3be3b1b 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -67,6 +67,8 @@
     jmethodID filterJumpyTouchEvents;
     jmethodID getVirtualKeyQuietTimeMillis;
     jmethodID getExcludedDeviceNames;
+    jmethodID getKeyRepeatTimeout;
+    jmethodID getKeyRepeatDelay;
     jmethodID getMaxEventsPerSecond;
     jmethodID getPointerLayer;
     jmethodID getPointerIcon;
@@ -199,6 +201,10 @@
     int32_t mFilterJumpyTouchEvents;
     nsecs_t mVirtualKeyQuietTime;
 
+    // Cached key repeat policy.
+    nsecs_t mKeyRepeatTimeout;
+    nsecs_t mKeyRepeatDelay;
+
     // Cached throttling policy.
     int32_t mMaxEventsPerSecond;
 
@@ -234,6 +240,7 @@
 NativeInputManager::NativeInputManager(jobject callbacksObj, const sp<Looper>& looper) :
         mLooper(looper),
         mFilterTouchEvents(-1), mFilterJumpyTouchEvents(-1), mVirtualKeyQuietTime(-1),
+        mKeyRepeatTimeout(-1), mKeyRepeatDelay(-1),
         mMaxEventsPerSecond(-1) {
     JNIEnv* env = jniEnv();
 
@@ -526,13 +533,34 @@
         // Disable key repeat when the screen is off.
         return -1;
     } else {
-        // TODO use ViewConfiguration.getLongPressTimeout()
-        return milliseconds_to_nanoseconds(500);
+        if (mKeyRepeatTimeout < 0) {
+            JNIEnv* env = jniEnv();
+
+            jint result = env->CallIntMethod(mCallbacksObj,
+                    gCallbacksClassInfo.getKeyRepeatTimeout);
+            if (checkAndClearExceptionFromCallback(env, "getKeyRepeatTimeout")) {
+                result = 500;
+            }
+
+            mKeyRepeatTimeout = milliseconds_to_nanoseconds(result);
+        }
+        return mKeyRepeatTimeout;
     }
 }
 
 nsecs_t NativeInputManager::getKeyRepeatDelay() {
-    return milliseconds_to_nanoseconds(50);
+    if (mKeyRepeatDelay < 0) {
+        JNIEnv* env = jniEnv();
+
+        jint result = env->CallIntMethod(mCallbacksObj,
+                gCallbacksClassInfo.getKeyRepeatDelay);
+        if (checkAndClearExceptionFromCallback(env, "getKeyRepeatDelay")) {
+            result = 50;
+        }
+
+        mKeyRepeatDelay = milliseconds_to_nanoseconds(result);
+    }
+    return mKeyRepeatDelay;
 }
 
 int32_t NativeInputManager::getMaxEventsPerSecond() {
@@ -1262,6 +1290,12 @@
     GET_METHOD_ID(gCallbacksClassInfo.getExcludedDeviceNames, gCallbacksClassInfo.clazz,
             "getExcludedDeviceNames", "()[Ljava/lang/String;");
 
+    GET_METHOD_ID(gCallbacksClassInfo.getKeyRepeatTimeout, gCallbacksClassInfo.clazz,
+            "getKeyRepeatTimeout", "()I");
+
+    GET_METHOD_ID(gCallbacksClassInfo.getKeyRepeatDelay, gCallbacksClassInfo.clazz,
+            "getKeyRepeatDelay", "()I");
+
     GET_METHOD_ID(gCallbacksClassInfo.getMaxEventsPerSecond, gCallbacksClassInfo.clazz,
             "getMaxEventsPerSecond", "()I");