Touch.java revision ab9289320f598509cf358523ba173d69178a55ea
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of 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, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.text.method; 18 19import android.text.Layout; 20import android.text.NoCopySpan; 21import android.text.Layout.Alignment; 22import android.text.Spannable; 23import android.util.Log; 24import android.view.MotionEvent; 25import android.view.ViewConfiguration; 26import android.widget.TextView; 27import android.view.KeyEvent; 28 29public class Touch { 30 private Touch() { } 31 32 /** 33 * Scrolls the specified widget to the specified coordinates, except 34 * constrains the X scrolling position to the horizontal regions of 35 * the text that will be visible after scrolling to the specified 36 * Y position. 37 */ 38 public static void scrollTo(TextView widget, Layout layout, int x, int y) { 39 int padding = widget.getTotalPaddingTop() + 40 widget.getTotalPaddingBottom(); 41 int top = layout.getLineForVertical(y); 42 int bottom = layout.getLineForVertical(y + widget.getHeight() - 43 padding); 44 45 int left = Integer.MAX_VALUE; 46 int right = 0; 47 Alignment a = null; 48 49 for (int i = top; i <= bottom; i++) { 50 left = (int) Math.min(left, layout.getLineLeft(i)); 51 right = (int) Math.max(right, layout.getLineRight(i)); 52 53 if (a == null) { 54 a = layout.getParagraphAlignment(i); 55 } 56 } 57 58 padding = widget.getTotalPaddingLeft() + widget.getTotalPaddingRight(); 59 int width = widget.getWidth(); 60 int diff = 0; 61 62 if (right - left < width - padding) { 63 if (a == Alignment.ALIGN_CENTER) { 64 diff = (width - padding - (right - left)) / 2; 65 } else if (a == Alignment.ALIGN_OPPOSITE) { 66 diff = width - padding - (right - left); 67 } 68 } 69 70 x = Math.min(x, right - (width - padding) - diff); 71 x = Math.max(x, left - diff); 72 73 widget.scrollTo(x, y); 74 } 75 76 /** 77 * @hide 78 * Returns the maximum scroll value in x. 79 */ 80 public static int getMaxScrollX(TextView widget, Layout layout, int y) { 81 int top = layout.getLineForVertical(y); 82 int bottom = layout.getLineForVertical(y + widget.getHeight() 83 - widget.getTotalPaddingTop() -widget.getTotalPaddingBottom()); 84 int left = Integer.MAX_VALUE; 85 int right = 0; 86 for (int i = top; i <= bottom; i++) { 87 left = (int) Math.min(left, layout.getLineLeft(i)); 88 right = (int) Math.max(right, layout.getLineRight(i)); 89 } 90 return right - left - widget.getWidth() - widget.getTotalPaddingLeft() 91 - widget.getTotalPaddingRight(); 92 } 93 94 /** 95 * Handles touch events for dragging. You may want to do other actions 96 * like moving the cursor on touch as well. 97 */ 98 public static boolean onTouchEvent(TextView widget, Spannable buffer, 99 MotionEvent event) { 100 DragState[] ds; 101 102 switch (event.getAction()) { 103 case MotionEvent.ACTION_DOWN: 104 ds = buffer.getSpans(0, buffer.length(), DragState.class); 105 106 for (int i = 0; i < ds.length; i++) { 107 buffer.removeSpan(ds[i]); 108 } 109 110 buffer.setSpan(new DragState(event.getX(), event.getY(), 111 widget.getScrollX(), widget.getScrollY()), 112 0, 0, Spannable.SPAN_MARK_MARK); 113 return true; 114 115 case MotionEvent.ACTION_UP: 116 ds = buffer.getSpans(0, buffer.length(), DragState.class); 117 118 for (int i = 0; i < ds.length; i++) { 119 buffer.removeSpan(ds[i]); 120 } 121 122 if (ds.length > 0 && ds[0].mUsed) { 123 return true; 124 } else { 125 return false; 126 } 127 128 case MotionEvent.ACTION_MOVE: 129 ds = buffer.getSpans(0, buffer.length(), DragState.class); 130 131 if (ds.length > 0) { 132 if (ds[0].mFarEnough == false) { 133 int slop = ViewConfiguration.get(widget.getContext()).getScaledTouchSlop(); 134 135 if (Math.abs(event.getX() - ds[0].mX) >= slop || 136 Math.abs(event.getY() - ds[0].mY) >= slop) { 137 ds[0].mFarEnough = true; 138 } 139 } 140 141 if (ds[0].mFarEnough) { 142 ds[0].mUsed = true; 143 boolean cap = (MetaKeyKeyListener.getMetaState(buffer, 144 KeyEvent.META_SHIFT_ON) == 1) || 145 (MetaKeyKeyListener.getMetaState(buffer, 146 MetaKeyKeyListener.META_SELECTING) != 0); 147 float dx; 148 float dy; 149 if (cap) { 150 // if we're selecting, we want the scroll to go in 151 // the direction of the drag 152 dx = event.getX() - ds[0].mX; 153 dy = event.getY() - ds[0].mY; 154 } else { 155 dx = ds[0].mX - event.getX(); 156 dy = ds[0].mY - event.getY(); 157 } 158 ds[0].mX = event.getX(); 159 ds[0].mY = event.getY(); 160 161 int nx = widget.getScrollX() + (int) dx; 162 int ny = widget.getScrollY() + (int) dy; 163 164 int padding = widget.getTotalPaddingTop() + 165 widget.getTotalPaddingBottom(); 166 Layout layout = widget.getLayout(); 167 168 ny = Math.min(ny, layout.getHeight() - (widget.getHeight() - 169 padding)); 170 ny = Math.max(ny, 0); 171 172 int oldX = widget.getScrollX(); 173 int oldY = widget.getScrollY(); 174 175 scrollTo(widget, layout, nx, ny); 176 177 // If we actually scrolled, then cancel the up action. 178 if (oldX != widget.getScrollX() 179 || oldY != widget.getScrollY()) { 180 widget.cancelLongPress(); 181 } 182 183 return true; 184 } 185 } 186 } 187 188 return false; 189 } 190 191 public static int getInitialScrollX(TextView widget, Spannable buffer) { 192 DragState[] ds = buffer.getSpans(0, buffer.length(), DragState.class); 193 return ds.length > 0 ? ds[0].mScrollX : -1; 194 } 195 196 public static int getInitialScrollY(TextView widget, Spannable buffer) { 197 DragState[] ds = buffer.getSpans(0, buffer.length(), DragState.class); 198 return ds.length > 0 ? ds[0].mScrollY : -1; 199 } 200 201 private static class DragState implements NoCopySpan { 202 public float mX; 203 public float mY; 204 public int mScrollX; 205 public int mScrollY; 206 public boolean mFarEnough; 207 public boolean mUsed; 208 209 public DragState(float x, float y, int scrollX, int scrollY) { 210 mX = x; 211 mY = y; 212 mScrollX = scrollX; 213 mScrollY = scrollY; 214 } 215 } 216} 217