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:
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>
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.