javaandroidandroid-tvandroid-input-methodtvbox

Android App Mouse Pointer Input Not working well on Activity UI Elements


Solved! https://stackoverflow.com/a/63790855/12021422

I am working on an Android App which works on Mobiles, Tabs and TV Boxes. My app will need to handle inputs from Touch, Mouse Pointer or Remote.

Currently, My Code works well to achieve the functionality but there is abnormal behaviour in handling of Mouse inputs only happens on TV Box.

Problem: When the app starts the remote can easily navigate on the focusable elements but the mouse at pointer does not get detected by app elements. Now When a mouse pointer is taken to Volume Option and then comes back with a Click. The app starts detecting mouse but after some Action, it again looses focus from App UI and motion of the mouse pointer and clicks become undetected again.

Please Watch the Video from Link below to see How the app is currently behaving. https://jumpshare.com/v/bvyfbqZFWNJfoUsXJbSU

Problem Gist: As the Volume controller is displayed above the app the mouse can make changes on volume tracker and come out after making left-click. The app becomes responsive to hovers and mouse pointer action and when some action is made on the app it again becomes unresponsive.

Some Conditions that App should Follow:

Code

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#dad6d6"
    android:orientation="vertical">

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">


            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="30sp"
                android:fontFamily="@font/poppinsregular"
                android:gravity="center"
                android:text="Mouse and Remote Input App"
                android:textColor="#000000"
                android:textSize="30sp" />


            <Button
                android:id="@+id/btn1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@drawable/buttondesign"
                android:focusable="true"
                android:focusableInTouchMode="true"
                android:fontFamily="@font/poppinsregular"
                android:text="Button 1"
                android:textColor="#ffffff"
                android:textSize="20sp"
                android:textStyle="bold" />

            <Button
                android:id="@+id/btn2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="10sp"
                android:background="@drawable/buttondesign"
                android:focusable="true"
                android:focusableInTouchMode="true"
                android:fontFamily="@font/poppinsregular"
                android:text="Button 2"
                android:textColor="#ffffff"
                android:textSize="20sp"
                android:textStyle="bold" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"

                android:layout_marginTop="20sp"
                android:fontFamily="@font/poppinsregular"
                android:text="Try Switch 1"
                android:textColor="#000000"
                android:textSize="20sp" />

            <Switch
                android:id="@+id/switch1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:layout_marginTop="2sp"
                android:focusable="true"
                android:focusableInTouchMode="true"

                />


            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:fontFamily="@font/poppinsregular"
                android:text="Edit Text 1"
                android:textColor="#000000"
                android:textSize="20sp" />

            <EditText
                android:id="@+id/edittext1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:autofillHints=""
                android:background="@drawable/edittext_design"
                android:ems="5"
                android:focusable="true"
                android:focusableInTouchMode="true"
                android:hint="Number"
                android:inputType="number"
                android:textAlignment="center"
                android:textColor="@android:color/black"
                android:textSize="30sp" />


        </LinearLayout>

    </ScrollView>
    </LinearLayout>

MainActivity.java

package com.example.remoteandmouseapp;


import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Switch;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;


public class MainActivity extends AppCompatActivity {
    LinearLayout root_layout;

    Switch switch1;
    EditText edittext1;
    Button btn1, btn2;


    @Override
    protected void onStart() {
        super.onStart();
    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
    }


    @SuppressLint("ClickableViewAccessibility")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getSupportActionBar().hide();
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        switch1 = (Switch) findViewById(R.id.switch1);

        edittext1 = (EditText) findViewById(R.id.edittext1);


        root_layout = findViewById(R.id.root_layout);


        edittext1.setText("4");


        btn1 = (Button) findViewById(R.id.btn1);
        btn2 = (Button) findViewById(R.id.btn2);

        btn1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                //textInfo.setText("");
                Toast toast = Toast.makeText(getApplicationContext(), "Button 1 Clicked", Toast.LENGTH_SHORT);
                toast.setGravity(Gravity.CENTER, 0, 0);
                toast.show();

            }
        });

        btn1.setOnTouchListener(new Button.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent arg1) {
                if ((arg1.getAction() == MotionEvent.ACTION_UP)) {
                    Toast toast = Toast.makeText(getApplicationContext(), "Button 1 Touched", Toast.LENGTH_SHORT);
                    toast.setGravity(Gravity.CENTER, 0, 0);
                    toast.show();

                }
                return true;
            }
        });

        btn1.setOnHoverListener(new View.OnHoverListener() {
            @Override
            public boolean onHover(View v, MotionEvent event) {

                if (event.getAction() == MotionEvent.ACTION_HOVER_ENTER) {
                    btn1.setBackgroundResource(R.drawable.onfoucsbuttondesign);

                }
                if (event.getAction() == MotionEvent.ACTION_HOVER_EXIT) {
                    btn1.setBackgroundResource(R.drawable.buttondesign);

                }

                return true;
            }
        });
        btn1.setOnFocusChangeListener(new View.OnFocusChangeListener() {

            @Override
            public void onFocusChange(View v, boolean hasFocus) {

                if (hasFocus) {
                    btn1.setBackgroundResource(R.drawable.onfoucsbuttondesign);
                } else {
                    btn1.setBackgroundResource(R.drawable.buttondesign);
                }
            }
        });


        btn2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                //textInfo.setText("");
                Toast toast = Toast.makeText(getApplicationContext(), "Button 2 Clicked", Toast.LENGTH_SHORT);
                toast.setGravity(Gravity.CENTER, 0, 0);
                toast.show();

            }
        });

        btn2.setOnHoverListener(new View.OnHoverListener() {
            @Override
            public boolean onHover(View v, MotionEvent event) {

                if (event.getAction() == MotionEvent.ACTION_HOVER_ENTER) {
                    btn2.setBackgroundResource(R.drawable.onfoucsbuttondesign);

                }
                if (event.getAction() == MotionEvent.ACTION_HOVER_EXIT) {
                    btn2.setBackgroundResource(R.drawable.buttondesign);
                }

                return true;
            }
        });

        btn2.setOnTouchListener(new Button.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent arg1) {
                if ((arg1.getAction() == MotionEvent.ACTION_UP)) {
                    Toast toast = Toast.makeText(getApplicationContext(), "Button 2 Touched", Toast.LENGTH_SHORT);
                    toast.setGravity(Gravity.CENTER, 0, 0);
                    toast.show();

                }
                return true;
            }
        });


        btn2.setOnFocusChangeListener(new View.OnFocusChangeListener() {

            @Override
            public void onFocusChange(View v, boolean hasFocus) {

                if (hasFocus) {
                    btn2.setBackgroundResource(R.drawable.onfoucsbuttondesign);
                } else {
                    btn2.setBackgroundResource(R.drawable.buttondesign);

                }
            }
        });

        edittext1.addTextChangedListener(new TextWatcher() {

            public void afterTextChanged(Editable s) {
                if (!s.toString().equals("")) {

                    Toast toast = Toast.makeText(getApplicationContext(), "Edit Text Changed to: " + s, Toast.LENGTH_SHORT);
                    toast.setGravity(Gravity.CENTER, 0, 0);
                    toast.show();
                } else {

                }
            }

            public void beforeTextChanged(CharSequence s, int start,
                                          int count, int after) {
            }

            public void onTextChanged(CharSequence s, int start,
                                      int before, int count) {

                // status.setText(""+s);
            }
        });

        edittext1.setOnTouchListener(new Button.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent arg1) {
                if ((arg1.getAction() == MotionEvent.ACTION_UP)) {

                    edittext1.requestFocus();
                    edittext1.setCursorVisible(true);
                    InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                    imm.showSoftInput(edittext1, InputMethodManager.SHOW_IMPLICIT);
                    edittext1.setSelection(edittext1.getText().length());
                }
                return true;
            }
        });


        switch1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {

            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                Log.v("Switch State=", "" + isChecked);
                Toast toast = Toast.makeText(getApplicationContext(), "Switch Boolean: " + isChecked, Toast.LENGTH_SHORT);
                toast.setGravity(Gravity.CENTER, 0, 0);
                toast.show();
            }
        });


        switch1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                toggleSwitchOnTap();
            }
        });

        switch1.setOnTouchListener(new Button.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent arg1) {
                if ((arg1.getAction() == MotionEvent.ACTION_UP)) {
                    toggleSwitchOnTap();
                }
                return true;
            }
        });


    }

    public void toggleSwitchOnTap() {
        if (switch1.isChecked()) {
            switch1.setChecked(false);
        } else {
            switch1.setChecked(true);
        }
    }


}


AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.remoteandmouseapp">
    <uses-feature android:name="android.hardware.touchscreen"
        android:required="false" />
    <uses-feature android:name="android.hardware.faketouch"
        android:required="false"
        />
    <application
        android:allowBackup="false"
        android:icon="@mipmap/ic_launcher"
        android:label="Testname"
        android:roundIcon="@mipmap/ic_launcher"
        android:hardwareAccelerated="true"
        android:largeHeap="true"
        android:theme="@style/AppTheme"
        >
        <activity android:name=".MainActivity"
            android:label="testname"
            android:configChanges="keyboard|keyboardHidden|navigation"
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>



</manifest>

Solution

  • I solved this weird Issue after removing get getSupportActionBar().hide(); from my MainActivity.

    Solution Description: I found that when the app bar was not removed from the theme the mouse events on the app started working.

    I was hiding app bar for clean UI for my use case but that was just an enhancement so unhide the app bar to make it work. I hope this helps if you are stuck with the same unique case.