net.majorkernelpanic.spydroid.ClientActivity.java Source code

Java tutorial

Introduction

Here is the source code for net.majorkernelpanic.spydroid.ClientActivity.java

Source

/*
 * Copyright (C) 2011 GUIGUI Simon, fyhertz@gmail.com
 * 
 * This file is part of Spydroid (http://code.google.com/p/spydroid-ipcamera/)
 * 
 * Spydroid 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 3 of the License, or
 * (at your option) any later version.
 * 
 * This source code 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 source code; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package net.majorkernelpanic.spydroid;

import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.json.JSONObject;
import org.json.JSONTokener;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.Spinner;
import android.widget.SpinnerAdapter;
import android.widget.VideoView;

/** 
 * Allow a user with two smartphones to control one from the other
 * Feature disabled, do not work well enough :( because of MediaPlayer that really really sucks
 **/
public class ClientActivity extends Activity
        implements OnCompletionListener, OnPreparedListener, OnItemSelectedListener {

    private final static String TAG = "ClientActivity";

    private SharedPreferences settings;

    private EditText editTextIP;
    private MyVideoView videoView;
    private MediaPlayer audioStream;
    private FrameLayout layoutContainer;
    private RelativeLayout layoutForm, layoutControl;
    private ProgressBar progressBar;

    private String videoParameters = "", audioParameters = "";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.client);

        editTextIP = (EditText) findViewById(R.id.server_ip);
        layoutContainer = (FrameLayout) findViewById(R.id.video_container);
        layoutForm = (RelativeLayout) findViewById(R.id.form);
        layoutControl = (RelativeLayout) findViewById(R.id.control);
        progressBar = (ProgressBar) findViewById(R.id.progress);

        audioStream = new MediaPlayer();

        // Initiate connection with client
        findViewById(R.id.button_connect).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Editor editor = settings.edit();
                editor.putString("last_server_ip", editTextIP.getText().toString());
                editor.commit();
                layoutForm.setVisibility(View.GONE);
                progressBar.setVisibility(View.VISIBLE);
                getCurrentConfiguration();
            }
        });

        // Interrupt connection with the client
        findViewById(R.id.button_stop).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                stopStreaming();
                layoutControl.setVisibility(View.GONE);
                layoutForm.setVisibility(View.VISIBLE);
                progressBar.setVisibility(View.GONE);
            }
        });

        // Show configuration panel
        findViewById(R.id.button_config).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                findViewById(R.id.settings).setVisibility(View.VISIBLE);
            }
        });

        findViewById(R.id.reconnect).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                findViewById(R.id.settings).setVisibility(View.GONE);
                updateSettings();
            }
        });

        // Resolution
        Spinner spinner = (Spinner) findViewById(R.id.spinner1);
        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.videoResolutionArray,
                android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinner.setAdapter(adapter);

        // Framerate
        spinner = (Spinner) findViewById(R.id.spinner2);
        adapter = ArrayAdapter.createFromResource(this, R.array.videoFramerateArray,
                android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinner.setAdapter(adapter);
        spinner.setOnItemSelectedListener(this);

        // Bitrate
        spinner = (Spinner) findViewById(R.id.spinner3);
        adapter = ArrayAdapter.createFromResource(this, R.array.videoBitrateArray,
                android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinner.setAdapter(adapter);
        spinner.setOnItemSelectedListener(this);

        // Video Encoder
        spinner = (Spinner) findViewById(R.id.spinner4);
        adapter = ArrayAdapter.createFromResource(this, R.array.videoEncoderArray,
                android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinner.setAdapter(adapter);
        spinner.setOnItemSelectedListener(this);

        // Audio Encoder
        spinner = (Spinner) findViewById(R.id.spinner5);
        adapter = ArrayAdapter.createFromResource(this, R.array.audioEncoderArray,
                android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinner.setAdapter(adapter);
        spinner.setOnItemSelectedListener(this);

        settings = PreferenceManager.getDefaultSharedPreferences(this);
        editTextIP.setText(settings.getString("last_server_ip", "192.168.0.107"));

    }

    /** Fetch the current streaming configuration of the remote phone **/
    private void getCurrentConfiguration() {
        new AsyncTask<Void, Void, String>() {
            @Override
            protected String doInBackground(Void... params) {
                HttpParams httpParameters = new BasicHttpParams();
                HttpConnectionParams.setConnectionTimeout(httpParameters, 3000);
                HttpConnectionParams.setSoTimeout(httpParameters, 3000);
                HttpClient client = new DefaultHttpClient(httpParameters);
                HttpGet request = new HttpGet(
                        "http://" + editTextIP.getText().toString() + ":8080/config.json?get");
                ResponseHandler<String> responseHandler = new BasicResponseHandler();
                String response = "";
                try {
                    response = client.execute(request, responseHandler);
                } catch (ConnectTimeoutException e) {
                    Log.i(TAG, "Connection timeout ! ");
                    onCompletion(null);
                } catch (Exception e) {
                    Log.e(TAG, "Could not fetch current configuration on remote device !");
                    e.printStackTrace();
                }
                return response;
            }

            @Override
            protected void onPostExecute(String response) {
                try {
                    JSONObject object = (JSONObject) new JSONTokener(response).nextValue();
                    ((CheckBox) findViewById(R.id.checkbox1)).setChecked(object.getBoolean("streamVideo"));
                    ((CheckBox) findViewById(R.id.checkbox2)).setChecked(object.getBoolean("streamAudio"));
                    for (int spinner : new int[] { R.id.spinner1, R.id.spinner2, R.id.spinner3, R.id.spinner4,
                            R.id.spinner5 }) {
                        Spinner view = (Spinner) findViewById(spinner);
                        SpinnerAdapter adapter = view.getAdapter();
                        for (int i = 0; i < adapter.getCount(); i++) {
                            Iterator<String> keys = object.keys();
                            while (keys.hasNext()) {
                                String key = keys.next();
                                if (adapter.getItem(i).equals(object.get(key))) {
                                    view.setSelection(i);
                                }

                            }
                        }
                    }
                    generateURI();
                    connectToServer();
                } catch (Exception e) {
                    stopStreaming();
                    e.printStackTrace();
                }
            }
        }.execute();
    }

    private void updateSettings() {
        final String oldVideoParameters = videoParameters, oldAudioParameters = audioParameters;
        generateURI();
        if (oldVideoParameters == videoParameters && oldAudioParameters == audioParameters)
            return;
        stopStreaming();
        progressBar.setVisibility(View.VISIBLE);
        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... params) {
                HttpClient client = new DefaultHttpClient();
                //HttpGet request = new HttpGet("http://"+editTextIP.getText().toString()+":8080?set&"+uriParameters);
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException ignore) {
                }
                return null;
            }

            @Override
            protected void onPostExecute(Void weird) {
                Log.d(TAG, "Reconnecting to server...");
                connectToServer();
            }
        }.execute();
    }

    /** Generates the URL that will be used to configure the client **/
    private void generateURI() {
        int[] spinners = new int[] { R.id.spinner1, R.id.spinner2, R.id.spinner3, R.id.spinner4, R.id.spinner5 };

        videoParameters = "";
        audioParameters = "";

        // Video streaming enabled ?
        if (((CheckBox) findViewById(R.id.checkbox1)).isChecked()) {

            int fps = 0, br = 0, resX = 0, resY = 0;
            Pattern p;
            Matcher m;

            // User has changed the resolution
            try {
                p = Pattern.compile("(\\d+)x(\\d+)");
                m = p.matcher(((String) ((Spinner) findViewById(spinners[0])).getSelectedItem()));
                m.find();
                resX = Integer.parseInt(m.group(1));
                resY = Integer.parseInt(m.group(2));
            } catch (Exception ignore) {
            }

            // User has changed the framerate
            try {
                p = Pattern.compile("(\\d+)[^\\d]+");
                m = p.matcher(((String) ((Spinner) findViewById(spinners[1])).getSelectedItem()));
                m.find();
                fps = Integer.parseInt(m.group(1));
            } catch (Exception ignore) {
            }

            // User has changed the bitrate
            try {
                p = Pattern.compile("(\\d+)[^\\d]+");
                m = p.matcher(((String) ((Spinner) findViewById(spinners[2])).getSelectedItem()));
                m.find();
                br = Integer.parseInt(m.group(1));
            } catch (Exception ignore) {
            }

            videoParameters += ((String) ((Spinner) findViewById(spinners[3])).getSelectedItem()).equals("H.264")
                    ? "h264"
                    : "h263";
            videoParameters += "=" + br + "-" + fps + "-" + resX + "-" + resY;
        } else {
            videoParameters = "novideo";
        }

        // Audio streaming enabled ?
        if (((CheckBox) findViewById(R.id.checkbox2)).isChecked()) {
            audioParameters += ((String) ((Spinner) findViewById(spinners[4])).getSelectedItem()).equals("AMR-NB")
                    ? "amr"
                    : "aac";
        }

        Log.d(TAG, "Cient configuration: video=" + videoParameters + " audio=" + audioParameters);

    }

    /** Connect to the RTSP server of the remote phone **/
    private void connectToServer() {

        // Start video streaming
        if (videoParameters.length() > 0) {
            videoView = new MyVideoView(this);
            videoView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,
                    LinearLayout.LayoutParams.FILL_PARENT));
            layoutContainer.addView(videoView);
            videoView.setOnPreparedListener(this);
            videoView.setOnCompletionListener(this);
            videoView.setVideoURI(Uri.parse("rtsp://" + editTextIP.getText().toString() + ":8086/"
                    + (videoParameters.length() > 0 ? ("?" + videoParameters) : "")));
            videoView.requestFocus();
        }

        // Start audio streaming
        if (audioParameters.length() > 0) {
            try {
                audioStream.reset();
                audioStream.setDataSource(this, Uri.parse("rtsp://" + editTextIP.getText().toString() + ":8086/"
                        + (audioParameters.length() > 0 ? ("?" + audioParameters) : "")));
                audioStream.setAudioStreamType(AudioManager.STREAM_MUSIC);
                audioStream.setOnPreparedListener(new OnPreparedListener() {
                    @Override
                    public void onPrepared(MediaPlayer mp) {
                        audioStream.start();
                    }
                });
                audioStream.prepareAsync();
            } catch (Exception e) {
                Log.e(TAG, e.getMessage());
                e.printStackTrace();
            }
        }

        Log.e(TAG, "rtsp://" + editTextIP.getText().toString() + ":8086"
                + (videoParameters.length() > 0 ? ("?" + videoParameters) : ""));

    }

    private void stopStreaming() {
        try {
            if (videoView != null && videoView.isPlaying()) {
                layoutContainer.removeView(videoView);
                videoView.stopPlayback();
                videoView = null;
            }
        } catch (Exception ignore) {
        }
        try {
            if (audioStream != null && audioStream.isPlaying()) {
                audioStream.stop();
                audioStream.reset();
            }
        } catch (Exception ignore) {
        }
    }

    @Override
    public void onStart() {
        super.onStart();
    }

    @Override
    public void onStop() {
        super.onStop();
    }

    @Override
    public void onCompletion(MediaPlayer mp) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                layoutControl.setVisibility(View.GONE);
                progressBar.setVisibility(View.GONE);
                layoutForm.setVisibility(View.VISIBLE);
                stopStreaming();
            }
        });
    }

    @Override
    public void onPrepared(MediaPlayer mp) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                progressBar.setVisibility(View.GONE);
                layoutControl.setVisibility(View.VISIBLE);
                videoView.start();
            }
        });
    }

    static class MyVideoView extends VideoView {
        public MyVideoView(Context context) {
            super(context);
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int width = getDefaultSize(0, widthMeasureSpec);
            int height = getDefaultSize(0, heightMeasureSpec);
            setMeasuredDimension(width, height);
        }
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {

    }

    @Override
    public void onNothingSelected(AdapterView<?> arg0) {

    }

}