cc.echonet.coolmicapp.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for cc.echonet.coolmicapp.MainActivity.java

Source

/*
 *      Copyright (C) Jordan Erickson                     - 2014-2016,
 *      Copyright (C) Lwenfelsen UG (haftungsbeschrnkt) - 2015-2016
 *       on behalf of Jordan Erickson.
 */

/*
 * This file is part of Cool Mic.
 * 
 * Cool Mic 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.
 * 
 * Cool Mic 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 Cool Mic.  If not, see <http://www.gnu.org/licenses/>.
 */
package cc.echonet.coolmicapp;

import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.net.ConnectivityManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.PopupWindow;
import android.widget.TextView;
import android.widget.Toast;

import cc.echonet.coolmicdspjava.Wrapper;

/**
 * This activity demonstrates how to use JNI to encode and decode ogg/vorbis audio
 */
public class MainActivity extends Activity {

    final Context context = this;
    Thread streamThread;
    boolean isThreadOn = false;
    CoolMic coolmic = null;
    Button start_button;
    Button stop_button;
    Animation animation = new AlphaAnimation(1, 0);
    ColorDrawable gray_color = new ColorDrawable(Color.parseColor("#66999999"));
    ColorDrawable[] color = { gray_color, new ColorDrawable(Color.RED) };
    TransitionDrawable trans = new TransitionDrawable(color);
    Drawable buttonColor;
    ImageView imageView1;
    Menu myMenu;
    boolean backyes = false;
    ClipboardManager myClipboard;
    long timeInMilliseconds = 0L;
    long timeSwapBuff = 0L;
    long updatedTime = 0L;

    TextView txtListeners;

    StreamStatsReceiver mStreamStatsReceiver = new StreamStatsReceiver();
    String strStreamFetchStatsURL;

    /**
     * Text view to show logged messages
     */
    private TextView logArea;
    //variable declaration for timer starts here
    private long startTime = 0L;
    private long lastStatsFetch = 0L;
    //code for displaying timer starts here
    Runnable updateTimerThread = new Runnable() {

        @Override
        public void run() {
            runOnUiThread(new Thread(new Runnable() {
                @Override
                public void run() {
                    timeInMilliseconds = SystemClock.uptimeMillis() - startTime;
                    updatedTime = timeSwapBuff + timeInMilliseconds;
                    int secs = (int) (updatedTime / 1000);
                    int mins = secs / 60;
                    int hours = mins / 60;
                    secs = secs % 60;
                    mins = mins % 60;

                    timerValue.setText(MainActivity.this.getString(R.string.timer_format, hours, mins, secs));

                    if (lastStatsFetch + 15 * 1000 < timeInMilliseconds) {
                        StreamStatsService.startActionStatsFetch(MainActivity.this, strStreamFetchStatsURL);
                        lastStatsFetch = timeInMilliseconds;
                    }
                }
            }));
            customHandler.postDelayed(this, 0);
        }
    };
    private TextView timerValue;
    private Handler customHandler = new Handler();

    //variable declaration for timer ends here
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        super.onPrepareOptionsMenu(menu);
        if (isThreadOn) {
            menu.findItem(R.id.menu_action_settings).setVisible(false);
        } else {
            menu.findItem(R.id.menu_action_settings).setVisible(true);
        }
        return true;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.main_activity_menu, menu);
        myMenu = menu;
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.menu_action_settings:
            goSettings();
            return true;
        case R.id.menu_action_about:
            goAbout();
            return true;
        case R.id.menu_action_help:
            Intent helpIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://coolmic.net/help"));
            startActivity(helpIntent);
            return true;
        case R.id.menu_action_quit:
            exitApp();
            return true;
        default:
            Toast.makeText(getApplicationContext(), R.string.menu_action_default, Toast.LENGTH_LONG).show();
            break;
        }
        return true;
    }

    private void exitApp() {
        ClearLED();
        Wrapper.stop();
        Wrapper.unref();
        finish();
        System.exit(0);
    }

    private void goSettings() {
        Intent i = new Intent(MainActivity.this, SettingsActivity.class);
        startActivity(i);
        finish();
    }

    private void goAbout() {

        Log.d("MainActivity", "goAbout() ");

        LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View popUpView = inflater.inflate(R.layout.popup_about, null, false);

        final PopupWindow popUp = new PopupWindow(this);

        Button close = (Button) popUpView.findViewById(R.id.cmdPopUpDismiss);
        close.setOnClickListener(new View.OnClickListener() {
            public void onClick(View popupView) {
                popUp.dismiss();
            }
        });

        ((TextView) popUpView.findViewById(R.id.txtVersion)).setText(BuildConfig.VERSION_NAME);
        ((TextView) popUpView.findViewById(R.id.txtBuildType)).setText(BuildConfig.BUILD_TYPE);
        ((TextView) popUpView.findViewById(R.id.txtGITBranch)).setText(BuildConfig.GIT_BRANCH);
        ((TextView) popUpView.findViewById(R.id.txtGITRevision)).setText(BuildConfig.GIT_REVISION);
        ((TextView) popUpView.findViewById(R.id.txtGITAuthor)).setText(BuildConfig.GIT_AUTHOR);
        ((TextView) popUpView.findViewById(R.id.txtGITDirty)).setText(BuildConfig.GIT_DIRTY);

        popUpView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);

        popUp.setContentView(popUpView);

        Log.d("MainActivity", String.format("h: %s w: %s h: %s w: %s", popUp.getHeight(), popUp.getWidth(),
                popUpView.getMeasuredHeight(), popUpView.getMeasuredWidth()));

        popUp.setHeight(popUpView.getMeasuredHeight());
        popUp.setWidth(popUpView.getMeasuredWidth());

        popUp.showAtLocation(popUpView, Gravity.CENTER, 0, 0);

        Log.d("MainActivity", "goAbout() end ");
    }

    public boolean isOnline() {
        ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        return cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnectedOrConnecting();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            imageView1.getLayoutParams().height = 180;
        } else {
            imageView1.getLayoutParams().height = 400;
        }
    }

    private boolean checkPermission() {
        return ContextCompat.checkSelfPermission(this,
                Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED
                && ContextCompat.checkSelfPermission(this,
                        Manifest.permission.INTERNET) == PackageManager.PERMISSION_GRANTED
                && ContextCompat.checkSelfPermission(this,
                        Manifest.permission.ACCESS_NETWORK_STATE) == PackageManager.PERMISSION_GRANTED
                && ContextCompat.checkSelfPermission(this,
                        Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED;
    }

    private void RedFlashLight() {
        NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        Notification notif = new Notification.Builder(context).setLights(0xFFff0000, 100, 100)
                .setSmallIcon(R.drawable.icon).setContentTitle("Streaming").setContentText("Streaming...").build();
        nm.notify(Constants.NOTIFICATION_ID_LED, notif);
    }

    private void ClearLED() {
        NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        nm.cancel(Constants.NOTIFICATION_ID_LED);
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if (isThreadOn) {
            RedFlashLight();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.v("$$$$$$", "In Method: onDestroy()");
        ClearLED();
    }

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

        setContentView(R.layout.home);
        timerValue = (TextView) findViewById(R.id.timerValue);
        BroadcastReceiver mPowerKeyReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String strAction = intent.getAction();
                if (strAction.equals(Intent.ACTION_SCREEN_OFF) || strAction.equals(Intent.ACTION_SCREEN_ON)
                        || strAction.equals(Intent.ACTION_USER_PRESENT)) {
                    if (isThreadOn) {
                        RedFlashLight();
                    }
                }
            }
        };
        final IntentFilter theFilter = new IntentFilter();
        /** System Defined Broadcast */
        theFilter.addAction(Intent.ACTION_SCREEN_ON);
        theFilter.addAction(Intent.ACTION_SCREEN_OFF);
        theFilter.addAction(Intent.ACTION_USER_PRESENT);

        getApplicationContext().registerReceiver(mPowerKeyReceiver, theFilter);

        imageView1 = (ImageView) findViewById(R.id.imageView1);

        Log.v("onCreate", (imageView1 == null ? "iv null" : "iv ok"));

        android.view.ViewGroup.LayoutParams layoutParams = imageView1.getLayoutParams();

        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
            layoutParams.height = 400;
        } else {
            layoutParams.height = 180;
        }

        imageView1.setLayoutParams(layoutParams);

        myClipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        animation.setDuration(500); // duration - half a second
        animation.setInterpolator(new LinearInterpolator()); // do not alter animation rate
        animation.setRepeatCount(Animation.INFINITE); // Repeat animation infinitely
        animation.setRepeatMode(Animation.REVERSE);
        start_button = (Button) findViewById(R.id.start_recording_button);
        stop_button = (Button) findViewById(R.id.stop_recording_button);
        buttonColor = start_button.getBackground();
        logArea = (TextView) findViewById(R.id.log_area);
        logArea.setMovementMethod(new ScrollingMovementMethod());

        coolmic = new CoolMic(this, "default");

        if (Wrapper.getState() == Wrapper.WrapperInitializationStatus.WRAPPER_UNINITIALIZED) {
            if (Wrapper.init() == Wrapper.WrapperInitializationStatus.WRAPPER_INITIALIZATION_ERROR) {
                Log.d("WrapperInit", Wrapper.getInitException().toString());
                Toast.makeText(getApplicationContext(),
                        "Could not initialize native components :( Blocking controls!", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(getApplicationContext(), "Native components initialized!", Toast.LENGTH_SHORT)
                        .show();
            }
        } else if (Wrapper.init() == Wrapper.WrapperInitializationStatus.WRAPPER_INITIALIZATION_ERROR) {
            Toast.makeText(getApplicationContext(),
                    "Previous problem detected with native components :( Blocking controls!", Toast.LENGTH_SHORT)
                    .show();
        } else if (Wrapper.init() != Wrapper.WrapperInitializationStatus.WRAPPER_INTITIALIZED) {
            Toast.makeText(getApplicationContext(), "Native components in unknown state!", Toast.LENGTH_SHORT)
                    .show();
        }

        txtListeners = (TextView) findViewById(R.id.txtListeners);
        IntentFilter mStatusIntentFilter = new IntentFilter(Constants.BROADCAST_STREAM_STATS_SERVICE);
        LocalBroadcastManager.getInstance(this).registerReceiver(mStreamStatsReceiver, mStatusIntentFilter);
    }

    public void onImageClick(View view) {

        try {
            String portnum = "";
            String server = coolmic.getServerName();
            Integer port_num = 8000;
            int counter = 0;
            for (int i = 0; i < server.length(); i++) {
                if (server.charAt(i) == ':') {
                    counter++;
                }
            }
            if (counter == 1) {
                if (server.indexOf("/") > 0) {
                    String[] split = server.split(":");
                    server = split[0].concat(":").concat(split[1]);
                    portnum = "8000";
                    port_num = Integer.parseInt(portnum);
                } else {
                    String[] split = server.split(":");
                    server = split[0];
                    portnum = split[1];
                    port_num = Integer.parseInt(portnum);
                }
            } else if (counter == 2) {
                String[] split = server.split(":");
                server = split[0].concat(":").concat(split[1]);
                portnum = split[2];
                port_num = Integer.parseInt(portnum);
            }
            Log.d("VS", server);
            Log.d("VS", portnum);
            if (server != null && !server.isEmpty()) {
                String text = server + ":" + port_num.toString() + "/" + coolmic.getMountpoint();
                ClipData myClip = ClipData.newPlainText("text", text);
                myClipboard.setPrimaryClip(myClip);
                Toast.makeText(getApplicationContext(), "Broadcast URL copied to clipboard!", Toast.LENGTH_SHORT)
                        .show();
            } else {
                Toast.makeText(getApplicationContext(), "Set the connection details", Toast.LENGTH_SHORT).show();
            }
        } catch (Exception e) {
            Log.e("VS", "Exception", e);
        }

    }

    @Override
    public void onBackPressed() {
        // Write your code here
        if (isThreadOn) {
            AlertDialog.Builder alertDialog = new AlertDialog.Builder(MainActivity.this);
            alertDialog.setTitle("Stop Broadcasting?");
            alertDialog.setMessage("Tap [ Ok ] to stop broadcasting.");
            alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    backyes = false;
                    dialog.cancel();
                }
            });
            alertDialog.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    backyes = true;
                    dialog.cancel();
                    invalidateOptionsMenu();
                    start_button.clearAnimation();
                    start_button.setBackground(buttonColor);
                    start_button.setText(R.string.start_broadcast);

                    ClearLED();

                    android.os.Process.killProcess(android.os.Process.myPid());
                }
            });
            alertDialog.show();
        } else {
            android.os.Process.killProcess(android.os.Process.myPid());
        }
    }

    public void startRecording(View view) {
        if (isThreadOn) {
            stopRecording(view);

            return;
        }

        if (!checkPermission()) {
            Toast.makeText(getApplicationContext(), "Missing Permissions. Please request them in the Settings.",
                    Toast.LENGTH_LONG).show();
            return;
        }

        if (Wrapper.getState() != Wrapper.WrapperInitializationStatus.WRAPPER_INTITIALIZED) {
            Toast.makeText(getApplicationContext(), "Native components not ready.", Toast.LENGTH_LONG).show();
            return;
        }

        if (!isOnline()) {
            Toast.makeText(getApplicationContext(), "Check Internet Connection !", Toast.LENGTH_LONG).show();
            return;
        }

        if (!coolmic.isConnectionSet()) {
            Toast.makeText(getApplicationContext(), "Set the connection details !", Toast.LENGTH_LONG).show();
            return;
        }

        invalidateOptionsMenu();
        isThreadOn = true;
        //screenreceiver.setThreadStatus(true);
        startService(new Intent(getBaseContext(), MyService.class));
        RedFlashLight();
        timeInMilliseconds = 0L;
        timeSwapBuff = 0L;
        start_button.startAnimation(animation);
        start_button.setBackground(trans);
        trans.startTransition(5000);
        start_button.setText(R.string.broadcasting);
        streamThread = new Thread(new Runnable() {
            @Override
            public void run() {
                if (isThreadOn) {
                    try {
                        String portnum;
                        String server = coolmic.getServerName();
                        Integer port_num = 8000;

                        if (server.indexOf(":") > 0) {
                            String[] split = server.split(":");
                            server = split[0];
                            portnum = split[1];
                            port_num = Integer.parseInt(portnum);
                        }

                        Log.d("VS", server);
                        Log.d("VS", port_num.toString());
                        String username = coolmic.getUsername();
                        String password = coolmic.getPassword();
                        String mountpoint = coolmic.getMountpoint();
                        String sampleRate_string = coolmic.getSampleRate();
                        String channel_string = coolmic.getChannels();
                        String quality_string = coolmic.getQuality();
                        String title = coolmic.getTitle();
                        String artist = coolmic.getArtist();

                        Log.d("VS", String.format(
                                "Server: %s Port: %d Username: %s Password: %s Mountpoint: %s Samplerate: %s Channels: %s Quality: %s Title: %s Artist: %s",
                                server, port_num, username, password, mountpoint, sampleRate_string, channel_string,
                                quality_string, title, artist));

                        Integer buffersize = AudioRecord.getMinBufferSize(Integer.parseInt(sampleRate_string),
                                Integer.parseInt(channel_string) == 1 ? AudioFormat.CHANNEL_IN_MONO
                                        : AudioFormat.CHANNEL_IN_STEREO,
                                AudioFormat.ENCODING_PCM_16BIT);
                        Log.d("VS", "Minimum Buffer Size: " + String.valueOf(buffersize));
                        Wrapper.init(MainActivity.this, server, port_num, username, password, mountpoint,
                                "audio/ogg; codec=vorbis", Integer.parseInt(sampleRate_string),
                                Integer.parseInt(channel_string), buffersize);

                        int status = Wrapper.start();

                        Log.d("VS", "Status:" + status);

                        if (status != 0) {
                            throw new Exception("Failed to start Recording: " + String.valueOf(status));
                        }

                        strStreamFetchStatsURL = String.format("http://%s:%s@%s:%s/admin/stats.xml?mount=/%s",
                                username, password, server, port_num, mountpoint);
                    } catch (Exception e) {
                        e.printStackTrace();
                        Log.e("VS", "Recording Start: Exception: ", e);

                        MainActivity.this.runOnUiThread(new Runnable() {
                            public void run() {
                                stopRecording(null);

                                Toast.makeText(MainActivity.this, "Failed to start Recording. ", Toast.LENGTH_LONG)
                                        .show();
                            }
                        });
                    }
                }

            }

        });
        streamThread.start();
    }

    public void stopRecording(@SuppressWarnings("unused") View view) {
        if (Wrapper.getState() != Wrapper.WrapperInitializationStatus.WRAPPER_INTITIALIZED) {
            Toast.makeText(getApplicationContext(), "Native components not ready.", Toast.LENGTH_LONG).show();
        }

        timeSwapBuff += timeInMilliseconds;
        customHandler.removeCallbacks(updateTimerThread);
        //code to stop timer starts here
        ClearLED();
        invalidateOptionsMenu();
        start_button.clearAnimation();
        start_button.setBackground(buttonColor);
        start_button.setText(R.string.start_broadcast);
        stopService(new Intent(getBaseContext(), MyService.class));

        Wrapper.stop();
        Wrapper.unref();

        isThreadOn = false;
    }

    @SuppressWarnings("unused")
    private void logMessage(String msg) {
        logArea.append(msg + "\n");
        final int scrollAmount = logArea.getLayout().getLineTop(logArea.getLineCount()) - logArea.getHeight();
        if (scrollAmount > 0)
            logArea.scrollTo(0, scrollAmount);
        else
            logArea.scrollTo(0, 0);
    }

    @SuppressWarnings("unused")
    private void callbackHandler(int what) {
        Log.d("Handler", String.valueOf(what));

        final int what_final = what;
        MainActivity.this.runOnUiThread(new Runnable() {
            public void run() {
                switch (what_final) {
                case 1:
                    timeInMilliseconds = 0L;
                    timeSwapBuff = 0L;
                    updatedTime = 0L;
                    timeSwapBuff += timeInMilliseconds;
                    customHandler.removeCallbacks(updateTimerThread);
                    startTime = SystemClock.uptimeMillis();
                    customHandler.postDelayed(updateTimerThread, 0);
                    break;
                case 2:
                    //code to stop timer starts here
                    timeSwapBuff += timeInMilliseconds;
                    customHandler.removeCallbacks(updateTimerThread);
                    //code to stop timer starts here
                    start_button.clearAnimation();
                    start_button.setBackground(buttonColor);
                    start_button.setText(R.string.start_broadcast);

                    ClearLED();
                    //logMessage("Stopping the broadcasting");
                    break;
                case 3:
                    //code to stop timer starts here
                    timeSwapBuff += timeInMilliseconds;
                    customHandler.removeCallbacks(updateTimerThread);
                    //code to stop timer starts here
                    start_button.clearAnimation();
                    start_button.setBackground(buttonColor);
                    start_button.setText(R.string.start_broadcast);

                    ClearLED();

                    isThreadOn = false;

                    Toast.makeText(MainActivity.this, "there was an error!", Toast.LENGTH_LONG).show();

                    break;
                }
            }
        });
    }

    // Broadcast receiver for receiving status updates from the IntentService
    private class StreamStatsReceiver extends BroadcastReceiver {
        // Prevents instantiation
        private StreamStatsReceiver() {
        }
        // Called when the BroadcastReceiver gets an Intent it's registered to receive

        public void onReceive(Context context, Intent intent) {
            StreamStats obj = intent.getParcelableExtra(Constants.EXTRA_DATA_STATS_OBJ);

            txtListeners.setText(String.format("%s(%s)", obj.getListenersCurrent(), obj.getListenersPeak()));
        }
    }
}