Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 27018317 authored by George Mount's avatar George Mount Committed by Android (Google) Code Review
Browse files

Merge "Tests for DatePicker keyboard interaction."

parents 29b7dd8d 57bbd6e9
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -146,6 +146,16 @@
            </intent-filter>
        </activity>

        <activity android:name="android.widget.DatePickerActivity"
                android:label="DatePickerActivity"
                android:screenOrientation="portrait"
                android:theme="@android:style/Theme.Material.Light">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
            </intent-filter>
        </activity>

        <activity android:name="android.widget.focus.DescendantFocusability" android:label="DescendantFocusability">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
+33 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2015 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.
-->

<RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    <DatePicker
            android:id="@+id/datePicker"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"/>
    <EditText
            android:id="@+id/belowPicker"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Some Text"
            android:textAlignment="center"
            android:layout_below="@id/datePicker"/>
</RelativeLayout>
+32 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 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.widget;

import android.app.Activity;
import android.os.Bundle;
import com.android.frameworks.coretests.R;

/**
 * A minimal application for DatePickerFocusTest.
 */
public class DatePickerActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.datepicker_layout);
    }
}
+250 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 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.widget;

import android.app.Activity;
import android.app.Instrumentation;
import android.os.SystemClock;
import android.test.ActivityInstrumentationTestCase2;
import android.view.KeyEvent;
import android.view.View;

import com.android.frameworks.coretests.R;

/**
 * Test {@link DatePicker} focus changes.
 */
public class DatePickerFocusTest extends ActivityInstrumentationTestCase2<DatePickerActivity> {

    private Activity mActivity;
    private Instrumentation mInstrumentation;
    private DatePicker mDatePicker;

    public DatePickerFocusTest() {
        super(DatePickerActivity.class);
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();

        mActivity = getActivity();
        mInstrumentation = getInstrumentation();

        mDatePicker = (DatePicker) mActivity.findViewById(R.id.datePicker);
    }

    /**
     * Tabs (forward and backward) through the DatePicker to ensure the correct
     * Views gain focus.
     */
    public void testFocusTravel() throws Throwable {
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                assertTrue(mDatePicker.requestFocus());
            }
        });
        assertViewHasFocus(com.android.internal.R.id.date_picker_header_year);
        sendKey(KeyEvent.KEYCODE_TAB);
        assertViewHasFocus(com.android.internal.R.id.prev);
        sendKey(KeyEvent.KEYCODE_TAB);
        assertViewHasFocus(com.android.internal.R.id.next);
        sendKey(KeyEvent.KEYCODE_TAB);
        assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
        sendKey(KeyEvent.KEYCODE_TAB);
        assertViewHasFocus(R.id.belowPicker);
        sendShiftKey(KeyEvent.KEYCODE_TAB);
        assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
        sendShiftKey(KeyEvent.KEYCODE_TAB);
        assertViewHasFocus(com.android.internal.R.id.next);
        sendShiftKey(KeyEvent.KEYCODE_TAB);
        assertViewHasFocus(com.android.internal.R.id.prev);
        sendShiftKey(KeyEvent.KEYCODE_TAB);
        assertViewHasFocus(com.android.internal.R.id.date_picker_header_year);
    }

    private void sendKey(int keycode) {
        mInstrumentation.sendKeyDownUpSync(keycode);
        mInstrumentation.waitForIdleSync();
    }

    private void assertViewHasFocus(final int id) throws Throwable {
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                View view = mActivity.findViewById(id);
                assertTrue(view.hasFocus());
            }
        });
    }

    private void sendShiftKey(int keycode) {
        final KeyEvent shiftDown = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SHIFT_LEFT);
        mInstrumentation.sendKeySync(shiftDown);

        final KeyEvent keyDown = new KeyEvent(SystemClock.uptimeMillis(),
                SystemClock.uptimeMillis(), KeyEvent.ACTION_DOWN, keycode, 0,
                KeyEvent.META_SHIFT_ON);
        mInstrumentation.sendKeySync(keyDown);

        final KeyEvent keyUp = new KeyEvent(SystemClock.uptimeMillis(),
                SystemClock.uptimeMillis(), KeyEvent.ACTION_UP, keycode, 0,
                KeyEvent.META_SHIFT_ON);
        mInstrumentation.sendKeySync(keyUp);

        final KeyEvent shiftUp = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SHIFT_LEFT);
        mInstrumentation.sendKeySync(shiftUp);

        mInstrumentation.waitForIdleSync();
    }

    /**
     * Tests to ensure the keyboard can select the current year.
     */
    public void testYearChoice() throws Throwable {
        setKnownDate();
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                View year = mDatePicker.
                        findViewById(com.android.internal.R.id.date_picker_header_year);
                assertTrue(year.requestFocus());
            }
        });
        sendKey(KeyEvent.KEYCODE_ENTER);
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                View yearSelect = mDatePicker.
                        findViewById(com.android.internal.R.id.date_picker_year_picker);
                assertEquals(yearSelect, mDatePicker.findFocus());
            }
        });
        sendKey(KeyEvent.KEYCODE_DPAD_UP);
        sendKey(KeyEvent.KEYCODE_ENTER);
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                View yearSelect = mDatePicker.
                        findViewById(com.android.internal.R.id.date_picker_year_picker);
                assertNotSame(View.VISIBLE, yearSelect.getVisibility());
                View year = mDatePicker.
                        findViewById(com.android.internal.R.id.date_picker_header_year);
                assertTrue(year.hasFocus());
                assertEquals(2014, mDatePicker.getYear());
            }
        });
    }

    public void testArrowThroughDays() throws Throwable {
        setKnownDate();
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                View prev = mDatePicker.findViewById(com.android.internal.R.id.next);
                prev.requestFocus();
            }
        });
        sendKey(KeyEvent.KEYCODE_TAB);
        // Should select the current date and the date shouldn't change
        sendKey(KeyEvent.KEYCODE_ENTER);
        assertDateIs(12, 31, 2015);
        // Move right to January 24, 2016
        sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
        sendKey(KeyEvent.KEYCODE_ENTER);
        assertDateIs(1, 24, 2016);
        // Move down to January 31, 2016
        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
        sendKey(KeyEvent.KEYCODE_ENTER);
        assertDateIs(1, 31, 2016);
        // Move up to January 5, 2016
        sendKey(KeyEvent.KEYCODE_DPAD_UP);
        sendKey(KeyEvent.KEYCODE_DPAD_UP);
        sendKey(KeyEvent.KEYCODE_DPAD_UP);
        sendKey(KeyEvent.KEYCODE_DPAD_UP);
        sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
        sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
        sendKey(KeyEvent.KEYCODE_ENTER);
        assertDateIs(1, 5, 2016);
        // Move up to prev arrow key
        sendKey(KeyEvent.KEYCODE_DPAD_UP);
        assertViewHasFocus(com.android.internal.R.id.prev);
        // tab back into the day-selection pager
        sendKey(KeyEvent.KEYCODE_TAB);
        sendKey(KeyEvent.KEYCODE_TAB);
        sendKey(KeyEvent.KEYCODE_ENTER);
        assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
        assertDateIs(1, 5, 2016);

        // Move up out again, then down back into the day-selection pager.
        // It should land right below the prev button (1/3/2016)
        sendKey(KeyEvent.KEYCODE_DPAD_UP);
        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
        sendKey(KeyEvent.KEYCODE_ENTER);
        assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
        assertDateIs(1, 3, 2016);

        // Move left to previous month (12/12/2015)
        sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
        sendKey(KeyEvent.KEYCODE_ENTER);
        assertDateIs(12, 12, 2015);
        // Now make sure the start of the month works
        // Move up to 12/5/2015 and right to 1/1/2016
        sendKey(KeyEvent.KEYCODE_DPAD_UP);
        sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
        sendKey(KeyEvent.KEYCODE_ENTER);
        assertDateIs(1, 1, 2016);
        // Now make sure the left key goes back to previous month (12/5/2015)
        sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
        sendKey(KeyEvent.KEYCODE_ENTER);
        assertDateIs(12, 5, 2015);
        // Now go to a mismatched row (no such row on previous month)
        // This moves over to 1/31/2016 and then left to 12/31/2015
        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
        sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
        sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
        sendKey(KeyEvent.KEYCODE_ENTER);
        assertDateIs(12, 31, 2015);
    }

    private void assertDateIs(int month, final int day, final int year) throws Throwable {
        final int monthInt = month - 1; // months are 0-based
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                assertEquals(day, mDatePicker.getDayOfMonth());
                assertEquals(year, mDatePicker.getYear());
                assertEquals(monthInt, mDatePicker.getMonth());
            }
        });
    }

    private void setKnownDate() throws Throwable {
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                mDatePicker.updateDate(2015, 11, 31); // December 31, 2015
            }
        });
        mInstrumentation.waitForIdleSync();
    }
}