Search code examples
androidstdin

How can I capture data coming into my Android app from the standard input (stdin)?


I am writing an app that uses an external USB barcode/RFID scanner. The scanner is a standard HID, and works well on my Android devices. I plug it in, hit the scan button, and data pops up in a text editing app. The same can be said for a standard USB keyboard. I plug it in, start typing, and data shows up in a text editing app.

Here is where I need assistance. What I need to do is manipulate the data coming into my app, from the scanner or external keyboard, before I can place it into the correct form fields of the app.

At this point, I thought I could just intercept the data at the standard input, so this is what I came up with:

activity_main.xml

<LinearLayout>
    <EditText android:id="@+id/scan_data" />
</LinearLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    EditText scannedInput = (EditText)findViewById(R.id.scan_data);

    BufferedReader scanner = new BufferedReader(new InputStreamReader(System.in));

    StringBuilder sBuilder = new StringBuilder();
    String buffer;

    while((buffer = scanner.readLine()) != null){
        sBuilder.append(buffer);
    }

    String[] dataPoints = sBuilder.toString().split("\u003D|\u0026");

    scannedInput.setTextColor(Color.RED);
    scannedInput.setTextSize(34f);
    scannedInput.setText(dataPoints[0]); // or dataPoints[1], dataPoints[2], etc.
}

I wrote this, hooked up my scanner, and scanned an RFID tag. To my surprise, the entire scanned string showed up in my EditText field, and not just a part. After some debugging, I found out I could delete all code after setContentView() and the entire string still shows up in my EditText field.

So, what I need to know is, how I can capture the stdin from any external source (e.g., scanner, keyboard, etc.), and manipulate it before placing it where I want it (form field, database, etc.).

How can I go about doing this?


Solution

  • The short answer is that you can't access stdin, there is no such animal in Android for apps. The text is being injected into the active EditText because the RFID / USB device you are using is presenting itself as a HID device. These are automatically picked up by the Android subsystem as an input source and their input routed to the active view as if it came from a keyboard.

    All is not lost, however. What you can do is attach a TextWatcher to your EditText and manipulate the text in the Editable:

    EditText et = (EditText)findViewById(R.id.whatever_your_id);
    et.addTextChangedListener(new TextWatcher() {
            @Override
            void afterTextChanged (Editable s) {
                //  Make your changes to 's' here, carefully as your changes will
                //  cause this method to be called again!
            }
    
            @Override
            void beforeTextChanged(CharSequence s, int start, int count, int after) {
                //  Nothing to do here
            }
    
            @Override
            void onTextChanged(CharSequence s, int start, int before, int count) {
                //  Nothing to do here
            }
        });