Toggeling Touch by external keyboard - android

I am building a firmware for visually disabled people. I have to disable touch screen as and when the external key board is connected. And toggle it with Alt + T . For this I have a static volatile flag in View class called misTouchScreenEnabled. Upon plug in of external keyboard I return false from dispatchTouchEvent(). In View Class :
/*
* A register to hold the status of touch screen
*
*{#hide}
*/
public static volatile boolean misTouchScreenEnabled = false;
public boolean dispatchTouchEvent(MotionEvent event) {
if(event == null)
{
return false;
}
Log.d ("CnxsTA","View :: Into dispatchTouchEvent");
// Added by Harsh Vardhan 05102013
Configuration config = getResources().getConfiguration();
if (config.keyboard != Configuration.KEYBOARD_NOKEYS)
{
// And if the device has a hard keyboard, even if it is
// currently hidden, don't pass the touch events to the view
if(!mIsTouchScreenEnabled)
{
Log.d ("CnxsTA","View :: Into dispatchTouchEvent :: Returning False");
return false;
}
}
// Added By Harsh Vardhan
// Some Other Code...
}
In Launcher I catch the ALT + T in dispatchTouchEvent() and toggle the flag using reflection:
case KeyEvent.KEYCODE_T:
{
//Added By Harsh Vardhan 31052013
Log.d ("CnxsTA","Launcher :: onKeyDown :: T pressed");
if ((event.getMetaState() & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON)
{
Object s;
try
{
Log.d ("CnxsTA","Launcher :: In onKeyDown :: In isAltPressed");
s = ToogleTouchScreen(Class.forName("android.view.View"), "mIsTouchScreenEnabled");
if (s instanceof Boolean)
{
boolean v = ((Boolean) s).booleanValue();
//do something
Log.d ("CnxsTA","Launcher :: onKeyDown :: In isAltPressed :: Toggling touchscreen enable flag :: " + v);
if (accessibilityEnabled)
{
if (mTts != null)
{
if (v)
mTts.speak("Touch Screen enabled", TextToSpeech.QUEUE_FLUSH, null);
else
mTts.speak("Touch Screen disabled", TextToSpeech.QUEUE_FLUSH, null);
}
}
}
else if (s == null)
{
//do something
Log.d ("CnxsTA","Launcher :: onKeyDown :: S is Null");
}
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
}
//return super.dispatchKeyEvent(event);
return true;
//break;
//Added By Harsh Vardhan 31052013
}
This works well for the Launcher and its workspace, ie. the touch gets enabled and disabled when ALT + T is pressed. But the Panel in the bottom containing the back, home, recent apps and notifications remains unresponsive on touch and so is the UI in the application; though in Exploration Mode the Icons names are spoken on touch but the touch is not implemented. And it all retains to normal sate once the external keyboard is removed.
I think the reason behind this could be that the StatusBar Class and Other Classes extending the View which are taking the flag to be false only has cached the whole class or the variables and methods and is not referring to main memory where the flags have been toggled. I am aware that I have made the flag volatile.
I know that my flag gets toggle as I could confirm this from logcat. Please suggest me the direction I could solve this. Thanking in advance.

Related

isHardwareAccelerated() always returns false

I am trying to turn on hardware acceleration for my application
but I never seem to get a 'true' result from this function.
I tried all the methods in the Android Developers blog post about the
the tag android:hardwareAccelerated=true to the application
and even called
getWindow().setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
You should always call isHardwareAccelearted() after the view is attached to the window. I am not sure about your case as I can't see where actually you are calling it.
Also, the support level of various operations across API levels are mentioned here. I hope this helps.
You can also try this method to verify hardwareAcceleration.
public static boolean hasHardwareAcceleration(Activity activity) {
// Has HW acceleration been enabled manually in the current window?
Window window = activity.getWindow();
if (window != null) {
if ((window.getAttributes().flags
& WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0) {
return true;
}
}
// Has HW acceleration been enabled in the manifest?
try {
ActivityInfo info = activity.getPackageManager().getActivityInfo(
activity.getComponentName(), 0);
if ((info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
return true;
}
} catch (PackageManager.NameNotFoundException e) {
Log.e("Chrome", "getActivityInfo(self) should not fail");
}
return false;
}
For checking for View try this.
chat_wv.post(new Runnable() {
#Override
public void run() {
Log.e("isHardwareAccelerated", ""+chat_wv.isHardwareAccelerated());
}
});

How to disable call inside onChecked change conditionally?

I have toggle(Switch) buttons inside my fragment.After coming on the fragment I am reading BLE values and setting the toggle buttons.
#Override
public void sosStatus(boolean sosvalue, BluetoothGattCharacteristic sosCharac) {
if (sosvalue) {
byte[] charValue = sosCharac.getValue();
String valueOfCharInstring = StringUtils.byteToHex(charValue[0]);
Log.d("+++++SosStatus",""+sosCharac.getUuid().toString() + " " + valueOfCharInstring);
if (sosCharac.getUuid().toString().equalsIgnoreCase(BLEConstants._BUTTON_CHARACTERISTIC)) {
if (valueOfCharInstring.equalsIgnoreCase(BLEConstants.EnableCharacInString)) {
setButtonStatus(touchButton,R.id.switch_btn_device_touch,"Enabled");
// touchButton.setChecked(true);
// tvTouchButtonAction.setText("Enabled");
} else if (valueOfCharInstring.equalsIgnoreCase(BLEConstants.DisableCharacInString)) {
setButtonStatus(touchButton,R.id.switch_btn_device_touch,"Disabled");
// touchButton.setChecked(false);
// tvTouchButtonAction.setText("Disabled");
}
}
if (characList.size() > 0) {
gattclientCallBack.readCharacteristicMain(UUID.fromString(characList.remove(characList.size() - 1)));
} else {
useOnCheckedChangeMethod = true;
showProgress(false);
}
} else {
useOnCheckedChangeMethod = true;
showProgress(false);
HandleCharacListData(true,false,"");
}
}
Now since Switch widget is used, what is happening is that when I read the values programatically for first time, it works fine.but when I toggle the button with touch, onCheckChanged is repeatedly getting called as if I set some value, it keeps on calling itself in infinite loop. This is my oncheckchanged code.
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
try {
if (useOnCheckedChangeMethod) {
switch (compoundButton.getId()) {
case R.id.switch_btn_device_touch:
touchButton.setOnCheckedChangeListener(null);
//showProgress(true);
HandleCharacListData(true,false,"");
HandleCharacListData(false,false,BLEConstants.TOUCH_BUTTON_CHARACTERISTIC);
if(characList!=null && characList.size()>0) {
if(b) {
gattclientCallBack.writeCharacteristic(characList.remove(characList.size() - 1), BLEConstants.DisableCharac);
}
else {
gattclientCallBack.writeCharacteristic(characList.remove(characList.size() - 1), BLEConstants.EnableCharac);
}
}
Log.d("Touch++++", "+++");
break;
}
So it continuously keep on toggling as on and off due to the check if(b). :)
what can I do to ensure that the onCheckChange methos only gets called once after the value is set ?
Things that I have also tried
1) Use onClick listener and disable call in oncheckchanged and enable on click.
2) Use onTouch
Thank you :)
That interesting, because inside of setChecked() it actually checks to see if it's in the middle of broadcasting and returns...
public void setChecked(boolean checked) {
if (mChecked != checked) {
mChecked = checked;
refreshDrawableState();
notifyViewAccessibilityStateChangedIfNeeded(
AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
// Avoid infinite recursions if setChecked() is called from a listener
if (mBroadcasting) {
return;
}
mBroadcasting = true;
if (mOnCheckedChangeListener != null) {
mOnCheckedChangeListener.onCheckedChanged(this, mChecked);
}
if (mOnCheckedChangeWidgetListener != null) {
mOnCheckedChangeWidgetListener.onCheckedChanged(this, mChecked);
}
mBroadcasting = false;
}
}
The only solution I know of is un-registering the callback before calling setChecked() and register the callback again after your call returns. This works because the callback isn't called asynchronously but instead, called immediately inside of setChecked().
Hey I got my answer in the link below to a question framed little differently . Thanks to this guy :)
onCheckedChanged called automatically

Codename One - scanning barcodes checking for new line/ENTER character

in Android I can easily detect the ENTER character using the setOnEditorActionListener method so that when a barcode is scanned into a textfield I know when the whole barcode has been read.
[Here is the Android code as requested:]
scanEditText.setOnEditorActionListener(new TextView.OnEditorActionListener()
{
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event)
{
if ( (actionId == EditorInfo.IME_ACTION_DONE) || ((event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN )))
{
System.out.println(" *** ENTER!");
return true;
}
else
return false;
}
});
I have been trying to replicate this in Codename One but with no luck. I have tried
setDoneListener
addDataChangedListener
ActionEvent on the text field and text area
overriding the keyPressed and keyReleased methods
but with no joy. If I set a textField with setSingleLineTextArea(false) I can see the barcode characters appear in the box followed by what I am assuming is a
new line character as the next scan appears on a new line. None of the methods listed seem to catch this event. If I change the focus to another box the ActionEvent is triggered but I don't want to have to move the focus each time.
[Here is the Codenameone code]
gui_searchTextField.setSingleLineTextArea(false);
gui_searchTextField.setDoneListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
Dialog.show("KB", "doneListener " +
gui_searchTextField.getText().trim(), "OK", null);
}
});
gui_searchTextField.addDataChangedListener((evt1, evt2) ->
{
System.out.println("DataChanged " + gui_searchTextField.getText());
});
So, how do I catch the end of the barcode like I can easily in the Android SDK?
Text input is very much a special case for us in all OS's so the keys go directly into the native OS text editing and don't "travel" through Codename One API's. However, DataChangeListener should be invoked for every key input so I'm not sure how this is happening exactly.
I did notice you are using System.out instead of Log.p so you might miss the output from the device related to the changes. Also I would recommend overriding the key pressed/released events and not starting the text editing. Then adding the key value to the text field instead of letting the native input handle it e.g.:
class MyForm extends Form {
public void keyReleased(int key) {
if(isCrLf(key)) {
// do this...
} else {
myTextField.setText(myTextField.getText() + ((char)key));
}
}
}

onKeyUp function not calling second time

I have been trying to built an app based on GHOST game.
I have written an onKeyUp function which only accepts lowercase alphabets and adds it to a string called wordfragment and then calling the function computerTurn in it. But i had seen after successfully running first time i.e. calling the computerTurn function and getting return statement from computerturn function it(onkeyup) does not works second time.
Here my code to onKeyUp function.
#Override
public boolean onKeyUp(int KeyCode, KeyEvent event) {
char ch = (char)event.getUnicodeChar();
if( !( ch >= 'a' && ch <='z' ) ) {
return super.onKeyUp(KeyCode, event);
}
wordFragment = wordFragment + ch;
label.setText(COMPUTER_TURN);
text.setText(wordFragment);
userTurn = false;
computerTurn();
return true;
}
and my code to computerTurn function is
private boolean computerTurn() {
if(wordFragment.length() >= 4 && dictionary.isWord(wordFragment)){
label.setText("Computer wins");
// challenge.setEnabled(false);
return true;
}
else {
String word = dictionary.getAnyWordStartingWith(wordFragment.toLowerCase());
if(word!=null){
Toast.makeText(GhostActivity.this, "comp word found", Toast.LENGTH_SHORT).show();
wordFragment += word.charAt(wordFragment.length());
}
else{
Toast.makeText(GhostActivity.this, "comp word not found", Toast.LENGTH_SHORT).show();
label.setText("User Wins!!");
//challenge.setEnabled(false);
// wordFragment += (char)(random.nextInt(26) + 61);
}
}
// Do computer turn stuff then make it the user's turn again
userTurn = true;
label.setText(USER_TURN);
text.setText(wordFragment);
Toast.makeText(GhostActivity.this, "return true", Toast.LENGTH_SHORT).show();
return true;
}
Android softkeyboards rarely use key events. The correct way to use an android soft keyboard is via InputConnection. Only hardware keys generally issue key events. Basically you're coding this the right way for Windows or web, but the wrong way for Android.

Scrolling lag with GestureDetector onScroll

I use GestureDetector to implement scrolling inside a custom View. My implementation is based on this: Smooth scrolling with inertia and edge resistance/snapback
I noticed a short pause before the scrolling starts: I examined the onScroll messages and noticed that the first one arrives only after a larger movement of a finger, which causes noticable lag at the beginning of the scrolling. After that the scrolling is smooth.
It seems GestureDetector starts sending onScroll messages only after a minimal distance between the motionevents to make sure the gesture is not a longtap or tap (btw I set setIsLongpressEnabled(false)).
Is there any way to change this behaviour and create a smooth scroll without implementing a custom scroll gesture using low level touch events?
The answer is no, you have to create your own GestureDetector. If you look at the Android source code (GestureDetector.java) lines 524 to 540 are use to detect the "touch slop" for a single tap. Specifically line 528 prevents the onScroll event from being called until the movement is outside the touch slop (which is pulled from the view configuration). You cannot change the view configuration and the slop is hard coded at 16 pixels. This is the radius that causes the lag that you are seeing.
You can use reflection to change mTouchSlopSquare from GestureDetector.java
public static void setGestureDetectorTouchSlop(GestureDetector gestureDetector, int value) {
try {
Field f_mTouchSlopSquare = GestureDetector.class.getDeclaredField("mTouchSlopSquare");
f_mTouchSlopSquare.setAccessible(true);
f_mTouchSlopSquare.setInt(gestureDetector, value * value);
} catch (NoSuchFieldException | IllegalAccessException | NullPointerException e) {
Log.w(TAG, gestureDetector.toString(), e);
}
}
Also, here is the method to change the slop for the GestureDetectorCompat.java
public static void setGestureDetectorTouchSlop(GestureDetectorCompat gestureDetector, int value) {
try {
Field f_mImpl = GestureDetectorCompat.class.getDeclaredField("mImpl");
f_mImpl.setAccessible(true);
Object mImpl = f_mImpl.get(gestureDetector);
if (mImpl == null) {
Log.w(TAG, f_mImpl + " is null");
return;
}
Class<?> c_GDCIJellybeanMr2 = null;
Class<?> c_GDCIBase = null;
try {
c_GDCIJellybeanMr2 = Class.forName(GestureDetectorCompat.class.getName() + "$GestureDetectorCompatImplJellybeanMr2");
c_GDCIBase = Class.forName(GestureDetectorCompat.class.getName() + "$GestureDetectorCompatImplBase");
} catch (ClassNotFoundException ignored) {
}
if (c_GDCIJellybeanMr2 != null && c_GDCIJellybeanMr2.isInstance(mImpl)) {
Field f_mDetector = c_GDCIJellybeanMr2.getDeclaredField("mDetector");
f_mDetector.setAccessible(true);
Object mDetector = f_mDetector.get(mImpl);
if (mDetector instanceof GestureDetector)
setGestureDetectorTouchSlop((GestureDetector) mDetector, value);
} else if (c_GDCIBase != null) {
Field f_mTouchSlopSquare = c_GDCIBase.getDeclaredField("mTouchSlopSquare");
f_mTouchSlopSquare.setAccessible(true);
f_mTouchSlopSquare.setInt(mImpl, value * value);
} else {
Log.w(TAG, "not handled: " + mImpl.getClass().toString());
}
} catch (NoSuchFieldException | IllegalAccessException | NullPointerException e) {
Log.w(TAG, gestureDetector.getClass().toString(), e);
}
}

Categories

Resources