1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
|
/*
* Copyright (C) 2007-2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package android.inputmethodservice;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Rect;
import android.os.IBinder;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.WindowManager;
/**
* A SoftInputWindow is a Dialog that is intended to be used for a top-level input
* method window. It will be displayed along the edge of the screen, moving
* the application user interface away from it so that the focused item is
* always visible.
* @hide
*/
public class SoftInputWindow extends Dialog {
final String mName;
final Callback mCallback;
final KeyEvent.Callback mKeyEventCallback;
final KeyEvent.DispatcherState mDispatcherState;
final boolean mTakesFocus;
private final Rect mBounds = new Rect();
public interface Callback {
public void onBackPressed();
}
public void setToken(IBinder token) {
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.token = token;
getWindow().setAttributes(lp);
}
/**
* Create a SoftInputWindow that uses a custom style.
*
* @param context The Context in which the DockWindow should run. In
* particular, it uses the window manager and theme from this context
* to present its UI.
* @param theme A style resource describing the theme to use for the window.
* See <a href="{@docRoot}reference/available-resources.html#stylesandthemes">Style
* and Theme Resources</a> for more information about defining and
* 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.
*/
public SoftInputWindow(Context context, String name, int theme, Callback callback,
KeyEvent.Callback keyEventCallback, KeyEvent.DispatcherState dispatcherState,
boolean takesFocus) {
super(context, theme);
mName = name;
mCallback = callback;
mKeyEventCallback = keyEventCallback;
mDispatcherState = dispatcherState;
mTakesFocus = takesFocus;
initDockWindow();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
mDispatcherState.reset();
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
getWindow().getDecorView().getHitRect(mBounds);
if (ev.isWithinBoundsNoHistory(mBounds.left, mBounds.top,
mBounds.right - 1, mBounds.bottom - 1)) {
return super.dispatchTouchEvent(ev);
} else {
MotionEvent temp = ev.clampNoHistory(mBounds.left, mBounds.top,
mBounds.right - 1, mBounds.bottom - 1);
boolean handled = super.dispatchTouchEvent(temp);
temp.recycle();
return handled;
}
}
/**
* Get the size of the DockWindow.
*
* @return If the DockWindow sticks to the top or bottom of the screen, the
* return value is the height of the DockWindow, and its width is
* equal to the width of the screen; If the DockWindow sticks to the
* left or right of the screen, the return value is the width of the
* DockWindow, and its height is equal to the height of the screen.
*/
public int getSize() {
WindowManager.LayoutParams lp = getWindow().getAttributes();
if (lp.gravity == Gravity.TOP || lp.gravity == Gravity.BOTTOM) {
return lp.height;
} else {
return lp.width;
}
}
/**
* Set the size of the DockWindow.
*
* @param size If the DockWindow sticks to the top or bottom of the screen,
* <var>size</var> is the height of the DockWindow, and its width is
* equal to the width of the screen; If the DockWindow sticks to the
* left or right of the screen, <var>size</var> is the width of the
* DockWindow, and its height is equal to the height of the screen.
*/
public void setSize(int size) {
WindowManager.LayoutParams lp = getWindow().getAttributes();
if (lp.gravity == Gravity.TOP || lp.gravity == Gravity.BOTTOM) {
lp.width = -1;
lp.height = size;
} else {
lp.width = size;
lp.height = -1;
}
getWindow().setAttributes(lp);
}
/**
* Set which boundary of the screen the DockWindow sticks to.
*
* @param gravity The boundary of the screen to stick. See {#link
* android.view.Gravity.LEFT}, {#link android.view.Gravity.TOP},
* {#link android.view.Gravity.BOTTOM}, {#link
* android.view.Gravity.RIGHT}.
*/
public void setGravity(int gravity) {
WindowManager.LayoutParams lp = getWindow().getAttributes();
boolean oldIsVertical = (lp.gravity == Gravity.TOP || lp.gravity == Gravity.BOTTOM);
lp.gravity = gravity;
boolean newIsVertical = (lp.gravity == Gravity.TOP || lp.gravity == Gravity.BOTTOM);
if (oldIsVertical != newIsVertical) {
int tmp = lp.width;
lp.width = lp.height;
lp.height = tmp;
getWindow().setAttributes(lp);
}
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (mKeyEventCallback != null && mKeyEventCallback.onKeyDown(keyCode, event)) {
return true;
}
return super.onKeyDown(keyCode, event);
}
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
if (mKeyEventCallback != null && mKeyEventCallback.onKeyLongPress(keyCode, event)) {
return true;
}
return super.onKeyLongPress(keyCode, event);
}
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (mKeyEventCallback != null && mKeyEventCallback.onKeyUp(keyCode, event)) {
return true;
}
return super.onKeyUp(keyCode, event);
}
public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
if (mKeyEventCallback != null && mKeyEventCallback.onKeyMultiple(keyCode, count, event)) {
return true;
}
return super.onKeyMultiple(keyCode, count, event);
}
public void onBackPressed() {
if (mCallback != null) {
mCallback.onBackPressed();
} else {
super.onBackPressed();
}
}
private void initDockWindow() {
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.type = WindowManager.LayoutParams.TYPE_INPUT_METHOD;
lp.setTitle(mName);
lp.gravity = Gravity.BOTTOM;
lp.width = -1;
// Let the input method window's orientation follow sensor based rotation
// Turn this off for now, it is very problematic.
//lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
getWindow().setAttributes(lp);
int windowSetFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
int windowModFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_DIM_BEHIND;
if (!mTakesFocus) {
windowSetFlags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
} else {
windowSetFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
windowModFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
}
getWindow().setFlags(windowSetFlags, windowModFlags);
}
}
|