Merge change 24850 into eclair
* changes: Last big work on #1991910: Make swipes work with capacitive keys
This commit is contained in:
318
api/current.xml
318
api/current.xml
@@ -16089,6 +16089,17 @@
|
|||||||
visibility="public"
|
visibility="public"
|
||||||
>
|
>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="onBackPressed"
|
||||||
|
return="void"
|
||||||
|
abstract="false"
|
||||||
|
native="false"
|
||||||
|
synchronized="false"
|
||||||
|
static="false"
|
||||||
|
final="false"
|
||||||
|
deprecated="not deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
</method>
|
||||||
<method name="onChildTitleChanged"
|
<method name="onChildTitleChanged"
|
||||||
return="void"
|
return="void"
|
||||||
abstract="false"
|
abstract="false"
|
||||||
@@ -16318,6 +16329,21 @@
|
|||||||
<parameter name="event" type="android.view.KeyEvent">
|
<parameter name="event" type="android.view.KeyEvent">
|
||||||
</parameter>
|
</parameter>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="onKeyLongPress"
|
||||||
|
return="boolean"
|
||||||
|
abstract="false"
|
||||||
|
native="false"
|
||||||
|
synchronized="false"
|
||||||
|
static="false"
|
||||||
|
final="false"
|
||||||
|
deprecated="not deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
<parameter name="keyCode" type="int">
|
||||||
|
</parameter>
|
||||||
|
<parameter name="event" type="android.view.KeyEvent">
|
||||||
|
</parameter>
|
||||||
|
</method>
|
||||||
<method name="onKeyMultiple"
|
<method name="onKeyMultiple"
|
||||||
return="boolean"
|
return="boolean"
|
||||||
abstract="false"
|
abstract="false"
|
||||||
@@ -20085,6 +20111,17 @@
|
|||||||
visibility="public"
|
visibility="public"
|
||||||
>
|
>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="onBackPressed"
|
||||||
|
return="void"
|
||||||
|
abstract="false"
|
||||||
|
native="false"
|
||||||
|
synchronized="false"
|
||||||
|
static="false"
|
||||||
|
final="false"
|
||||||
|
deprecated="not deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
</method>
|
||||||
<method name="onContentChanged"
|
<method name="onContentChanged"
|
||||||
return="void"
|
return="void"
|
||||||
abstract="false"
|
abstract="false"
|
||||||
@@ -20219,6 +20256,21 @@
|
|||||||
<parameter name="event" type="android.view.KeyEvent">
|
<parameter name="event" type="android.view.KeyEvent">
|
||||||
</parameter>
|
</parameter>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="onKeyLongPress"
|
||||||
|
return="boolean"
|
||||||
|
abstract="false"
|
||||||
|
native="false"
|
||||||
|
synchronized="false"
|
||||||
|
static="false"
|
||||||
|
final="false"
|
||||||
|
deprecated="not deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
<parameter name="keyCode" type="int">
|
||||||
|
</parameter>
|
||||||
|
<parameter name="event" type="android.view.KeyEvent">
|
||||||
|
</parameter>
|
||||||
|
</method>
|
||||||
<method name="onKeyMultiple"
|
<method name="onKeyMultiple"
|
||||||
return="boolean"
|
return="boolean"
|
||||||
abstract="false"
|
abstract="false"
|
||||||
@@ -69570,6 +69622,17 @@
|
|||||||
visibility="public"
|
visibility="public"
|
||||||
>
|
>
|
||||||
</constructor>
|
</constructor>
|
||||||
|
<method name="getKeyDispatcherState"
|
||||||
|
return="android.view.KeyEvent.DispatcherState"
|
||||||
|
abstract="false"
|
||||||
|
native="false"
|
||||||
|
synchronized="false"
|
||||||
|
static="false"
|
||||||
|
final="false"
|
||||||
|
deprecated="not deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
</method>
|
||||||
<method name="onBind"
|
<method name="onBind"
|
||||||
return="android.os.IBinder"
|
return="android.os.IBinder"
|
||||||
abstract="false"
|
abstract="false"
|
||||||
@@ -70315,6 +70378,21 @@
|
|||||||
<parameter name="event" type="android.view.KeyEvent">
|
<parameter name="event" type="android.view.KeyEvent">
|
||||||
</parameter>
|
</parameter>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="onKeyLongPress"
|
||||||
|
return="boolean"
|
||||||
|
abstract="false"
|
||||||
|
native="false"
|
||||||
|
synchronized="false"
|
||||||
|
static="false"
|
||||||
|
final="false"
|
||||||
|
deprecated="not deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
<parameter name="keyCode" type="int">
|
||||||
|
</parameter>
|
||||||
|
<parameter name="event" type="android.view.KeyEvent">
|
||||||
|
</parameter>
|
||||||
|
</method>
|
||||||
<method name="onKeyMultiple"
|
<method name="onKeyMultiple"
|
||||||
return="boolean"
|
return="boolean"
|
||||||
abstract="false"
|
abstract="false"
|
||||||
@@ -144823,7 +144901,7 @@
|
|||||||
type="android.view.KeyEvent"
|
type="android.view.KeyEvent"
|
||||||
static="false"
|
static="false"
|
||||||
final="false"
|
final="false"
|
||||||
deprecated="not deprecated"
|
deprecated="deprecated"
|
||||||
visibility="public"
|
visibility="public"
|
||||||
>
|
>
|
||||||
<parameter name="origEvent" type="android.view.KeyEvent">
|
<parameter name="origEvent" type="android.view.KeyEvent">
|
||||||
@@ -144880,6 +144958,25 @@
|
|||||||
<parameter name="newRepeat" type="int">
|
<parameter name="newRepeat" type="int">
|
||||||
</parameter>
|
</parameter>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="changeTimeRepeat"
|
||||||
|
return="android.view.KeyEvent"
|
||||||
|
abstract="false"
|
||||||
|
native="false"
|
||||||
|
synchronized="false"
|
||||||
|
static="true"
|
||||||
|
final="false"
|
||||||
|
deprecated="not deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
<parameter name="event" type="android.view.KeyEvent">
|
||||||
|
</parameter>
|
||||||
|
<parameter name="eventTime" type="long">
|
||||||
|
</parameter>
|
||||||
|
<parameter name="newRepeat" type="int">
|
||||||
|
</parameter>
|
||||||
|
<parameter name="newFlags" type="int">
|
||||||
|
</parameter>
|
||||||
|
</method>
|
||||||
<method name="describeContents"
|
<method name="describeContents"
|
||||||
return="int"
|
return="int"
|
||||||
abstract="false"
|
abstract="false"
|
||||||
@@ -144891,6 +144988,19 @@
|
|||||||
visibility="public"
|
visibility="public"
|
||||||
>
|
>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="dispatch"
|
||||||
|
return="boolean"
|
||||||
|
abstract="false"
|
||||||
|
native="false"
|
||||||
|
synchronized="false"
|
||||||
|
static="false"
|
||||||
|
final="true"
|
||||||
|
deprecated="deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
<parameter name="receiver" type="android.view.KeyEvent.Callback">
|
||||||
|
</parameter>
|
||||||
|
</method>
|
||||||
<method name="dispatch"
|
<method name="dispatch"
|
||||||
return="boolean"
|
return="boolean"
|
||||||
abstract="false"
|
abstract="false"
|
||||||
@@ -144903,6 +145013,10 @@
|
|||||||
>
|
>
|
||||||
<parameter name="receiver" type="android.view.KeyEvent.Callback">
|
<parameter name="receiver" type="android.view.KeyEvent.Callback">
|
||||||
</parameter>
|
</parameter>
|
||||||
|
<parameter name="state" type="android.view.KeyEvent.DispatcherState">
|
||||||
|
</parameter>
|
||||||
|
<parameter name="target" type="java.lang.Object">
|
||||||
|
</parameter>
|
||||||
</method>
|
</method>
|
||||||
<method name="getAction"
|
<method name="getAction"
|
||||||
return="int"
|
return="int"
|
||||||
@@ -145149,6 +145263,17 @@
|
|||||||
visibility="public"
|
visibility="public"
|
||||||
>
|
>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="isLongPress"
|
||||||
|
return="boolean"
|
||||||
|
abstract="false"
|
||||||
|
native="false"
|
||||||
|
synchronized="false"
|
||||||
|
static="false"
|
||||||
|
final="true"
|
||||||
|
deprecated="not deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
</method>
|
||||||
<method name="isModifierKey"
|
<method name="isModifierKey"
|
||||||
return="boolean"
|
return="boolean"
|
||||||
abstract="false"
|
abstract="false"
|
||||||
@@ -145206,6 +145331,28 @@
|
|||||||
visibility="public"
|
visibility="public"
|
||||||
>
|
>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="isTracking"
|
||||||
|
return="boolean"
|
||||||
|
abstract="false"
|
||||||
|
native="false"
|
||||||
|
synchronized="false"
|
||||||
|
static="false"
|
||||||
|
final="true"
|
||||||
|
deprecated="not deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
</method>
|
||||||
|
<method name="startTracking"
|
||||||
|
return="void"
|
||||||
|
abstract="false"
|
||||||
|
native="false"
|
||||||
|
synchronized="false"
|
||||||
|
static="false"
|
||||||
|
final="true"
|
||||||
|
deprecated="not deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
</method>
|
||||||
<method name="writeToParcel"
|
<method name="writeToParcel"
|
||||||
return="void"
|
return="void"
|
||||||
abstract="false"
|
abstract="false"
|
||||||
@@ -145275,6 +145422,17 @@
|
|||||||
visibility="public"
|
visibility="public"
|
||||||
>
|
>
|
||||||
</field>
|
</field>
|
||||||
|
<field name="FLAG_CANCELED_LONG_PRESS"
|
||||||
|
type="int"
|
||||||
|
transient="false"
|
||||||
|
volatile="false"
|
||||||
|
value="256"
|
||||||
|
static="true"
|
||||||
|
final="true"
|
||||||
|
deprecated="not deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
</field>
|
||||||
<field name="FLAG_EDITOR_ACTION"
|
<field name="FLAG_EDITOR_ACTION"
|
||||||
type="int"
|
type="int"
|
||||||
transient="false"
|
transient="false"
|
||||||
@@ -145308,6 +145466,17 @@
|
|||||||
visibility="public"
|
visibility="public"
|
||||||
>
|
>
|
||||||
</field>
|
</field>
|
||||||
|
<field name="FLAG_LONG_PRESS"
|
||||||
|
type="int"
|
||||||
|
transient="false"
|
||||||
|
volatile="false"
|
||||||
|
value="128"
|
||||||
|
static="true"
|
||||||
|
final="true"
|
||||||
|
deprecated="not deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
</field>
|
||||||
<field name="FLAG_SOFT_KEYBOARD"
|
<field name="FLAG_SOFT_KEYBOARD"
|
||||||
type="int"
|
type="int"
|
||||||
transient="false"
|
transient="false"
|
||||||
@@ -145319,6 +145488,17 @@
|
|||||||
visibility="public"
|
visibility="public"
|
||||||
>
|
>
|
||||||
</field>
|
</field>
|
||||||
|
<field name="FLAG_TRACKING"
|
||||||
|
type="int"
|
||||||
|
transient="false"
|
||||||
|
volatile="false"
|
||||||
|
value="512"
|
||||||
|
static="true"
|
||||||
|
final="true"
|
||||||
|
deprecated="not deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
</field>
|
||||||
<field name="FLAG_VIRTUAL_HARD_KEY"
|
<field name="FLAG_VIRTUAL_HARD_KEY"
|
||||||
type="int"
|
type="int"
|
||||||
transient="false"
|
transient="false"
|
||||||
@@ -146464,6 +146644,21 @@
|
|||||||
<parameter name="event" type="android.view.KeyEvent">
|
<parameter name="event" type="android.view.KeyEvent">
|
||||||
</parameter>
|
</parameter>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="onKeyLongPress"
|
||||||
|
return="boolean"
|
||||||
|
abstract="true"
|
||||||
|
native="false"
|
||||||
|
synchronized="false"
|
||||||
|
static="false"
|
||||||
|
final="false"
|
||||||
|
deprecated="not deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
<parameter name="keyCode" type="int">
|
||||||
|
</parameter>
|
||||||
|
<parameter name="event" type="android.view.KeyEvent">
|
||||||
|
</parameter>
|
||||||
|
</method>
|
||||||
<method name="onKeyMultiple"
|
<method name="onKeyMultiple"
|
||||||
return="boolean"
|
return="boolean"
|
||||||
abstract="true"
|
abstract="true"
|
||||||
@@ -146497,6 +146692,101 @@
|
|||||||
</parameter>
|
</parameter>
|
||||||
</method>
|
</method>
|
||||||
</interface>
|
</interface>
|
||||||
|
<class name="KeyEvent.DispatcherState"
|
||||||
|
extends="java.lang.Object"
|
||||||
|
abstract="false"
|
||||||
|
static="true"
|
||||||
|
final="false"
|
||||||
|
deprecated="not deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
<constructor name="KeyEvent.DispatcherState"
|
||||||
|
type="android.view.KeyEvent.DispatcherState"
|
||||||
|
static="false"
|
||||||
|
final="false"
|
||||||
|
deprecated="not deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
</constructor>
|
||||||
|
<method name="handleUpEvent"
|
||||||
|
return="void"
|
||||||
|
abstract="false"
|
||||||
|
native="false"
|
||||||
|
synchronized="false"
|
||||||
|
static="false"
|
||||||
|
final="false"
|
||||||
|
deprecated="not deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
<parameter name="event" type="android.view.KeyEvent">
|
||||||
|
</parameter>
|
||||||
|
</method>
|
||||||
|
<method name="isTracking"
|
||||||
|
return="boolean"
|
||||||
|
abstract="false"
|
||||||
|
native="false"
|
||||||
|
synchronized="false"
|
||||||
|
static="false"
|
||||||
|
final="false"
|
||||||
|
deprecated="not deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
<parameter name="event" type="android.view.KeyEvent">
|
||||||
|
</parameter>
|
||||||
|
</method>
|
||||||
|
<method name="performedLongPress"
|
||||||
|
return="void"
|
||||||
|
abstract="false"
|
||||||
|
native="false"
|
||||||
|
synchronized="false"
|
||||||
|
static="false"
|
||||||
|
final="false"
|
||||||
|
deprecated="not deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
<parameter name="event" type="android.view.KeyEvent">
|
||||||
|
</parameter>
|
||||||
|
</method>
|
||||||
|
<method name="reset"
|
||||||
|
return="void"
|
||||||
|
abstract="false"
|
||||||
|
native="false"
|
||||||
|
synchronized="false"
|
||||||
|
static="false"
|
||||||
|
final="false"
|
||||||
|
deprecated="not deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
</method>
|
||||||
|
<method name="reset"
|
||||||
|
return="void"
|
||||||
|
abstract="false"
|
||||||
|
native="false"
|
||||||
|
synchronized="false"
|
||||||
|
static="false"
|
||||||
|
final="false"
|
||||||
|
deprecated="not deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
<parameter name="target" type="java.lang.Object">
|
||||||
|
</parameter>
|
||||||
|
</method>
|
||||||
|
<method name="startTracking"
|
||||||
|
return="void"
|
||||||
|
abstract="false"
|
||||||
|
native="false"
|
||||||
|
synchronized="false"
|
||||||
|
static="false"
|
||||||
|
final="false"
|
||||||
|
deprecated="not deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
<parameter name="event" type="android.view.KeyEvent">
|
||||||
|
</parameter>
|
||||||
|
<parameter name="target" type="java.lang.Object">
|
||||||
|
</parameter>
|
||||||
|
</method>
|
||||||
|
</class>
|
||||||
<class name="LayoutInflater"
|
<class name="LayoutInflater"
|
||||||
extends="java.lang.Object"
|
extends="java.lang.Object"
|
||||||
abstract="true"
|
abstract="true"
|
||||||
@@ -150871,6 +151161,17 @@
|
|||||||
visibility="public"
|
visibility="public"
|
||||||
>
|
>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="getKeyDispatcherState"
|
||||||
|
return="android.view.KeyEvent.DispatcherState"
|
||||||
|
abstract="false"
|
||||||
|
native="false"
|
||||||
|
synchronized="false"
|
||||||
|
static="false"
|
||||||
|
final="false"
|
||||||
|
deprecated="not deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
</method>
|
||||||
<method name="getLayoutParams"
|
<method name="getLayoutParams"
|
||||||
return="android.view.ViewGroup.LayoutParams"
|
return="android.view.ViewGroup.LayoutParams"
|
||||||
abstract="false"
|
abstract="false"
|
||||||
@@ -151997,6 +152298,21 @@
|
|||||||
<parameter name="event" type="android.view.KeyEvent">
|
<parameter name="event" type="android.view.KeyEvent">
|
||||||
</parameter>
|
</parameter>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="onKeyLongPress"
|
||||||
|
return="boolean"
|
||||||
|
abstract="false"
|
||||||
|
native="false"
|
||||||
|
synchronized="false"
|
||||||
|
static="false"
|
||||||
|
final="false"
|
||||||
|
deprecated="not deprecated"
|
||||||
|
visibility="public"
|
||||||
|
>
|
||||||
|
<parameter name="keyCode" type="int">
|
||||||
|
</parameter>
|
||||||
|
<parameter name="event" type="android.view.KeyEvent">
|
||||||
|
</parameter>
|
||||||
|
</method>
|
||||||
<method name="onKeyMultiple"
|
<method name="onKeyMultiple"
|
||||||
return="boolean"
|
return="boolean"
|
||||||
abstract="false"
|
abstract="false"
|
||||||
|
|||||||
@@ -1752,8 +1752,9 @@ public class Activity extends ContextThemeWrapper
|
|||||||
*
|
*
|
||||||
* <p>If the focused view didn't want this event, this method is called.
|
* <p>If the focused view didn't want this event, this method is called.
|
||||||
*
|
*
|
||||||
* <p>The default implementation handles KEYCODE_BACK to stop the activity
|
* <p>The default implementation sets up state to call
|
||||||
* and go back, and other default key handling if configured with {@link #setDefaultKeyMode}.
|
* {@link #onKeyLongPress}, and does other default key handling
|
||||||
|
* if configured with {@link #setDefaultKeyMode}.
|
||||||
*
|
*
|
||||||
* @return Return <code>true</code> to prevent this event from being propagated
|
* @return Return <code>true</code> to prevent this event from being propagated
|
||||||
* further, or <code>false</code> to indicate that you have not handled
|
* further, or <code>false</code> to indicate that you have not handled
|
||||||
@@ -1762,16 +1763,19 @@ public class Activity extends ContextThemeWrapper
|
|||||||
* @see android.view.KeyEvent
|
* @see android.view.KeyEvent
|
||||||
*/
|
*/
|
||||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||||
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
|
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||||
finish();
|
event.startTracking();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mDefaultKeyMode == DEFAULT_KEYS_DISABLE) {
|
if (mDefaultKeyMode == DEFAULT_KEYS_DISABLE) {
|
||||||
return false;
|
return false;
|
||||||
} else if (mDefaultKeyMode == DEFAULT_KEYS_SHORTCUT) {
|
} else if (mDefaultKeyMode == DEFAULT_KEYS_SHORTCUT) {
|
||||||
return getWindow().performPanelShortcut(Window.FEATURE_OPTIONS_PANEL,
|
if (getWindow().performPanelShortcut(Window.FEATURE_OPTIONS_PANEL,
|
||||||
keyCode, event, Menu.FLAG_ALWAYS_PERFORM_CLOSE);
|
keyCode, event, Menu.FLAG_ALWAYS_PERFORM_CLOSE)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
} else {
|
} else {
|
||||||
// Common code for DEFAULT_KEYS_DIALER & DEFAULT_KEYS_SEARCH_*
|
// Common code for DEFAULT_KEYS_DIALER & DEFAULT_KEYS_SEARCH_*
|
||||||
boolean clearSpannable = false;
|
boolean clearSpannable = false;
|
||||||
@@ -1780,8 +1784,8 @@ public class Activity extends ContextThemeWrapper
|
|||||||
clearSpannable = true;
|
clearSpannable = true;
|
||||||
handled = false;
|
handled = false;
|
||||||
} else {
|
} else {
|
||||||
handled = TextKeyListener.getInstance().onKeyDown(null, mDefaultKeySsb,
|
handled = TextKeyListener.getInstance().onKeyDown(
|
||||||
keyCode, event);
|
null, mDefaultKeySsb, keyCode, event);
|
||||||
if (handled && mDefaultKeySsb.length() > 0) {
|
if (handled && mDefaultKeySsb.length() > 0) {
|
||||||
// something useable has been typed - dispatch it now.
|
// something useable has been typed - dispatch it now.
|
||||||
|
|
||||||
@@ -1812,12 +1816,24 @@ public class Activity extends ContextThemeWrapper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
|
||||||
|
* KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
|
||||||
|
* the event).
|
||||||
|
*/
|
||||||
|
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a key was released and not handled by any of the views
|
* Called when a key was released and not handled by any of the views
|
||||||
* inside of the activity. So, for example, key presses while the cursor
|
* inside of the activity. So, for example, key presses while the cursor
|
||||||
* is inside a TextView will not trigger the event (unless it is a navigation
|
* is inside a TextView will not trigger the event (unless it is a navigation
|
||||||
* to another object) because TextView handles its own key presses.
|
* to another object) because TextView handles its own key presses.
|
||||||
*
|
*
|
||||||
|
* <p>The default implementation handles KEYCODE_BACK to stop the activity
|
||||||
|
* and go back.
|
||||||
|
*
|
||||||
* @return Return <code>true</code> to prevent this event from being propagated
|
* @return Return <code>true</code> to prevent this event from being propagated
|
||||||
* further, or <code>false</code> to indicate that you have not handled
|
* further, or <code>false</code> to indicate that you have not handled
|
||||||
* this event and it should continue to be propagated.
|
* this event and it should continue to be propagated.
|
||||||
@@ -1825,6 +1841,11 @@ public class Activity extends ContextThemeWrapper
|
|||||||
* @see KeyEvent
|
* @see KeyEvent
|
||||||
*/
|
*/
|
||||||
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
||||||
|
if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()
|
||||||
|
&& !event.isCanceled()) {
|
||||||
|
onBackPressed();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1837,6 +1858,15 @@ public class Activity extends ContextThemeWrapper
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the activity has detected the user's press of the back
|
||||||
|
* key. The default implementation simply finishes the current activity,
|
||||||
|
* but you can override this to do whatever you want.
|
||||||
|
*/
|
||||||
|
public void onBackPressed() {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a touch screen event was not handled by any of the views
|
* Called when a touch screen event was not handled by any of the views
|
||||||
* under it. This is most useful to process touch events that happen
|
* under it. This is most useful to process touch events that happen
|
||||||
@@ -1909,9 +1939,10 @@ public class Activity extends ContextThemeWrapper
|
|||||||
/**
|
/**
|
||||||
* Called when the current {@link Window} of the activity gains or loses
|
* Called when the current {@link Window} of the activity gains or loses
|
||||||
* focus. This is the best indicator of whether this activity is visible
|
* focus. This is the best indicator of whether this activity is visible
|
||||||
* to the user.
|
* to the user. The default implementation clears the key tracking
|
||||||
|
* state, so should always be called.
|
||||||
*
|
*
|
||||||
* <p>Note that this provides information what global focus state, which
|
* <p>Note that this provides information about global focus state, which
|
||||||
* is managed independently of activity lifecycles. As such, while focus
|
* is managed independently of activity lifecycles. As such, while focus
|
||||||
* changes will generally have some relation to lifecycle changes (an
|
* changes will generally have some relation to lifecycle changes (an
|
||||||
* activity that is stopped will not generally get window focus), you
|
* activity that is stopped will not generally get window focus), you
|
||||||
@@ -1988,7 +2019,8 @@ public class Activity extends ContextThemeWrapper
|
|||||||
if (getWindow().superDispatchKeyEvent(event)) {
|
if (getWindow().superDispatchKeyEvent(event)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return event.dispatch(this);
|
return event.dispatch(this, mDecor != null
|
||||||
|
? mDecor.getKeyDispatcherState() : null, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -481,30 +481,45 @@ public class Dialog implements DialogInterface, Window.Callback,
|
|||||||
*
|
*
|
||||||
* <p>If the focused view didn't want this event, this method is called.
|
* <p>If the focused view didn't want this event, this method is called.
|
||||||
*
|
*
|
||||||
* <p>The default implementation handles KEYCODE_BACK to close the
|
* <p>The default implementation consumed the KEYCODE_BACK to later
|
||||||
* dialog.
|
* handle it in {@link #onKeyUp}.
|
||||||
*
|
*
|
||||||
* @see #onKeyUp
|
* @see #onKeyUp
|
||||||
* @see android.view.KeyEvent
|
* @see android.view.KeyEvent
|
||||||
*/
|
*/
|
||||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||||
if (mCancelable) {
|
event.startTracking();
|
||||||
cancel();
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
|
||||||
|
* KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
|
||||||
|
* the event).
|
||||||
|
*/
|
||||||
|
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A key was released.
|
* A key was released.
|
||||||
*
|
*
|
||||||
|
* <p>The default implementation handles KEYCODE_BACK to close the
|
||||||
|
* dialog.
|
||||||
|
*
|
||||||
* @see #onKeyDown
|
* @see #onKeyDown
|
||||||
* @see KeyEvent
|
* @see KeyEvent
|
||||||
*/
|
*/
|
||||||
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
||||||
|
if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()
|
||||||
|
&& !event.isCanceled()) {
|
||||||
|
onBackPressed();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -517,6 +532,17 @@ public class Dialog implements DialogInterface, Window.Callback,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the dialog has detected the user's press of the back
|
||||||
|
* key. The default implementation simply cancels the dialog (only if
|
||||||
|
* it is cancelable), but you can override this to do whatever you want.
|
||||||
|
*/
|
||||||
|
public void onBackPressed() {
|
||||||
|
if (mCancelable) {
|
||||||
|
cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a touch screen event was not handled by any of the views
|
* Called when a touch screen event was not handled by any of the views
|
||||||
* under it. This is most useful to process touch events that happen outside
|
* under it. This is most useful to process touch events that happen outside
|
||||||
@@ -599,7 +625,8 @@ public class Dialog implements DialogInterface, Window.Callback,
|
|||||||
if (mWindow.superDispatchKeyEvent(event)) {
|
if (mWindow.superDispatchKeyEvent(event)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return event.dispatch(this);
|
return event.dispatch(this, mDecor != null
|
||||||
|
? mDecor.getKeyDispatcherState() : null, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -745,11 +745,9 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyCode == KeyEvent.KEYCODE_SEARCH && event.getRepeatCount() < 1) {
|
if (keyCode == KeyEvent.KEYCODE_SEARCH) {
|
||||||
// If the search key is pressed, toggle between global and in-app search. If we are
|
// Consume search key for later use.
|
||||||
// currently doing global search and there is no in-app search context to toggle to,
|
return true;
|
||||||
// just don't do anything.
|
|
||||||
return toggleGlobalSearch();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if it's an action specified by the searchable activity, launch the
|
// if it's an action specified by the searchable activity, launch the
|
||||||
@@ -763,6 +761,29 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
||||||
|
if (DBG) Log.d(LOG_TAG, "onKeyUp(" + keyCode + "," + event + ")");
|
||||||
|
if (mSearchable == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle back key to go back to previous searchable, etc.
|
||||||
|
if (handleBackKey(keyCode, event)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyCode == KeyEvent.KEYCODE_SEARCH && event.isTracking()
|
||||||
|
&& !event.isCanceled()) {
|
||||||
|
// If the search key is pressed, toggle between global and in-app search. If we are
|
||||||
|
// currently doing global search and there is no in-app search context to toggle to,
|
||||||
|
// just don't do anything.
|
||||||
|
return toggleGlobalSearch();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback to watch the textedit field for empty/non-empty
|
* Callback to watch the textedit field for empty/non-empty
|
||||||
*/
|
*/
|
||||||
@@ -1500,11 +1521,13 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
|
|||||||
*
|
*
|
||||||
* @return <code>true</code> if there was a previous component that we could go back to.
|
* @return <code>true</code> if there was a previous component that we could go back to.
|
||||||
*/
|
*/
|
||||||
private boolean backToPreviousComponent() {
|
private boolean backToPreviousComponent(boolean doIt) {
|
||||||
ComponentName previous = popPreviousComponent();
|
ComponentName previous = popPreviousComponent();
|
||||||
if (previous == null) {
|
if (previous == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (doIt) {
|
||||||
if (!show(previous, mAppSearchData, false)) {
|
if (!show(previous, mAppSearchData, false)) {
|
||||||
Log.w(LOG_TAG, "Failed to switch to source " + previous);
|
Log.w(LOG_TAG, "Failed to switch to source " + previous);
|
||||||
return false;
|
return false;
|
||||||
@@ -1515,6 +1538,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
|
|||||||
// the source that we are now going back to?
|
// the source that we are now going back to?
|
||||||
String query = mSearchAutoComplete.getText().toString();
|
String query = mSearchAutoComplete.getText().toString();
|
||||||
setUserQuery(query);
|
setUserQuery(query);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1660,6 +1684,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
|
|||||||
public static class SearchAutoComplete extends AutoCompleteTextView {
|
public static class SearchAutoComplete extends AutoCompleteTextView {
|
||||||
|
|
||||||
private int mThreshold;
|
private int mThreshold;
|
||||||
|
private int mLastKeyDown;
|
||||||
private SearchDialog mSearchDialog;
|
private SearchDialog mSearchDialog;
|
||||||
|
|
||||||
public SearchAutoComplete(Context context) {
|
public SearchAutoComplete(Context context) {
|
||||||
@@ -1740,11 +1765,27 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
|
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
|
||||||
|
mLastKeyDown = keyCode;
|
||||||
if (mSearchDialog.mSearchable == null) {
|
if (mSearchDialog.mSearchable == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
|
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||||
if (mSearchDialog.backToPreviousComponent()) {
|
if (event.getAction() == KeyEvent.ACTION_DOWN
|
||||||
|
&& event.getRepeatCount() == 0) {
|
||||||
|
// We releae the back key, might we want to do
|
||||||
|
// something before the IME?
|
||||||
|
if (mSearchDialog.backToPreviousComponent(false)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (isInputMethodNotNeeded() ||
|
||||||
|
(isEmpty() && getDropDownChildCount() >= getAdapterCount())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
mLastKeyDown = 0;
|
||||||
|
return false; // will dismiss soft keyboard if necessary
|
||||||
|
} else if (event.getAction() == KeyEvent.ACTION_UP
|
||||||
|
&& mLastKeyDown == keyCode && !event.isCanceled()) {
|
||||||
|
if (mSearchDialog.backToPreviousComponent(true)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// If the drop-down obscures the keyboard, the user wouldn't see anything
|
// If the drop-down obscures the keyboard, the user wouldn't see anything
|
||||||
@@ -1762,6 +1803,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
|
|||||||
}
|
}
|
||||||
return false; // will dismiss soft keyboard if necessary
|
return false; // will dismiss soft keyboard if necessary
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1772,11 +1814,18 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected boolean handleBackKey(int keyCode, KeyEvent event) {
|
protected boolean handleBackKey(int keyCode, KeyEvent event) {
|
||||||
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
|
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||||
if (backToPreviousComponent()) {
|
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||||
|
// Consume the event, to get an up at which point we execute.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (event.getAction() == KeyEvent.ACTION_UP && event.isTracking()
|
||||||
|
&& !event.isCanceled()) {
|
||||||
|
if (backToPreviousComponent(true)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
cancel();
|
cancel();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -45,6 +45,9 @@ public abstract class AbstractInputMethodService extends Service
|
|||||||
implements KeyEvent.Callback {
|
implements KeyEvent.Callback {
|
||||||
private InputMethod mInputMethod;
|
private InputMethod mInputMethod;
|
||||||
|
|
||||||
|
final KeyEvent.DispatcherState mDispatcherState
|
||||||
|
= new KeyEvent.DispatcherState();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for derived classes to implement their {@link InputMethod}
|
* Base class for derived classes to implement their {@link InputMethod}
|
||||||
* interface. This takes care of basic maintenance of the input method,
|
* interface. This takes care of basic maintenance of the input method,
|
||||||
@@ -129,7 +132,8 @@ public abstract class AbstractInputMethodService extends Service
|
|||||||
* callbacks on the service, and tell the client when this is done.
|
* callbacks on the service, and tell the client when this is done.
|
||||||
*/
|
*/
|
||||||
public void dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback) {
|
public void dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback) {
|
||||||
boolean handled = event.dispatch(AbstractInputMethodService.this);
|
boolean handled = event.dispatch(AbstractInputMethodService.this,
|
||||||
|
mDispatcherState, this);
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
callback.finishedEvent(seq, handled);
|
callback.finishedEvent(seq, handled);
|
||||||
}
|
}
|
||||||
@@ -147,6 +151,16 @@ public abstract class AbstractInputMethodService extends Service
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState}
|
||||||
|
* for used for processing events from the target application.
|
||||||
|
* Normally you will not need to use this directly, but
|
||||||
|
* just use the standard high-level event callbacks like {@link #onKeyDown}.
|
||||||
|
*/
|
||||||
|
public KeyEvent.DispatcherState getKeyDispatcherState() {
|
||||||
|
return mDispatcherState;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the framework during initialization, when the InputMethod
|
* Called by the framework during initialization, when the InputMethod
|
||||||
* interface for this service needs to be created.
|
* interface for this service needs to be created.
|
||||||
|
|||||||
@@ -554,7 +554,7 @@ public class InputMethodService extends AbstractInputMethodService {
|
|||||||
mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
|
mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
|
||||||
mInflater = (LayoutInflater)getSystemService(
|
mInflater = (LayoutInflater)getSystemService(
|
||||||
Context.LAYOUT_INFLATER_SERVICE);
|
Context.LAYOUT_INFLATER_SERVICE);
|
||||||
mWindow = new SoftInputWindow(this, mTheme);
|
mWindow = new SoftInputWindow(this, mTheme, mDispatcherState);
|
||||||
initViews();
|
initViews();
|
||||||
mWindow.getWindow().setLayout(FILL_PARENT, WRAP_CONTENT);
|
mWindow.getWindow().setLayout(FILL_PARENT, WRAP_CONTENT);
|
||||||
}
|
}
|
||||||
@@ -1557,6 +1557,28 @@ public class InputMethodService extends AbstractInputMethodService {
|
|||||||
mImm.showSoftInputFromInputMethod(mToken, flags);
|
mImm.showSoftInputFromInputMethod(mToken, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean handleBack(boolean doIt) {
|
||||||
|
if (mShowInputRequested) {
|
||||||
|
// If the soft input area is shown, back closes it and we
|
||||||
|
// consume the back key.
|
||||||
|
if (doIt) requestHideSelf(0);
|
||||||
|
return true;
|
||||||
|
} else if (mWindowVisible) {
|
||||||
|
if (mCandidatesVisibility == View.VISIBLE) {
|
||||||
|
// If we are showing candidates even if no input area, then
|
||||||
|
// hide them.
|
||||||
|
if (doIt) setCandidatesViewShown(false);
|
||||||
|
} else {
|
||||||
|
// If we have the window visible for some other reason --
|
||||||
|
// most likely to show candidates -- then just get rid
|
||||||
|
// of it. This really shouldn't happen, but just in case...
|
||||||
|
if (doIt) hideWindow();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override this to intercept key down events before they are processed by the
|
* Override this to intercept key down events before they are processed by the
|
||||||
* application. If you return true, the application will not itself
|
* application. If you return true, the application will not itself
|
||||||
@@ -1564,37 +1586,32 @@ public class InputMethodService extends AbstractInputMethodService {
|
|||||||
* will occur as if the IME had not seen the event at all.
|
* will occur as if the IME had not seen the event at all.
|
||||||
*
|
*
|
||||||
* <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK
|
* <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK
|
||||||
* KeyEvent.KEYCODE_BACK} to hide the current IME UI if it is shown. In
|
* KeyEvent.KEYCODE_BACK} if the IME is currently shown, to
|
||||||
* additional, in fullscreen mode only, it will consume DPAD movement
|
* possibly hide it when the key goes up (if not canceled or long pressed). In
|
||||||
|
* addition, in fullscreen mode only, it will consume DPAD movement
|
||||||
* events to move the cursor in the extracted text view, not allowing
|
* events to move the cursor in the extracted text view, not allowing
|
||||||
* them to perform navigation in the underlying application.
|
* them to perform navigation in the underlying application.
|
||||||
*/
|
*/
|
||||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||||
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
|
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
|
||||||
&& event.getRepeatCount() == 0) {
|
if (handleBack(false)) {
|
||||||
if (mShowInputRequested) {
|
event.startTracking();
|
||||||
// If the soft input area is shown, back closes it and we
|
|
||||||
// consume the back key.
|
|
||||||
requestHideSelf(0);
|
|
||||||
return true;
|
|
||||||
} else if (mWindowVisible) {
|
|
||||||
if (mCandidatesVisibility == View.VISIBLE) {
|
|
||||||
// If we are showing candidates even if no input area, then
|
|
||||||
// hide them.
|
|
||||||
setCandidatesViewShown(false);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
// If we have the window visible for some other reason --
|
|
||||||
// most likely to show candidates -- then just get rid
|
|
||||||
// of it. This really shouldn't happen, but just in case...
|
|
||||||
hideWindow();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
return false;
|
||||||
}
|
}
|
||||||
return doMovementKey(keyCode, event, MOVEMENT_DOWN);
|
return doMovementKey(keyCode, event, MOVEMENT_DOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
|
||||||
|
* KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
|
||||||
|
* the event).
|
||||||
|
*/
|
||||||
|
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override this to intercept special key multiple events before they are
|
* Override this to intercept special key multiple events before they are
|
||||||
* processed by the
|
* processed by the
|
||||||
@@ -1617,12 +1634,18 @@ public class InputMethodService extends AbstractInputMethodService {
|
|||||||
* process the event. If you return true, the normal application processing
|
* process the event. If you return true, the normal application processing
|
||||||
* will occur as if the IME had not seen the event at all.
|
* will occur as if the IME had not seen the event at all.
|
||||||
*
|
*
|
||||||
* <p>The default implementation always returns false, except when
|
* <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK
|
||||||
* in fullscreen mode, where it will consume DPAD movement
|
* KeyEvent.KEYCODE_BACK} to hide the current IME UI if it is shown. In
|
||||||
|
* addition, in fullscreen mode only, it will consume DPAD movement
|
||||||
* events to move the cursor in the extracted text view, not allowing
|
* events to move the cursor in the extracted text view, not allowing
|
||||||
* them to perform navigation in the underlying application.
|
* them to perform navigation in the underlying application.
|
||||||
*/
|
*/
|
||||||
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
||||||
|
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.isTracking()
|
||||||
|
&& !event.isCanceled()) {
|
||||||
|
return handleBack(true);
|
||||||
|
}
|
||||||
|
|
||||||
return doMovementKey(keyCode, event, MOVEMENT_UP);
|
return doMovementKey(keyCode, event, MOVEMENT_UP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import android.content.Context;
|
|||||||
import android.content.pm.ActivityInfo;
|
import android.content.pm.ActivityInfo;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
|
import android.view.KeyEvent;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,6 +31,7 @@ import android.view.WindowManager;
|
|||||||
* always visible.
|
* always visible.
|
||||||
*/
|
*/
|
||||||
class SoftInputWindow extends Dialog {
|
class SoftInputWindow extends Dialog {
|
||||||
|
final KeyEvent.DispatcherState mDispatcherState;
|
||||||
|
|
||||||
public void setToken(IBinder token) {
|
public void setToken(IBinder token) {
|
||||||
WindowManager.LayoutParams lp = getWindow().getAttributes();
|
WindowManager.LayoutParams lp = getWindow().getAttributes();
|
||||||
@@ -49,11 +51,19 @@ class SoftInputWindow extends Dialog {
|
|||||||
* using styles. This theme is applied on top of the current theme in
|
* using styles. This theme is applied on top of the current theme in
|
||||||
* <var>context</var>. If 0, the default dialog theme will be used.
|
* <var>context</var>. If 0, the default dialog theme will be used.
|
||||||
*/
|
*/
|
||||||
public SoftInputWindow(Context context, int theme) {
|
public SoftInputWindow(Context context, int theme,
|
||||||
|
KeyEvent.DispatcherState dispatcherState) {
|
||||||
super(context, theme);
|
super(context, theme);
|
||||||
|
mDispatcherState = dispatcherState;
|
||||||
initDockWindow();
|
initDockWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onWindowFocusChanged(boolean hasFocus) {
|
||||||
|
super.onWindowFocusChanged(hasFocus);
|
||||||
|
mDispatcherState.reset();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the size of the DockWindow.
|
* Get the size of the DockWindow.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package android.view;
|
|||||||
|
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
import android.util.SparseIntArray;
|
||||||
import android.view.KeyCharacterMap;
|
import android.view.KeyCharacterMap;
|
||||||
import android.view.KeyCharacterMap.KeyData;
|
import android.view.KeyCharacterMap.KeyData;
|
||||||
|
|
||||||
@@ -276,6 +277,32 @@ public class KeyEvent implements Parcelable {
|
|||||||
*/
|
*/
|
||||||
public static final int FLAG_VIRTUAL_HARD_KEY = 0x40;
|
public static final int FLAG_VIRTUAL_HARD_KEY = 0x40;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This flag is set for the first key repeat that occurs after the
|
||||||
|
* long press timeout.
|
||||||
|
*/
|
||||||
|
public static final int FLAG_LONG_PRESS = 0x80;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set when a key event has {@link #FLAG_CANCELED} set because a long
|
||||||
|
* press action was executed while it was down.
|
||||||
|
*/
|
||||||
|
public static final int FLAG_CANCELED_LONG_PRESS = 0x100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set for {@link #ACTION_UP} when this event's key code is still being
|
||||||
|
* tracked from its initial down. That is, somebody requested that tracking
|
||||||
|
* started on the key down and a long press has not caused
|
||||||
|
* the tracking to be canceled.
|
||||||
|
*/
|
||||||
|
public static final int FLAG_TRACKING = 0x200;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private control to determine when an app is tracking a key sequence.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static final int FLAG_START_TRACKING = 0x40000000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the maximum keycode.
|
* Returns the maximum keycode.
|
||||||
*/
|
*/
|
||||||
@@ -305,7 +332,11 @@ public class KeyEvent implements Parcelable {
|
|||||||
|
|
||||||
public interface Callback {
|
public interface Callback {
|
||||||
/**
|
/**
|
||||||
* Called when a key down event has occurred.
|
* Called when a key down event has occurred. If you return true,
|
||||||
|
* you can first call {@link KeyEvent#startTracking()
|
||||||
|
* KeyEvent.startTracking()} to have the framework track the event
|
||||||
|
* through its {@link #onKeyUp(int, KeyEvent)} and also call your
|
||||||
|
* {@link #onKeyLongPress(int, KeyEvent)} if it occurs.
|
||||||
*
|
*
|
||||||
* @param keyCode The value in event.getKeyCode().
|
* @param keyCode The value in event.getKeyCode().
|
||||||
* @param event Description of the key event.
|
* @param event Description of the key event.
|
||||||
@@ -315,6 +346,22 @@ public class KeyEvent implements Parcelable {
|
|||||||
*/
|
*/
|
||||||
boolean onKeyDown(int keyCode, KeyEvent event);
|
boolean onKeyDown(int keyCode, KeyEvent event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a long press has occurred. If you return true,
|
||||||
|
* the final key up will have {@link KeyEvent#FLAG_CANCELED} and
|
||||||
|
* {@link KeyEvent#FLAG_CANCELED_LONG_PRESS} set. Note that in
|
||||||
|
* order to receive this callback, someone in the event change
|
||||||
|
* <em>must</em> return true from {@link #onKeyDown} <em>and</em>
|
||||||
|
* call {@link KeyEvent#startTracking()} on the event.
|
||||||
|
*
|
||||||
|
* @param keyCode The value in event.getKeyCode().
|
||||||
|
* @param event Description of the key event.
|
||||||
|
*
|
||||||
|
* @return If you handled the event, return true. If you want to allow
|
||||||
|
* the event to be handled by the next receiver, return false.
|
||||||
|
*/
|
||||||
|
boolean onKeyLongPress(int keyCode, KeyEvent event);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a key up event has occurred.
|
* Called when a key up event has occurred.
|
||||||
*
|
*
|
||||||
@@ -500,11 +547,15 @@ public class KeyEvent implements Parcelable {
|
|||||||
/**
|
/**
|
||||||
* Copy an existing key event, modifying its time and repeat count.
|
* Copy an existing key event, modifying its time and repeat count.
|
||||||
*
|
*
|
||||||
|
* @deprecated Use {@link #changeTimeRepeat(KeyEvent, long, int)}
|
||||||
|
* instead.
|
||||||
|
*
|
||||||
* @param origEvent The existing event to be copied.
|
* @param origEvent The existing event to be copied.
|
||||||
* @param eventTime The new event time
|
* @param eventTime The new event time
|
||||||
* (in {@link android.os.SystemClock#uptimeMillis}) of the event.
|
* (in {@link android.os.SystemClock#uptimeMillis}) of the event.
|
||||||
* @param newRepeat The new repeat count of the event.
|
* @param newRepeat The new repeat count of the event.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public KeyEvent(KeyEvent origEvent, long eventTime, int newRepeat) {
|
public KeyEvent(KeyEvent origEvent, long eventTime, int newRepeat) {
|
||||||
mDownTime = origEvent.mDownTime;
|
mDownTime = origEvent.mDownTime;
|
||||||
mEventTime = eventTime;
|
mEventTime = eventTime;
|
||||||
@@ -532,6 +583,26 @@ public class KeyEvent implements Parcelable {
|
|||||||
return new KeyEvent(event, eventTime, newRepeat);
|
return new KeyEvent(event, eventTime, newRepeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new key event that is the same as the given one, but whose
|
||||||
|
* event time and repeat count are replaced with the given value.
|
||||||
|
*
|
||||||
|
* @param event The existing event to be copied. This is not modified.
|
||||||
|
* @param eventTime The new event time
|
||||||
|
* (in {@link android.os.SystemClock#uptimeMillis}) of the event.
|
||||||
|
* @param newRepeat The new repeat count of the event.
|
||||||
|
* @param newFlags New flags for the event, replacing the entire value
|
||||||
|
* in the original event.
|
||||||
|
*/
|
||||||
|
public static KeyEvent changeTimeRepeat(KeyEvent event, long eventTime,
|
||||||
|
int newRepeat, int newFlags) {
|
||||||
|
KeyEvent ret = new KeyEvent(event);
|
||||||
|
ret.mEventTime = eventTime;
|
||||||
|
ret.mRepeatCount = newRepeat;
|
||||||
|
ret.mFlags = newFlags;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy an existing key event, modifying its action.
|
* Copy an existing key event, modifying its action.
|
||||||
*
|
*
|
||||||
@@ -720,6 +791,34 @@ public class KeyEvent implements Parcelable {
|
|||||||
return (mFlags&FLAG_CANCELED) != 0;
|
return (mFlags&FLAG_CANCELED) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this during {@link Callback#onKeyDown} to have the system track
|
||||||
|
* the key through its final up (possibly including a long press). Note
|
||||||
|
* that only one key can be tracked at a time -- if another key down
|
||||||
|
* event is received while a previous one is being tracked, tracking is
|
||||||
|
* stopped on the previous event.
|
||||||
|
*/
|
||||||
|
public final void startTracking() {
|
||||||
|
mFlags |= FLAG_START_TRACKING;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For {@link #ACTION_UP} events, indicates that the event is still being
|
||||||
|
* tracked from its initial down event as per
|
||||||
|
* {@link #FLAG_TRACKING}.
|
||||||
|
*/
|
||||||
|
public final boolean isTracking() {
|
||||||
|
return (mFlags&FLAG_TRACKING) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For {@link #ACTION_DOWN} events, indicates that the event has been
|
||||||
|
* canceled as per {@link #FLAG_LONG_PRESS}.
|
||||||
|
*/
|
||||||
|
public final boolean isLongPress() {
|
||||||
|
return (mFlags&FLAG_LONG_PRESS) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the key code of the key event. This is the physical key that
|
* Retrieve the key code of the key event. This is the physical key that
|
||||||
* was pressed, <em>not</em> the Unicode character.
|
* was pressed, <em>not</em> the Unicode character.
|
||||||
@@ -905,20 +1004,50 @@ public class KeyEvent implements Parcelable {
|
|||||||
return KeyCharacterMap.load(mDeviceId).isPrintingKey(mKeyCode);
|
return KeyCharacterMap.load(mDeviceId).isPrintingKey(mKeyCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #dispatch(Callback, DispatcherState, Object)} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public final boolean dispatch(Callback receiver) {
|
||||||
|
return dispatch(receiver, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deliver this key event to a {@link Callback} interface. If this is
|
* Deliver this key event to a {@link Callback} interface. If this is
|
||||||
* an ACTION_MULTIPLE event and it is not handled, then an attempt will
|
* an ACTION_MULTIPLE event and it is not handled, then an attempt will
|
||||||
* be made to deliver a single normal event.
|
* be made to deliver a single normal event.
|
||||||
*
|
*
|
||||||
* @param receiver The Callback that will be given the event.
|
* @param receiver The Callback that will be given the event.
|
||||||
|
* @param state State information retained across events.
|
||||||
|
* @param target The target of the dispatch, for use in tracking.
|
||||||
*
|
*
|
||||||
* @return The return value from the Callback method that was called.
|
* @return The return value from the Callback method that was called.
|
||||||
*/
|
*/
|
||||||
public final boolean dispatch(Callback receiver) {
|
public final boolean dispatch(Callback receiver, DispatcherState state,
|
||||||
|
Object target) {
|
||||||
switch (mAction) {
|
switch (mAction) {
|
||||||
case ACTION_DOWN:
|
case ACTION_DOWN: {
|
||||||
return receiver.onKeyDown(mKeyCode, this);
|
mFlags &= ~FLAG_START_TRACKING;
|
||||||
|
boolean res = receiver.onKeyDown(mKeyCode, this);
|
||||||
|
if (state != null) {
|
||||||
|
if (res && mRepeatCount == 0 && (mFlags&FLAG_START_TRACKING) != 0) {
|
||||||
|
state.startTracking(this, target);
|
||||||
|
} else if (isLongPress() && state.isTracking(this)) {
|
||||||
|
try {
|
||||||
|
if (receiver.onKeyLongPress(mKeyCode, this)) {
|
||||||
|
state.performedLongPress(this);
|
||||||
|
res = true;
|
||||||
|
}
|
||||||
|
} catch (AbstractMethodError e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
case ACTION_UP:
|
case ACTION_UP:
|
||||||
|
if (state != null) {
|
||||||
|
state.handleUpEvent(this);
|
||||||
|
}
|
||||||
return receiver.onKeyUp(mKeyCode, this);
|
return receiver.onKeyUp(mKeyCode, this);
|
||||||
case ACTION_MULTIPLE:
|
case ACTION_MULTIPLE:
|
||||||
final int count = mRepeatCount;
|
final int count = mRepeatCount;
|
||||||
@@ -938,10 +1067,97 @@ public class KeyEvent implements Parcelable {
|
|||||||
mRepeatCount = count;
|
mRepeatCount = count;
|
||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use with {@link KeyEvent#dispatch(Callback, DispatcherState, Object)}
|
||||||
|
* for more advanced key dispatching, such as long presses.
|
||||||
|
*/
|
||||||
|
public static class DispatcherState {
|
||||||
|
int mDownKeyCode;
|
||||||
|
Object mDownTarget;
|
||||||
|
SparseIntArray mActiveLongPresses = new SparseIntArray();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset back to initial state.
|
||||||
|
*/
|
||||||
|
public void reset() {
|
||||||
|
mDownKeyCode = 0;
|
||||||
|
mDownTarget = null;
|
||||||
|
mActiveLongPresses.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop any tracking associated with this target.
|
||||||
|
*/
|
||||||
|
public void reset(Object target) {
|
||||||
|
if (mDownTarget == target) {
|
||||||
|
mDownKeyCode = 0;
|
||||||
|
mDownTarget = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start tracking the key code associated with the given event. This
|
||||||
|
* can only be called on a key down. It will allow you to see any
|
||||||
|
* long press associated with the key, and will result in
|
||||||
|
* {@link KeyEvent#isTracking} return true on the long press and up
|
||||||
|
* events.
|
||||||
|
*
|
||||||
|
* <p>This is only needed if you are directly dispatching events, rather
|
||||||
|
* than handling them in {@link Callback#onKeyDown}.
|
||||||
|
*/
|
||||||
|
public void startTracking(KeyEvent event, Object target) {
|
||||||
|
if (event.getAction() != ACTION_DOWN) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Can only start tracking on a down event");
|
||||||
|
}
|
||||||
|
mDownKeyCode = event.getKeyCode();
|
||||||
|
mDownTarget = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the key event is for a key code that is currently
|
||||||
|
* being tracked by the dispatcher.
|
||||||
|
*/
|
||||||
|
public boolean isTracking(KeyEvent event) {
|
||||||
|
return mDownKeyCode == event.getKeyCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keep track of the given event's key code as having performed an
|
||||||
|
* action with a long press, so no action should occur on the up.
|
||||||
|
* <p>This is only needed if you are directly dispatching events, rather
|
||||||
|
* than handling them in {@link Callback#onKeyLongPress}.
|
||||||
|
*/
|
||||||
|
public void performedLongPress(KeyEvent event) {
|
||||||
|
mActiveLongPresses.put(event.getKeyCode(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle key up event to stop tracking. This resets the dispatcher state,
|
||||||
|
* and updates the key event state based on it.
|
||||||
|
* <p>This is only needed if you are directly dispatching events, rather
|
||||||
|
* than handling them in {@link Callback#onKeyUp}.
|
||||||
|
*/
|
||||||
|
public void handleUpEvent(KeyEvent event) {
|
||||||
|
final int keyCode = event.getKeyCode();
|
||||||
|
int index = mActiveLongPresses.indexOfKey(keyCode);
|
||||||
|
if (index >= 0) {
|
||||||
|
event.mFlags |= FLAG_CANCELED | FLAG_CANCELED_LONG_PRESS;
|
||||||
|
mActiveLongPresses.removeAt(index);
|
||||||
|
}
|
||||||
|
if (mDownKeyCode == keyCode) {
|
||||||
|
event.mFlags |= FLAG_TRACKING;
|
||||||
|
mDownKeyCode = 0;
|
||||||
|
mDownTarget = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "KeyEvent{action=" + mAction + " code=" + mKeyCode
|
return "KeyEvent{action=" + mAction + " code=" + mKeyCode
|
||||||
+ " repeat=" + mRepeatCount
|
+ " repeat=" + mRepeatCount
|
||||||
|
|||||||
@@ -2600,6 +2600,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
|
|||||||
if (mOnFocusChangeListener != null) {
|
if (mOnFocusChangeListener != null) {
|
||||||
mOnFocusChangeListener.onFocusChange(this, gainFocus);
|
mOnFocusChangeListener.onFocusChange(this, gainFocus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mAttachInfo != null) {
|
||||||
|
mAttachInfo.mKeyDispatchState.reset(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -3608,6 +3612,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
|
|||||||
ViewDebug.dumpCapturedView(subTag, v);
|
ViewDebug.dumpCapturedView(subTag, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState}
|
||||||
|
* for this view's window. Returns null if the view is not currently attached
|
||||||
|
* to the window. Normally you will not need to use this directly, but
|
||||||
|
* just use the standard high-level event callbacks like {@link #onKeyDown}.
|
||||||
|
*/
|
||||||
|
public KeyEvent.DispatcherState getKeyDispatcherState() {
|
||||||
|
return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispatch a key event before it is processed by any input method
|
* Dispatch a key event before it is processed by any input method
|
||||||
* associated with the view hierarchy. This can be used to intercept
|
* associated with the view hierarchy. This can be used to intercept
|
||||||
@@ -3645,7 +3659,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return event.dispatch(this);
|
return event.dispatch(this, mAttachInfo != null
|
||||||
|
? mAttachInfo.mKeyDispatchState : null, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -3909,6 +3924,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
|
||||||
|
* KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
|
||||||
|
* the event).
|
||||||
|
*/
|
||||||
|
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent)
|
* Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent)
|
||||||
* KeyEvent.Callback.onKeyMultiple()}: perform clicking of the view
|
* KeyEvent.Callback.onKeyMultiple()}: perform clicking of the view
|
||||||
@@ -8572,6 +8596,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
|
|||||||
*/
|
*/
|
||||||
final ArrayList<View> mScrollContainers = new ArrayList<View>();
|
final ArrayList<View> mScrollContainers = new ArrayList<View>();
|
||||||
|
|
||||||
|
final KeyEvent.DispatcherState mKeyDispatchState
|
||||||
|
= new KeyEvent.DispatcherState();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether the view's window currently has the focus.
|
* Indicates whether the view's window currently has the focus.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1812,6 +1812,7 @@ public final class ViewRoot extends Handler implements ViewParent,
|
|||||||
if (hasWindowFocus && imm != null && mLastWasImTarget) {
|
if (hasWindowFocus && imm != null && mLastWasImTarget) {
|
||||||
imm.startGettingWindowFocus(mView);
|
imm.startGettingWindowFocus(mView);
|
||||||
}
|
}
|
||||||
|
mAttachInfo.mKeyDispatchState.reset();
|
||||||
mView.dispatchWindowFocusChanged(hasWindowFocus);
|
mView.dispatchWindowFocusChanged(hasWindowFocus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2945,11 +2945,15 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
|||||||
okToSend = false;
|
okToSend = false;
|
||||||
break;
|
break;
|
||||||
case KeyEvent.KEYCODE_BACK:
|
case KeyEvent.KEYCODE_BACK:
|
||||||
if (mFiltered && mPopup != null && mPopup.isShowing() &&
|
if (mFiltered && mPopup != null && mPopup.isShowing()) {
|
||||||
event.getAction() == KeyEvent.ACTION_DOWN) {
|
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||||
|
handled = true;
|
||||||
|
} else if (event.getAction() == KeyEvent.ACTION_UP
|
||||||
|
&& event.isTracking() && !event.isCanceled()) {
|
||||||
handled = true;
|
handled = true;
|
||||||
mTextFilter.setText("");
|
mTextFilter.setText("");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
okToSend = false;
|
okToSend = false;
|
||||||
break;
|
break;
|
||||||
case KeyEvent.KEYCODE_SPACE:
|
case KeyEvent.KEYCODE_SPACE:
|
||||||
|
|||||||
@@ -132,6 +132,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
|
|||||||
|
|
||||||
private AutoCompleteTextView.PassThroughClickListener mPassThroughClickListener;
|
private AutoCompleteTextView.PassThroughClickListener mPassThroughClickListener;
|
||||||
|
|
||||||
|
private int mDownKeyCode;
|
||||||
|
|
||||||
public AutoCompleteTextView(Context context) {
|
public AutoCompleteTextView(Context context) {
|
||||||
this(context, null);
|
this(context, null);
|
||||||
}
|
}
|
||||||
@@ -603,14 +605,21 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
|
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
|
||||||
|
if (event.getAction() == KeyEvent.ACTION_DOWN
|
||||||
|
&& event.getRepeatCount() == 0) {
|
||||||
|
mDownKeyCode = keyCode;
|
||||||
|
}
|
||||||
if (isPopupShowing()) {
|
if (isPopupShowing()) {
|
||||||
// special case for the back key, we do not even try to send it
|
// special case for the back key, we do not even try to send it
|
||||||
// to the drop down list but instead, consume it immediately
|
// to the drop down list but instead, consume it immediately
|
||||||
if (keyCode == KeyEvent.KEYCODE_BACK && !mDropDownAlwaysVisible) {
|
if (keyCode == KeyEvent.KEYCODE_BACK && !mDropDownAlwaysVisible) {
|
||||||
|
if (event.getAction() == KeyEvent.ACTION_UP
|
||||||
|
&& mDownKeyCode == keyCode && !event.isCanceled()) {
|
||||||
dismissDropDown();
|
dismissDropDown();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return super.onKeyPreIme(keyCode, event);
|
return super.onKeyPreIme(keyCode, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1017,6 +1026,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
|
|||||||
@Override
|
@Override
|
||||||
public void onWindowFocusChanged(boolean hasWindowFocus) {
|
public void onWindowFocusChanged(boolean hasWindowFocus) {
|
||||||
super.onWindowFocusChanged(hasWindowFocus);
|
super.onWindowFocusChanged(hasWindowFocus);
|
||||||
|
mDownKeyCode = 0;
|
||||||
performValidation();
|
performValidation();
|
||||||
if (!hasWindowFocus && !mDropDownAlwaysVisible) {
|
if (!hasWindowFocus && !mDropDownAlwaysVisible) {
|
||||||
dismissDropDown();
|
dismissDropDown();
|
||||||
@@ -1026,6 +1036,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
|
|||||||
@Override
|
@Override
|
||||||
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
|
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
|
||||||
super.onFocusChanged(focused, direction, previouslyFocusedRect);
|
super.onFocusChanged(focused, direction, previouslyFocusedRect);
|
||||||
|
mDownKeyCode = 0;
|
||||||
performValidation();
|
performValidation();
|
||||||
if (!focused && !mDropDownAlwaysVisible) {
|
if (!focused && !mDropDownAlwaysVisible) {
|
||||||
dismissDropDown();
|
dismissDropDown();
|
||||||
|
|||||||
@@ -981,6 +981,29 @@ public abstract class KeyInputQueue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the queue has an up event pending that corresponds
|
||||||
|
* to the same key as the given key event.
|
||||||
|
*/
|
||||||
|
boolean hasKeyUpEvent(KeyEvent origEvent) {
|
||||||
|
synchronized (mFirst) {
|
||||||
|
final int keyCode = origEvent.getKeyCode();
|
||||||
|
QueuedEvent cur = mLast.prev;
|
||||||
|
while (cur.prev != null) {
|
||||||
|
if (cur.classType == RawInputEvent.CLASS_KEYBOARD) {
|
||||||
|
KeyEvent ke = (KeyEvent)cur.event;
|
||||||
|
if (ke.getAction() == KeyEvent.ACTION_UP
|
||||||
|
&& ke.getKeyCode() == keyCode) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cur = cur.prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void recycleEvent(QueuedEvent ev) {
|
void recycleEvent(QueuedEvent ev) {
|
||||||
synchronized (mFirst) {
|
synchronized (mFirst) {
|
||||||
//Log.i(TAG, "Recycle event: " + ev);
|
//Log.i(TAG, "Recycle event: " + ev);
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ import android.view.RawInputEvent;
|
|||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
import android.view.SurfaceSession;
|
import android.view.SurfaceSession;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.ViewConfiguration;
|
||||||
import android.view.ViewTreeObserver;
|
import android.view.ViewTreeObserver;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.view.WindowManagerImpl;
|
import android.view.WindowManagerImpl;
|
||||||
@@ -151,9 +152,6 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
|
|
||||||
static final int LOG_WM_NO_SURFACE_MEMORY = 31000;
|
static final int LOG_WM_NO_SURFACE_MEMORY = 31000;
|
||||||
|
|
||||||
/** How long to wait for first key repeat, in milliseconds */
|
|
||||||
static final int KEY_REPEAT_FIRST_DELAY = 750;
|
|
||||||
|
|
||||||
/** How long to wait for subsequent key repeats, in milliseconds */
|
/** How long to wait for subsequent key repeats, in milliseconds */
|
||||||
static final int KEY_REPEAT_DELAY = 50;
|
static final int KEY_REPEAT_DELAY = 50;
|
||||||
|
|
||||||
@@ -4900,6 +4898,16 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
return INJECT_SUCCEEDED;
|
return INJECT_SUCCEEDED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Okay we have finished waiting for the last event to be processed.
|
||||||
|
// First off, if this is a repeat event, check to see if there is
|
||||||
|
// a corresponding up event in the queue. If there is, we will
|
||||||
|
// just drop the repeat, because it makes no sense to repeat after
|
||||||
|
// the user has released a key. (This is especially important for
|
||||||
|
// long presses.)
|
||||||
|
if (event.getRepeatCount() > 0 && mQueue.hasKeyUpEvent(event)) {
|
||||||
|
return INJECT_SUCCEEDED;
|
||||||
|
}
|
||||||
|
|
||||||
WindowState focus = (WindowState)focusObj;
|
WindowState focus = (WindowState)focusObj;
|
||||||
|
|
||||||
if (DEBUG_INPUT) Log.v(
|
if (DEBUG_INPUT) Log.v(
|
||||||
@@ -6018,6 +6026,7 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
// Last keydown time for auto-repeating keys
|
// Last keydown time for auto-repeating keys
|
||||||
long lastKeyTime = SystemClock.uptimeMillis();
|
long lastKeyTime = SystemClock.uptimeMillis();
|
||||||
long nextKeyTime = lastKeyTime+LONG_WAIT;
|
long nextKeyTime = lastKeyTime+LONG_WAIT;
|
||||||
|
long downTime = 0;
|
||||||
|
|
||||||
// How many successive repeats we generated
|
// How many successive repeats we generated
|
||||||
int keyRepeatCount = 0;
|
int keyRepeatCount = 0;
|
||||||
@@ -6088,15 +6097,17 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
KeyEvent ke = (KeyEvent)ev.event;
|
KeyEvent ke = (KeyEvent)ev.event;
|
||||||
if (ke.isDown()) {
|
if (ke.isDown()) {
|
||||||
lastKey = ke;
|
lastKey = ke;
|
||||||
|
downTime = curTime;
|
||||||
keyRepeatCount = 0;
|
keyRepeatCount = 0;
|
||||||
lastKeyTime = curTime;
|
lastKeyTime = curTime;
|
||||||
nextKeyTime = lastKeyTime
|
nextKeyTime = lastKeyTime
|
||||||
+ KEY_REPEAT_FIRST_DELAY;
|
+ ViewConfiguration.getLongPressTimeout();
|
||||||
if (DEBUG_INPUT) Log.v(
|
if (DEBUG_INPUT) Log.v(
|
||||||
TAG, "Received key down: first repeat @ "
|
TAG, "Received key down: first repeat @ "
|
||||||
+ nextKeyTime);
|
+ nextKeyTime);
|
||||||
} else {
|
} else {
|
||||||
lastKey = null;
|
lastKey = null;
|
||||||
|
downTime = 0;
|
||||||
// Arbitrary long timeout.
|
// Arbitrary long timeout.
|
||||||
lastKeyTime = curTime;
|
lastKeyTime = curTime;
|
||||||
nextKeyTime = curTime + LONG_WAIT;
|
nextKeyTime = curTime + LONG_WAIT;
|
||||||
@@ -6144,7 +6155,19 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
if (DEBUG_INPUT) Log.v(
|
if (DEBUG_INPUT) Log.v(
|
||||||
TAG, "Key repeat: count=" + keyRepeatCount
|
TAG, "Key repeat: count=" + keyRepeatCount
|
||||||
+ ", next @ " + nextKeyTime);
|
+ ", next @ " + nextKeyTime);
|
||||||
dispatchKey(KeyEvent.changeTimeRepeat(lastKey, curTime, keyRepeatCount), 0, 0);
|
KeyEvent newEvent;
|
||||||
|
if (downTime != 0 && (downTime
|
||||||
|
+ ViewConfiguration.getLongPressTimeout())
|
||||||
|
<= curTime) {
|
||||||
|
newEvent = KeyEvent.changeTimeRepeat(lastKey,
|
||||||
|
curTime, keyRepeatCount,
|
||||||
|
lastKey.getFlags() | KeyEvent.FLAG_LONG_PRESS);
|
||||||
|
downTime = 0;
|
||||||
|
} else {
|
||||||
|
newEvent = KeyEvent.changeTimeRepeat(lastKey,
|
||||||
|
curTime, keyRepeatCount);
|
||||||
|
}
|
||||||
|
dispatchKey(newEvent, 0, 0);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
curTime = SystemClock.uptimeMillis();
|
curTime = SystemClock.uptimeMillis();
|
||||||
|
|||||||
Reference in New Issue
Block a user