eu.geekgasm.kintrol.DeviceControlActivity.java Source code

Java tutorial

Introduction

Here is the source code for eu.geekgasm.kintrol.DeviceControlActivity.java

Source

/*
 Kintrol: Remote control app for LINN(R) KINOS(TM) and KISTO(TM) system controllers.
 Copyright (C) 2015 Oliver Gtz
    
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License version 3.
    
 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, see <http://www.gnu.org/licenses/>.
 */
package eu.geekgasm.kintrol;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.NavUtils;
import android.support.v7.app.ActionBarActivity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DeviceControlActivity extends ActionBarActivity implements KinosNotificationListener {

    public static final String EXTRA_IP_ADDRESS = "eu.geekgasm.kintrol.IP_ADDRESS";
    public static final String EXTRA_DEVICE_NAME = "eu.geekgasm.kintrol.DEVICE_NAME";
    public static final String EXTRA_DEVICE_VOLUMES = "eu.geekgasm.kintrol.DEVICE_VOLUMES";
    private final DeviceInfoPersistenceHandler deviceListPersistor = new DeviceInfoPersistenceHandler(this);
    private Handler handler;
    private TextView deviceNameView;
    private AutoSizeText volumeView;
    private AutoSizeText operationStateView;
    private AutoSizeText sourceView;
    private KinosKontrollerThread kontrollerThread;
    private DeviceInfo deviceInfo;
    private String powerCounterValue;
    private String deviceId;
    private String softwareVersion;
    private AutoSizeText surroundModeView;
    private int discreteVolumeValue;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_device_control);

        Intent intent = getIntent();
        deviceInfo = new DeviceInfo(intent.getStringExtra(EXTRA_IP_ADDRESS),
                intent.getStringExtra(EXTRA_DEVICE_NAME), intent.getStringArrayExtra(EXTRA_DEVICE_VOLUMES));

        handler = new Handler();

        deviceNameView = (TextView) findViewById(R.id.device_name);
        volumeView = new AutoSizeText(this, R.id.volume);
        operationStateView = new AutoSizeText(this, R.id.operation_state);
        sourceView = new AutoSizeText(this, R.id.current_source);
        surroundModeView = new AutoSizeText(this, R.id.current_surround_mode);
        deviceNameView.setText(deviceInfo.deviceName);
        discreteVolumeValue = deviceInfo.getFirstDiscreteVolumeValue();
    }

    @Override
    protected void onResume() {
        super.onResume();
        Button discreteVolumeButton = (Button) findViewById(R.id.discrete_volume_button);
        if (discreteVolumeValue >= 0) {
            discreteVolumeButton.setText(String.valueOf(discreteVolumeValue));
            discreteVolumeButton.setVisibility(View.VISIBLE);
        } else {
            discreteVolumeButton.setVisibility(View.INVISIBLE);
        }
        startKontrollerThread(deviceInfo);
    }

    private void setNoConnectionInfo() {
        operationStateView.setText(KinosNotificationListener.NOT_CONNECTED_STATUS_TEXT);
        volumeView.setText(KinosNotificationListener.NOT_AVAILABLE);
        sourceView.setText(KinosNotificationListener.NOT_AVAILABLE);
        surroundModeView.setText(KinosNotificationListener.NOT_AVAILABLE);
    }

    private void startKontrollerThread(DeviceInfo deviceInfo) {
        if (kontrollerThread != null)
            kontrollerThread.requestStop();
        kontrollerThread = new KinosKontrollerThread(deviceInfo.ipAddress, this);
        kontrollerThread.start();
    }

    @Override
    protected void onPause() {
        super.onPause();
        // request the thread to stop
        kontrollerThread.requestStop();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_device_control, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_delete_device) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        int action = event.getAction();
        int keyCode = event.getKeyCode();
        switch (keyCode) {
        case KeyEvent.KEYCODE_VOLUME_UP:
            if (action == KeyEvent.ACTION_DOWN) {
                kontrollerThread.increaseVolume();
            }
            return true;
        case KeyEvent.KEYCODE_VOLUME_DOWN:
            if (action == KeyEvent.ACTION_DOWN) {
                kontrollerThread.decreaseVolume();
            }
            return true;
        default:
            return super.dispatchKeyEvent(event);
        }
    }

    public void decreaseVolume(View view) {
        kontrollerThread.decreaseVolume();
    }

    public void increaseVolume(View view) {
        kontrollerThread.increaseVolume();
    }

    public void switchOn(View view) {
        kontrollerThread.switchOn();
    }

    public void switchOff(View view) {
        kontrollerThread.switchOff();
    }

    public void previousSource(View view) {
        kontrollerThread.previousInputProfile();
    }

    public void nextSource(View view) {
        kontrollerThread.nextInputProfile();
    }

    public void muteToggle(View view) {
        kontrollerThread.toggleMute();
    }

    public void setDiscreteVolume(View view) {
        kontrollerThread.setVolume(discreteVolumeValue);
    }

    public void previousSurroundMode(View view) {
        kontrollerThread.previousSurroundMode();
    }

    public void nextSurroundMode(View view) {
        kontrollerThread.nextSurroundMode();
    }

    @Override
    public void handleOperationStatusUpdate(final String operationState) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                operationStateView.setText(operationState);
            }
        });
    }

    @Override
    public void handleVolumeUpdate(final String volumeValue) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                volumeView.setText(unescapeHexCharacters(volumeValue));
            }
        });
    }

    @Override
    public void handleSourceUpdate(final String sourceName) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                sourceView.setText(unescapeHexCharacters(sourceName));
            }
        });
    }

    private String unescapeHexCharacters(String escapedString) {
        try {
            return URLDecoder.decode(escapedString.replaceAll("\\\\x", "%"), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            // UTF-8 encoding must always exist
            return escapedString;
        }
    }

    @Override
    public void handleSurroundModeUpdate(final String currentSurroundMode) {

        handler.post(new Runnable() {
            @Override
            public void run() {
                surroundModeView.setText(SurroundModes.renderSurroundModeString(currentSurroundMode));
            }
        });
    }

    @Override
    public void handleNoConnectionStatusUpdate() {
        runJustBeforeBeingDrawn(surroundModeView.getViewGroup(), new Runnable() {
            @Override
            public void run() {
                setNoConnectionInfo();
            }
        });
    }

    @Override
    public void handlePowerCounterUpdate(String powerCounterValue) {
        this.powerCounterValue = powerCounterValue;
    }

    @Override
    public void handleDeviceIdUpdate(String deviceId) {
        this.deviceId = deviceId;
    }

    @Override
    public void handleSoftwareVersionUpdate(String softwareVersion) {
        this.softwareVersion = softwareVersion;
    }

    public void openEditDeviceDialog(MenuItem item) {
        final DeviceInfo newDevice = new DeviceInfo();
        LayoutInflater li = LayoutInflater.from(this);
        View promptsView = li.inflate(R.layout.fragment_dialog_edit_device, null);
        final EditText deviceNameText = (EditText) promptsView.findViewById(R.id.edit_device_name);
        deviceNameText.setText(deviceInfo.deviceName);
        final EditText ipAddressText = (EditText) promptsView.findViewById(R.id.edit_ip_address);
        ipAddressText.setText(deviceInfo.ipAddress);
        final EditText discreteVolumeText = (EditText) promptsView.findViewById(R.id.edit_discrete_volume);
        if (deviceInfo.discreteVolumeValues != null && deviceInfo.discreteVolumeValues.length > 0)
            discreteVolumeText.setText(deviceInfo.discreteVolumeValues[0]);
        AlertDialog alertDialog = new AlertDialog.Builder(this).setView(promptsView).setTitle("Edit Device")
                .setCancelable(false).setPositiveButton("OK", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        final DeviceInfo newDevice = new DeviceInfo(ipAddressText.getText().toString(),
                                deviceNameText.getText().toString(),
                                DeviceChooserActivity.getDiscreteVolumes(discreteVolumeText));
                        deviceListPersistor.updateDevice(deviceInfo, newDevice);
                        startControlActivity(newDevice);
                        finish();
                    }
                }).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.cancel();
                    }
                }).create();
        alertDialog.show();
    }

    private void startControlActivity(DeviceInfo deviceInfo) {
        Intent intent = new Intent(this, DeviceControlActivity.class);
        intent.putExtra(EXTRA_IP_ADDRESS, deviceInfo.getIpAddress());
        intent.putExtra(EXTRA_DEVICE_NAME, deviceInfo.getDeviceName());
        intent.putExtra(EXTRA_DEVICE_VOLUMES, deviceInfo.getDiscreteVolumeValues());
        startActivity(intent);
    }

    public void openDeleteDeviceDialog(MenuItem item) {
        AlertDialog alertDialog = new AlertDialog.Builder(this)
                .setTitle("Delete Device " + deviceInfo.getDeviceName() + "?").setCancelable(false)
                .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        deviceListPersistor.deleteDevice(deviceInfo);
                        Intent upIntent = new Intent(DeviceControlActivity.this, DeviceChooserActivity.class);
                        NavUtils.navigateUpTo(DeviceControlActivity.this, upIntent);
                    }
                }).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.cancel();
                    }
                }).create();
        alertDialog.show();
    }

    public void openShowDeviceInfoDialog(MenuItem item) {
        ListView deviceInfoListView = new ListView(this);
        deviceInfoListView.setAdapter(createDeviceInfoListAdapter());
        AlertDialog alertDialog = new AlertDialog.Builder(this).setTitle("Device Info").setCancelable(false)
                .setView(deviceInfoListView).setPositiveButton("OK", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                    }
                }).create();
        alertDialog.show();
    }

    ListAdapter createDeviceInfoListAdapter() {
        final String[] fromMapKey = new String[] { "key", "value" };
        final int[] toLayoutId = new int[] { android.R.id.text1, android.R.id.text2 };
        final List<Map<String, String>> list = new ArrayList<>();
        list.add(createListEntry("Device Name", deviceInfo.deviceName));
        list.add(createListEntry("IP Address", deviceInfo.ipAddress));
        list.add(createListEntry("Device ID", deviceId != null ? deviceId : "unknown"));
        list.add(createListEntry("Total Operation Time", renderOperationTime(powerCounterValue)));
        addSoftwareVersions(list);

        return new SimpleAdapter(this, list, android.R.layout.simple_list_item_2, fromMapKey, toLayoutId);
    }

    private String renderOperationTime(String powerCounterValue) {
        if (powerCounterValue == null)
            return "unknown";
        String[] segments = powerCounterValue.split(":");
        if (segments.length == 4) {
            return String.format("%s days %s hours %s minutes %s seconds", (Object[]) segments);
        }
        return powerCounterValue;
    }

    private void addSoftwareVersions(List<Map<String, String>> list) {
        if (softwareVersion == null) {
            list.add(createListEntry("Software Version", "unknown"));
        } else {
            String[] versions = softwareVersion.split("\\s");
            for (int i = 0; i < versions.length - 1; i += 2) {
                list.add(createListEntry(versions[i] + " version", versions[i + 1]));
            }
        }
    }

    private HashMap<String, String> createListEntry(String key, String value) {
        HashMap<String, String> map = new HashMap<>();
        map.put("key", key);
        map.put("value", value);
        return map;
    }

    public void showAbout(MenuItem item) {
        AboutDialog.showAbout(this);
    }

    private static void runJustBeforeBeingDrawn(final View view, final Runnable runnable) {
        final ViewTreeObserver.OnPreDrawListener preDrawListener = new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                runnable.run();
                view.getViewTreeObserver().removeOnPreDrawListener(this);
                return true;
            }
        };
        view.getViewTreeObserver().addOnPreDrawListener(preDrawListener);
    }

}