Android Native DatePicker not showing


#1

I’m trying to write a plugin for a specific project I’m working on, I need to use the Date and Time Pickers for this. I found the way to get the pickers, even using properties such as “isShowing()” give me a result. But, when I try to show the dialog on screen it comes up with an error that starts like this:

Error: android.view.WindowManager$BadTokenException: Unable to add window - token null is not for an application ...

Here is the code I’ve used for it. I’m making tests on the main-page.js instead of the view model:

var Application = require(‘application’);
var createViewModel = require("./main-view-model").createViewModel;
var View = require(‘ui/core/view’).View;
var btn = new android.widget.Button(Application.android.context);
var datepicker = new android.app.DatePickerDialog(Application.android.context);
//var view = new android.view.Window(Application.android.context);
function onNavigatingTo(args) {
btn.setText(“Hello there”);
datepicker.show();
page.bindingContext = createViewModel();
}
exports.onNavigatingTo = onNavigatingTo;

Thanks in advance!


#2

@BryanYomar I think you are missing the part where the datepicker is displayed inside an Android fragment

Read up https://developer.android.com/guide/topics/ui/controls/pickers.html for implementation details in Android

you then call .show() on the DialogFragment.

PS. Apologies for not elaborating more, in a rush :smiley:


#3

Thanks a lot, I’ll be looking into that!
No worries!! :smile:


#4

So far this is what I’ve done:

var Application = require('application');
var createViewModel = require("./main-view-model").createViewModel;

var View = require('ui/core/view').View;
var btn = new android.widget.Button(Application.android.context);
var datepicker = new android.app.DatePickerDialog(Application.android.context);
var dialogFragment = new android.app.DialogFragment;
var frag = new android.support.v4.app.FragmentActivity;
//var view = new android.view.Window(Application.android.context);

var DatePickerDialog = android.app.DialogFragment.extend({
    init: function() {
        console.log("Estoy vivo");
    },
    onCreateDialog: function() {
        console.log("I'm here now");
        return new android.app.DatePickerDialog(Application.android.context);
    }
});

function onNavigatingTo(args) {
    var page = args.object;
    btn.setText("Hello there");

    // console.log(dialogFragment.getShowsDialog());
    // dialogFragment.setShowsDialog(true);
    var dfrag = new DatePickerDialog();
    dfrag.onCreateDialog().show(frag.getSupportFragmentManager(), 'DatePicker');


    // datepicker.show();

    page.bindingContext = createViewModel();
}
exports.onNavigatingTo = onNavigatingTo;

But still it gives me this error:

Failed resolving method show on class android.app.Dialog

I don’t see why, since I’m feeding it the FragmentManager it wants.


#5

@BryanYomar I noticed that you have some var declarations in the beginning that don’t even invoke the constructor. That’s invalid code.

I am not sure what you are hoping to achieve by trying to create a FragmentActivity instance.

Seeing that you are using the standard DialogFragment instead of the support version’s DialogFragment. - https://developer.android.com/reference/android/app/DialogFragment.html

You need to get the current android activity instance, which will get you the necessary FragmentManager - that’s the thing that manages your dialog windows - spawns them and destroys them.

Note: Now, getting the current foreground activity to run getFragmentManager() is the tricky part here, and I cannot really tell you how to do it properly without extending a FragmentActivity yourself.

I’d remove the pointless new operators at the beginning of your code, and end up with something like this: (havent tested the code)

var Application = require('application');
var createViewModel = require("./main-view-model").createViewModel;

var View = require('ui/core/view').View;
var btn = new android.widget.Button(Application.android.context);
var ctx = Application.android.context;

var DatePickerDialog = android.app.DialogFragment.extend({
    init: function() {
        console.log("esto no es necesario");
    },
    onCreateDialog: function() {
        console.log("I'm here now");
        return new android.app.DatePickerDialog(Application.android.context);
    }
});

function onNavigatingTo(args) {
    var page = args.object;
    btn.setText("Hello there");

    var dfrag = new DatePickerDialog();
    // dfrag.onCreateDialog() - the android runtime does that, you don't want to invoke it manually

   // The following is not recommended, it is a hacky and unreliable way related to the 'Note' mentioned above
    var am = ctx.getSystemService(android.content.Context.ACTIVITY_SERVICE);
    var topActivity = am.getRunningTasks(1).get(0).topActivity;
    var fragmentManager = topActivity.getFragmentManager();
    dfrag.show(fragmentManager, 'DatePicker');

    page.bindingContext = createViewModel();
}
exports.onNavigatingTo = onNavigatingTo;

#6

It’s still not working, I’ll be looking more into it. Thanks!


#7

I noticed I was missing a . in my code. Can you say which part isn’t working?


#8

Yeah, I noticed the ., and kept looking for more to make the dialog show up.

I actually found a way (correct me if I’m wrong) to get the foreground activity:

Application.android.foregroundActivity;

And with that, I only add .getFragmentManager(), it doesn’t blow up but it still gives an error when calling the show function. Here’s the error:

And here's the code:

var Application = require('application');
var createViewModel = require("./main-view-model").createViewModel;

var View = require('ui/core/view').View;
var btn = new android.widget.Button(Application.android.context);
var ctx = Application.android.context;

var DatePickerDialog = android.app.DialogFragment.extend({
    init: function() {
    },
    onCreateDialog: function() {
        console.log("I'm here now");
        return new android.app.DatePickerDialog(Application.android.context);
    }
});

function onNavigatingTo(args) {
    var page = args.object;
    btn.setText("Hello there");

    var dfrag = new DatePickerDialog();
    // dfrag.onCreateDialog() - the android runtime does that, you don't want to invoke it manually

   // The following is not recommended, it is a hacky and unreliable way related to the 'Note' mentioned above
    var am = ctx.getSystemService(android.content.Context.ACTIVITY_SERVICE);
    var topActivity = am.getRunningTasks(1).get(0).topActivity;

    //The other not Hacky way?
    var fragmentManager = Application.android.foregroundActivity.getFragmentManager(); 

    dfrag.show(fragmentManager, 'DatePicker');

    page.bindingContext = createViewModel();
}
exports.onNavigatingTo = onNavigatingTo;

#9

I’ll make an app on monday to test it


#10

Thanks for your interest in the topic, appreciate it!


#11

I dug in deeper - turns out the datePicker needs to be created with an Activity instance, and not a Context one. Additionally, the 1-parameter DatePickerDialog constructor is valid only in API 24 and up. So I used the API Level-1-compatible methods and constructors to ensure that the app would work on devices on the lower end. Finally I added a necessary user-permission in the AndroidManifest to be able to access the FragmentManager instance.

var Application = require('application');
var createViewModel = require("./main-view-model").createViewModel;

var View = require('ui/core/view').View;
var ctx = Application.android.context;

var DatePickerFrag = android.app.DialogFragment.extend({
    onCreateDialog: function() {
        var monthNames = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ]; 

        var onDateSetListener = new android.app.DatePickerDialog.OnDateSetListener({
            onDateSet: function (DPView, year, month, day) {
                console.log("Year: " + year + " Month: " + monthNames[month] + " Day: " + day);
            }
        });

        var Calendar = java.util.Calendar; 
        var calendar = Calendar.getInstance();
        var year = calendar.get(Calendar.YEAR);
        var m = calendar.get(Calendar.MONTH);
        var d = calendar.get(Calendar.DAY_OF_MONTH);

        return new android.app.DatePickerDialog(Application.android.foregroundActivity /* Application.android.context */, onDateSetListener, year, m, d);
    }
});

function onNavigatingTo(args) {
    var page = args.object;

    var fragmentManager = Application.android.foregroundActivity.getFragmentManager(); 

    var dfrag = new DatePickerFrag();
    // dfrag.onCreateDialog() - the android runtime does that, you don't want to invoke it manually

    dfrag.show(fragmentManager, 'DatePicker');

    page.bindingContext = createViewModel();
}
exports.onNavigatingTo = onNavigatingTo;

and the AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	package="__PACKAGE__"
	android:versionCode="1"
	android:versionName="1.0">
...
	<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
	<uses-permission android:name="android.permission.INTERNET"/>
	<uses-permission android:name="android.permission.GET_TASKS"/>
...
</manifest>

#12

Wow, now I got it! That was great of you, now I get the tasks concept. I see it very clearly, thanks for your help @Pete.K!!! :smiley: