Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2016 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.cts;
     18 
     19 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
     20 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
     21 import static android.widget.TextView.BufferType.EDITABLE;
     22 
     23 import static org.junit.Assert.assertEquals;
     24 import static org.junit.Assert.assertFalse;
     25 import static org.junit.Assert.assertTrue;
     26 
     27 import android.app.Activity;
     28 import android.app.Instrumentation;
     29 import android.os.SystemClock;
     30 import androidx.annotation.NonNull;
     31 import android.support.test.InstrumentationRegistry;
     32 import android.support.test.filters.MediumTest;
     33 import android.support.test.rule.ActivityTestRule;
     34 import android.support.test.runner.AndroidJUnit4;
     35 import android.text.Spannable;
     36 import android.text.method.BaseMovementMethod;
     37 import android.view.InputDevice;
     38 import android.view.KeyEvent;
     39 import android.view.MotionEvent;
     40 import android.view.MotionEvent.PointerProperties;
     41 import android.view.View;
     42 import android.view.ViewGroup;
     43 import android.widget.FrameLayout;
     44 import android.widget.TextView;
     45 
     46 import com.android.compatibility.common.util.WidgetTestUtils;
     47 
     48 import org.junit.Before;
     49 import org.junit.Rule;
     50 import org.junit.Test;
     51 import org.junit.runner.RunWith;
     52 
     53 /**
     54  * Test {@link BaseMovementMethod}.
     55  */
     56 @MediumTest
     57 @RunWith(AndroidJUnit4.class)
     58 public class BaseMovementMethodTest {
     59     private Instrumentation mInstrumentation;
     60     private BaseMovementMethod mMovementMethod;
     61     private TextView mTextView;
     62 
     63     @Rule
     64     public ActivityTestRule<CtsActivity> mActivityRule = new ActivityTestRule<>(CtsActivity.class);
     65 
     66     @Before
     67     public void setup() {
     68         mInstrumentation = InstrumentationRegistry.getInstrumentation();
     69         mMovementMethod = new BaseMovementMethod();
     70     }
     71 
     72     @Test
     73     public void testOnGenericMotionEvent_horizontalScroll() throws Throwable {
     74         final String testLine = "some text some text";
     75         final String testString = testLine + "\n" + testLine;
     76 
     77         mActivityRule.runOnUiThread(() -> mTextView = createTextView());
     78         // limit lines for horizontal scroll
     79         mTextView.setSingleLine();
     80         mTextView.setText(testString, EDITABLE);
     81 
     82         // limit width for horizontal scroll
     83 
     84         setContentView(mTextView, (int) mTextView.getPaint().measureText(testLine) / 3);
     85         // assert the default scroll position
     86         assertEquals(0, mTextView.getScrollX());
     87 
     88         final Spannable text = (Spannable) mTextView.getText();
     89         final double lineSpacing = Math.ceil(mTextView.getPaint().getFontSpacing());
     90 
     91         // scroll right
     92         MotionEvent event = createScrollEvent(1, 0);
     93         assertTrue(mMovementMethod.onGenericMotionEvent(mTextView, text, event));
     94         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mTextView, null);
     95         assertEquals(lineSpacing, mTextView.getScrollX(), lineSpacing / 4);
     96         event.recycle();
     97 
     98         // scroll left
     99         event = createScrollEvent(-1, 0);
    100         assertTrue(mMovementMethod.onGenericMotionEvent(mTextView, text, event));
    101         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mTextView, null);
    102         assertEquals(0, mTextView.getScrollX());
    103         event.recycle();
    104 
    105         // cannot scroll to left
    106         event = createScrollEvent(-1, 0);
    107         assertFalse(mMovementMethod.onGenericMotionEvent(mTextView, text, event));
    108         event.recycle();
    109 
    110         // cannot scroll to right
    111         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mTextView,
    112                 () -> mTextView.scrollTo((int) mTextView.getLayout().getLineWidth(0), 0));
    113         event = createScrollEvent(1, 0);
    114         assertFalse(mMovementMethod.onGenericMotionEvent(mTextView, text, event));
    115         event.recycle();
    116 
    117         // meta shift on
    118         // reset scroll
    119         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mTextView,
    120                 () -> mTextView.scrollTo(0, 0));
    121 
    122         // scroll top becomes scroll right
    123         event = createScrollEvent(0, 1, KeyEvent.META_SHIFT_ON);
    124         assertTrue(mMovementMethod.onGenericMotionEvent(mTextView, text, event));
    125         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mTextView, null);
    126         assertEquals(lineSpacing, mTextView.getScrollX(), lineSpacing / 4);
    127         event.recycle();
    128 
    129         // scroll down becomes scroll left
    130         event = createScrollEvent(0, -1, KeyEvent.META_SHIFT_ON);
    131         assertTrue(mMovementMethod.onGenericMotionEvent(mTextView, text, event));
    132         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mTextView, null);
    133         assertEquals(0, mTextView.getScrollX());
    134         event.recycle();
    135     }
    136 
    137     @Test
    138     public void testOnGenericMotionEvent_verticalScroll() throws Throwable {
    139         final String testLine = "some text some text";
    140         final String testString = testLine + "\n" + testLine;
    141 
    142         mActivityRule.runOnUiThread(() -> mTextView = createTextView());
    143         // limit lines for vertical scroll
    144         mTextView.setMaxLines(1);
    145         mTextView.setText(testString, EDITABLE);
    146         setContentView(mTextView, WRAP_CONTENT);
    147         // assert the default scroll positions
    148         assertEquals(0, mTextView.getScrollY());
    149 
    150         final Spannable text = (Spannable) mTextView.getText();
    151         final int lineHeight = mTextView.getLineHeight();
    152 
    153         // scroll down
    154         MotionEvent event = createScrollEvent(0, -1);
    155         assertTrue(mMovementMethod.onGenericMotionEvent(mTextView, text, event));
    156         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mTextView, null);
    157         assertEquals(lineHeight, mTextView.getScrollY(), lineHeight / 4);
    158         event.recycle();
    159 
    160         // scroll up
    161         event = createScrollEvent(0, 1);
    162         assertTrue(mMovementMethod.onGenericMotionEvent(mTextView, text, event));
    163         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mTextView, null);
    164         assertEquals(0, mTextView.getScrollY());
    165         event.recycle();
    166 
    167         // cannot scroll up
    168         event = createScrollEvent(0, 1);
    169         assertFalse(mMovementMethod.onGenericMotionEvent(mTextView, text, event));
    170         event.recycle();
    171 
    172         // cannot scroll down
    173         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mTextView,
    174                 () -> mTextView.scrollTo(0, mTextView.getLayout().getHeight()));
    175         event = createScrollEvent(0, -1);
    176         assertFalse(mMovementMethod.onGenericMotionEvent(mTextView, text, event));
    177         event.recycle();
    178     }
    179 
    180     private TextView createTextView() {
    181         final TextView textView = new TextViewNoIme(mActivityRule.getActivity());
    182         textView.setFocusable(true);
    183         textView.setMovementMethod(mMovementMethod);
    184         textView.setTextDirection(View.TEXT_DIRECTION_LTR);
    185         return textView;
    186     }
    187 
    188     private void setContentView(@NonNull TextView textView, int textWidth) throws Throwable {
    189         final Activity activity = mActivityRule.getActivity();
    190         final FrameLayout layout = new FrameLayout(activity);
    191         layout.addView(textView, new ViewGroup.LayoutParams(textWidth, WRAP_CONTENT));
    192 
    193         mActivityRule.runOnUiThread(() -> {
    194             activity.setContentView(layout, new ViewGroup.LayoutParams(MATCH_PARENT,
    195                     MATCH_PARENT));
    196             textView.requestFocus();
    197         });
    198         mInstrumentation.waitForIdleSync();
    199         assertTrue(textView.isFocused());
    200     }
    201 
    202     private static MotionEvent createScrollEvent(int horizontal, int vertical) {
    203         return createScrollEvent(horizontal, vertical, 0);
    204     }
    205 
    206     private static MotionEvent createScrollEvent(int horizontal, int vertical, int meta) {
    207         final PointerProperties[] pointerProperties = new PointerProperties[1];
    208         pointerProperties[0] = new PointerProperties();
    209         pointerProperties[0].id = 0;
    210         final MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[1];
    211         coords[0] = new MotionEvent.PointerCoords();
    212         coords[0].setAxisValue(MotionEvent.AXIS_VSCROLL, vertical);
    213         coords[0].setAxisValue(MotionEvent.AXIS_HSCROLL, horizontal);
    214         final long time = SystemClock.uptimeMillis();
    215         return MotionEvent.obtain(time, time, MotionEvent.ACTION_SCROLL, 1,
    216                 pointerProperties, coords, meta, 0, 1.0f, 1.0f, 0, 0,
    217                 InputDevice.SOURCE_CLASS_POINTER, 0);
    218     }
    219 }
    220