From 3ce4ce27b0c402aa37b6a389c1340690d36f4e26 Mon Sep 17 00:00:00 2001 From: Arturo Espinosa Date: Wed, 18 Dec 2024 14:31:38 -0600 Subject: [PATCH 01/11] RemoteFragment.java:linkRepeatingRemoteButton use ontouch + keyup/dn instead of onclick + keypress. This allows for a smoother control for situations where holding a button down is handled (as a test case, check the Retaliate Roku Game). --- .../media/romote/fragment/RemoteFragment.java | 37 ++++++++++++++++--- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/wseemann/media/romote/fragment/RemoteFragment.java b/app/src/main/java/wseemann/media/romote/fragment/RemoteFragment.java index 54f02ec..2549a72 100644 --- a/app/src/main/java/wseemann/media/romote/fragment/RemoteFragment.java +++ b/app/src/main/java/wseemann/media/romote/fragment/RemoteFragment.java @@ -23,6 +23,7 @@ import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.ImageButton; @@ -36,7 +37,10 @@ import com.wseemann.ecp.api.ResponseCallback; import com.wseemann.ecp.core.KeyPressKeyValues; +import com.wseemann.ecp.core.ECPRequest; import com.wseemann.ecp.request.KeyPressRequest; +import com.wseemann.ecp.request.KeyupRequest; +import com.wseemann.ecp.request.KeydownRequest; import com.wseemann.ecp.request.QueryDeviceInfoRequest; import java.util.List; @@ -171,11 +175,18 @@ public void onDestroy() { private void linkRepeatingRemoteButton(final KeyPressKeyValues keypressKeyValue, int id) { RepeatingImageButton button = getView().findViewById(id); - button.setOnClickListener(view -> { - performKeypress(keypressKeyValue); - }); - - button.setRepeatListener((v, duration, repeatcount) -> performKeypress(keypressKeyValue), 400); + button.setOnTouchListener((view, event) -> { + switch(event.getAction()) { + case MotionEvent.ACTION_DOWN: + performKeydown(keypressKeyValue); + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + performKeyup(keypressKeyValue); + break; + } + return false; + }); } private void linkButton(final KeyPressKeyValues keypressKeyValue, int id) { @@ -192,7 +203,7 @@ private void linkButton(final KeyPressKeyValues keypressKeyValue, int id) { }); } - private void performRequest(final KeyPressRequest request) { + private void performRequest(final ECPRequest request) { request.sendAsync(new ResponseCallback<>() { @Override public void onSuccess(@Nullable Void unused) { @@ -257,6 +268,20 @@ private void performKeypress(KeyPressKeyValues keypressKeyValue) { performRequest(keyPressRequest); } + private void performKeydown(KeyPressKeyValues keypressKeyValue) { + String url = commandHelper.getDeviceURL(); + + KeydownRequest keydownRequest = new KeydownRequest(url, keypressKeyValue.getValue()); + performRequest(keydownRequest); + } + + private void performKeyup(KeyPressKeyValues keypressKeyValue) { + String url = commandHelper.getDeviceURL(); + + KeyupRequest keyupRequest = new KeyupRequest(url, keypressKeyValue.getValue()); + performRequest(keyupRequest); + } + @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.remote_menu, menu); From c76b185c7ed1ab5ff098bf8ec42ac6f973d4b558 Mon Sep 17 00:00:00 2001 From: Arturo Espinosa Date: Wed, 18 Dec 2024 15:09:30 -0600 Subject: [PATCH 02/11] RemoteFragment.java: all standard buttons now use ontouch + keyup/dn instead of onclick + keypress. This allows for a smoother control for situations where holding a button down is handled (as a test case, check the Retaliate Roku Game, or scrolling through videos on YouTube and moving through a video replay). Even the main Roku menu uses rew/ff buttons as PgUp/PgDn alternatives to skip options by screenfulls, and changing the behaviour of the buttons here has an impact too. Same case for back in standard navigation. So, this is the only behaviour for buttons that emmit key events now. --- .../media/romote/fragment/RemoteFragment.java | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/wseemann/media/romote/fragment/RemoteFragment.java b/app/src/main/java/wseemann/media/romote/fragment/RemoteFragment.java index 2549a72..e674d2b 100644 --- a/app/src/main/java/wseemann/media/romote/fragment/RemoteFragment.java +++ b/app/src/main/java/wseemann/media/romote/fragment/RemoteFragment.java @@ -105,25 +105,25 @@ public void onClick(View v) { }); mVoiceSearcButton.requestFocus();*/ - linkButton(KeyPressKeyValues.BACK, R.id.back_button); + linkRepeatingRemoteButton(KeyPressKeyValues.BACK, R.id.back_button); linkRepeatingRemoteButton(KeyPressKeyValues.UP, R.id.up_button); - linkButton(KeyPressKeyValues.HOME, R.id.home_button); + linkRepeatingRemoteButton(KeyPressKeyValues.HOME, R.id.home_button); linkRepeatingRemoteButton(KeyPressKeyValues.LEFT, R.id.left_button); - linkButton(KeyPressKeyValues.SELECT, R.id.ok_button); + linkRepeatingRemoteButton(KeyPressKeyValues.SELECT, R.id.ok_button); linkRepeatingRemoteButton(KeyPressKeyValues.RIGHT, R.id.right_button); - linkButton(KeyPressKeyValues.INTANT_REPLAY, R.id.instant_replay_button); + linkRepeatingRemoteButton(KeyPressKeyValues.INTANT_REPLAY, R.id.instant_replay_button); linkRepeatingRemoteButton(KeyPressKeyValues.DOWN, R.id.down_button); - linkButton(KeyPressKeyValues.INFO, R.id.info_button); + linkRepeatingRemoteButton(KeyPressKeyValues.INFO, R.id.info_button); - linkButton(KeyPressKeyValues.REV, R.id.rev_button); - linkButton(KeyPressKeyValues.PLAY, R.id.play_button); - linkButton(KeyPressKeyValues.FWD, R.id.fwd_button); + linkRepeatingRemoteButton(KeyPressKeyValues.REV, R.id.rev_button); + linkRepeatingRemoteButton(KeyPressKeyValues.PLAY, R.id.play_button); + linkRepeatingRemoteButton(KeyPressKeyValues.FWD, R.id.fwd_button); - linkButton(KeyPressKeyValues.VOLUME_MUTE, R.id.mute_button); - linkButton(KeyPressKeyValues.VOLUME_DOWN, R.id.volume_down_button); - linkButton(KeyPressKeyValues.VOLUME_UP, R.id.volume_up_button); + linkRepeatingRemoteButton(KeyPressKeyValues.VOLUME_MUTE, R.id.mute_button); + linkRepeatingRemoteButton(KeyPressKeyValues.VOLUME_DOWN, R.id.volume_down_button); + linkRepeatingRemoteButton(KeyPressKeyValues.VOLUME_UP, R.id.volume_up_button); ImageButton keyboardButton = getView().findViewById(R.id.keyboard_button); keyboardButton.setOnClickListener(view -> { @@ -173,12 +173,17 @@ public void onDestroy() { } private void linkRepeatingRemoteButton(final KeyPressKeyValues keypressKeyValue, int id) { - RepeatingImageButton button = getView().findViewById(id); + View button = getView().findViewById(id); button.setOnTouchListener((view, event) -> { switch(event.getAction()) { case MotionEvent.ACTION_DOWN: performKeydown(keypressKeyValue); + if (id == R.id.back_button || + id == R.id.home_button || + id == R.id.ok_button) { + BroadcastUtils.Companion.sendUpdateDeviceBroadcast(requireContext()); + } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: From 35c5b3fef836292f21538337c9d62c05a8d21348 Mon Sep 17 00:00:00 2001 From: Arturo Espinosa Date: Thu, 19 Dec 2024 22:56:45 -0600 Subject: [PATCH 03/11] ViewUtils.java: new provideHapticEffect for modern vibration effects with a fallback for old platform versions. Also, new private getVibrator and code factorization to avoid repetition between the new provideHapticEffect and provideHapticFeedback. --- .../media/romote/utils/ViewUtils.java | 42 ++++++++++++++----- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/wseemann/media/romote/utils/ViewUtils.java b/app/src/main/java/wseemann/media/romote/utils/ViewUtils.java index 62776f8..f2d935a 100644 --- a/app/src/main/java/wseemann/media/romote/utils/ViewUtils.java +++ b/app/src/main/java/wseemann/media/romote/utils/ViewUtils.java @@ -19,16 +19,38 @@ private ViewUtils() { } - public static void provideHapticFeedback(View view, int vibrateDurationMs) { - if (CommonModule.PreferenceUtilsSingleton.preferenceUtils.shouldProvideHapticFeedback()) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - VibratorManager vibratorManager = (VibratorManager) view.getContext().getSystemService(Context.VIBRATOR_MANAGER_SERVICE); - Vibrator vibrator = vibratorManager.getDefaultVibrator(); - vibrator.vibrate(VibrationEffect.createOneShot(vibrateDurationMs,VibrationEffect.DEFAULT_AMPLITUDE)); + private static Vibrator getVibrator(View view) { + if (!CommonModule.PreferenceUtilsSingleton.preferenceUtils.shouldProvideHapticFeedback()) { + return null; + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + VibratorManager vibratorManager = (VibratorManager) view.getContext().getSystemService(Context.VIBRATOR_MANAGER_SERVICE); + return vibratorManager.getDefaultVibrator(); + } + return (Vibrator) view.getContext().getSystemService(Context.VIBRATOR_SERVICE); + } + + // effect: use one of android.os.VibrationEffect + public static void provideHapticEffect(View view, int effect_id, int fallbackVibrateDurationMs) { + Vibrator vibrator = getVibrator(view); + if (vibrator == null) { + return; + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + VibrationEffect effect; + if (effect_id == VibrationEffect.DEFAULT_AMPLITUDE) { + effect = VibrationEffect.createOneShot(fallbackVibrateDurationMs, effect_id); } else { - Vibrator vibrator = (Vibrator) view.getContext().getSystemService(Context.VIBRATOR_SERVICE); - vibrator.vibrate(vibrateDurationMs); + effect = VibrationEffect.createPredefined(effect_id); } - } + vibrator.vibrate(effect); + } else { + vibrator.vibrate(fallbackVibrateDurationMs); + } + } + + public static void provideHapticFeedback(View view, int vibrateDurationMs) { + provideHapticEffect(view, VibrationEffect.DEFAULT_AMPLITUDE, vibrateDurationMs); } -} \ No newline at end of file +} From 702ebc2aa12cd7028666be7b86fa9d9af0b4d439 Mon Sep 17 00:00:00 2001 From: Arturo Espinosa Date: Thu, 19 Dec 2024 23:00:25 -0600 Subject: [PATCH 04/11] VibratingImageButton: added touch listener support to allow for haptic feedback just as the button is touched instead of at the end on the click process, and to allow for the click process to be prevented so that finer keyup and keydown commands can be sent to the Roku while preventing a duplicitous keypress to be sent at the end of the interaction. A click/keypress can still be used in case the button is "clicked" by different means than touch input. VIBRATE_DURATION_MS reduced to 25ms, and provideHapticFeedback calls were replaced with provideHapticEffect with EFFECT_TICK for a more subtle vibration pattern. --- .../romote/view/VibratingImageButton.java | 41 +++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/wseemann/media/romote/view/VibratingImageButton.java b/app/src/main/java/wseemann/media/romote/view/VibratingImageButton.java index 8d4a85c..2c3f08d 100644 --- a/app/src/main/java/wseemann/media/romote/view/VibratingImageButton.java +++ b/app/src/main/java/wseemann/media/romote/view/VibratingImageButton.java @@ -1,8 +1,10 @@ package wseemann.media.romote.view; import android.content.Context; +import android.os.VibrationEffect; import android.util.AttributeSet; import android.view.View; +import android.view.MotionEvent; import androidx.appcompat.widget.AppCompatImageButton; @@ -10,9 +12,12 @@ public class VibratingImageButton extends AppCompatImageButton { - private static final int VIBRATE_DURATION_MS = 100; + private static final int VIBRATE_DURATION_MS = 25; - private View.OnClickListener mListener; + private View.OnClickListener mClickListener; + private View.OnTouchListener mTouchListener; + + private boolean preventClick = false; public VibratingImageButton(Context context) { this(context, null); @@ -25,16 +30,38 @@ public VibratingImageButton(Context context, AttributeSet attrs) { public VibratingImageButton(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); super.setOnClickListener((View view) -> { - ViewUtils.provideHapticFeedback(view, VIBRATE_DURATION_MS); - - if (mListener != null) { - mListener.onClick(view); + if (mClickListener != null && !preventClick) { + ViewUtils.provideHapticEffect(view, VibrationEffect.EFFECT_TICK, VIBRATE_DURATION_MS); + mClickListener.onClick(view); } + preventClick = false; }); + + super.setOnTouchListener((View view, MotionEvent event) -> { + switch(event.getAction()) { + case MotionEvent.ACTION_DOWN: + ViewUtils.provideHapticEffect(view, VibrationEffect.EFFECT_TICK, VIBRATE_DURATION_MS); + preventClick = true; + break; + case MotionEvent.ACTION_CANCEL: + preventClick = false; + break; + } + + if (mTouchListener != null) { + return mTouchListener.onTouch(view, event); + } + return false; + }); } @Override public void setOnClickListener(View.OnClickListener listener) { - mListener = listener; + mClickListener = listener; + } + + @Override + public void setOnTouchListener(View.OnTouchListener listener) { + mTouchListener = listener; } } From b48a080b1ef4744f88f8f5a8c2c4cd7f0db78680 Mon Sep 17 00:00:00 2001 From: Arturo Espinosa Date: Thu, 19 Dec 2024 23:09:20 -0600 Subject: [PATCH 05/11] remote_dpad_controls_view.xml: replaced RepeatingImageButton with VibratingImageButton, as the RepeatingImageButton behaviour is no longer needed: finer keyup/keydown commands sent on touch events render the timed keypresses obsolete. All buttons, including the dpad can be implemented with VibratingImageButton directly. --- app/src/main/res/layout/remote_dpad_controls_view.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/layout/remote_dpad_controls_view.xml b/app/src/main/res/layout/remote_dpad_controls_view.xml index b63c847..2359fa7 100644 --- a/app/src/main/res/layout/remote_dpad_controls_view.xml +++ b/app/src/main/res/layout/remote_dpad_controls_view.xml @@ -16,7 +16,7 @@ android:layout_height="match_parent" android:layout_weight="1" /> - - - - Date: Thu, 19 Dec 2024 23:11:31 -0600 Subject: [PATCH 06/11] RemoteFragment.java: unify linkRepeatingRemoteButton and linkButton RepeatingImageButton class no longer needed. All buttons have their listeners configured with linkButton, which sets up click and touch listeners. --- .../media/romote/fragment/RemoteFragment.java | 84 +++++++++---------- 1 file changed, 39 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/wseemann/media/romote/fragment/RemoteFragment.java b/app/src/main/java/wseemann/media/romote/fragment/RemoteFragment.java index e674d2b..a79fc8e 100644 --- a/app/src/main/java/wseemann/media/romote/fragment/RemoteFragment.java +++ b/app/src/main/java/wseemann/media/romote/fragment/RemoteFragment.java @@ -57,7 +57,6 @@ import wseemann.media.romote.utils.CommandHelper; import wseemann.media.romote.utils.Constants; import wseemann.media.romote.utils.PreferenceUtils; -import wseemann.media.romote.view.RepeatingImageButton; import wseemann.media.romote.view.VibratingImageButton; /** @@ -105,25 +104,25 @@ public void onClick(View v) { }); mVoiceSearcButton.requestFocus();*/ - linkRepeatingRemoteButton(KeyPressKeyValues.BACK, R.id.back_button); - linkRepeatingRemoteButton(KeyPressKeyValues.UP, R.id.up_button); - linkRepeatingRemoteButton(KeyPressKeyValues.HOME, R.id.home_button); + linkButton(KeyPressKeyValues.BACK, R.id.back_button); + linkButton(KeyPressKeyValues.UP, R.id.up_button); + linkButton(KeyPressKeyValues.HOME, R.id.home_button); - linkRepeatingRemoteButton(KeyPressKeyValues.LEFT, R.id.left_button); - linkRepeatingRemoteButton(KeyPressKeyValues.SELECT, R.id.ok_button); - linkRepeatingRemoteButton(KeyPressKeyValues.RIGHT, R.id.right_button); + linkButton(KeyPressKeyValues.LEFT, R.id.left_button); + linkButton(KeyPressKeyValues.SELECT, R.id.ok_button); + linkButton(KeyPressKeyValues.RIGHT, R.id.right_button); - linkRepeatingRemoteButton(KeyPressKeyValues.INTANT_REPLAY, R.id.instant_replay_button); - linkRepeatingRemoteButton(KeyPressKeyValues.DOWN, R.id.down_button); - linkRepeatingRemoteButton(KeyPressKeyValues.INFO, R.id.info_button); + linkButton(KeyPressKeyValues.INTANT_REPLAY, R.id.instant_replay_button); + linkButton(KeyPressKeyValues.DOWN, R.id.down_button); + linkButton(KeyPressKeyValues.INFO, R.id.info_button); - linkRepeatingRemoteButton(KeyPressKeyValues.REV, R.id.rev_button); - linkRepeatingRemoteButton(KeyPressKeyValues.PLAY, R.id.play_button); - linkRepeatingRemoteButton(KeyPressKeyValues.FWD, R.id.fwd_button); + linkButton(KeyPressKeyValues.REV, R.id.rev_button); + linkButton(KeyPressKeyValues.PLAY, R.id.play_button); + linkButton(KeyPressKeyValues.FWD, R.id.fwd_button); - linkRepeatingRemoteButton(KeyPressKeyValues.VOLUME_MUTE, R.id.mute_button); - linkRepeatingRemoteButton(KeyPressKeyValues.VOLUME_DOWN, R.id.volume_down_button); - linkRepeatingRemoteButton(KeyPressKeyValues.VOLUME_UP, R.id.volume_up_button); + linkButton(KeyPressKeyValues.VOLUME_MUTE, R.id.mute_button); + linkButton(KeyPressKeyValues.VOLUME_DOWN, R.id.volume_down_button); + linkButton(KeyPressKeyValues.VOLUME_UP, R.id.volume_up_button); ImageButton keyboardButton = getView().findViewById(R.id.keyboard_button); keyboardButton.setOnClickListener(view -> { @@ -172,40 +171,35 @@ public void onDestroy() { getActivity().unregisterReceiver(mUpdateReceiver); } - private void linkRepeatingRemoteButton(final KeyPressKeyValues keypressKeyValue, int id) { - View button = getView().findViewById(id); - - button.setOnTouchListener((view, event) -> { - switch(event.getAction()) { - case MotionEvent.ACTION_DOWN: - performKeydown(keypressKeyValue); - if (id == R.id.back_button || - id == R.id.home_button || - id == R.id.ok_button) { - BroadcastUtils.Companion.sendUpdateDeviceBroadcast(requireContext()); - } - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - performKeyup(keypressKeyValue); - break; - } - return false; - }); - } - private void linkButton(final KeyPressKeyValues keypressKeyValue, int id) { - ImageButton button = getView().findViewById(id); + View button = getView().findViewById(id); button.setOnClickListener(view -> { - performKeypress(keypressKeyValue); - - if (id == R.id.back_button || + if (id == R.id.back_button || id == R.id.home_button || id == R.id.ok_button) { - BroadcastUtils.Companion.sendUpdateDeviceBroadcast(requireContext()); - } - }); + BroadcastUtils.Companion.sendUpdateDeviceBroadcast(requireContext()); + } + performKeypress(keypressKeyValue); + }); + + button.setOnTouchListener((view, event) -> { + switch(event.getAction()) { + case MotionEvent.ACTION_DOWN: + performKeydown(keypressKeyValue); + if (id == R.id.back_button || + id == R.id.home_button || + id == R.id.ok_button) { + BroadcastUtils.Companion.sendUpdateDeviceBroadcast(requireContext()); + } + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + performKeyup(keypressKeyValue); + break; + } + return false; + }); } private void performRequest(final ECPRequest request) { From 25e106ae54d02fd66272cc2ac28b61a2b430ef3a Mon Sep 17 00:00:00 2001 From: Arturo Espinosa Date: Thu, 19 Dec 2024 23:31:39 -0600 Subject: [PATCH 07/11] RemoteFragment:linkButton: call performKeydown after broadcast just to respect the original order of the code. --- .../java/wseemann/media/romote/fragment/RemoteFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/wseemann/media/romote/fragment/RemoteFragment.java b/app/src/main/java/wseemann/media/romote/fragment/RemoteFragment.java index a79fc8e..44ca05d 100644 --- a/app/src/main/java/wseemann/media/romote/fragment/RemoteFragment.java +++ b/app/src/main/java/wseemann/media/romote/fragment/RemoteFragment.java @@ -186,12 +186,12 @@ private void linkButton(final KeyPressKeyValues keypressKeyValue, int id) { button.setOnTouchListener((view, event) -> { switch(event.getAction()) { case MotionEvent.ACTION_DOWN: - performKeydown(keypressKeyValue); if (id == R.id.back_button || id == R.id.home_button || id == R.id.ok_button) { BroadcastUtils.Companion.sendUpdateDeviceBroadcast(requireContext()); } + performKeydown(keypressKeyValue); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: From f59b32987976e00716262faf9ba7377062de3235 Mon Sep 17 00:00:00 2001 From: Arturo Espinosa Date: Thu, 19 Dec 2024 23:32:31 -0600 Subject: [PATCH 08/11] VibratingImageButton: don't preventClick if no touch listener set as it doesn't make sense to do so, and this prevented special buttons such as Power from working --- .../wseemann/media/romote/view/VibratingImageButton.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/wseemann/media/romote/view/VibratingImageButton.java b/app/src/main/java/wseemann/media/romote/view/VibratingImageButton.java index 2c3f08d..20f8375 100644 --- a/app/src/main/java/wseemann/media/romote/view/VibratingImageButton.java +++ b/app/src/main/java/wseemann/media/romote/view/VibratingImageButton.java @@ -38,6 +38,10 @@ public VibratingImageButton(Context context, AttributeSet attrs, int defStyle) { }); super.setOnTouchListener((View view, MotionEvent event) -> { + if (mTouchListener == null) { + return false; + } + switch(event.getAction()) { case MotionEvent.ACTION_DOWN: ViewUtils.provideHapticEffect(view, VibrationEffect.EFFECT_TICK, VIBRATE_DURATION_MS); @@ -48,10 +52,7 @@ public VibratingImageButton(Context context, AttributeSet attrs, int defStyle) { break; } - if (mTouchListener != null) { - return mTouchListener.onTouch(view, event); - } - return false; + return mTouchListener.onTouch(view, event); }); } From e5fdb35e6a881f12e0fb06ba1b3f287d3899797f Mon Sep 17 00:00:00 2001 From: Arturo Espinosa Date: Thu, 19 Dec 2024 23:37:16 -0600 Subject: [PATCH 09/11] VibratingImageButton: send haptic feedback even if no click listener --- .../media/romote/view/VibratingImageButton.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/wseemann/media/romote/view/VibratingImageButton.java b/app/src/main/java/wseemann/media/romote/view/VibratingImageButton.java index 20f8375..38e5325 100644 --- a/app/src/main/java/wseemann/media/romote/view/VibratingImageButton.java +++ b/app/src/main/java/wseemann/media/romote/view/VibratingImageButton.java @@ -30,12 +30,14 @@ public VibratingImageButton(Context context, AttributeSet attrs) { public VibratingImageButton(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); super.setOnClickListener((View view) -> { - if (mClickListener != null && !preventClick) { - ViewUtils.provideHapticEffect(view, VibrationEffect.EFFECT_TICK, VIBRATE_DURATION_MS); - mClickListener.onClick(view); - } - preventClick = false; - }); + if (!preventClick) { + ViewUtils.provideHapticEffect(view, VibrationEffect.EFFECT_TICK, VIBRATE_DURATION_MS); + if (mClickListener != null) { + mClickListener.onClick(view); + } + } + preventClick = false; + }); super.setOnTouchListener((View view, MotionEvent event) -> { if (mTouchListener == null) { From 634cc46d46baa93a3ae7cf264857a6feaecc0c4f Mon Sep 17 00:00:00 2001 From: Arturo Espinosa Date: Sat, 21 Dec 2024 21:29:16 -0600 Subject: [PATCH 10/11] Aesthetic, indentation. --- .../wseemann/media/romote/utils/ViewUtils.java | 18 ++++++++---------- .../romote/view/VibratingImageButton.java | 6 ++---- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/wseemann/media/romote/utils/ViewUtils.java b/app/src/main/java/wseemann/media/romote/utils/ViewUtils.java index f2d935a..492021d 100644 --- a/app/src/main/java/wseemann/media/romote/utils/ViewUtils.java +++ b/app/src/main/java/wseemann/media/romote/utils/ViewUtils.java @@ -20,11 +20,12 @@ private ViewUtils() { } private static Vibrator getVibrator(View view) { - if (!CommonModule.PreferenceUtilsSingleton.preferenceUtils.shouldProvideHapticFeedback()) { + if (!CommonModule.PreferenceUtilsSingleton.preferenceUtils.shouldProvideHapticFeedback()) return null; - } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - VibratorManager vibratorManager = (VibratorManager) view.getContext().getSystemService(Context.VIBRATOR_MANAGER_SERVICE); + VibratorManager vibratorManager = (VibratorManager) view.getContext() + .getSystemService(Context.VIBRATOR_MANAGER_SERVICE); return vibratorManager.getDefaultVibrator(); } return (Vibrator) view.getContext().getSystemService(Context.VIBRATOR_SERVICE); @@ -33,21 +34,18 @@ private static Vibrator getVibrator(View view) { // effect: use one of android.os.VibrationEffect public static void provideHapticEffect(View view, int effect_id, int fallbackVibrateDurationMs) { Vibrator vibrator = getVibrator(view); - if (vibrator == null) { + if (vibrator == null) return; - } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { VibrationEffect effect; - if (effect_id == VibrationEffect.DEFAULT_AMPLITUDE) { + if (effect_id == VibrationEffect.DEFAULT_AMPLITUDE) effect = VibrationEffect.createOneShot(fallbackVibrateDurationMs, effect_id); - } else { + else effect = VibrationEffect.createPredefined(effect_id); - } vibrator.vibrate(effect); - } else { + } else vibrator.vibrate(fallbackVibrateDurationMs); - } } public static void provideHapticFeedback(View view, int vibrateDurationMs) { diff --git a/app/src/main/java/wseemann/media/romote/view/VibratingImageButton.java b/app/src/main/java/wseemann/media/romote/view/VibratingImageButton.java index 38e5325..c733280 100644 --- a/app/src/main/java/wseemann/media/romote/view/VibratingImageButton.java +++ b/app/src/main/java/wseemann/media/romote/view/VibratingImageButton.java @@ -32,17 +32,15 @@ public VibratingImageButton(Context context, AttributeSet attrs, int defStyle) { super.setOnClickListener((View view) -> { if (!preventClick) { ViewUtils.provideHapticEffect(view, VibrationEffect.EFFECT_TICK, VIBRATE_DURATION_MS); - if (mClickListener != null) { + if (mClickListener != null) mClickListener.onClick(view); - } } preventClick = false; }); super.setOnTouchListener((View view, MotionEvent event) -> { - if (mTouchListener == null) { + if (mTouchListener == null) return false; - } switch(event.getAction()) { case MotionEvent.ACTION_DOWN: From 38ad420bbb1e64fb73add8aac5bf8bdbdf8ece8d Mon Sep 17 00:00:00 2001 From: Arturo Espinosa Date: Fri, 3 Jan 2025 15:52:47 -0600 Subject: [PATCH 11/11] Catch UnsupportedEncodingException when creating new ECP key requests --- .../media/romote/fragment/RemoteFragment.java | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/wseemann/media/romote/fragment/RemoteFragment.java b/app/src/main/java/wseemann/media/romote/fragment/RemoteFragment.java index 44ca05d..eb4a1ac 100644 --- a/app/src/main/java/wseemann/media/romote/fragment/RemoteFragment.java +++ b/app/src/main/java/wseemann/media/romote/fragment/RemoteFragment.java @@ -263,21 +263,39 @@ public void onClick(DialogInterface dialog, int whichButton) { private void performKeypress(KeyPressKeyValues keypressKeyValue) { String url = commandHelper.getDeviceURL(); - KeyPressRequest keyPressRequest = new KeyPressRequest(url, keypressKeyValue.getValue()); + KeyPressRequest keyPressRequest; + try { + keyPressRequest = new KeyPressRequest(url, keypressKeyValue.getValue()); + } catch (UnsupportedEncodingException ex) { + ex.printStackTrace(); + return; + } performRequest(keyPressRequest); } private void performKeydown(KeyPressKeyValues keypressKeyValue) { String url = commandHelper.getDeviceURL(); - KeydownRequest keydownRequest = new KeydownRequest(url, keypressKeyValue.getValue()); + KeydownRequest keydownRequest; + try { + keydownRequest = new KeydownRequest(url, keypressKeyValue.getValue()); + } catch (UnsupportedEncodingException ex) { + ex.printStackTrace(); + return; + } performRequest(keydownRequest); } private void performKeyup(KeyPressKeyValues keypressKeyValue) { String url = commandHelper.getDeviceURL(); - KeyupRequest keyupRequest = new KeyupRequest(url, keypressKeyValue.getValue()); + KeyupRequest keyupRequest; + try { + keyupRequest = new KeyupRequest(url, keypressKeyValue.getValue()); + } catch (UnsupportedEncodingException ex) { + ex.printStackTrace(); + return; + } performRequest(keyupRequest); }