Řídíme PC pomocí Android SmartPhone, díl 1.

První díl poukazující na netradiční využití SP s OS Android připojeného k PC.

Tento projekt mě napadl při psaní aplikace pro Android, která využívala komunikaci přes USB port a pracovala s akcelerometrem.

Možností využití je samozřejmě nesčetné množství, já se pokusím v tomto seriálu ukázat několik menších využití a později se pokusím dát dohromady získané zkušenosti a vyvinout ovladač, který by dokázal nahradit myš a v mnohém jí i předčil.

V seriálu bude nutné znát Javu, aplikaci pro Android jsem psal v Eclipse.

Prvním cílem bude napsat aplikaci, která bude získávat data ze senzoru přiblížení (Sensor – Proximity). Tyto data později odešle na připojený PC a to může vykonat akci, kterou si vymyslíme – já ho využil jako malou featuru na Ubuntu – přepínám podle počtu impulzů na určitou obrazovku. Můžeme si tedy vymyslet např. kliknutí myší, stisknutí klávesové zkratky, vykonání příkazu v command lině,… Možností je znovu neskutečné množství a záleží jen na vašem nápadu.

Android aplikace pro odesílání dat ze senzoru Proximity:

V Eclipse si založíme nový projekt. Jelikož se bude pracovat s protokolovou komunikací je nutno po vytvoření projektu v Android manifestu přidat do Permissions typ uses-permission, její jméno je android.permission.INTERNET. Dále doporučuji v manifestu nastavit orientaci na portrait (android:screenOrientation=“portrait“).

Rozvržení prvků můžete navrhnout například takto:

v metodě onCreate inicializujeme instance pro Sensor:

mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mProximity = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);

a přidáme tam i listener pro naše tlačítko, které bude vyvolávat pokus o připojení k PC a handler pro výpis informací bublinou:

View connectButton = findViewById(R.id.button1);
connectButton.setOnClickListener(this);

mHandler = new Handler();

Nejdříve je však samozřejmě importovat interface:

implements SensorEventListener, OnClickListener

Ty vyžadují implementaci metod
public final void onAccuracyChanged(Sensor sensor, int accuracy)
která tak zajímavá není,

public final void onSensorChanged(SensorEvent event)
která vrací právě změněnou hodnotu ze senzoru, tuto hodnotu lze získat z parametru event (hodnota=event.values[0]). Metodu tedy použiji pro odeslání dat na PC, ta bude pojmenovaná sendText(String message).

Poslední vyžadovaná metoda je listeneru pro button:

public void onClick(View v)
ta bude spouštět vlákno starající se o přenos dat:

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.button1:
            // initialize server socket in a new separate thread
            String msg = "Pokus o připojení k NB...";
            setText(msg);
            new Thread(initializeConnection).start();
            Toast.makeText(this, msg, msg.length()).show();
            break;
    }
}

Vlákno bude vypadata takto:

	private Runnable initializeConnection = new Thread() {
		public void run() {
			Socket client = null;
			// initialize server socket
			try {
				server = new ServerSocket(38300);
				server.setSoTimeout(TIMEOUT * 1000);

				// attempt to accept a connection
				client = server.accept();
				Globals.socketIn = new Scanner(client.getInputStream());
				Globals.socketOut = new PrintWriter(client.getOutputStream(), true);

				// Globals.socketIn.
			} catch (SocketTimeoutException e) {
				// print out TIMEOUT
				setText("Čas vypršel, zkus se připojit znovu.");
				connectionStatus = "Čas vypršel, zkus se připojit znovu.";
				mHandler.post(showConnectionStatus);
			} catch (IOException e) {
				Log.e(TAG, "" + e);
			} finally {
				// close the server socket
				try {
					if (server != null)
						server.close();
				} catch (IOException ec) {
					setText("Nelze uzavřít socket serveru: " + ec);
					Log.e(TAG, "Nelze uzavřít socket serveru: " + ec);
				}
			}

			if (client != null) {
				Globals.connected = true;
				// print out success
				connectionStatus = "Spojení s NB navázáno!";
				setText("Spojení s NB navázáno!");
				Log.d(TAG, "navázáno!");
				mHandler.post(showConnectionStatus);
				while (Globals.socketIn.hasNext()) {
					socketData = Globals.socketIn.next();
					mHandler.post(socketStatus);

				}
			}
			else
				setText("Nepřipojeno!");
		}
	};

ServerSocket(38300) vytvoří připojení na zadaný port (to budiž PORT=38300) a

server.setSoTimeout(TIMEOUT * 1000) vytvoří dobu čekání na připojení odposlouchávající strany, která poběží na PC

Proměnné se kterými vlákno nachází se nacházejí v podtřídě Globals.

Metoda která pak data odesílá vypadá jednoduše takto:

	private void sendText(String text) {
		if (Globals.socketOut != null) {
			Globals.socketOut.println(text);
			Globals.socketOut.flush();
		}
	}

Úplný zdrojový kód lze nalézt na konci tutoriálu.

Java aplikace pro příjem dat z SP:

Data je nyní SP schopno odesílat, teď se tedy podíváme, jak tyto data jednoduše odchytávat pomocí Java aplikace.

Je to poměrně jednoduchá záležitost, získáme si jednoduše datové toky ze Socketu nastaveného na náš PORT:

    @Override
    public void run() {
        //Create socket connection
        try{
            socket = new Socket("localhost", PORT);
            // it's, of course, also possible to send some data back
            // out = new PrintWriter(socket.getOutputStream(), true);
            sc=new Scanner(socket.getInputStream());

            String line;
            while(beh) {
                line = sc.nextLine();
                // System.out.println(line);
                int i = Integer.valueOf(line);
                if(i==0) startTime();   // 0 - zakryto
                else stopTime();        // 1 - odkryto
            }

            socket.close();
        } catch (UnknownHostException e) {
            System.err.println("Problem with socket connection (unknown host): "+e+" & "+e.getStackTrace());
        } catch (IOException e) {
            System.err.println("Cannot initiate I/O on socket: "+e+" & "+e.getStackTrace());
        }
    }

Data jsou nyní odchytávány a můžete je dle libosti použít.

Já vymyslel originální způsob: počítám počet přerušení a na základě toho se na Ubuntu  přesunuji na jinou plochu. Toho docílím vyvoláním správné klávesové kombinace. Na kód se můžete podívat, poskytuji ho v souborech na konci tutoriálu.

Pro využívání pohybu kurzoru nebo stisk kláves skvěle poslouží třída Robot. V Java programu na PC/NB je také umístěna metoda execAdb(String command), která slouží k provedení jakéhokoliv příkazu na Command line, tahle umí i pipe. Program ji může využívat třeba i pro spuštění aplikace, skriptu atd. Zde jsem ji používal především na vytvoření přesměrování přes port na připojené Androidí zařízení.

Jak všechno nastartovat: 

  1. Připojení Androidího zařízení (SP) přes USB k PC/NB
  2. Vytvoření přesměrování na cíleném portu pomocí příkazu adb forward tcp:PORT tcp:PORT (PORT zaměnte za číslo, já využívám 38300)
  3. Spuštění klienta – aplikace na Androidu a pokus o připojení
  4. Spuštění Java odposlouchávající aplikace na PC/NB (stihněte to do 10s od předchozího kroku, tak dlouho bude klient defaultně čekat)
  5. Komunikace by měl být navázána

Nyní už zvládáme komunikaci přes USB. Můžete začít experimentovat. V případě jakýchkoliv dotazů pište do komentářů pod článek nebo na moji emailovou adresu.

Jelikož USB kabel není vždy nejlepší řešení, podíváme se příště na komunikaci bezdrátovou a to konkrétně přes rozhraní Wifi. Uvidíme, že jejím tělem je v podstatě čistá Java SE.

Zdrojové soubory:

Sensor – projekt aplikace pro Android vytvořen pod Eclipse

ServerProximity – projekt v Javě pro příjem dat z SP

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.