Qt QML - handle navigation buttons? - android

Context:
Qt QML 5.6
I could not find related documentation to handle the Android navigation buttons in my QML app (triangle, square and circle, at the bottom of the screen).
Currently, when touching them, it just puts my app in the background. I would like to give them some logic.
Question:
Is it possible to manage those buttons in QML? Or will I have to deal with a c++ event handler? (If so, which code should one look after?)
Thanks

Poor man's solution:
Within the Window or application window scope, use
onClosing: {
do_what_you_need()
close.accepted = false
}
In do_what_you_need(), you may call Qt.quit if it is ok.

It is possible to manage these buttons from the QML. In QML, those key presses are handled exactly like key presses on a keyboard. For example, Qt.Key_Back refers to the back key(triangle) and Qt.Key_Home refers to the home key(square). Here is an example of listening for the home key in QML:
Keys.onPressed: {
if (event.key == Qt.Key_Home) {
console.log("Square button(home) pressed");
}
}
For more on the key enumerations in Qt, see this documentation: http://doc.qt.io/qt-5/qt.html#Key-enum

For completeness, example with ignoring the back button (do not minimize the app)
focus: true
Keys.onPressed: {
if (event.key == Qt.Key_Back) {
event.accepted = true
}
}

Related

Ionic 4: Hardware Back Button Reloading Application

Working on a Project and stuck in an Issue:
Hardware Back Button Reloading Application (I am using Angular Router in this application).
My Code to Exit Application:
ionViewDidEnter(){
this.subscription = this.platform.backButton.subscribe(()=>{
navigator['app'].exitApp();
});
}
ionViewWillLeave(){
this.subscription.unsubscribe();
}
While same logic Working in other applications. but in this application its reloading the application not exiting it.
P.S: i have also tried it to put in platform.ready() but no luck.
With IONIC 4, there is new method subscribeWithPriority developed to handle race between soft & hard back button. Try modifying your code like below:
this.platform.backButton.subscribeWithPriority(1, () => {
navigator['app'].exitApp();
});
subscribeWithPriority() stops the propagation of the event after its execution and if we subscribe with high priority and execute our prefered navigation instead of default one then it is going to work as you want.
More reference docs for details:
https://github.com/ionic-team/ionic/commit/6a5aec8b5d76280ced5e8bb8fd9ea6fe75fe6795
https://medium.com/#aleksandarmitrev/ionic-hardware-back-button-nightmare-9f4af35cbfb0
UPDATES:
Try using this new version of exitApp cordova plugin. I haven't
tried myself but looks promising from popularity.
Also try to empty the page stack from Navcontroller or go to your home screen, seems like that's causing the reload for app with sidemenu's & tab pages... this.navCtrl.pop() / this._navCtrl.navigateBack('HomeScreen'), and then call exitApp.
NOTE: Tabs & SideMenu as those have its own routing module does create lot of complexity with app navigation.
Solved:
As Mention by #rtpHarry template of SideMenu / Tabs have History which leads application to Reload it self on root page. i was able to solve this by clearing History.
ionViewDidEnter(){
navigator['app'].clearHistory();
}
on Your Root Page just Clear your history and your Hardware Back Button will close the Application instead of Reloading it.
Do you have a sidemenu in your app? I'm just curious because this seems to be when I get this problem as well.
If you look in your inspector, you will see that window.history has a length of 1.
I don't see it in some of my apps, but the app that I have a side menu setup acts this way - on the homepage if you press back the screen goes white then it reloads the app.
Like I say, looking in the inspector shows that there is a history to step back to, which it is trying to do, and whatever that history step is, it just pushes it forward back to the homepage, which made me wonder if it was the sidemenu setting up its own control of the navigation system.
I've probably said some poorly worded terminology but as I haven't solved this myself I thought I would just let you know what I had found... hopefully it helps you move forward.
In my scenario, I wasn't even trying to do the exit on back code - I just noticed that the app would appear to "reboot" if I kept pressing back.
This explain the solution on Ionic 5 (and 4.6+ too I think).
private backButtonSub: Subscription;
ionViewDidEnter() {
this.backButtonSub = this.platform.backButton.subscribeWithPriority(
10000,
() => {
// do your stuff
}
);
}
ionViewWillLeave() {
this.backButtonSub.unsubscribe();
}
also keep
IonicModule.forRoot({
hardwareBackButton: true
}),
to true (default) in your app.module.ts
Sources:
https://www.damirscorner.com/blog/posts/20191122-CustomizingAndroidBackButtonInIonic4.html
The Doc

Disable Android keyboard in qml application

I'm porting an existing QML/C++ application to the Android system. The application is already running on the Android tablet, but I have issues with Android keyboard.
Since my QML/C++ application has implemented its own keyboard, I would like to disable an Android one.
I've tried to add android:windowSoftInputMode="stateAlwaysHidden" line in AndroidManifest.xml file, but keyboard still appears when I press an edit box.
Since I'm porting an existing application, I do not want to edit the code of application itself. The only things I can edit are AndroidManifest.xml, QtApplication.java and QtActivity.java files. QtApplication and QtActivity are derived from Application and Activity Android classes.
Is it possible to disable the Android keyboard globally for whole app at the startup of application(with editing manifest file or overriding onCreate, onStart or similar functions)?
Are there any functions in Application and Activity classes that I can override them and consequently disable native keyboard?
After some time I found a solution, actually workaround for this problem. The idea was to consume an event that requests Software Input Panel (QEvent::RequestSoftwareInputPanel). This event is sent by QML/C++ application to the host Android system.
So, I implemented an event filter called SIPRequestEater.
class SIPRequestEater: public QObject
{
Q_OBJECT
protected:
bool eventFilter(QObject *obj, QEvent *event)
{
if(event->type() == QEvent::RequestSoftwareInputPanel)
{
// filter out RequestSoftwareInputPanel event
return true;
}
else
{
// standard event processing
return QObject::eventFilter(obj, event);
}
}
};
This filter has to be installed to QCoreApplication berfore the QCoreApplication::run is called.
QCoreApplication *coreApp = QCoreApplication::instance();
SIPRequestEater *sipRequestEater = new SIPRequestEater();
coreApp->installEventFilter(sipRequestEater);
It can be installed also on QApllication.
The problem is, that this filter does not catch QEvent::RequestSoftwareInputPanel event. My explanation for this is that filters, which are installed with QCoreApplication::installEventFilter(<filter>) are filters only for input events, from Android to QML application. QEvent::RequestSoftwareInputPanel is actually going in other direction, from QML application to the Android system. I didn't find out if it is possible to filter/disable output events. Because of this I decided to filter out the focus in event QEvent::FocusIn which actually causes QEvent::RequestSoftwareInputPanel.For our application this works as it should. The Android keyboard is not appearing anymore and our edit text fields still get focus, because we have our own implementation of focus and keyboard. I believe that this is not the perfect solution for everyone, that's why I called it workaround.
If someone knows, how to filter out output events, specially QEvent::RequestSoftwareInputPanel, please post it here.
The final implementation of filter is:
class SIPRequestEater: public QObject
{
Q_OBJECT
protected:
bool eventFilter(QObject *obj, QEvent *event)
{
if(event->type() == QEvent::FocusIn)
{
// filter out FocusIn event
return true;
}
else
{
// standard event processing
return QObject::eventFilter(obj, event);
}
}
};
QApplication::setAutoSipEnabled(false) disables the software virtual keyboard from popping up automatically. You can use the "Q_OS_ANDROID" preprocessor directive to avoid modifying behavior on your other target platforms:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
#ifdef Q_OS_ANDROID
a.setAutoSipEnabled(false);
#endif
(...)
}
You can programmatically display or hide the virtual keyboard using this code:
QInputMethod* input;
input = QGuiApplication::inputMethod();
if(input->isVisible())
{
input->setVisible(false);
}
else
{
input->setVisible(true);
}
Here is another approach using Qt.inputMethod - hide virtual keyboard immediately when it get visible for example by adding visibleChanged handler in qml root item
Component.onCompleted: {
Qt.inputMethod.visibleChanged.connect(function () {
if (Qt.inputMethod.visible)
Qt.inputMethod.hide()
})
}
With this approach it is also possible to add user interface setting to choose what keyboard to use (system or built in app).
Update:
Have figured out that sometimes there can be a blink of system virtual keyboard before hiding, especially when tapping to text input field to much. Handling visibleChanged in C++ don't solve this issue but seems to make it less frequently.
QObject::connect(QGuiApplication::inputMethod(), &QInputMethod::visibleChanged, [] {
QGuiApplication::inputMethod()->hide();
});

Qt Android: Pressing "Done" does not hide the keyboard

When I write into a line edit using the Android keyboard, and I press the "Done" button (screenshot below), the keyboard does not disappear. This happens even in a newly created project with just a line edit (I tested it).
How can I make "Done" to hide the keyboard?
Please note that I am looking for a developer solution (i.e. programming, not user oriented) and a native way (i.e. C++/Qt, not Java).
I'm using Qt 5.2.0.
You have to call the QInputMethod::hide() slot.
C++ Solution
connect(ui->lineEdit, SIGNAL(editingFinished()), QGuiApplication::inputMethod(), SLOT(hide()));
QML Solution
TextInput {
Keys.onEnterPressed: {
//...
Qt.inputMethod.hide()
}
Keys.onReturnPressed: {
//...
Qt.inputMethod.hide()
}
}

How Removing window from a tab in titanium?

I am using titanium appecelerator to build an app in both ios and android.
I use the following code to create a tab group and add a tab to it.
var localTabGroup = Ti.UI.createTabGroup();
var planTab = Ti.UI.createTab({
title : NYC.Common.StringConstant.TAB_TITLE_PLAN,
icon : NYC.Common.ResourcePathConstant.IMG_TAB_PLAN,
window : planTabWin
});
localTabGroup.open();
And call the following function to create a window and add it to the tab
addWindowToTabGroup : function(window) {
tabGroup.activeTab.open(window, {
animated : true
});
},
Now, I often have to remove window from the stack of the tab ( eg: on android back button or ios navigation bar back)
Till now, I use window.close() to remove the window from the stack . But, it always shows warnings like.
[ERROR][TiBaseActivity( 378)] (main) [3320,4640528] Layout cleanup.
[WARN][InputManagerService( 62)] Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy#406e4258
I was just wondering if I am following the correct approach? Or is there a better way to remove a window from the tab?
Thanks.
Tabs behave a lot differently on iOS and Android, On Android, the tab does not maintain a stack of windows. Calling open opens a new, heavyweight window, which by default covers the tab group entirely.This is very different from iOS, but it is for Android applications. Users always use the Back button to close the window and return to the tab group.
This may be happening because you are trying to remove the window even though natively Android already removes it. Check out the Android Implementation Notes of the docs here
To completely eliminate this problem, I would just open up a modal window without using the TabGroup, this would be more cross platform:
addWindowToTabGroup : function(window) {
window.open({
modal : true,
animated : true
});
}
This will open a modal window which behaves the same on both platforms, and can be handled easily by the native back button functionality.

Is there any way to capture Android's back button in mobile webkit browsers?

I know that in PhoneGap there's a way to do this, but can it be done for an HTML5 web app? I'd like to have Android users be able to use the back button within the webapp to provide a consistent UX, but of course the default is to go back in the browser history and leave the app...
Edit: tried, didn't do anything on any button press on a Google Nexus S:
document.onkeydown = checkKeycode;
function checkKeycode(e) {
var keycode;
if (window.event) keycode = window.event.keyCode;
else if (e) keycode = e.which;
alert("keycode: " + keycode);
}
Edit again: The ultimate answer seems to be to create history points at each UX interaction -- using URL hashes like #!/main/about_us in the URL. This then allows for back-button use, so long as you make sure that the UI triggers a history.back() when a UI back button is tapped.
The ultimate answer seems to be to create history points at each UX interaction -- using URL hashes like #!/main/about_us in the URL. This then allows for back-button use, so long as you make sure that the UI triggers a history.back() when a UI back button is tapped.
Override the OnKeyDown Event in your app and look for KEYCODE_BACK.
If you are handling the event then return true else false.

Categories

Resources