Compare commits

...

10 Commits

Author SHA1 Message Date
Cameron Gutman e92a281fd8 Close the fd to wake the reading thread up for termination 2014-09-10 02:45:21 -07:00
Cameron Gutman b4c3f9678a Use poll() to avoid an infinite blocking read() that causes ANRs during cleanup 2014-09-10 02:35:55 -07:00
Cameron Gutman 82f79c466a Version to 2.5.4.1 2014-09-10 01:57:59 -07:00
Cameron Gutman d428f316b4 Don't unbind after an unexpected event 2014-09-10 01:57:24 -07:00
Cameron Gutman 828f4877b6 Only bind to keyboards and mice that aren't gamepads 2014-09-06 16:25:09 -07:00
Cameron Gutman 09e8e8e6b3 Remove isMouse() and replace it with more precise has*() functions 2014-09-06 16:03:09 -07:00
Cameron Gutman 77c8051ec6 Add support for keyboard and mouse combo devices in raw input mode 2014-09-06 14:09:09 -07:00
Cameron Gutman 6bae056e3a Fix a bug where an error change any permissions would cause the operation to fail and other files to not be changed 2014-09-03 23:33:25 -07:00
Cameron Gutman bb869a51fd Start using com.limelight.root package name 2014-09-03 23:32:37 -07:00
Cameron Gutman 25b3d08bb9 Revert "Remove root-specific stuff. DO NOT MERGE TO root!"
This reverts commit 2c23dbd2be.
2014-09-03 23:08:54 -07:00
23 changed files with 312 additions and 42 deletions
+6 -3
View File
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.limelight"
android:versionCode="32"
android:versionName="2.5.4" >
package="com.limelight.root"
android:versionCode="33"
android:versionName="2.5.4.1" >
<uses-sdk
android:minSdkVersion="16"
@@ -14,6 +14,9 @@
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- Root permissions -->
<uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
<uses-feature android:name="android.hardware.wifi" android:required="false" />
@@ -1,5 +1,5 @@
/** Automatically generated file. DO NOT MODIFY */
package com.limelight;
package com.limelight.root;
public final class BuildConfig {
public final static boolean DEBUG = true;
@@ -5,7 +5,7 @@
* should not be modified by hand.
*/
package com.limelight;
package com.limelight.root;
public final class R {
public static final class attr {
@@ -123,8 +123,8 @@ or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>na
<colgroup align="left" />
<colgroup align="left" />
<tr><th>Attribute</th><th>Description</th></tr>
<tr><td><code>{@link #ButtonBarContainerTheme_buttonBarButtonStyle com.limelight:buttonBarButtonStyle}</code></td><td></td></tr>
<tr><td><code>{@link #ButtonBarContainerTheme_buttonBarStyle com.limelight:buttonBarStyle}</code></td><td></td></tr>
<tr><td><code>{@link #ButtonBarContainerTheme_buttonBarButtonStyle com.limelight.root:buttonBarButtonStyle}</code></td><td></td></tr>
<tr><td><code>{@link #ButtonBarContainerTheme_buttonBarStyle com.limelight.root:buttonBarStyle}</code></td><td></td></tr>
</table>
@see #ButtonBarContainerTheme_buttonBarButtonStyle
@see #ButtonBarContainerTheme_buttonBarStyle
@@ -133,23 +133,23 @@ or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>na
0x7f010000, 0x7f010001
};
/**
<p>This symbol is the offset where the {@link com.limelight.R.attr#buttonBarButtonStyle}
<p>This symbol is the offset where the {@link com.limelight.root.R.attr#buttonBarButtonStyle}
attribute's value can be found in the {@link #ButtonBarContainerTheme} array.
<p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
@attr name com.limelight:buttonBarButtonStyle
@attr name com.limelight.root:buttonBarButtonStyle
*/
public static final int ButtonBarContainerTheme_buttonBarButtonStyle = 1;
/**
<p>This symbol is the offset where the {@link com.limelight.R.attr#buttonBarStyle}
<p>This symbol is the offset where the {@link com.limelight.root.R.attr#buttonBarStyle}
attribute's value can be found in the {@link #ButtonBarContainerTheme} array.
<p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
@attr name com.limelight:buttonBarStyle
@attr name com.limelight.root:buttonBarStyle
*/
public static final int ButtonBarContainerTheme_buttonBarStyle = 0;
};
+45 -10
View File
@@ -6,6 +6,7 @@
#include <fcntl.h>
#include <linux/input.h>
#include <unistd.h>
#include <poll.h>
JNIEXPORT jint JNICALL
Java_com_limelight_binding_input_evdev_EvdevReader_open(JNIEnv *env, jobject this, jstring absolutePath) {
@@ -26,33 +27,67 @@ Java_com_limelight_binding_input_evdev_EvdevReader_ungrab(JNIEnv *env, jobject t
return ioctl(fd, EVIOCGRAB, 0) == 0;
}
// isMouse() and friends are based on Android's EventHub.cpp
// has*() and friends are based on Android's EventHub.cpp
#define test_bit(bit, array) (array[bit/8] & (1<<(bit%8)))
JNIEXPORT jboolean JNICALL
Java_com_limelight_binding_input_evdev_EvdevReader_isMouse(JNIEnv *env, jobject this, jint fd) {
unsigned char keyBitmask[(KEY_MAX + 1) / 8];
Java_com_limelight_binding_input_evdev_EvdevReader_hasRelAxis(JNIEnv *env, jobject this, jint fd, jshort axis) {
unsigned char relBitmask[(REL_MAX + 1) / 8];
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keyBitmask)), keyBitmask);
ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relBitmask)), relBitmask);
// If this device has all required features of a mouse, it's a mouse!
return test_bit(BTN_MOUSE, keyBitmask) &&
test_bit(REL_X, relBitmask) &&
test_bit(REL_Y, relBitmask);
return test_bit(axis, relBitmask);
}
JNIEXPORT jboolean JNICALL
Java_com_limelight_binding_input_evdev_EvdevReader_hasAbsAxis(JNIEnv *env, jobject this, jint fd, jshort axis) {
unsigned char absBitmask[(ABS_MAX + 1) / 8];
ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absBitmask)), absBitmask);
return test_bit(axis, absBitmask);
}
JNIEXPORT jboolean JNICALL
Java_com_limelight_binding_input_evdev_EvdevReader_hasKey(JNIEnv *env, jobject this, jint fd, jshort key) {
unsigned char keyBitmask[(KEY_MAX + 1) / 8];
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keyBitmask)), keyBitmask);
return test_bit(key, keyBitmask);
}
JNIEXPORT jint JNICALL
Java_com_limelight_binding_input_evdev_EvdevReader_read(JNIEnv *env, jobject this, jint fd, jbyteArray buffer) {
jint ret;
jbyte *data = (*env)->GetByteArrayElements(env, buffer, NULL);
jbyte *data;
int pollres;
struct pollfd pollinfo;
data = (*env)->GetByteArrayElements(env, buffer, NULL);
if (data == NULL) {
return -1;
}
ret = read(fd, data, sizeof(struct input_event));
do
{
// Unwait every 250 ms to return to caller if the fd is closed
pollinfo.fd = fd;
pollinfo.events = POLLIN;
pollinfo.revents = 0;
pollres = poll(&pollinfo, 1, 250);
}
while (pollres == 0);
if (pollres > 0 && (pollinfo.revents & POLLIN)) {
// We'll have data available now
ret = read(fd, data, sizeof(struct input_event));
}
else {
// There must have been a failure
ret = -1;
}
(*env)->ReleaseByteArrayElements(env, buffer, data, 0);
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Limelight</string>
<string name="app_name">Limelight (Root)</string>
<string name="title_activity_game">Game</string>
</resources>
@@ -5,6 +5,7 @@ import java.net.UnknownHostException;
import java.util.concurrent.LinkedBlockingQueue;
import com.limelight.computers.ComputerManagerService;
import com.limelight.root.R;
import com.limelight.utils.Dialog;
import android.app.Activity;
+1
View File
@@ -1,5 +1,6 @@
package com.limelight;
import com.limelight.root.R;
import com.limelight.utils.Dialog;
import android.app.Activity;
+1
View File
@@ -12,6 +12,7 @@ import com.limelight.binding.PlatformBinding;
import com.limelight.nvstream.http.GfeHttpResponseException;
import com.limelight.nvstream.http.NvApp;
import com.limelight.nvstream.http.NvHTTP;
import com.limelight.root.R;
import com.limelight.utils.Dialog;
import com.limelight.utils.SpinnerDialog;
+14
View File
@@ -14,6 +14,7 @@ import com.limelight.nvstream.StreamConfiguration;
import com.limelight.nvstream.av.video.VideoDecoderRenderer;
import com.limelight.nvstream.input.KeyboardPacket;
import com.limelight.nvstream.input.MouseButtonPacket;
import com.limelight.root.R;
import com.limelight.utils.Dialog;
import com.limelight.utils.SpinnerDialog;
@@ -695,4 +696,17 @@ public class Game extends Activity implements SurfaceHolder.Callback,
public void mouseScroll(byte amount) {
conn.sendMouseScroll(amount);
}
@Override
public void keyboardEvent(boolean buttonDown, short keyCode) {
short keyMap = keybTranslator.translate(keyCode);
if (keyMap != 0) {
if (buttonDown) {
keybTranslator.sendKeyDown(keyMap, (byte) 0);
}
else {
keybTranslator.sendKeyUp(keyMap, (byte) 0);
}
}
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
package com.limelight;
public class LimelightBuildProps {
public static final boolean ROOT_BUILD = false;
public static final boolean ROOT_BUILD = true;
}
+1
View File
@@ -13,6 +13,7 @@ import com.limelight.nvstream.http.NvHTTP;
import com.limelight.nvstream.http.PairingManager;
import com.limelight.nvstream.http.PairingManager.PairState;
import com.limelight.nvstream.wol.WakeOnLanSender;
import com.limelight.root.R;
import com.limelight.utils.Dialog;
import android.app.Activity;
+1
View File
@@ -1,5 +1,6 @@
package com.limelight;
import com.limelight.root.R;
import com.limelight.utils.Dialog;
import android.os.Bundle;
@@ -8,6 +8,7 @@ public class EvdevEvent {
public static final short EV_SYN = 0x00;
public static final short EV_KEY = 0x01;
public static final short EV_REL = 0x02;
public static final short EV_MSC = 0x04;
/* Relative axes */
public static final short REL_X = 0x00;
@@ -18,6 +19,15 @@ public class EvdevEvent {
public static final short BTN_LEFT = 0x110;
public static final short BTN_RIGHT = 0x111;
public static final short BTN_MIDDLE = 0x112;
public static final short BTN_SIDE = 0x113;
public static final short BTN_EXTRA = 0x114;
public static final short BTN_FORWARD = 0x115;
public static final short BTN_BACK = 0x116;
public static final short BTN_TASK = 0x117;
public static final short BTN_GAMEPAD = 0x130;
/* Keys */
public static final short KEY_Q = 16;
public short type;
public short code;
@@ -10,6 +10,7 @@ public class EvdevHandler {
private String absolutePath;
private EvdevListener listener;
private boolean shutdown = false;
private int fd = -1;
private Thread handlerThread = new Thread() {
@Override
@@ -19,16 +20,17 @@ public class EvdevHandler {
// system-wide input problems.
// Open the /dev/input/eventX file
int fd = EvdevReader.open(absolutePath);
fd = EvdevReader.open(absolutePath);
if (fd == -1) {
LimeLog.warning("Unable to open "+absolutePath);
return;
}
try {
// Check if it's a mouse
if (!EvdevReader.isMouse(fd)) {
// We only handle mice
// Check if it's a mouse or keyboard, but not a gamepad
if ((!EvdevReader.isMouse(fd) && !EvdevReader.isAlphaKeyboard(fd)) ||
EvdevReader.isGamepad(fd)) {
// We only handle keyboards and mice
return;
}
@@ -38,7 +40,7 @@ public class EvdevHandler {
return;
}
LimeLog.info("Grabbed device for raw mouse input: "+absolutePath);
LimeLog.info("Grabbed device for raw keyboard/mouse input: "+absolutePath);
ByteBuffer buffer = ByteBuffer.allocate(EvdevEvent.EVDEV_MAX_EVENT_SIZE).order(ByteOrder.nativeOrder());
@@ -96,7 +98,31 @@ public class EvdevHandler {
listener.mouseButtonEvent(EvdevListener.BUTTON_RIGHT,
event.value != 0);
break;
case EvdevEvent.BTN_SIDE:
case EvdevEvent.BTN_EXTRA:
case EvdevEvent.BTN_FORWARD:
case EvdevEvent.BTN_BACK:
case EvdevEvent.BTN_TASK:
// Other unhandled mouse buttons
break;
default:
// We got some unrecognized button. This means
// someone is trying to use the other device in this
// "combination" input device. We'll try to handle
// it via keyboard, but we're not going to disconnect
// if we can't
short keyCode = EvdevTranslator.translateEvdevKeyCode(event.code);
if (keyCode != 0) {
listener.keyboardEvent(event.value != 0, keyCode);
}
break;
}
break;
case EvdevEvent.EV_MSC:
break;
}
}
} finally {
@@ -120,6 +146,13 @@ public class EvdevHandler {
}
public void stop() {
// Close the fd. It doesn't matter if this races
// with the handler thread. We'll close this out from
// under the thread to wake it up
if (fd != -1) {
EvdevReader.close(fd);
}
shutdown = true;
handlerThread.interrupt();
@@ -8,4 +8,5 @@ public interface EvdevListener {
public void mouseMove(int deltaX, int deltaY);
public void mouseButtonEvent(int buttonId, boolean down);
public void mouseScroll(byte amount);
public void keyboardEvent(boolean buttonDown, short keyCode);
}
@@ -12,16 +12,16 @@ public class EvdevReader {
}
// Requires root to chmod /dev/input/eventX
public static boolean setPermissions(int octalPermissions) {
String chmodString = String.format("chmod %o /dev/input/*\n", octalPermissions);
public static boolean setPermissions(String[] files, int octalPermissions) {
ProcessBuilder builder = new ProcessBuilder("su");
try {
Process p = builder.start();
OutputStream stdin = p.getOutputStream();
stdin.write(chmodString.getBytes("UTF-8"));
for (String file : files) {
stdin.write(String.format("chmod %o %s\n", octalPermissions, file).getBytes("UTF-8"));
}
stdin.write("exit\n".getBytes("UTF-8"));
stdin.flush();
@@ -43,8 +43,26 @@ public class EvdevReader {
public static native boolean grab(int fd);
public static native boolean ungrab(int fd);
// Returns true if the device is a mouse
public static native boolean isMouse(int fd);
// Used for checking device capabilities
public static native boolean hasRelAxis(int fd, short axis);
public static native boolean hasAbsAxis(int fd, short axis);
public static native boolean hasKey(int fd, short key);
public static boolean isMouse(int fd) {
// This is the same check that Android does in EventHub.cpp
return hasRelAxis(fd, EvdevEvent.REL_X) &&
hasRelAxis(fd, EvdevEvent.REL_Y) &&
hasKey(fd, EvdevEvent.BTN_LEFT);
}
public static boolean isAlphaKeyboard(int fd) {
// This is the same check that Android does in EventHub.cpp
return hasKey(fd, EvdevEvent.KEY_Q);
}
public static boolean isGamepad(int fd) {
return hasKey(fd, EvdevEvent.BTN_GAMEPAD);
}
// Returns the bytes read or -1 on error
private static native int read(int fd, byte[] buffer);
@@ -0,0 +1,139 @@
package com.limelight.binding.input.evdev;
import android.view.KeyEvent;
public class EvdevTranslator {
public static final short EVDEV_KEY_CODES[] = {
0, //KeyEvent.VK_RESERVED
KeyEvent.KEYCODE_ESCAPE,
KeyEvent.KEYCODE_1,
KeyEvent.KEYCODE_2,
KeyEvent.KEYCODE_3,
KeyEvent.KEYCODE_4,
KeyEvent.KEYCODE_5,
KeyEvent.KEYCODE_6,
KeyEvent.KEYCODE_7,
KeyEvent.KEYCODE_8,
KeyEvent.KEYCODE_9,
KeyEvent.KEYCODE_0,
KeyEvent.KEYCODE_MINUS,
KeyEvent.KEYCODE_EQUALS,
KeyEvent.KEYCODE_DEL,
KeyEvent.KEYCODE_TAB,
KeyEvent.KEYCODE_Q,
KeyEvent.KEYCODE_W,
KeyEvent.KEYCODE_E,
KeyEvent.KEYCODE_R,
KeyEvent.KEYCODE_T,
KeyEvent.KEYCODE_Y,
KeyEvent.KEYCODE_U,
KeyEvent.KEYCODE_I,
KeyEvent.KEYCODE_O,
KeyEvent.KEYCODE_P,
KeyEvent.KEYCODE_LEFT_BRACKET,
KeyEvent.KEYCODE_RIGHT_BRACKET,
KeyEvent.KEYCODE_ENTER,
KeyEvent.KEYCODE_CTRL_LEFT,
KeyEvent.KEYCODE_A,
KeyEvent.KEYCODE_S,
KeyEvent.KEYCODE_D,
KeyEvent.KEYCODE_F,
KeyEvent.KEYCODE_G,
KeyEvent.KEYCODE_H,
KeyEvent.KEYCODE_J,
KeyEvent.KEYCODE_K,
KeyEvent.KEYCODE_L,
KeyEvent.KEYCODE_SEMICOLON,
KeyEvent.KEYCODE_APOSTROPHE,
KeyEvent.KEYCODE_GRAVE,
KeyEvent.KEYCODE_SHIFT_LEFT,
KeyEvent.KEYCODE_BACKSLASH,
KeyEvent.KEYCODE_Z,
KeyEvent.KEYCODE_X,
KeyEvent.KEYCODE_C,
KeyEvent.KEYCODE_V,
KeyEvent.KEYCODE_B,
KeyEvent.KEYCODE_N,
KeyEvent.KEYCODE_M,
KeyEvent.KEYCODE_COMMA,
KeyEvent.KEYCODE_PERIOD,
KeyEvent.KEYCODE_SLASH,
KeyEvent.KEYCODE_SHIFT_RIGHT,
KeyEvent.KEYCODE_NUMPAD_MULTIPLY,
KeyEvent.KEYCODE_ALT_LEFT,
KeyEvent.KEYCODE_SPACE,
KeyEvent.KEYCODE_CAPS_LOCK,
KeyEvent.KEYCODE_F1,
KeyEvent.KEYCODE_F2,
KeyEvent.KEYCODE_F3,
KeyEvent.KEYCODE_F4,
KeyEvent.KEYCODE_F5,
KeyEvent.KEYCODE_F6,
KeyEvent.KEYCODE_F7,
KeyEvent.KEYCODE_F8,
KeyEvent.KEYCODE_F9,
KeyEvent.KEYCODE_F10,
KeyEvent.KEYCODE_NUM_LOCK,
KeyEvent.KEYCODE_SCROLL_LOCK,
KeyEvent.KEYCODE_NUMPAD_7,
KeyEvent.KEYCODE_NUMPAD_8,
KeyEvent.KEYCODE_NUMPAD_9,
KeyEvent.KEYCODE_NUMPAD_SUBTRACT,
KeyEvent.KEYCODE_NUMPAD_4,
KeyEvent.KEYCODE_NUMPAD_5,
KeyEvent.KEYCODE_NUMPAD_6,
KeyEvent.KEYCODE_NUMPAD_ADD,
KeyEvent.KEYCODE_NUMPAD_1,
KeyEvent.KEYCODE_NUMPAD_2,
KeyEvent.KEYCODE_NUMPAD_3,
KeyEvent.KEYCODE_NUMPAD_0,
KeyEvent.KEYCODE_NUMPAD_DOT,
0,
0, //KeyEvent.VK_ZENKAKUHANKAKU,
0, //KeyEvent.VK_102ND,
KeyEvent.KEYCODE_F11,
KeyEvent.KEYCODE_F12,
0, //KeyEvent.VK_RO,
0, //KeyEvent.VK_KATAKANA,
0, //KeyEvent.VK_HIRAGANA,
0, //KeyEvent.VK_HENKAN,
0, //KeyEvent.VK_KATAKANAHIRAGANA,
0, //KeyEvent.VK_MUHENKAN,
0, //KeyEvent.VK_KPJPCOMMA,
KeyEvent.KEYCODE_NUMPAD_ENTER,
KeyEvent.KEYCODE_CTRL_RIGHT,
KeyEvent.KEYCODE_NUMPAD_DIVIDE,
KeyEvent.KEYCODE_SYSRQ,
KeyEvent.KEYCODE_ALT_RIGHT,
0, //KeyEvent.VK_LINEFEED,
KeyEvent.KEYCODE_HOME,
KeyEvent.KEYCODE_DPAD_UP,
KeyEvent.KEYCODE_PAGE_UP,
KeyEvent.KEYCODE_DPAD_LEFT,
KeyEvent.KEYCODE_DPAD_RIGHT,
KeyEvent.KEYCODE_MOVE_END,
KeyEvent.KEYCODE_DPAD_DOWN,
KeyEvent.KEYCODE_PAGE_DOWN,
KeyEvent.KEYCODE_INSERT,
KeyEvent.KEYCODE_FORWARD_DEL,
0, //KeyEvent.VK_MACRO,
0, //KeyEvent.VK_MUTE,
0, //KeyEvent.VK_VOLUMEDOWN,
0, //KeyEvent.VK_VOLUMEUP,
0, //KeyEvent.VK_POWER, /* SC System Power Down */
KeyEvent.KEYCODE_NUMPAD_EQUALS,
0, //KeyEvent.VK_KPPLUSMINUS,
KeyEvent.KEYCODE_BREAK,
0, //KeyEvent.VK_SCALE, /* AL Compiz Scale (Expose) */
};
public static short translateEvdevKeyCode(short evdevKeyCode) {
if (evdevKeyCode < EVDEV_KEY_CODES.length) {
return EVDEV_KEY_CODES[evdevKeyCode];
}
return 0;
}
}
@@ -38,7 +38,7 @@ public class EvdevWatcher {
if (!init) {
// If this a real new device, update permissions again so we can read it
EvdevReader.setPermissions(0666);
EvdevReader.setPermissions(new String[]{PATH + "/" + fileName}, 0666);
}
EvdevHandler handler = new EvdevHandler(PATH + "/" + fileName, listener);
@@ -63,17 +63,29 @@ public class EvdevWatcher {
this.listener = listener;
}
private File[] rundownWithPermissionsChange(int newPermissions) {
// Rundown existing files
File devInputDir = new File(PATH);
File[] files = devInputDir.listFiles();
// Set desired permissions
String[] filePaths = new String[files.length];
for (int i = 0; i < files.length; i++) {
filePaths[i] = files[i].getAbsolutePath();
}
EvdevReader.setPermissions(filePaths, newPermissions);
return files;
}
public void start() {
startThread = new Thread() {
@Override
public void run() {
// Get permissions to read the eventX files
EvdevReader.setPermissions(0666);
init = true;
// List all files and allow us access
File[] files = rundownWithPermissionsChange(0666);
// Rundown existing files and generate synthetic events
File devInputDir = new File(PATH);
File[] files = devInputDir.listFiles();
init = true;
for (File f : files) {
observer.onEvent(FileObserver.CREATE, f.getName());
}
@@ -92,7 +104,7 @@ public class EvdevWatcher {
}
// Giveup eventX permissions
EvdevReader.setPermissions(0066);
rundownWithPermissionsChange(066);
}
};
startThread.start();