How can I handle press on volume button up for 5 seconds in this override function
override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
val action = event!!.action
return when (val keyCode = event.keyCode) {
//handle press on volume up button
KeyEvent.KEYCODE_VOLUME_UP -> {
true
}
else -> super.dispatchKeyEvent(event)
}
}
I suggest using a delay on ACTION_DOWN and after the delay do your operation.
private var volumeUpJob : Job? = null
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
if (event.keyCode == KEYCODE_VOLUME_UP) {
if (event.action == ACTION_DOWN) {
if (volumeUpJob?.isActive != true) {
volumeUpJob = lifecycleScope.launch {
delay(5_000)
println("pressed for 5 sec")
// do your operation here
volumeUpJob?.cancel()
}
}
} else {
volumeUpJob?.cancel()
}
}
return super.dispatchKeyEvent(event)
}
Note that you need to cancel the job when user pull their finger up of the button. and also when we caught the 5 seconds as well.
Related
I have 2 alerts in sequence, where the last one does not close with dismiss, could you help me please? Below my code snippet. I have a custom view
fun MaterialDialog.Builder.alertChangedIcon (action: () -> Unit) {
this.apply {
customView(R.layout.change_icon_dialog, false)
canceledOnTouchOutside(false)
build().run {
val btnPosition = this.findViewById(R.id.yesBtnView) as Button
btnPosition.setOnClickListener {
this.dismiss()
action.invoke()
}
}
show()
}
}
fun MaterialDialog.Builder.alertIconInfoChanged(action: () -> Unit) {
this.apply {
customView(R.layout.title_subtitle_two_buttons_dialog_prime,false)
canceledOnTouchOutside(false)
build().run {
val title = this.findViewById(R.id.alertTitleView) as TextView
val subtitle = this.findViewById(R.id.alertSubtitleView) as TextView
val positiveButton = this.findViewById(R.id.yesBtnView) as Button
val negativeButton = this.findViewById(R.id.noBtnView) as Button
title.text = context.getString(R.string.happy_birthday)
subtitle.text = context.getString(R.string.message_change_icon)
negativeButton.let {
it.text = context.getString(R.string.ok)
it.setOnClickListener {
this.dismiss()
action.invoke()
}
}
positiveButton.gone(false)
}
show()
}
}
And use as follows in my view:
override fun showAlertChangedIcon(action: () -> Unit) {
MaterialDialog.Builder(rootView.context).alertIconInfoChanged {
MaterialDialog.Builder(rootView.context).alertChangedIcon {
action.invoke()
}
}
}
And in my controller I have the functions that direct screens
.subscribe({ response ->
when (response) {
is Result.Success -> {
viewContract.showAlertChangedIcon {
when {
...
}
else -> {
...
}
}
}
I suspect it has to do with the labeled returns.
When you call run here:
fun MaterialDialog.Builder.alertChangedIcon (action: () -> Unit) {
this.apply {
...
build().run { <----- when you call here
...
btnPosition.setOnClickListener {
this.dismiss() <----- "this" may be the builder of the dialog,
and not the dialog itself
...
Try replacing this.dismiss() with the labeled return this#apply.dismiss() so you tell Kotlin exactly what to dismiss.
I hope this helps!
i am working on comment section of an application like play store using mvvm,coroutine,kodein and DataBinding.i set login page in my main activity After the user presses the login button Comment Activity will become apparent.
I set recyclerview in comment activity. at end of every item i asked a question that was this review helpful or not. if not press no else press yes.i used shared preferences to save button state. for example when i clicked on yes button yesclicked(boolean variable) will be saved in sharedpref. till here everything works fine.
the problem--> i saved that state then i getYesButtonState() in onBindViewHolder method of recyclerview class and i said when activity recreated change the background color of yes button to #D5FFD7 for this purpose that you clicked on this before
but nothing happend and it didnt work
this code is for shared pref
val SPP_NAME = "ButtonState"
var buttonLocalState: SharedPreferences = context.getSharedPreferences(SPP_NAME, Context.MODE_PRIVATE)
fun setYesButtonState(isClicked: Boolean) {
val userLocalDatabaseEditor: SharedPreferences.Editor = buttonLocalState.edit()
userLocalDatabaseEditor.putBoolean("yesClicked", isClicked)
userLocalDatabaseEditor.apply()
}
fun setNoButtonState(isClicked: Boolean) {
val userLocalDatabaseEditor: SharedPreferences.Editor = buttonLocalState.edit()
userLocalDatabaseEditor.putBoolean("noClicked", isClicked)
userLocalDatabaseEditor.apply()
}
fun getYesButtonState(): Boolean? {
if (buttonLocalState.getBoolean("yesClicked", false) == false) {
return null
} else {
return true
}
}
fun getNoButtonState(): Boolean? {
if (buttonLocalState.getBoolean("noClicked", false) == false) {
return null
} else {
return true
}
}
fun clearButtonState() {
val userLocalDatabaseEditor: SharedPreferences.Editor = buttonLocalState.edit()
userLocalDatabaseEditor.clear()
userLocalDatabaseEditor.apply()
}
this is for recyclerview class:
//yes button clicked
yesbtn.setOnClickListener {
yesClicked = true
localStore.clearButtonState()
localStore.setYesButtonState(yesClicked)
val Helpful = 1
if (localStore.getYesButtonState() == true) {
nobtn.setBackgroundColor(Color.WHITE)
startColorAnimation(yesbtn)
activity.handler.postDelayed({
yesbtn.setBackgroundColor(Color.parseColor("#D5FFD7"))
nobtn.isClickable = true
}, 892.25.toLong())
}
try {
viewModel.deleteperson(
localStore.getUserName().toString(),
currentItem.id
).observe(mlifecycleOwner, Observer {
})
} catch (e: IllegalStateException) {
e.fillInStackTrace()
}
viewModel.feedback(
currentItem.id,
localStore.getUserName().toString(),
currentItem.description,
Helpful
).observe(mlifecycleOwner, Observer {
})
Toast.makeText(
context,
"thanks for your feedback",
Toast.LENGTH_SHORT
).show()
yesbtn.isClickable = false
}
//no button clicked
nobtn.setOnClickListener {
noClicked = true
localStore.clearButtonState()
localStore.setNoButtonState(noClicked)
val Helpful = 0
if (localStore.getNoButtonState() == true) {
yesbtn.setBackgroundColor(Color.WHITE)
startColorAnimation(nobtn)
activity.handler.postDelayed({
nobtn.setBackgroundColor(Color.parseColor("#D5FFD7"))
yesbtn.isClickable = true
}, 892.25.toLong())
}
try {
viewModel.deleteperson(
localStore.getUserName().toString(),
currentItem.id
).observe(mlifecycleOwner, Observer {
})
} catch (e: IllegalStateException) {
e.fillInStackTrace()
}
viewModel.feedback(
currentItem.id,
localStore.getUserName().toString(),
currentItem.description,
Helpful
).observe(mlifecycleOwner, Observer {
})
Toast.makeText(
context,
"please tell us why",
Toast.LENGTH_SHORT
).show()
it.isClickable = false
}
where i did wrong. thanks for your Help
try this
after the button click .. call notifyDataSetChanged(); in your adapter class
You have propaply seen those pretty cheap android tv boxes available on the market. They are usually followed with a remote control that has some functionalities like clicking, swipe or slide to left and right up and down.
Recently i made an app and tried to navigate it using the remote control. I have some gesture methods in the project. I tried to swipe to left and right but the app didnt do anything while when i try it on my phone that has a screen gets the gesture and do what it should. Like opening the navigation drawer etc.
Now to my question: does one need to use speciel methods? Is there some rules that one should be ware of?
Edit
This is what Ive done so far. I made a class that defines the action: It's from google.developer
public class Dpad {
public final static int UP = 0;
public final static int LEFT = 1;
public final static int RIGHT = 2;
public final static int DOWN = 3;
public final static int CENTER = 4;
int directionPressed = -1; // initialized to -1
public int getDirectionPressed(InputEvent event) {
if (!isDpadDevice(event)) {
return -1;
}
// If the input event is a MotionEvent, check its hat axis values.
if (event instanceof MotionEvent) {
// Use the hat axis value to find the D-pad direction
MotionEvent motionEvent = (MotionEvent) event;
float xaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_X);
float yaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_Y);
// Check if the AXIS_HAT_X value is -1 or 1, and set the D-pad
// LEFT and RIGHT direction accordingly.
if (Float.compare(xaxis, -1.0f) == 0) {
directionPressed = Dpad.LEFT;
} else if (Float.compare(xaxis, 1.0f) == 0) {
directionPressed = Dpad.RIGHT;
}
// Check if the AXIS_HAT_Y value is -1 or 1, and set the D-pad
// UP and DOWN direction accordingly.
else if (Float.compare(yaxis, -1.0f) == 0) {
directionPressed = Dpad.UP;
} else if (Float.compare(yaxis, 1.0f) == 0) {
directionPressed = Dpad.DOWN;
}
}
// If the input event is a KeyEvent, check its key code.
else if (event instanceof KeyEvent) {
// Use the key code to find the D-pad direction.
KeyEvent keyEvent = (KeyEvent) event;
if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT) {
directionPressed = Dpad.LEFT;
} else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_RIGHT) {
directionPressed = Dpad.RIGHT;
} else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP) {
directionPressed = Dpad.UP;
} else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN) {
directionPressed = Dpad.DOWN;
} else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER) {
directionPressed = Dpad.CENTER;
}
}
return directionPressed;
}
public static boolean isDpadDevice(InputEvent event) {
// Check that input comes from a device with directional pads.
if ((event.getSource() & InputDevice.SOURCE_DPAD)
!= InputDevice.SOURCE_DPAD) {
return true;
} else {
return false;
}
}
}
In my MainActivity I have a navigationdrawer. which I want to open and close when remotecontrol D-pad wants it
mDrawerLayout.setOnGenericMotionListener(new View.OnGenericMotionListener() {
#Override
public boolean onGenericMotion(View view, MotionEvent motionEvent) {
if (Dpad.isDpadDevice(motionEvent)) {
int press = mDpad.getDirectionPressed(motionEvent);
switch (press) {
case Dpad.RIGHT:
// Do something for UP direction press Open the drawer
mDrawerLayout.openDrawer(Gravity.START);
return true;
case Dpad.LEFT:
mDrawerLayout.closeDrawer(Gravity.START);
return true;
}
}
return false;
}
});
In one of the fragments I have a media player and using D-pad up and D-pad down I change the video.
v.setOnGenericMotionListener(new View.OnGenericMotionListener() {
#Override
public boolean onGenericMotion(View view, MotionEvent motionEvent) {
if (Dpad.isDpadDevice(motionEvent)) {
int press = mDpad.getDirectionPressed(motionEvent);
switch (press) {
case Dpad.UP:
// Do something for UP direction press
UP(); // Change the video to next
return true;
case Dpad.DOWN:
DOWN(); // Change the video the earlier on
return true;
}
}
return false;
}
});
EDIT
It' now become a problem since it doesn't response to any motion. I tried on a emulator with physical keyboard and not a single action happens. I would appritiate if someone gives me a hint.
i mean this kind of remote control in the picture below
Thanks in advance
I think the code on Android Developer is wrong:
public static boolean isDpadDevice(InputEvent event) {
// Check that input comes from a device with directional pads.
if ((event.getSource() & InputDevice.SOURCE_DPAD)
!= InputDevice.SOURCE_DPAD) {
return true;
} else {
return false;
}
}
The condition should be "==" instead of "!=", so this is correct:
public static boolean isDpadDevice(InputEvent event) {
// Check that input comes from a device with directional pads.
if ((event.getSource() & InputDevice.SOURCE_DPAD)
== InputDevice.SOURCE_DPAD) {
return true;
} else {
return false;
}
}
I have a list view with the following cell factory:
availableSymbolsTable.setCellFactory(lv -> {
ListCell<Symbol> cell = new ListCell<Symbol>() {
#Override
protected void updateItem(Symbol t, boolean empty) {
super.updateItem(t, empty);
if (empty) {
setText(null);
} else {
setText(t.getSymbolName());
}
}
};
cell.setOnKeyPressed(e ->
{
//This never fires
}
);
cell.setOnMouseEntered(e -> {
//This works
});
cell.setOnMouseClicked(e -> {
if (cell.getItem() != null) {
if(e.getClickCount() == 2)
{
//This works
}
}
});
return cell ;
} );
I have added 3 event handles in the same manner. OnMouseEntered and OnMouseClicked both work as expected. However, OnKeyPressed is never executed. The same goes for OnKeyReleased. When pressing arrow keys, the listview changes the selected row as expected, but my event handler code is never executed. What seems to be the problem?
I thought I'd figured out this problem, by making a function showMessage, which can take a Runnable as an argument and run that piece of code if that particular button has been pressed.
Now I find the problem that I need to wait on several inputs before running the code. I essentially go through a bunch of questions which are added dynamically, so I don't know how many there'll be. When the users presses "Submit", it checks if any that are "soft" required and if there's no answer pops up with the message "There isn't an answer, would you like to continue anyway?".
The way I thought I could handle this is by counting the amount of questions which are like that, assigning them an Enumerator with a boolean variable to say if they're INPROGRESS or COMPLETE. I then had the Runnable to set that particular question's Progress state to COMPLETE and if they click "No", then to set the boolean variable to false.
Since the the dialogs are launched asynchronously, I can't just do an if statement, so I did a while any were still in progress. Buuuuuut! When I click submit now, it just freezes. I'm guessing because it's stuck at the while loop, whilst also not launching the dialogs asynchronously. I think it has to "complete" the code before launching them?
My code for reference to the points made above, this is all in the onClick of the submit button:
//Prep work
final ArrayList<Result> results = new ArrayList<Result>();
for (BaseQuestion q : questionViews)
{
if (q.requiredSoft)
{
results.add(Result.INPROGRESS);
}
}
final int[] i = {0};
//Validation checks
Boolean allOk = true;
for (BaseQuestion questionView : questionViews)
{
if (questionView.isRequiredHard())
{
if (questionView.getResponse().isEmpty())
{
Utils.showMessage("You have to fill in '" + questionView.getQuestionText() + "'", v.getContext());
allOk = false;
break;
}
}
else if (questionView.isRequiredSoft())
{
if (questionView.getResponse().isEmpty())
{
Runnable isOk = new Runnable()
{
#Override
public void run()
{
results.get(i[0]).value = 1;
results.get(i[0]).result = true;
i[0]++;
}
};
Runnable isNotOk = new Runnable() {
#Override
public void run() {
results.get(i[0]).value = 1;
i[0]++;
}
};
Utils.showMessage("You've not filled in '" + questionView.getQuestionText() + "'. Do you wish to continue?", v.getContext() , isOk, "Yes", isNotOk, "No");
}
}
else
{
}
}
if (allOk)
{
for (Result result : results)
{
while (result == Result.INPROGRESS)
{
}
if (!result.result)
{
allOk = false;
}
}
if (allOk)
{
submitQuestionnaire();
}
}
you can put all soft check into a runnable linkļ¼ and do the submit action at the last runnable. I not have a IDE now, see following logic
on submit button clicked{
allOk = true;
foreach(question in questions){
if(question require hard && question is empty){
allOk = false;
break;
}
}
if(allOk){
boolean needMoreConfirm = false;
for(int i = 0; i < questions.length; i++){
if(question require soft && question is empty){
Runnable isOk = new MyRunnable(i + 1, questions);/*begin check from next question*/
Utils.showMessage("your question",
new MyRunnable(i + 1)/* check next soft */,
null/*do nothing, wait another submit click*/);
needMoreConfirm = true;
break;
}
}
if(!needMoreConfirm){
do real submit here
}
}
}
class MyRunnable extends Runnable{
protected int mIdx;
Question[] mQuestions;
public MyOkRunnalbe(int idx, Question[] qs){mIdx = idx; mQuestions = qs;}
public void run(){
boolean needMoreConfirm = false;
for(int i = mIdx; i < questions.length; i++){
if(mQuestions[i] is empty && mQuestions[i] is soft){
Utils.showMessage("your question",
new MyRunnable(i + 1)/* begin to check from next soft */,
null/*do nothing, wait another submit click*/);
needMoreCOnfirm = true;
break;
}
}
if(!needMoreConfirm){
do real submit here
}
}
}
SOLVED
If I gave myself another half an hour to tinker, would've been fine! I whacked the checking code in a separate thread, this means it wasn't hanging.
But then I had the problem of the result not changing state. So instead of doing my for loop as a for each item loop, I did it as an index, as it wasn't changing the state when it kept checking.
As shown below:
new Thread(new Runnable() {
#Override
public void run() {
if (allOk[0])
{
for (int i=0; i<results.size(); i++)
{
while (results.get(i) == Result.INPROGRESS)
{
}
if (!results.get(i).result)
{
allOk[0] = false;
}
}
if (allOk[0])
{
submitQuestionnaire();
}
}
}
}).start();