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