Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

First touch being ignored?

Tags:

android

I'm working on an Alarm Clock. As part of it, I have an IntentService that starts an activity when the alarm actually goes off. In the Activity's onCreate I'm waking up the screen, obtaining wake lock, forcing the activity to full screen, and playing a sound. Here's all that in the onCreate:

super.onCreate(savedInstanceState);

// Get Alarm ID from the extras
Bundle extras = getIntent().getExtras();
int id = extras.getInt("AlarmID", -1);

// Get Alarm info from the DB 
DB = new DatabaseHelper(this);
alarm = DB.getAlarm(id);

if (alarm == null || !alarm.isEnabled()) finish();

getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
setContentView(R.layout.activity_alarm);

// My root view
View contentView = findViewById(R.id.fullscreen_content);

// Hide action bar for full screen
ActionBar bar = getActionBar();
if (bar != null) bar.hide();
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

// Hide nav bar
mSystemUiHider = SystemUiHider.getInstance(this, contentView, HIDER_FLAGS);
mSystemUiHider.setup();
mSystemUiHider.hide();

// Show over lock screen
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);

// Wake up screen
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "MyWakeLock");
wakeLock.acquire();

// Get UI Elements
TextView time = (TextView)findViewById(R.id.Time);
TextView name = (TextView)findViewById(R.id.SmallAlarmName);

// Fill UI Elements
time.setText(Alarm.FormatTime(alarm.getHour(), alarm.getMinute()));
name.setText(alarm.getName());

// Play selected ringtone
tone = RingtoneManager.getRingtone(this, alarm.getSound());
tone.setStreamType(RingtoneManager.TYPE_ALARM);
tone.play();

The view is rather simple: 2x TextViews to show the time and the name of the alarm, and 2x clickable ImageViews for Snooze and Disable.

The problem I'm having is that the first time I touch the screen, nothing happens. Both of the ImageViews start with a Log.i so I know when I push it if the event fires. On the first push, there's no log output. On the second push, the proper ImageView's event is fired. It doesn't matter if the screen was originally on or off when the activity is created, the first touch is very repeatably ignored. What's happening and how can I fix it so that the first touch works as expected?

I'm testing on my Nexus 5, 4.4.3, Rooted, stock rom, Xposed Framework (but no module that would affect my app). I can't really test in a virtual machine because of the need to use ringtones (of which the VM has none).

Also, for the record, no other logs happen for the first tap. I have no clue what the phone thinks I'm tapping.

EDIT: I thought it had something to do with the flags. I noticed that I was calling setFlags instead of addFlags in my call getWindow().setFlags(...). Instead, I changed it to addFlags and tried changing it to:

int flags = WindowManager.LayoutParams.FLAG_FULLSCREEN |
            WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
            WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING |
            WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
getWindow().addFlags(flags);

But no change.

Is there a way I can tell what might be intercepting the first tap?

I tried setting a break point at the end of onCreate and continually stepping over until it eventually is awaiting for an event to arise, but even in this state the first tap won't make a change in the debugger. A second tap on one of my ImageViews will, as expected, stop the debugger at the first line inside my click handlers.

EDIT 2: I think I'm on to something. I was watching the logcat through a filter, only seeing things relating to my app. I tried looking at the logcat without a filter and was able to reliably get these kinds of messages on first tap:

06-12 23:28:04.437      812-844/? W/InputEventReceiver﹕ Attempted to finish an input event but the input event receiver has already been disposed.

The first tap would respond with two of these warnings. Additional taps after the first would give no such warning and my handlers would execute as expected.

A quick search came back with this question but is unhelpful for my situation. More than just a warning, I think this may be the root cause for why the first tap is ignored. However, I still don't have any idea as to how to fix it.

like image 602
Corey Ogburn Avatar asked Jun 12 '14 05:06

Corey Ogburn


2 Answers

Not sure if this is even answer or how much universal it is, but.. I somehow managed to solve this issue for me by removing these flags:

getWindow().getDecorView().setSystemUiVisibility(
    View.SYSTEM_UI_FLAG_LAYOUT_STABLE
          //| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
          //| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
          | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);

I can only speculate about reason why those 2 flags caused ignorance of the first touch. Maybe it is the "Immersive mode" correlating with these tags, bacause it should (and does) hide navigation by itself, so maybe it conflicts under the hood somehow.. I don't know :-)

like image 134
teejay Avatar answered Oct 30 '22 01:10

teejay


I eventually came across this question which linked to this answer.

I ended up moving this block of code:

int flags = WindowManager.LayoutParams.FLAG_FULLSCREEN |
        WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
        WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING |
        WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
getWindow().addFlags(flags);

To just after I acquire wake lock (just before I start filling the views) and added the code in the answer, specifically:

getWindow().getDecorView().setSystemUiVisibility(
        View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_FULLSCREEN
                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);

Both of these changes now give me the result I'm looking for: the first input is accepted! My guess is that something in the UI hider or the wake lock acquisition is changing the apps flags. I don't know what to, I don't know which flag is causing my issue. All I know is that by moving this code around, I no longer have to press on the screen twice. I'd love a real explanation for WHY this fixed it but in lieu of that, I'll take this.

like image 30
Corey Ogburn Avatar answered Oct 30 '22 00:10

Corey Ogburn