• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package android.text.method;
18 
19 import android.text.Layout;
20 import android.text.NoCopySpan;
21 import android.text.Layout.Alignment;
22 import android.text.Spannable;
23 import android.view.MotionEvent;
24 import android.view.ViewConfiguration;
25 import android.widget.TextView;
26 
27 public class Touch {
Touch()28     private Touch() { }
29 
30     /**
31      * Scrolls the specified widget to the specified coordinates, except
32      * constrains the X scrolling position to the horizontal regions of
33      * the text that will be visible after scrolling to the specified
34      * Y position.
35      */
scrollTo(TextView widget, Layout layout, int x, int y)36     public static void scrollTo(TextView widget, Layout layout, int x, int y) {
37         int padding = widget.getTotalPaddingTop() +
38                       widget.getTotalPaddingBottom();
39         int top = layout.getLineForVertical(y);
40         int bottom = layout.getLineForVertical(y + widget.getHeight() -
41                                                padding);
42 
43         int left = Integer.MAX_VALUE;
44         int right = 0;
45         Alignment a = null;
46 
47         for (int i = top; i <= bottom; i++) {
48             left = (int) Math.min(left, layout.getLineLeft(i));
49             right = (int) Math.max(right, layout.getLineRight(i));
50 
51             if (a == null) {
52                 a = layout.getParagraphAlignment(i);
53             }
54         }
55 
56         padding = widget.getTotalPaddingLeft() + widget.getTotalPaddingRight();
57         int width = widget.getWidth();
58         int diff = 0;
59 
60         if (right - left < width - padding) {
61             if (a == Alignment.ALIGN_CENTER) {
62                 diff = (width - padding - (right - left)) / 2;
63             } else if (a == Alignment.ALIGN_OPPOSITE) {
64                 diff = width - padding - (right - left);
65             }
66         }
67 
68         x = Math.min(x, right - (width - padding) - diff);
69         x = Math.max(x, left - diff);
70 
71         widget.scrollTo(x, y);
72     }
73 
74     /**
75      * @hide
76      * Returns the maximum scroll value in x.
77      */
getMaxScrollX(TextView widget, Layout layout, int y)78     public static int getMaxScrollX(TextView widget, Layout layout, int y) {
79         int top = layout.getLineForVertical(y);
80         int bottom = layout.getLineForVertical(y + widget.getHeight()
81                 - widget.getTotalPaddingTop() -widget.getTotalPaddingBottom());
82         int left = Integer.MAX_VALUE;
83         int right = 0;
84         for (int i = top; i <= bottom; i++) {
85             left = (int) Math.min(left, layout.getLineLeft(i));
86             right = (int) Math.max(right, layout.getLineRight(i));
87         }
88         return right - left - widget.getWidth() - widget.getTotalPaddingLeft()
89                 - widget.getTotalPaddingRight();
90     }
91 
92     /**
93      * Handles touch events for dragging.  You may want to do other actions
94      * like moving the cursor on touch as well.
95      */
onTouchEvent(TextView widget, Spannable buffer, MotionEvent event)96     public static boolean onTouchEvent(TextView widget, Spannable buffer,
97                                        MotionEvent event) {
98         DragState[] ds;
99 
100         switch (event.getAction()) {
101         case MotionEvent.ACTION_DOWN:
102             ds = buffer.getSpans(0, buffer.length(), DragState.class);
103 
104             for (int i = 0; i < ds.length; i++) {
105                 buffer.removeSpan(ds[i]);
106             }
107 
108             buffer.setSpan(new DragState(event.getX(), event.getY(),
109                             widget.getScrollX(), widget.getScrollY()),
110                     0, 0, Spannable.SPAN_MARK_MARK);
111             return true;
112 
113         case MotionEvent.ACTION_UP:
114             ds = buffer.getSpans(0, buffer.length(), DragState.class);
115 
116             for (int i = 0; i < ds.length; i++) {
117                 buffer.removeSpan(ds[i]);
118             }
119 
120             if (ds.length > 0 && ds[0].mUsed) {
121                 return true;
122             } else {
123                 return false;
124             }
125 
126         case MotionEvent.ACTION_MOVE:
127             ds = buffer.getSpans(0, buffer.length(), DragState.class);
128 
129             if (ds.length > 0) {
130                 if (ds[0].mFarEnough == false) {
131                     int slop = ViewConfiguration.get(widget.getContext()).getScaledTouchSlop();
132 
133                     if (Math.abs(event.getX() - ds[0].mX) >= slop ||
134                         Math.abs(event.getY() - ds[0].mY) >= slop) {
135                         ds[0].mFarEnough = true;
136                     }
137                 }
138 
139                 if (ds[0].mFarEnough) {
140                     ds[0].mUsed = true;
141 
142                     float dx = ds[0].mX - event.getX();
143                     float dy = ds[0].mY - event.getY();
144 
145                     ds[0].mX = event.getX();
146                     ds[0].mY = event.getY();
147 
148                     int nx = widget.getScrollX() + (int) dx;
149                     int ny = widget.getScrollY() + (int) dy;
150 
151                     int padding = widget.getTotalPaddingTop() +
152                                   widget.getTotalPaddingBottom();
153                     Layout layout = widget.getLayout();
154 
155                     ny = Math.min(ny, layout.getHeight() - (widget.getHeight() -
156                                                             padding));
157                     ny = Math.max(ny, 0);
158 
159                     scrollTo(widget, layout, nx, ny);
160                     widget.cancelLongPress();
161                     return true;
162                 }
163             }
164         }
165 
166         return false;
167     }
168 
getInitialScrollX(TextView widget, Spannable buffer)169     public static int getInitialScrollX(TextView widget, Spannable buffer) {
170         DragState[] ds = buffer.getSpans(0, buffer.length(), DragState.class);
171         return ds.length > 0 ? ds[0].mScrollX : -1;
172     }
173 
getInitialScrollY(TextView widget, Spannable buffer)174     public static int getInitialScrollY(TextView widget, Spannable buffer) {
175         DragState[] ds = buffer.getSpans(0, buffer.length(), DragState.class);
176         return ds.length > 0 ? ds[0].mScrollY : -1;
177     }
178 
179     private static class DragState implements NoCopySpan {
180         public float mX;
181         public float mY;
182         public int mScrollX;
183         public int mScrollY;
184         public boolean mFarEnough;
185         public boolean mUsed;
186 
DragState(float x, float y, int scrollX, int scrollY)187         public DragState(float x, float y, int scrollX, int scrollY) {
188             mX = x;
189             mY = y;
190             mScrollX = scrollX;
191             mScrollY = scrollY;
192         }
193     }
194 }
195