简体   繁体   中英

Android: Triggering MotionEvent.ACTION_CANCEL

The Requirements: Ensure that itemLookup is only performed if the button has been held for at least 1 second. Stop the button event when the button has been held for 3 seconds, so the recording used for the lookup will not contain unnecessary data.

  • The Problem: MotionEvent.ACTION_CANCEL is never called even though debugging confirms that TableLayoutForIntercept 's onInterceptTouchEvent is being called before MainActivity 's OnTouchListener event is called, as expected. Perhaps I am not understanding the purpose of onInterceptTouchEvent ? I've looked at other posts about this matter, but all of them are dealing with swipe or drag events, not cancelling a button press . Perhaps this can't be done?
  • The Code: Only the relevant parts of MainActivity are shown, along with the full TableLayoutForIntercept class, and of course <com.company.myapplication.TableLayoutForIntercept></com.company.myapplication.TableLayoutForIntercept> tags surround my xml layout.

     public class MainActivity extends Activity { //... DateTime recordingStartedTime; DateTime recordingEndedTime; boolean buttonHeldLongEnough = false; PackageManager pm = getPackageManager(); boolean micPresent = pm.hasSystemFeature(PackageManager.FEATURE_MICROPHONE); if (micPresent) { recordBtn.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View recordView, MotionEvent recordEvent) { switch (recordEvent.getAction()) { case MotionEvent.ACTION_DOWN: // Try to record audio try { recordingOff.setVisibility(View.INVISIBLE); recordingOn.setVisibility(View.VISIBLE); recordingStartedTime = DateTime.now(); constructPrepareStartRecording(); } catch (Exception ex) { Log.e(MainActivity.class.getSimpleName(), "An unknown error occurred."); } return true; case MotionEvent.ACTION_UP: recordingOff.setVisibility(View.VISIBLE); recordingOn.setVisibility(View.INVISIBLE); recordingEndedTime = DateTime.now(); Seconds seconds = Seconds.secondsBetween(recordingStartedTime, recordingEndedTime); int secondsButtonHeld = seconds.getSeconds(); // Button must have been held at least 1 second before running itemLookup if (secondsButtonHeld > 0 ) { buttonHeldLongEnough = true; } else { buttonHeldLongEnough = false; } // Need to release resources regardless stopReleaseResetRecording(); if (buttonHeldLongEnough) { itemLookup(); } return true; case MotionEvent.ACTION_CANCEL: // I think this is the event I have to trigger to halt the button press boolean codeHasHitCancel = true; return codeHasHitCancel; } return false; } }); } else { toastTitle = "Unable To Record"; toastMessage = "Device microphone not found."; toast = new GenericCustomToast(); toast.show(toastTitle, toastMessage, MainActivity.this); } //... } public class TableLayoutForIntercept extends TableLayout { public TableLayoutForIntercept (Context context) { super(context); } public TableLayoutForIntercept (Context context, AttributeSet attrs) { super(context, attrs); } private CancelPressTask cancelPressTask = null; private boolean stopTouchEvent = false; @Override public boolean onInterceptTouchEvent (MotionEvent event) { final int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: stopTouchEvent = false; cancelPressTask = new CancelPressTask(); break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: cancelPressTask.resetCancelPressTimer(); cancelPressTask.stopCancelPressTimer(); return stopTouchEvent; } return super.onInterceptTouchEvent(event); } @Override public boolean onTouchEvent (MotionEvent event) { if (!stopTouchEvent) { return super.onTouchEvent(event); } return true; } private class CancelPressTask { public final long CANCEL_PRESS_TIMEOUT = 3000; // 3 seconds private Handler cancelPressHandler = new Handler(){ public void handleMessage(Message msg) { } }; private Runnable cancelPressCallback = new Runnable() { @Override public void run() { stopTouchEvent = true; } }; public void resetCancelPressTimer(){ cancelPressHandler.removeCallbacks(cancelPressCallback); cancelPressHandler.postDelayed(cancelPressCallback, CANCEL_PRESS_TIMEOUT); } public void stopCancelPressTimer(){ cancelPressHandler.removeCallbacks(cancelPressCallback); } } } 

I figured out another way to go about this. Instead of trying to trigger an event, I decided to steal it instead! The below code will stop the recording, then do the item look-up after 3 seconds has elapsed, no matter how long the user tries to hold the button down for. The only catch is for recordings that are too short (less than 1 second) it will still take the full 3 seconds to notify the user via toast message. But I'm willing to live with that.

    public class Main Activity extends Activity {

        DateTime recordingStartedTime;
        DateTime recordingEndedTime = null;
        boolean buttonHeldLongEnough = false;
        LimitRecordingTask limitRecordingTask;

        PackageManager pm = getPackageManager();
        boolean micPresent = pm.hasSystemFeature(PackageManager.FEATURE_MICROPHONE);

        if (micPresent) {
            recordBtn.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View recordView, MotionEvent recordEvent) {

                    limitRecordingTask = new LimitRecordingTask();
                    switch (recordEvent.getAction()) {

                        case MotionEvent.ACTION_DOWN:
                            // Try to record audio
                            try {
                                recordBtn.setBackgroundColor(Color.DKGRAY);
                                recordingOff.setVisibility(View.INVISIBLE);
                                recordingOn.setVisibility(View.VISIBLE);

                                recordingStartedTime = DateTime.now();
                                constructPrepareStartRecording();
                                limitRecordingTask.resetRecordingTimer();
                            }
                            catch (Exception ex) {
                                Log.e(MainActivity.class.getSimpleName(), "An unknown error occurred.");
                                limitRecordingTask.stopRecordingTimer();
                            }
                            return true;

                        case MotionEvent.ACTION_UP:
                            // After 3 seconds limitRecordingTask will 'steal' this event
                            recordBtn.setBackgroundResource(R.drawable.custom_button);
                            recordingOff.setVisibility(View.VISIBLE);
                            recordingOn.setVisibility(View.INVISIBLE);

                            recordingEndedTime = DateTime.now();
                            Seconds seconds = Seconds.secondsBetween(recordingStartedTime, recordingEndedTime);
                            int secondsButtonHeld = Math.abs(seconds.getSeconds());

                            if (secondsButtonHeld > 0 ) {
                                buttonHeldLongEnough = true;
                            }
                            else {
                                buttonHeldLongEnough = false;
                            }
                            return true;
                    }
                    return false;
                }
            });
        }
        else {
            toastTitle = "Unable To Record";
            toastMessage = "Device microphone not found.";
            toast = new GenericCustomToast();
            toast.show(toastTitle, toastMessage, MainActivity.this);
        }

        private class LimitRecordingTask {

            public final long RECORDING_TIMEOUT = 3000; // 3 seconds

            private Handler limitRecordingHandler = new Handler(){
                public void handleMessage(Message msg) {
                }
            };

            private Runnable limitRecordingCallback = new Runnable() {
                @Override
                public void run() {
                    // 'Stolen' MotionEvent.ACTION_UP
                    recordBtn.setBackgroundResource(R.drawable.custom_button);
                    recordingOff.setVisibility(View.VISIBLE);
                    recordingOn.setVisibility(View.INVISIBLE);

                    if (recordingEndedTime == null) {
                        recordingEndedTime = DateTime.now();
                    }
                    Seconds seconds = Seconds.secondsBetween(recordingStartedTime, recordingEndedTime);
                    int secondsButtonHeld = Math.abs(seconds.getSeconds());

                    if (secondsButtonHeld > 0 ) {
                        buttonHeldLongEnough = true;
                    }
                    else {
                        buttonHeldLongEnough = false;
                    }

                    limitRecordingTask.stopRecordingTimer();

                    stopReleaseResetRecording();
                    itemLookup();
                }
            };

            public void resetRecordingTimer(){
                limitRecordingHandler.removeCallbacks(limitRecordingCallback);
                limitRecordingHandler.postDelayed(limitRecordingCallback, RECORDING_TIMEOUT);
            }

            public void stopRecordingTimer(){
                limitRecordingHandler.removeCallbacks(limitRecordingCallback);
            }
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM