net.pocketmagic.android.eventinjector.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for net.pocketmagic.android.eventinjector.MainActivity.java

Source

/*
 * Android Event Injector 
 *
 * Copyright (c) 2013 by Radu Motisan , radu.motisan@gmail.com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * For more information on the GPL, please go to:
 * http://www.gnu.org/copyleft/gpl.html
 *
 */

package net.pocketmagic.android.eventinjector;

import java.util.ArrayList;

import net.pocketmagic.android.eventinjector.Events.InputDevice;
import net.pocketmagic.android.utils.CustomAdapter;
import net.pocketmagic.android.utils.ListViewItem;
import android.os.Bundle;
import android.app.Activity;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.GradientDrawable.Orientation;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import android.support.v4.app.NavUtils;

public class MainActivity extends Activity implements OnClickListener, OnItemSelectedListener {
    final static String LT = "MainActivity";

    Events events = new Events();
    boolean m_bMonitorOn = false; // used in the thread to poll for input event node  messages

    // interface view ids
    final static int idButScan = Menu.FIRST + 1001, idLVDevices = Menu.FIRST + 1002, idSelSpin = Menu.FIRST + 1003,
            idButInjectKey = Menu.FIRST + 1004, idButInjectTouch = Menu.FIRST + 1005,
            idButMonitorStart = Menu.FIRST + 1006, idButMonitorStop = Menu.FIRST + 1007,
            idButTest = Menu.FIRST + 1008, idTextView = Menu.FIRST + 1009, idLVFirstItem = Menu.FIRST + 5000;

    // interface views
    TextView m_tvMonitor; // used to display monitored events, in the format code-type-value. See input.h in the NDK
    ListView m_lvDevices; // the listview showing devices found
    Spinner m_selDevSpinner; // The spinner is used to select a target for the Key and Touch buttons
    int m_selectedDev = -1; // index of spinner selected device, or -1 is no selection

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(LT, "App created.");
        Events.intEnableDebug(1);
        // disable the titlebar
        requestWindowFeature(Window.FEATURE_NO_TITLE);

        // create a basic user interface
        LinearLayout panel = new LinearLayout(this);
        panel.setOrientation(LinearLayout.VERTICAL);
        setContentView(panel);

        EditText v = new EditText(this);
        v.setId(idTextView);
        v.setOnClickListener(this);
        panel.addView(v);

        // --
        Button b = new Button(this);
        b.setText("Scan Input Devs");
        b.setId(idButScan);
        b.setOnClickListener(this);
        panel.addView(b);

        // put list in a scroll view
        LinearLayout listLayout = new LinearLayout(this);
        listLayout.setLayoutParams(
                new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 1.0f));
        m_lvDevices = new ListView(this);
        LayoutParams lvLayoutParam = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
        m_lvDevices.setLayoutParams(lvLayoutParam);
        m_lvDevices.setId(idLVDevices);
        m_lvDevices.setDividerHeight(0);
        m_lvDevices.setFadingEdgeLength(0);
        m_lvDevices.setCacheColorHint(0);
        m_lvDevices.setAdapter(null);

        listLayout.addView(m_lvDevices);
        panel.addView(listLayout);
        // --
        LinearLayout panelH = new LinearLayout(this);
        panelH.setOrientation(LinearLayout.HORIZONTAL);
        panel.addView(panelH);
        // --
        m_selDevSpinner = new Spinner(this);
        m_selDevSpinner.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
        m_selDevSpinner.setId(idSelSpin);
        m_selDevSpinner.setOnItemSelectedListener((OnItemSelectedListener) this);
        panelH.addView(m_selDevSpinner);
        // -- simulate key event
        b = new Button(this);
        b.setText(">Key");
        b.setId(idButInjectKey);
        b.setOnClickListener(this);
        panelH.addView(b);
        // -- simulate touch event
        b = new Button(this);
        b.setText(">Tch");
        b.setId(idButInjectTouch);
        b.setOnClickListener(this);
        panelH.addView(b);
        // --
        m_tvMonitor = new TextView(this);
        m_tvMonitor.setText("Event Monitor stopped.");
        panel.addView(m_tvMonitor);
        // --
        panelH = new LinearLayout(this);
        panelH.setOrientation(LinearLayout.HORIZONTAL);
        panel.addView(panelH);
        // --
        b = new Button(this);
        b.setText("Monitor Start");
        b.setId(idButMonitorStart);
        b.setOnClickListener(this);
        panelH.addView(b);
        // --
        b = new Button(this);
        b.setText("Monitor Stop");
        b.setId(idButMonitorStop);
        b.setOnClickListener(this);
        panelH.addView(b);
        // -- simulate test event
        b = new Button(this);
        b.setText(">Test");
        b.setId(idButTest);
        b.setOnClickListener(this);
        panelH.addView(b);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(LT, "App destroyed.");
        StopEventMonitor();
        events.Release();
    }

    public void onClick(View v) {
        int id = v.getId();
        if (id >= idLVFirstItem) {
            int nLVIndexClick = id - idLVFirstItem;
            Log.d(LT, "LV Item Click:" + nLVIndexClick);
            for (InputDevice idev : events.m_Devs) {
                if (idev.getId() == nLVIndexClick) {
                    if (idev.Open(true)) {
                        // refresh listview
                        PopulateListView();
                        // inform user
                        Toast.makeText(this, "Device opened successfully!", Toast.LENGTH_SHORT).show();
                    } else {
                        Toast.makeText(this, "Device failed to open. Do you have root?", Toast.LENGTH_SHORT).show();
                    }
                    break;
                }
            }
        }

        switch (id) {
        case idButScan: {
            Log.d(LT, "Scanning for input dev files.");
            // init event node files
            int res = events.Init();
            // debug results
            Log.d(LT, "Event files:" + res);
            // try opening all
            PopulateListView();
        }
        case idButInjectKey:
            if (m_selectedDev != -1) {
                // see input.h in Android NDK, sequence represents the codes for
                // pocketmagic.net
                final int keys[] = new int[] { 25, 24, 46, 37, 18, 20, 50, 30, 34, 23, 46, 52, 49, 18, 20 };
                // send all these keys with half a second delay
                Thread sender = new Thread(new Runnable() {
                    public void run() {
                        for (int i = 0; i < keys.length; i++) {
                            Log.d(LT, "Sending:" + keys[i] + " to:" + events.m_Devs.get(m_selectedDev).getName());
                            events.m_Devs.get(m_selectedDev).SendKey(keys[i], true); // key down
                            events.m_Devs.get(m_selectedDev).SendKey(keys[i], false); // key up
                            // a short delay before next character, just for
                            // testing purposes
                            try {
                                Thread.sleep(2000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                });
                sender.start();
            } else
                Toast.makeText(this, "Select a valid device first, using the spinner to the left.",
                        Toast.LENGTH_SHORT).show();
            break;

        case idButInjectTouch:
            // absolute coordinates, on my device they go up to 570x960
            if (m_selectedDev != -1)
                events.m_Devs.get(m_selectedDev).SendTouchDownAbs(155, 183);
            else
                Toast.makeText(this, "Select a valid device first, using the spinner to the left.",
                        Toast.LENGTH_SHORT).show();
            break;

        case idButTest:
            Thread sender = new Thread(new Runnable() {
                public void run() {
                    for (int i = 0; i < 5; i++) {
                        SendHomeKeyToKeypad();
                        // a short delay before next character, just for testing
                        // purposes
                        try {
                            Thread.sleep(2000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
            sender.start();
            break;
        case idButMonitorStart:
            if (m_bMonitorOn)
                Toast.makeText(this, "Event monitor already working. Consider opening more devices to monitor.",
                        Toast.LENGTH_SHORT).show();
            else {
                m_tvMonitor.post(new Runnable() {
                    public void run() {
                        m_tvMonitor.setText("Event Monitor running, waiting for data.");
                    }
                });
                StartEventMonitor();
            }
            break;
        case idButMonitorStop:
            Toast.makeText(this, "Event monitor stopped.", Toast.LENGTH_SHORT).show();
            StopEventMonitor();
            m_tvMonitor.post(new Runnable() {
                public void run() {
                    m_tvMonitor.setText("Event Monitor stopped.");
                }
            });
            break;

        }
    }

    /**
     * Handle events when the user selects a new item in the spinner. The
     * spinner is used to select a target for the Key and Touch buttons So what
     * we do here, is to find which open-dev has been selected from within our
     * global events.m_Devs structure result saved in m_selectedDev, as the
     * index of our selected open dev.
     */
    public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
        int sel = arg2;

        int i = 0, j = 0;
        m_selectedDev = -1;
        for (InputDevice idev : events.m_Devs) {
            if (idev.getOpen()) {
                if (i == sel) {
                    m_selectedDev = j;
                    break;
                } else
                    i++;
            }
            j++;
        }
        if (m_selectedDev != -1) {
            String name = events.m_Devs.get(m_selectedDev).getName();
            Log.d(LT, "spinner selected:" + sel + " Name:" + name);
            Toast.makeText(this, "New device selected:" + name, Toast.LENGTH_SHORT).show();
        } else
            Toast.makeText(this, "Invalid device selection!", Toast.LENGTH_SHORT).show();

    }

    // not used
    public void onNothingSelected(AdapterView<?> arg0) {
    }

    /**
     * Populated the listview with discovered devices, and the spinner with
     * those that are open
     */
    private void PopulateListView() {
        m_lvDevices.post(new Runnable() {
            public void run() {
                m_lvDevices.setAdapter(null);
                ArrayList<ListViewItem> m_Devices = new ArrayList<ListViewItem>();
                for (InputDevice idev : events.m_Devs) {
                    ListViewItem device = new ListViewItem(idev.getName(), idev.getPath(), idev.getOpen(),
                            idLVFirstItem + idev.getId());
                    m_Devices.add(device);
                }
                CustomAdapter m_lvAdapter = new CustomAdapter(MainActivity.this, m_Devices);
                if (m_lvDevices != null)
                    m_lvDevices.setAdapter(m_lvAdapter);
            }
        });
        m_selDevSpinner.post(new Runnable() {
            public void run() {
                ArrayList<String> openDevs = new ArrayList<String>();

                for (InputDevice idev : events.m_Devs) {
                    if (idev.getOpen())
                        openDevs.add(idev.getName());
                }
                // populate spinner
                ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this,
                        android.R.layout.simple_spinner_item, openDevs);
                adapter.setDropDownViewResource(android.R.layout.select_dialog_singlechoice);
                // changes spin size and popup box size/color
                m_selDevSpinner.setAdapter(adapter);

            }
        });
    }

    /**
     * Stops our event monitor thread
     */
    public void StopEventMonitor() {
        m_bMonitorOn = false; // stop reading thread
    }

    /**
     * Starts our event monitor thread that does the data extraction via polling
     * all data is displayed in the textview, as type-code-value, see input.h in
     * the Android NDK for more details Monitor output is also sent to Logcat,
     * so make sure you used that as well
     */
    public void StartEventMonitor() {
        m_bMonitorOn = true;
        Thread b = new Thread(new Runnable() {
            public void run() {
                while (m_bMonitorOn) {
                    for (InputDevice idev : events.m_Devs) {
                        // Open more devices to see their messages
                        if (idev.getOpen() && (0 == idev.getPollingEvent())) {
                            final String line = idev.getName() + ":" + idev.getSuccessfulPollingType() + " "
                                    + idev.getSuccessfulPollingCode() + " " + idev.getSuccessfulPollingValue();
                            Log.d(LT, "Event:" + line);
                            // update textview to show data
                            // if (idev.getSuccessfulPollingValue() != 0)
                            m_tvMonitor.post(new Runnable() {
                                public void run() {
                                    m_tvMonitor.setText(line);
                                }
                            });
                        }

                    }
                }
            }
        });
        b.start();
    }

    /**
     * Finds an open device that has a name containing keypad. This probably is
     * the event node associated with the keypad Its purpose is to handle all
     * hardware Android buttons such as Back, Home, Volume, etc Key codes are
     * defined in input.h (see NDK) , or use the Event Monitor to see keypad
     * messages This function sends the Settings key
     */
    public void SendSettingsKeyToKeypad() {
        for (InputDevice idev : events.m_Devs) {
            // * Finds an open device that has a name containing keypad. This
            // probably is the keypad associated event node
            if (idev.getOpen() && idev.getName().contains("keypad")) {
                idev.SendKey(139, true); // settings key down
                idev.SendKey(139, false); // settings key up
            }
        }
    }

    /**
     * Finds an open device that has a name containing keypad. This probably is
     * the event node associated with the keypad Its purpose is to handle all
     * hardware Android buttons such as Back, Home, Volume, etc Key codes are
     * defined in input.h (see NDK) , or use the Event Monitor to see keypad
     * messages This function sends the HOME key
     */
    public void SendHomeKeyToKeypad() {
        boolean found = false;
        for (InputDevice idev : events.m_Devs) {
            // * Finds an open device that has a name containing keypad. This
            // probably is the keypad associated event node
            if (idev.getOpen() && idev.getName().contains("key")) {
                idev.SendKey(102, true); // home key down
                idev.SendKey(102, false); // home key up
                found = true;
                break;
            }
        }
        if (found == false)
            Toast.makeText(this, "Keypad not found.", Toast.LENGTH_SHORT).show();
    }

    /**
     * Finds an open device that has a name containing keypad. This probably is
     * the event node associated with the keypad Its purpose is to handle all
     * hardware Android buttons such as Back, Home, Volume, etc Key codes are
     * defined in input.h (see NDK) , or use the Event Monitor to see keypad
     * messages This function sends the BACK key
     */
    public void SendBackKeyToKeypad() {
        for (InputDevice idev : events.m_Devs) {
            // * Finds an open device that has a name containing keypad. This
            // probably is the keypad associated event node
            if (idev.getOpen() && idev.getName().contains("keypad")) {
                idev.SendKey(158, true); // Back key down
                idev.SendKey(158, false); // back key up
            }
        }
    }
}