diff -Nru ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/debian/changelog ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/debian/changelog --- ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/debian/changelog 2013-08-27 05:06:13.000000000 +0000 +++ ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/debian/changelog 2013-08-27 05:06:13.000000000 +0000 @@ -1,3 +1,26 @@ +ubuntu-keyboard (0.99.trunk.phablet2+13.10.20130827-0ubuntu1) saucy; urgency=low + + [ Bill Filler ] + * adding autopilot test, and re-merge from trunk. + + [ Gerry Boland ] + * Create UbuntuApplicationApiWrapper to consolidate the differences + between the ubuntu-application-api on SurfaceFlinger and Mir (some + portions of the API are deprecated, so not implemented on Mir). + Fixes crash on Mir-only platform. + + [ Christopher Lee ] + * adding autopilot test, and re-merge from trunk. + + [ Ɓukasz 'sil2100' Zemczak ] + * As pointed out by Sebastian, the package:any stanza is not really + valid - we already had to revert a similar change in the past. + + [ Ubuntu daily release ] + * Automatic snapshot from revision 25 + + -- Ubuntu daily release Tue, 27 Aug 2013 02:10:27 +0000 + ubuntu-keyboard (0.99.trunk.phablet2+13.10.20130823-0ubuntu1) saucy; urgency=low [ Gerry Boland ] diff -Nru ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/debian/control ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/debian/control --- ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/debian/control 2013-08-27 05:06:13.000000000 +0000 +++ ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/debian/control 2013-08-27 05:06:13.000000000 +0000 @@ -14,6 +14,8 @@ libubuntu-platform-api1-dev, maliit-framework-dev (>= 0.99.0+git20130615+97e8335-0ubuntu3), pkg-config, + python (>= 2.7), + python-setuptools, qt5-default, qtbase5-dev, qtdeclarative5-dev, @@ -55,3 +57,12 @@ ${shlibs:Depends}, Description: Ubuntu on-screen keyboard tests Tests for the Ubuntu virtual keyboard + +Package: ubuntu-keyboard-autopilot +Architecture: all +Depends: libautopilot-qt, + ${misc:Depends}, + ${python:Depends}, + ubuntu-keyboard (>= ${source:Version}), +Description: Tests and emulators package for ubuntu-keyboard + Autopilot tests for the ubuntu-keyboard package diff -Nru ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/debian/rules ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/debian/rules --- ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/debian/rules 2013-08-27 05:06:13.000000000 +0000 +++ ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/debian/rules 2013-08-27 05:06:13.000000000 +0000 @@ -4,7 +4,7 @@ export DPKG_GENSYMBOLS_CHECK_LEVEL=4 %: - dh $@ --fail-missing + dh $@ --fail-missing --with python2 override_dh_auto_configure: dh_auto_configure -- -recursive \ @@ -19,10 +19,16 @@ CONFIG+=enable-qt-mobility override_dh_install: - # Don't install the tests + # install autopilot tests + cd tests/autopilot; \ + set -ex; for python in $(shell pyversions -r); do \ + $$python setup.py install --root=$(CURDIR)/debian/tmp --install-layout=deb; \ + done; \ + cd $(CURDIR) + # Don't install the other tests rm debian/tmp/usr/bin/language-layout-loading rm debian/tmp/usr/bin/language-layout-switching rm debian/tmp/usr/bin/repeat-backspace rm debian/tmp/usr/bin/ut_editor rm debian/tmp/usr/bin/word-candidates - dh_install + dh_install -X'*.pyc' --fail-missing diff -Nru ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/debian/ubuntu-keyboard-autopilot.install ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/debian/ubuntu-keyboard-autopilot.install --- ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/debian/ubuntu-keyboard-autopilot.install 1970-01-01 00:00:00.000000000 +0000 +++ ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/debian/ubuntu-keyboard-autopilot.install 2013-08-27 05:06:13.000000000 +0000 @@ -0,0 +1 @@ +usr/lib/python*/*/ubuntu_keyboard* diff -Nru ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/qml/Keyboard.qml ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/qml/Keyboard.qml --- ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/qml/Keyboard.qml 2013-08-23 10:08:11.000000000 +0000 +++ ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/qml/Keyboard.qml 2013-08-27 02:10:15.000000000 +0000 @@ -33,6 +33,7 @@ Item { id: canvas + objectName: "ubuntuKeyboard" // Allow us to specify a specific keyboard within autopilot. property alias layout: keyRepeater.model property variant event_handler property bool area_enabled // MouseArea has no id property so we cannot alias its enabled property. @@ -40,6 +41,10 @@ visible: layout.visible + // Expose details for use with Autopilot. + readonly property var layoutState: layout.keyboard_state + readonly property string activeView: layout.activeView + property int contentOrientation: Qt.PrimaryOrientation property bool shown: false; @@ -77,6 +82,7 @@ WordRibbon { id: wordRibbon + objectName: "wordRibbon" anchors.bottom: keypadMouseArea.top width: parent.width; @@ -125,6 +131,7 @@ } Item { + objectName: "keyboardKeypad" id: keyPad anchors.top: borderTop.bottom @@ -160,6 +167,9 @@ Text { id: key_text_item + // Expose detail for use within Autopilot + property var action_type: key_action_type + anchors.fill: parent text: key_text font.family: key_font diff -Nru ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/qml/WordRibbon.qml ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/qml/WordRibbon.qml --- ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/qml/WordRibbon.qml 2013-08-23 10:08:11.000000000 +0000 +++ ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/qml/WordRibbon.qml 2013-08-27 02:10:15.000000000 +0000 @@ -20,6 +20,7 @@ Rectangle { id: wordRibbonCanvas + objectName: "wordRibbenCanvas" state: "NORMAL" Rectangle { @@ -29,6 +30,7 @@ ListView { id: listView + objectName: "wordListView" anchors.fill: parent; model: maliit_wordribbon @@ -44,6 +46,7 @@ id: wordCandidateItem width: wordItem.width + units.gu(2); height: wordRibbonCanvas.height + property alias word_text: wordItem // For testing in Autopilot Item { anchors.fill: parent diff -Nru ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/src/lib/logic/layouthelper.h ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/src/lib/logic/layouthelper.h --- ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/src/lib/logic/layouthelper.h 2013-08-23 10:08:11.000000000 +0000 +++ ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/src/lib/logic/layouthelper.h 2013-08-27 02:10:15.000000000 +0000 @@ -35,6 +35,7 @@ #include "models/key.h" #include "models/keyarea.h" #include "models/wordribbon.h" +#include "models/layout.h" #include @@ -143,6 +144,7 @@ Q_SLOT void onKeysOverriden(const Logic::KeyOverrides &overriden_keys, bool update); + Q_SIGNAL void stateChanged(Model::Layout::State state); private: const QScopedPointer d_ptr; }; diff -Nru ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/src/lib/logic/layoutupdater.cpp ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/src/lib/logic/layoutupdater.cpp --- ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/src/lib/logic/layoutupdater.cpp 2013-08-23 10:08:11.000000000 +0000 +++ ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/src/lib/logic/layoutupdater.cpp 2013-08-27 02:10:15.000000000 +0000 @@ -733,6 +733,13 @@ converter.setLayoutOrientation(orientation); d->layout->setCenterPanel(d->inShiftedState() ? converter.shiftedKeyArea() : converter.keyArea()); + + if (d->inShiftedState()) + Q_EMIT d->layout->stateChanged(Model::Layout::ShiftedState); + else if (d->inDeadkeyState()) + Q_EMIT d->layout->stateChanged(Model::Layout::DeadkeyState); + else + Q_EMIT d->layout->stateChanged(Model::Layout::DefaultState); } void LayoutUpdater::switchToPrimarySymView() @@ -750,6 +757,8 @@ // Reset shift state machine, also see switchToMainView. d->shift_machine.restart(); + + Q_EMIT d->layout->stateChanged(Model::Layout::PrimarySymbolState); } void LayoutUpdater::switchToSecondarySymView() @@ -764,6 +773,8 @@ KeyAreaConverter converter(d->style->attributes(), &d->loader); converter.setLayoutOrientation(orientation); d->layout->setCenterPanel(converter.symbolsKeyArea(1)); + + Q_EMIT d->layout->stateChanged(Model::Layout::SecondarySymbolState); } void LayoutUpdater::switchToAccentedView() diff -Nru ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/src/lib/models/layout.cpp ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/src/lib/models/layout.cpp --- ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/src/lib/models/layout.cpp 2013-08-23 10:08:11.000000000 +0000 +++ ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/src/lib/models/layout.cpp 2013-08-27 02:10:15.000000000 +0000 @@ -63,6 +63,7 @@ KeyArea key_area; QString image_directory; QHash roles; + Layout::State state; QString activeViewId; explicit LayoutPrivate(); @@ -74,6 +75,7 @@ , key_area() , image_directory() , roles() + , state(Layout::DefaultState) { // Model roles are used as variables in QML, hence the under_score naming // convention: @@ -88,6 +90,7 @@ roles[Layout::RoleKeyFontStretch] = "key_font_stretch"; roles[Layout::RoleKeyIcon] = "key_icon"; roles[Layout::RoleKeyActionInsert] = "key_action_insert"; + roles[Layout::RoleKeyAction] = "key_action_type"; } @@ -230,6 +233,18 @@ qGuiApp->primaryScreen()->orientation()) ); } +Layout::State Layout::state() const +{ + Q_D(const Layout); + return d->state; +} + +void Layout::setState(Model::Layout::State state) +{ + Q_D(Layout); + d->state = state; + Q_EMIT stateChanged(state); +} QString Layout::activeView() const { @@ -321,6 +336,9 @@ case RoleKeyActionInsert: return QVariant(key.action() == Key::ActionInsert); + + case RoleKeyAction: + return QVariant(key.action()); } qWarning() << __PRETTY_FUNCTION__ diff -Nru ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/src/lib/models/layout.h ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/src/lib/models/layout.h --- ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/src/lib/models/layout.h 2013-08-23 10:08:11.000000000 +0000 +++ ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/src/lib/models/layout.h 2013-08-27 02:10:15.000000000 +0000 @@ -78,11 +78,22 @@ Q_PROPERTY(int invisible_toucharea_height READ invisibleTouchAreaHeight NOTIFY invisibleTouchAreaHeightChanged) + Q_PROPERTY(State keyboard_state READ state WRITE setState + NOTIFY stateChanged) Q_PROPERTY(QString activeView READ activeView WRITE setActiveView NOTIFY activeViewChanged) + Q_ENUMS(State) public: + enum State { + DefaultState, + ShiftedState, + PrimarySymbolState, + SecondarySymbolState, + DeadkeyState + }; + enum Roles { RoleKeyRectangle = Qt::UserRole + 1, RoleKeyReactiveArea, @@ -94,7 +105,8 @@ RoleKeyFontSize, RoleKeyFontStretch, RoleKeyIcon, - RoleKeyActionInsert + RoleKeyActionInsert, + RoleKeyAction // Extra introspection detail for testing. }; explicit Layout(QObject *parent = 0); @@ -137,6 +149,10 @@ Q_SLOT int invisibleTouchAreaHeight() const; Q_SIGNAL void invisibleTouchAreaHeightChanged(int &changed); + Q_SLOT State state() const; + Q_SLOT void setState(Model::Layout::State state); + Q_SIGNAL void stateChanged(Model::Layout::State state); + Q_SLOT QString activeView() const; Q_SLOT void setActiveView(const QString& activeViewId); Q_SIGNAL void activeViewChanged(const QString &activeViewId); diff -Nru ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/src/plugin/inputmethod.cpp ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/src/plugin/inputmethod.cpp --- ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/src/plugin/inputmethod.cpp 2013-08-23 10:08:11.000000000 +0000 +++ ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/src/plugin/inputmethod.cpp 2013-08-27 02:10:15.000000000 +0000 @@ -33,6 +33,7 @@ #include "editor.h" #include "updatenotifier.h" #include "maliitcontext.h" +#include "ubuntuapplicationapiwrapper.h" #include "models/key.h" #include "models/keyarea.h" @@ -69,12 +70,6 @@ #include #include -#ifdef QT_OPENGL_ES_2 -#include -#include - #define HAVE_UBUNTU_PLATFORM_API -#endif - class MImUpdateEvent; namespace MaliitKeyboard { @@ -168,6 +163,7 @@ QRect keyboardVisibleRect; MAbstractInputMethodHost* host; QQuickView* view; + UbuntuApplicationApiWrapper* applicationApiWrapper; bool predictionEnabled; Maliit::TextContentType contentType; @@ -175,6 +171,7 @@ explicit InputMethodPrivate(InputMethod * const q, MAbstractInputMethodHost *host); + ~InputMethodPrivate(); void setLayoutOrientation(Qt::ScreenOrientation qtOrientation); void updateKeyboardOrientation(); void updateWordRibbon(); @@ -207,6 +204,7 @@ , context(q, style) , host(host) , view(0) + , applicationApiWrapper(new UbuntuApplicationApiWrapper) , predictionEnabled(false) , contentType(Maliit::FreeTextContentType) , activeLanguageId("en_us") @@ -246,6 +244,9 @@ QObject::connect(&layout.updater, SIGNAL(languageChanged(QString)), &editor, SLOT(onLanguageChanged(const QString&))); + QObject::connect(&layout.helper, SIGNAL(stateChanged(Model::Layout::State)), + &layout.model, SLOT(setState(Model::Layout::State))); + #ifdef EXTENDED_SURFACE_TEMP_DISABLED QObject::connect(&layout.event_handler, SIGNAL(extendedKeysShown(Key)), &extended_layout.event_handler, SLOT(onExtendedKeysShown(Key))); @@ -286,19 +287,21 @@ magnifier_surface->view()->setSource(QUrl::fromLocalFile(g_maliit_magnifier_qml)); #endif -#ifdef HAVE_UBUNTU_PLATFORM_API + // following used to help shell identify the OSK surface - view->setProperty("role", static_cast(U_ON_SCREEN_KEYBOARD_ROLE)); + view->setProperty("role", applicationApiWrapper->oskWindowRole()); view->setTitle("MaliitOnScreenKeyboard"); -#else - view->setProperty("role", 7); -#endif // workaround: resizeMode not working in current qpa imlementation // http://qt-project.org/doc/qt-5.0/qtquick/qquickview.html#ResizeMode-enum view->setResizeMode(QQuickView::SizeRootObjectToView); } +InputMethodPrivate::~InputMethodPrivate() +{ + delete applicationApiWrapper; +} + void InputMethodPrivate::updateWordRibbon() { layout.helper.wordRibbon()->setEnabled( predictionEnabled ); @@ -338,9 +341,8 @@ qmlRootItem->setProperty("contentOrientation", screenOrientation); -#ifdef HAVE_UBUNTU_PLATFORM_API if (qmlRootItem->property("shown").toBool()) { - ubuntu_ui_report_osk_invisible(); + applicationApiWrapper->reportOSKInvisible(); qDebug() << "keyboard is reporting: total : <" << windowGeometryRect.x() @@ -355,15 +357,13 @@ << "> to the app manager."; // report the visible part as input trap, the invisible part can click through, e.g. browser url bar - ubuntu_ui_report_osk_visible( + applicationApiWrapper->reportOSKVisible( keyboardVisibleRect.x(), keyboardVisibleRect.y(), keyboardVisibleRect.width(), keyboardVisibleRect.height() ); } - -#endif } void InputMethodPrivate::updateKeyboardOrientation() @@ -498,7 +498,6 @@ rect.moveTop( d->windowGeometryRect.height() - d->keyboardVisibleRect.height() ); inputMethodHost()->setInputMethodArea(rect, d->view); -#ifdef HAVE_UBUNTU_PLATFORM_API qDebug() << "keyboard is reporting : <" << d->keyboardVisibleRect.x() << d->keyboardVisibleRect.y() @@ -506,13 +505,12 @@ << d->keyboardVisibleRect.height() << "> to the app manager."; - ubuntu_ui_report_osk_visible( + d->applicationApiWrapper->reportOSKVisible( d->keyboardVisibleRect.x(), d->keyboardVisibleRect.y(), d->keyboardVisibleRect.width(), d->keyboardVisibleRect.height() ); -#endif d->qmlRootItem->setProperty("shown", true); } @@ -534,9 +532,7 @@ inputMethodHost()->setInputMethodArea(r); #endif -#ifdef HAVE_UBUNTU_PLATFORM_API - ubuntu_ui_report_osk_invisible(); -#endif + d->applicationApiWrapper->reportOSKInvisible(); d->qmlRootItem->setProperty("shown", false); } diff -Nru ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/src/plugin/plugin.pro ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/src/plugin/plugin.pro --- ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/src/plugin/plugin.pro 2013-08-23 10:08:11.000000000 +0000 +++ ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/src/plugin/plugin.pro 2013-08-27 02:10:15.000000000 +0000 @@ -25,6 +25,7 @@ editor.h \ updatenotifier.h \ maliitcontext.h \ + ubuntuapplicationapiwrapper.h SOURCES += \ plugin.cpp \ @@ -32,6 +33,7 @@ editor.cpp \ updatenotifier.cpp \ maliitcontext.cpp \ + ubuntuapplicationapiwrapper.cpp target.path += $${MALIIT_PLUGINS_DIR} INSTALLS += target diff -Nru ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/src/plugin/ubuntuapplicationapiwrapper.cpp ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/src/plugin/ubuntuapplicationapiwrapper.cpp --- ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/src/plugin/ubuntuapplicationapiwrapper.cpp 1970-01-01 00:00:00.000000000 +0000 +++ ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/src/plugin/ubuntuapplicationapiwrapper.cpp 2013-08-27 02:10:15.000000000 +0000 @@ -0,0 +1,67 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "ubuntuapplicationapiwrapper.h" + +#ifdef QT_OPENGL_ES_2 +#include +#include + #define HAVE_UBUNTU_PLATFORM_API +#endif + +#include +#include + +UbuntuApplicationApiWrapper::UbuntuApplicationApiWrapper() + : m_runningOnMir(false) +{ + if (qgetenv("QT_QPA_PLATFORM") == "ubuntumirclient") { + m_runningOnMir = false; + } +} + +void UbuntuApplicationApiWrapper::reportOSKVisible(const int x, const int y, const int width, const int height) +{ +#ifdef HAVE_UBUNTU_PLATFORM_API + if (!m_runningOnMir) { // following method not implemented on Mir + ubuntu_ui_report_osk_visible(x, y, width, height); + } +#else + Q_UNUSED(x) + Q_UNUSED(y) + Q_UNUSED(width) + Q_UNUSED(height) +#endif +} + +void UbuntuApplicationApiWrapper::reportOSKInvisible() +{ +#ifdef HAVE_UBUNTU_PLATFORM_API + if (!m_runningOnMir) { // following method not implemented on Mir + ubuntu_ui_report_osk_invisible(); + } +#endif +} + +int UbuntuApplicationApiWrapper::oskWindowRole() const +{ +#ifdef HAVE_UBUNTU_PLATFORM_API + return static_cast(U_ON_SCREEN_KEYBOARD_ROLE); +#else + return 7; +#endif +} + diff -Nru ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/src/plugin/ubuntuapplicationapiwrapper.h ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/src/plugin/ubuntuapplicationapiwrapper.h --- ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/src/plugin/ubuntuapplicationapiwrapper.h 1970-01-01 00:00:00.000000000 +0000 +++ ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/src/plugin/ubuntuapplicationapiwrapper.h 2013-08-27 02:10:15.000000000 +0000 @@ -0,0 +1,45 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef UBUNTUAPPLICATIONAPIWRAPPER_H +#define UBUNTUAPPLICATIONAPIWRAPPER_H + +/* + * Class: UbuntuApplicationApiWrapper + * The OSK-related functions in the ubuntu application api are marked as deprecated. + * To ensure OSK works on platforms with & without (i.e. Mir), check which platform + * we are running on: if SurfaceFlinger-based, call the deprecated API, else NOOP. + * + * Have added other little methods to help smooth the transition. + * + * Once we discard the SurfaceFlinger-base, much of this can be removed. + */ + +class UbuntuApplicationApiWrapper +{ +public: + UbuntuApplicationApiWrapper(); + + int oskWindowRole() const; + + void reportOSKVisible(const int, const int, const int, const int); + void reportOSKInvisible(); + +private: + bool m_runningOnMir; +}; + +#endif // UBUNTUAPPLICATIONAPIWRAPPER_H diff -Nru ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/tests/autopilot/setup.py ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/tests/autopilot/setup.py --- ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/tests/autopilot/setup.py 1970-01-01 00:00:00.000000000 +0000 +++ ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/tests/autopilot/setup.py 2013-08-27 02:10:15.000000000 +0000 @@ -0,0 +1,32 @@ +#!/usr/bin/python +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- +# +# Ubuntu Keyboard Autopilot Test Suite +# Copyright (C) 2013 Canonical +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + + +from distutils.core import setup +from setuptools import find_packages + +setup( + name='ubuntu_keyboard', + version='1.0', + description='Ubuntu Keyboard autopilot tests and emulators.', + url='https://launchpad.net/ubuntu-keyboard', + license='GPLv3', + packages=find_packages(), +) diff -Nru ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/tests/autopilot/ubuntu_keyboard/__init__.py ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/tests/autopilot/ubuntu_keyboard/__init__.py --- ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/tests/autopilot/ubuntu_keyboard/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/tests/autopilot/ubuntu_keyboard/__init__.py 2013-08-27 02:10:15.000000000 +0000 @@ -0,0 +1,18 @@ +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- +# +# Ubuntu Keyboard Test Suite +# Copyright (C) 2013 Canonical +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# diff -Nru ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/tests/autopilot/ubuntu_keyboard/emulators/__init__.py ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/tests/autopilot/ubuntu_keyboard/emulators/__init__.py --- ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/tests/autopilot/ubuntu_keyboard/emulators/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/tests/autopilot/ubuntu_keyboard/emulators/__init__.py 2013-08-27 02:10:15.000000000 +0000 @@ -0,0 +1,18 @@ +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- +# +# Ubuntu Keyboard Test Suite +# Copyright (C) 2013 Canonical +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# diff -Nru ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/tests/autopilot/ubuntu_keyboard/emulators/keyboard.py ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/tests/autopilot/ubuntu_keyboard/emulators/keyboard.py --- ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/tests/autopilot/ubuntu_keyboard/emulators/keyboard.py 1970-01-01 00:00:00.000000000 +0000 +++ ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/tests/autopilot/ubuntu_keyboard/emulators/keyboard.py 2013-08-27 02:10:15.000000000 +0000 @@ -0,0 +1,346 @@ +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- +# +# Ubuntu Keyboard Test Suite +# Copyright (C) 2013 Canonical +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +from collections import defaultdict, namedtuple +from time import sleep +import logging + +from autopilot.input import Pointer, Touch +from autopilot.introspection import ( + get_proxy_object_for_existing_process, + ProcessSearchError +) + + +logger = logging.getLogger(__name__) + + +# Definitions of enums used within the cpp source code. +class KeyboardState: + DEFAULT = 0 + SHIFTED = 1 + SYMBOL_1 = 2 + SYMBOL_2 = 3 + + +class KeyAction: + INSERT = 0 + SHIFT = 1 + BACKSPACE = 2 + SPACE = 3 + SYM = 6 + RETURN = 7 + SWITCH = 11 + + +class UnsupportedKey(RuntimeError): + pass + + +class Keyboard(object): + + KeyPos = namedtuple("KeyPos", ['x', 'y', 'h', 'w']) + + # Note (veebers 19-aug-13): this hardcoded right now, but will be reading + # data from the keyboard itself in the very near future. Moved '/' to + # primary symbol, default layout can have a .com instead. + default_keys = "qwertyuiopasdfghjklzxcvbnm." + shifted_keys = "QWERTYUIOPASDFGHJKLZXCVBNM." + primary_symbol = "1234567890*#+-=()!?@~/\\';:,." + secondary_symbol = u"$%<>[]`^|_{}\"&,.\u20ac\xa3\xa5\u20b9\xa7\xa1\xbf" \ + u"\xab\xbb\u201c\u201d\u201e" + + # The ability to name the non-text keys. + _action_id_to_text = { + KeyAction.SHIFT: 'SHIFT', + KeyAction.BACKSPACE: '\b', + KeyAction.SPACE: ' ', + KeyAction.RETURN: '\n' + } + + def __init__(self, pointer=None): + try: + maliit = get_proxy_object_for_existing_process( + connection_name='org.maliit.server' + ) + except ProcessSearchError as e: + e.args += ( + "Unable to find maliit-server dbus object. Has it been " + "started with introspection enabled?", + ) + raise + + try: + self.keyboard = maliit.select_single( + "Keyboard", + objectName="ubuntuKeyboard" + ) + if self.keyboard is None: + raise RuntimeError( + "Unable to find the Ubuntu Keyboard object within the " + "maliit server" + ) + except ValueError as e: + e.args += ( + "There was more than one Keyboard object found, aborting.", + ) + raise + + try: + self.keypad = self.keyboard.select_single( + "QQuickItem", + objectName="keyboardKeypad" + ) + + if self.keypad is None: + raise RuntimeError( + "Unable to find the keypad object within the " + "maliit server" + ) + except ValueError as e: + e.args += ( + "There was more than one keyboard keypad object found, " + "aborting.", + ) + raise + + # Contains instructions on how to move the keyboard into a specific + # state/layout so that we can successfully press the required key. + self._state_lookup_table = self._generate_state_lookup_table() + # Cache the position of the keys + self._key_pos_table = defaultdict(dict) + + if pointer is None: + self.pointer = Pointer(Touch.create()) + else: + self.pointer = pointer + + def dismiss(self): + """Swipe the keyboard down to hide it. + + :raises: *AssertionError* if the state.wait_for fails meaning that the + keyboard failed to hide. + + """ + if self.is_available(): + x, y, h, w = self.keyboard.globalRect + x_pos = int(w / 2) + # start_y: just inside the keyboard, must be a better way than +1px + start_y = y + 1 + end_y = y + int(h / 2) + self.pointer.drag(x_pos, start_y, x_pos, end_y) + + self.keyboard.state.wait_for("HIDDEN") + + def is_available(self): + """Returns true if the keyboard is shown and ready to use.""" + return ( + self.keyboard.state == "SHOWN" + and not self.keyboard.hideAnimationFinished + ) + + @property + def current_state(self): + return self.keyboard.layoutState + + # Much like is_available, but attempts to wait for the keyboard to be + # ready. + def wait_for_keyboard_ready(self, timeout=10): + """Waits for *timeout* for the keyboard to be ready and returns + true. Returns False if the keyboard fails to be considered ready within + the alloted time. + + """ + try: + self.keyboard.state.wait_for("SHOWN", timeout=timeout) + self.keyboard.hideAnimationFinished.wait_for( + False, + timeout=timeout + ) + return True + except RuntimeError: + return False + + def get_key_position(self, key): + """Returns the global rect of the given key. + + It may need to do a lookup to update the table of positions. + + """ + current_state = self.keyboard.layoutState + if self._key_pos_table.get(current_state) is None: + self._update_pos_table_for_current_state() + + return self._key_pos_table[current_state][key] + + def _update_pos_table_for_current_state(self): + all_keys = self.keypad.select_many('QQuickText') + current_state = self.keyboard.layoutState + labeled_keys = (KeyAction.INSERT, KeyAction.SWITCH, KeyAction.SYM) + for key in all_keys: + with key.no_automatic_refreshing(): + key_pos = Keyboard.KeyPos(*key.globalRect) + if key.action_type in labeled_keys: + self._key_pos_table[current_state][key.text] = key_pos + else: + key_text = Keyboard._action_id_to_text[key.action_type] + self._key_pos_table[current_state][key_text] = key_pos + + def press_key(self, key): + """Tap on the key with the internal pointer + + :params key: String containing the text of the key to tap. + + :raises: *RuntimeError* if the keyboard is not available and thus not + ready to be used. + :raises: *UnsupportedKey* if the supplied key cannot be found on any of + the the current keyboards layouts. + """ + if not self.is_available(): + raise RuntimeError("Keyboard is not on screen") + + if not self._is_special_key(key): + required_state_for_key = self._get_keys_required_state(key) + self._switch_keyboard_to_state(required_state_for_key) + + key_rect = self.get_key_position(key) + self.pointer.click_object(key_rect) + + def type(self, string, delay=0.1): + """Type the string *string* with a delay of *delay* between each key + press + + .. note:: The delay provides a minimum delay, it may take longer + between each press as the keyboard shifts between states etc. + + Only 'normal' or single characters can be typed this way. + + :raises: *UnsupportedKey* if one of the the supplied keys cannot be + found on any of the the current keyboards layouts. + + """ + for char in string: + self.press_key(char) + sleep(delay) + + def _get_keys_required_state(self, char): + """Given a character determine which state the keyboard needs to be in + so that it is visible and can be clicked. + + """ + + if char in Keyboard.default_keys: + return KeyboardState.DEFAULT + elif char in Keyboard.shifted_keys: + return KeyboardState.SHIFTED + elif char in Keyboard.primary_symbol: + return KeyboardState.SYMBOL_1 + elif char in Keyboard.secondary_symbol: + return KeyboardState.SYMBOL_2 + else: + raise UnsupportedKey( + "Don't know which state key '%s' requires" % char + ) + + def _switch_keyboard_to_state(self, target_state): + """Given a target_state, presses the required keys to bring the + keyboard into the correct state. + + :raises: *RuntimeError* if unable to change the keyboard into the + expected state. + + """ + current_state = self.keyboard.layoutState + + if target_state == current_state: + return + + instructions = self._state_lookup_table[target_state].get( + current_state, + None + ) + if instructions is None: + raise RuntimeError( + "Don't know how to get to state %d from current state (%d)" + % (target_state, current_state) + ) + + for step in instructions: + key, expected_state = step + self.press_key(key) + self.keyboard.layoutState.wait_for(expected_state) + + def _is_special_key(self, key): + return key in ["\n", "\b", " ", "SHIFT", "?123", "ABC", "1/2", "2/2"] + + # Give the state that you want and the current state, get instructions on + # how to move to that state. + # lookup_table[REQUESTED_STATE][CURRENT_STATE] -> Instructions(Key to + # press, Expected state after key press.) + def _generate_state_lookup_table(self): + return { + KeyboardState.DEFAULT: { + KeyboardState.SHIFTED: [ + ("SHIFT", KeyboardState.DEFAULT) + ], + KeyboardState.SYMBOL_1: [ + ("ABC", KeyboardState.DEFAULT) + ], + KeyboardState.SYMBOL_2: [ + ("ABC", KeyboardState.DEFAULT) + ], + }, + KeyboardState.SHIFTED: { + KeyboardState.DEFAULT: [ + ("SHIFT", KeyboardState.SHIFTED) + ], + KeyboardState.SYMBOL_1: [ + ("ABC", KeyboardState.DEFAULT), + ("SHIFT", KeyboardState.SHIFTED) + ], + KeyboardState.SYMBOL_2: [ + ("ABC", KeyboardState.DEFAULT), + ("SHIFT", KeyboardState.SHIFTED) + ], + }, + KeyboardState.SYMBOL_1: { + KeyboardState.DEFAULT: [ + ("?123", KeyboardState.SYMBOL_1) + ], + KeyboardState.SHIFTED: [ + ("?123", KeyboardState.SYMBOL_1) + ], + KeyboardState.SYMBOL_2: [ + ("2/2", KeyboardState.SYMBOL_1) + ], + }, + KeyboardState.SYMBOL_2: { + KeyboardState.DEFAULT: [ + ("?123", KeyboardState.SYMBOL_1), + ("1/2", KeyboardState.SYMBOL_2) + ], + KeyboardState.SHIFTED: [ + ("?123", KeyboardState.SYMBOL_1), + ("1/2", KeyboardState.SYMBOL_2) + ], + KeyboardState.SYMBOL_1: [ + ("1/2", KeyboardState.SYMBOL_2) + ], + }, + } diff -Nru ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/tests/autopilot/ubuntu_keyboard/tests/__init__.py ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/tests/autopilot/ubuntu_keyboard/tests/__init__.py --- ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/tests/autopilot/ubuntu_keyboard/tests/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/tests/autopilot/ubuntu_keyboard/tests/__init__.py 2013-08-27 02:10:15.000000000 +0000 @@ -0,0 +1,18 @@ +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- +# +# Ubuntu Keyboard Test Suite +# Copyright (C) 2013 Canonical +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# diff -Nru ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/tests/autopilot/ubuntu_keyboard/tests/test_keyboard.py ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/tests/autopilot/ubuntu_keyboard/tests/test_keyboard.py --- ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130823/tests/autopilot/ubuntu_keyboard/tests/test_keyboard.py 1970-01-01 00:00:00.000000000 +0000 +++ ubuntu-keyboard-0.99.trunk.phablet2+13.10.20130827/tests/autopilot/ubuntu_keyboard/tests/test_keyboard.py 2013-08-27 02:10:15.000000000 +0000 @@ -0,0 +1,342 @@ +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- +# +# Ubuntu Keyboard Test Suite +# Copyright (C) 2013 Canonical +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import os + +from testtools.matchers import Equals +from tempfile import mktemp +from textwrap import dedent + +from autopilot.testcase import AutopilotTestCase +from autopilot.input import Pointer, Touch +from autopilot.matchers import Eventually + +from ubuntu_keyboard.emulators.keyboard import Keyboard, KeyboardState + + +class UbuntuKeyboardTests(AutopilotTestCase): + def setUp(self): + super(UbuntuKeyboardTests, self).setUp() + self.pointer = Pointer(Touch.create()) + + def launch_test_input_area(self, label="", input_hints=None): + self.app = self._launch_simple_input(label, input_hints) + text_area = self.app.select_single("QQuickTextInput") + + return text_area + + def ensure_focus_on_input(self, input_area): + self.pointer.click_object(input_area) + keyboard = Keyboard() + self.addCleanup(keyboard.dismiss) + self.assertThat(keyboard.is_available, Eventually(Equals(True))) + + def _start_qml_script(self, script_contents): + """Launch a qml script.""" + qml_path = mktemp(suffix='.qml') + open(qml_path, 'w').write(script_contents) + self.addCleanup(os.remove, qml_path) + + return self.launch_test_application( + "qmlscene", + qml_path, + app_type='qt', + ) + + def _launch_simple_input(self, label="", input_hints=None): + if input_hints is None: + extra_script = "Qt.ImhNoPredictiveText" + else: + extra_script = "|".join(input_hints) + + simple_script = dedent(""" + import QtQuick 2.0 + import Ubuntu.Components 0.1 + + Rectangle { + id: window + objectName: "windowRectangle" + color: "lightgrey" + + Text { + id: inputLabel + text: "%(label)s" + font.pixelSize: units.gu(3) + anchors { + left: input.left + top: parent.top + topMargin: 25 + bottomMargin: 25 + } + } + + TextField { + id: input; + objectName: "input" + anchors { + top: inputLabel.bottom + horizontalCenter: parent.horizontalCenter + topMargin: 10 + } + inputMethodHints: %(input_method)s + } + } + + """ % {'label': label, 'input_method': extra_script}) + + return self._start_qml_script(simple_script) + + +class UbuntuKeyboardTestsAccess(UbuntuKeyboardTests): + + def test_keyboard_is_available(self): + keyboard = Keyboard() + self.addCleanup(keyboard.dismiss) + app = self._launch_simple_input() + text_rectangle = app.select_single("QQuickTextInput") + + self.pointer.click_object(text_rectangle) + + self.assertThat(keyboard.is_available, Eventually(Equals(True))) + + +class UbuntuKeyboardTypingTests(UbuntuKeyboardTests): + + scenarios = [ + ( + 'lower_alpha', + dict( + label="Lowercase", + input='abcdefghijklmnopqrstuvwxyz' + ) + ), + ( + 'upper_alpha', + dict( + label="Uppercase", + input='ABCDEFGHIJKLMNOPQRSTUVWXYZ' + ) + ), + ( + 'numeric', + dict( + label="Numeric", + input='0123456789' + ) + ), + ( + 'punctuation', + dict( + label="Puncuation", + input='`~!@#$%^&*()_-+={}[]|\\:;"\'<>,.?/' + ) + ) + ] + + def test_can_type_string(self): + text_area = self.launch_test_input_area(label=self.label) + self.ensure_focus_on_input(text_area) + keyboard = Keyboard() + self.addCleanup(keyboard.dismiss) + + keyboard.type(self.input) + + self.assertThat(text_area.text, Eventually(Equals(self.input))) + + +class UbuntuKeyboardStateChanges(UbuntuKeyboardTests): + + # Note: this is a failing test due to bug lp:1214695 + # Note: based on UX design doc + def test_keyboard_layout_starts_shifted(self): + """When first launched the keyboard state must be + shifted/capitalised. + + """ + text_area = self.launch_test_input_area() + self.ensure_focus_on_input(text_area) + keyboard = Keyboard() + self.addCleanup(keyboard.dismiss) + + self.assertThat( + keyboard.keyboard.layoutState, + Eventually(Equals(KeyboardState.SHIFTED)) + ) + + def test_shift_latch(self): + """Double tap of the shift key must lock it 'On' until the shift key + tapped again. + + Normally hitting shift then a letter reverts from the shifted state + back to the default. If double clicked it should stay in the shifted + until the shift key is clicked again. + + """ + text_area = self.launch_test_input_area() + self.ensure_focus_on_input(text_area) + keyboard = Keyboard() + self.addCleanup(keyboard.dismiss) + + keyboard.type('abc') + keyboard.press_key('SHIFT') + keyboard.press_key('SHIFT') + keyboard.type('S') + + self.assertThat( + keyboard.keyboard.layoutState, + Eventually(Equals(KeyboardState.SHIFTED)) + ) + self.assertThat(text_area.text, Eventually(Equals('abcS'))) + + # Note: based on UX design doc + def test_shift_state_returns_to_default_after_letter_typed(self): + """Pushing shift and then typing an uppercase letter must automatically + shift the keyboard back into the default state. + + """ + text_area = self.launch_test_input_area() + self.ensure_focus_on_input(text_area) + keyboard = Keyboard() + self.addCleanup(keyboard.dismiss) + + # Normally, type and (press_key) take care of shifting into the correct + # state, we do it manually here as that's what we're testing. + keyboard.type('abc') + keyboard.press_key('SHIFT') + keyboard.type('A') + + # Once the capital letter has been typed, we must be able to access the + # lowercase letters, otherwise it's not in the correct state. + self.assertThat( + keyboard.keyboard.layoutState, + Eventually(Equals(KeyboardState.DEFAULT)) + ) + + self.assertThat(text_area.text, Eventually(Equals('abcA'))) + + # Note: this is a failing test due to bug lp:1214695 + # Note: Based on UX design doc. + def test_shift_state_entered_after_fullstop(self): + """After typing a fullstop the keyboard state must automatically + enter the shifted state. + + """ + text_area = self.launch_test_input_area() + self.ensure_focus_on_input(text_area) + keyboard = Keyboard() + self.addCleanup(keyboard.dismiss) + + keyboard.type("abc.") + + self.assertThat( + text_area.text, + Eventually(Equals("abc.")) + ) + + self.assertThat( + keyboard.keyboard.layoutState, + Eventually(Equals(KeyboardState.SHIFTED)) + ) + + def test_switching_between_states(self): + """The user must be able to type many different characters including + spaces and backspaces. + + """ + text_area = self.launch_test_input_area() + self.ensure_focus_on_input(text_area) + keyboard = Keyboard() + self.addCleanup(keyboard.dismiss) + + keyboard.type( + 'abc gone\b\b & \bABC (123)' + ) + + expected = "abc go & ABC (123)" + self.assertThat( + text_area.text, + Eventually(Equals(expected)) + ) + + +class UbuntuKeyboardInputTypeStateChange(UbuntuKeyboardTests): + """Note: these tests are currently failing due to bug lp:1214694 (the + activeView detail isn't exposed correctly nor is it updated as expected + (i.e. when the view changes.)) + + """ + + scenarios = [ + ( + "Url", + dict( + label="Url", + hints=['Qt.ImhUrlCharactersOnly'], + expected_activeview="url" + ) + ), + ( + "Password", + dict( + label="Password", + hints=['Qt.ImhHiddenText', 'Qt.ImhSensitiveData'], + expected_activeview="password" + ) + ), + ( + "Email", + dict( + label="Email", + hints=['Qt.ImhEmailCharactersOnly'], + expected_activeview="email" + ) + ), + ( + "Number", + dict( + label="Number", + hints=['Qt.ImhFormattedNumbersOnly'], + expected_activeview="number" + ) + ), + ( + "Telephone", + dict( + label="Telephone", + hints=['Qt.ImhDigitsOnly'], + expected_activeview="phonenumber" + ) + ), + ] + + # Note: based on UX design doc + def test_keyboard_layout(self): + """The Keyboard must respond to the input type and change to be the + correct state. + + """ + text_area = self.launch_test_input_area(self.label, self.hints) + self.ensure_focus_on_input(text_area) + keyboard = Keyboard() + self.addCleanup(keyboard.dismiss) + + self.assertThat( + keyboard.keyboard.activeView, + Eventually(Equals(self.expected_activeview)) + )