Why doesn't DialogFragment.dismiss kill the dialog right away? - java

I am building a very basic vocabulary application. The feature I am trying to implement right now is a go to feature, that is taking the user to a specific vocab term. i am doing this by prompting the user with a dialog fragment that asks the user for a page number. (dialog fragment will get triggered via a callback, button press)
This is my code for doing so
public class GoToDialog extends DialogFragment{
submit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String pgn = pageNumber.getText().toString();
if(!isNumeric(pgn) || pgn.isEmpty()) {
Toast.makeText(getActivity(), "Please enter a valid number", Toast.LENGTH_SHORT).show();
} else {
int pagina = Integer.parseInt(pgn);
if(pagina <= 0 || pagina > total) {
Toast.makeText(getActivity(), String.format("Please enter a valid " +
"term number between 0 and %d", total), Toast.LENGTH_SHORT).show();
} else {
getDialog().dismiss();
getFragmentManager().executePendingTransactions();
communicator.onDialogMessage(pagina);
}
}
}
});
Here are screenshots when I run my application
Screenshot2(right after screenshot 1)
In terms of functionality The dialog loads up fine and is able to take the user to the right location. However in that example of taking the user from term 7 to term 5, the user is taken to the
right term but the dialog doesn't close as it should from getDialog().dismiss(). I know dismiss is being called because I walked through the code and communicator.onDialogMessage(pagina) returns the right term number to the activity. The dialog does close when I select another term number to go to. Does anyone see the issue? This doesn't make sense to me at all.
To close a dialog, dismiss is the correct method to use
- How to correctly dismiss a DialogFragment?
I also tried what a user suggested in Correct way to remove a DialogFragment: dismiss() or transaction.remove()?, which is to call executePendingTransactions().

If anyone's having a similar issue, the issue with my application was my OnTouchListener.
When I set up on OnTouchListener to trigger the DialogFragment, here was my original code for doing so
goTo - TextView
private void setUpGoToTouchListener() {
goTo.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
FragmentManager fm = MainActivity.this.getFragmentManager();
GoToDialog dialog = new GoToDialog();
Bundle bundle = new Bundle();
bundle.putInt("Size", defMan.getTotalCount());
dialog.setArguments(bundle);
dialog.show(fm, "Manager");
return true;
}
});
}
When the gesture(a touch) on the TextView occurs, two MotionEvents will be generated, the press, ACTION_DOWN - first finger has touched the screen, and the release, ACTION_UP - the last of the fingers has stopped touching the screen. Because two motion events occurred, two dialog fragments were created. Thats why dismiss had to be called twice in my situation to get rid of both dialog fragments. I fixed this by having a conditional test for event.getAction()

Related

Remap physical back button for "select_button" in android tv webvew application with java

I'm a french developer , i'm creating an android tv application about cloud Gaming in a webview with java.
My application start a gaming stream direcly in the webview, on fullscreen, the physical buttons of controlers are working with the game, eccept the "view button" the "back button'.
This "view button" or if your prefer "select button" is for android tv a back button to the homescreen. So i have to overiding this back button, and i want replace it by a "select button" that it can interact with the games for displaying maps and inventory like in rpg games.
I know that the name will be "button_select" for interact with the pc game. So in android tv for now i will always redirected to the home page.
this is a sample of my code.
public class MainActivity extends AppCompatActivity {
#Override
public void onBackPressed() {
return;
}
With this overide, the back button is completly disabled for now, i want replace it or call the "button_select". I readed something about "handler" perhaps this is the solution.
Edit 16/06/2021
I tested much coded, but nothing work.
this one
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode == KeyEvent.KEYCODE_BACK){
keyCode = KeyEvent.KEYCODE_BUTTON_SELECT;
}
return super.onKeyDown(keyCode, event);
}
And its variants
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
int action = event.getAction();
int keyCode = event.getKeyCode();
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
if (action == KeyEvent.ACTION_DOWN ){
//Do something in the back button
keyCode = KeyEvent.KEYCODE_BUTTON_SELECT;
}
return true;
default:
return super.dispatchKeyEvent(event);
}
}
In game, the back button is disabled but, the" keycode_button_select "not interact with the game. There is nothing. I test with the "keycode button_start" the same things.
I tested the app button mapper for android tv, there is an option for custom keycodes with adb, and nothing is working in game.
https://play.google.com/store/apps/details?id=flar2.homebutton&hl=fr&gl=US
So by the code or by an app, nothing is working for now, i don't want to forcing the "root mode" for this things. Perhaps i'll just have to implementing a gamepad Plugin in java. I don't know...
Edit 18/06/21
I can capture the "back button" and display a dialog alert that appear on middle of the screen. But the actions after has no effect for now. I tested "dispatchEvent" with no success for now. I will testing the functions "robots". Perhaps "robot" and "dispatchEvent" will working together.
Thank you for your help.
I am assuming that you want to call button_select key when user presses back button.
In this case, create a method to call upon pressing back button. And call that method from the onBackPressed method.
For example:
public void callButtonSelectKey() {
//This could be done in either ways.
//1.
val i = Instrumentation()
i.sendKeyDownUpSync(KeyEvent.KEYCODE_BUTTON_SELECT)
//2.
val keyEventDown = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BUTTON_SELECT)
val keyEventUp = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BUTTON_SELECT)
dispatchKeyEvent(keyEventDown)
dispatchKeyEvent(keyEventUp)
}
#Override
public void onBackPressed() {
methodToCallUponBackPress();
return;
}
Now when the user presses the back button, it will call callButtonSelectKey method invoke "button_select" key. (i.e. remapped backbutton to button_select)
Let me know if you have any more questions.
EDIT
In an Object Oriented Language, overriding the class's (in this case KeyEvent) field (in this case, keycode) will do nothing. Like the code below:
//Do something in the back button
keyCode = KeyEvent.KEYCODE_BUTTON_SELECT;
To call button_select when you receive the event of KEYCODE_BACK, you should manually invoke the method to call Key Event, in this case the method I gave you earlier dispatchKeyEvent .
So you should make your change into something like this:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode == KeyEvent.KEYCODE_BACK){
//This could be done in either ways.
//1.
val i = Instrumentation()
i.sendKeyDownUpSync(KeyEvent.KEYCODE_BUTTON_SELECT)
//2.
val keyEventDown = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BUTTON_SELECT)
val keyEventUp = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BUTTON_SELECT)
dispatchKeyEvent(keyEventDown)
dispatchKeyEvent(keyEventUp)
}
return super.onKeyDown(keyCode, event); //Edit this return statement if you want to ignore a keypress.
}

EditText onFocus doesn't work properly

I have an EditText which I adjust the position on screen of when the user clicks it (when it gains focus). However, the method is not working properly. My code:
etHashtag.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if(hasFocus){
Log.d("EditText", "has focus");
originalHashtagPos = etHashtag.getY();
etHashtag.setY(targetH / 2);
}else {
Log.d("EditText", "no focus");
etHashtag.setY(originalHashtagPos);
}
}
});
The log shows that the focus is gained when the user clicks the EditText, and it loses focus when the user clicks outside the view. However, the Y position is not moved everytime. It only works in about 50% of the times. Thought this would be simple?

In a snackbar action, how can I be sure it's safe to permanently delete a soft-deleted record from the database?

I am using Snackbar in android and I have implemented an action so that user can undo the action (the action is clearing all the items in the listview).Removing and adding the items back to the listview has already been done and working fine.
My issue is that, items are stored in sqlite database and how can I delete the items from tables? (How can I know that the user has not clicked the undo button, so that I can completely remove the data from database).
This is the code inside OnOptionsItemSelcted()
case R.id.action_clear:
final List<Word> temp = new ArrayList<Word>(data);
data.clear();
adapter.notifyDataSetChanged();
View view = findViewById(R.id.layoutFavWords);
Snackbar.make(view,"Deleted Saved Selection.", Snackbar.LENGTH_LONG).
setAction("Undo", new OnClickListener() {
#Override
public void onClick(View v) {
for(Word word:temp)
data.add(word);
adapter.notifyDataSetChanged();
}
}).show();
break;
So if the user has not clicked the undo button during the visible period of the snackbar, then I need to permanently delete the data from database.
Any solutions for this?
As far as I know, it is by design. You should:
Delete the item as soon as the user taps the delete button;
Store it temporarily in a class variable;
If the user taps Undo, add the item again to the database.
This approach is safer and more robust; you shouldn't wait for the snackbar to be dismissed, because that action could not even happen. Just think of user force-quitting the app while the snackbar is still on: should the item be deleted or not? It should.
A more trustworthy source is g+ post by Ian Lake (deleted because of G+ deprecation). In the comments you can read:
you want your UI to react immediately (not wait for the snackbar to
disappear) - most systems (particularly those that sync to an external
server) have the concept of a 'soft delete' where things are marked as
deleted. In those cases, an undo action would just be unmarking the
record as deleted. This system works even if the user were to leave
the app before the snackbar finishes (you can't assume the snackbar
will always complete its animation!).
The easiest way to do that is to temporarily save the record elsewhere (even a local
variable), then re-insert it if they happen to hit the undo button.
Android Support library v23 added Snackbar.Callback which you can use to listen if the snackbar was dismissed by user or timeout.
Example borrowed from astinxs post:
Snackbar.make(getView(), "Hi there!", Snackbar.LENGTH_LONG).setCallback( new Snackbar.Callback() {
#Override
public void onDismissed(Snackbar snackbar, int event) {
switch(event) {
case Snackbar.Callback.DISMISS_EVENT_ACTION:
Toast.makeText(getActivity(), "Clicked the action", Toast.LENGTH_LONG).show();
break;
case Snackbar.Callback.DISMISS_EVENT_TIMEOUT:
Toast.makeText(getActivity(), "Time out", Toast.LENGTH_LONG).show();
break;
}
}
#Override
public void onShown(Snackbar snackbar) {
Toast.makeText(getActivity(), "This is my annoying step-brother", Toast.LENGTH_LONG).show();
}
}).setAction("Go away!", new View.OnClickListener() {
#Override
public void onClick(View v) {
}
}).show();
Example:
final java.util.Timer timer = new Timer();
Snackbar snackbar = Snackbar.make(...).setAction("Undo", new OnClickListener() {
#Override
public void onClick(View v) {
timer.cancel();
for(Word word:temp)
data.add(word);
adapter.notifyDataSetChanged();
}
}).show();
timer.schedule(new TimerTask() {
public void run() {
// delete from db
}
}, snackbar.getDuration());
It may be a good idea to add a little to the snackbar.getDuration() time (100-200ms?) as timers are not very exact in terms of timing and this way they may get called just before the snackbar is about to close, althought the possibility is rather small in this case.
If you don't want to delete the record from database immediately, try this:
// Backup the item for undo
int itemIndex = viewHolder.getAdapterPosition();
Item item = adapter.getItem(itemIndex);
// Delete only from the adapter
adapter.removeItem(itemIndex);
Snackbar.make(getView(), "Item deleted", LENGTH_LONG)
.addCallback(new BaseCallback<Snackbar>() {
public void onDismissed(Snackbar transientBottomBar, int event) {
if (event != DISMISS_EVENT_ACTION) {
// Dismiss wasn't because of tapping "UNDO"
// so here delete the item from databse
}
}
})
.setAction("UNDO", v -> adapter.addItem(item, itemIndex))
.show();
My way is to hv "deleted" column that is boolean, just change the stat to be true if deleted then undo to change back stat to be false, also u maybe want trash controller or scheduler to delete all the false values on every week.

Hide a Button if EditText field is less than or equal to 13.5 & greater than 33.0 - Java Android

Hope you all are well.
I would like to hide a Button (btnAppointment) if my test readings in my EditText are below or equal 13.5 or greater than 33 in my Android Application window. The Button (btnAppointment) should only appear on the screen if my EditText field inputted values are between 13.60 and 32.99. And not be shown onscreen if outside these parameters.
I was wondering whether an IF statement with button.setEnabled(false); would do the trick and if so where about would I need to input it into my Code. Whether it be protected void onCreate(Bundle savedInstanceState) or Create my own public void appointmentTeacherOnClick?
Below I have inserted my code for calculating and displaying my Inputted Test field prompts.
public void calculateTest(View v){
String status;
test = Double.parseDouble(edtData.getText().toString());
String result = String.format("%.2f", test);
Log.d("MyActivity", result);
if( test < 9.5) {
status = "Normal - Well Done =)";
} else if (test >= 9.5 && test < 13.5){
status = "Caution - Keep on Track =|";
} else if (test >= 13.5 && test < 33.0) {
status ="Action Needed =(";
} else {
status = "Normal Results are between 0 - 33";
}
AlertDialog alertDialog = new AlertDialog.Builder(this).create();
alertDialog.setTitle("Result Feedback...");
alertDialog.setMessage(status);
alertDialog.setButton("Acknowledged", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
});
alertDialog.show();
if you want to control the visibility of button, enabling or disabling the button won't help. Enabling/Disabling property will still show the button and will only decide whether button can be clicked or not.
You need two things to achieve your task,
EditText - text change listener
Button Visibility property
How to do both the task are already answered on SO, here is the most popular one,
How to hide a button programmatically? (For hiding button).
Counting Chars in EditText Changed Listener (For creating edittext change listener)
To hide a view you need to use setVisibility() and set it to View.INVISIBLE
Button btnAppointment = (Button) findViewById(R.id.btn_appointment);
btnAppointment.setVisibility(View.INVISIBLE);
In your XML file:
<Button
android:id="#id+/btn_appointment
...
/>
See this question: How to hide a button programmatically?

TextView editable onLongClick -- But one small issue when BACK button pressed

I have been search SO for days and have finally compiled enough answers to accomplish what I wanted. First off, it seems to be an often asked question but not really answered (at least not the way I was looking for it). I thought I would share my findings but I also have one small issue left that I would like to ask for help with. Here goes:
I have a TextView which displays a score. It starts at 0 and at an onClick event the score increments and updates the TextView (score is tracked as a byte - valScore).
onLongClick: This was the challenge. I want the user to be able to do a LongClick to correct/change the score. I first found a solution that utilized another layout.xml file with just an EditText element and the OK and CANCEL buttons. This was very cumbersome to change the score as it involved the LongClick, then the dialog opens, then you had to click on the EditText element to open the keyboard, then you enter the value, click DONE and then click OK. I shortened it by figuring out how to open the software keyboard automatically when the dialog opened. However, you still had to click DONE and then OK. I didn't like this action so I continued searching.
Days later I came up with a bit of code and then more and with a lot of playing/hacking around I came up with the following solution:
// set the onLongClickListener for tvScoreHome
tvScoreHome.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
tvScoreHome.setInputType( InputType.TYPE_CLASS_NUMBER );
tvScoreHome.setFocusable(true);
tvScoreHome.setFocusableInTouchMode( true );
tvScoreHome.requestFocus();
InputMethodManager imm = (InputMethodManager) context.getSystemService(Service.INPUT_METHOD_SERVICE);
imm.showSoftInput(tvScoreHome, InputMethodManager.SHOW_FORCED);
tvScoreHome.setText("");
tvScoreHome.setOnEditorActionListener( new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE) {
valScoreHome = Byte.valueOf( tvScoreHome.getText().toString() );
// This part will hide the keyboard after input
InputMethodManager imm = (InputMethodManager) context.getSystemService(Service.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
tvScoreHome.setFocusable( false );
tvScoreHome.setFocusableInTouchMode( false );
tvScoreHome.setText( Byte.toString(valScoreHome) );
return true;
}
return false;
}
});
return true;
}
});
This works EXACTLY how I want. User performs LongClick the keyboard opens, the user enters the new value and clicks DONE. The TextView is updated and it works great!
The problem arises if the user changes their mind and hits the BACK button on the device. The keyboard closes (GOOD), but then the focus remains on the TextView instead of removing the focus like I do if the DONE button is pressed. So if you cancel out of a change every click after that results in the keyboard opening again instead of just incrementing the score -- until you actually type a value into the keyboard and click DONE (then the regular behavior takes over again. I need to setFocusableInTouchMode to FALSE if the BACK button is pressed.
The other issue is that the setText() method is executed even if the BACK button is pressed if a different value has been typed in. Even though valScoreHome isn't updated the TextView changes. On the next increment it goes to the correct number again, but the setText() should not execute if the BACK button is pressed.
Can someone help me figure this out please?
Both issues can be handled by subclassing TextView.
The back button press that closes the keyboard is handled by overriding onKeyPreIme.
To avoid updating the text when the user closes the keyboard, the score value is saved in the variable mScore, but only if the TextView is currently not focusable. That means, the TextView "remembers" the current value of the score, that was not entered by the user. When the user closes the the keyboard, the text is set back to the saved value.
public class ScoreTextView extends TextView {
private CharSequence mScore;
public ScoreTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public void setText(CharSequence text, BufferType type) {
if (!isFocusable()) {
mScore = text;
}
super.setText(text, type);
}
#Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
setFocusable(false);
setFocusableInTouchMode(false);
setText(mScore);
}
return super.onKeyPreIme(keyCode, event);
}
}

Categories