Java tutorial
/** Copyright (C) 2013 Marek Sebera <marek@msebera.cz> * * 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 3 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, see <http://www.gnu.org/licenses/>. * */ package cz.tomsuch.lampicka.activities; import java.io.OutputStream; import java.util.regex.Matcher; import java.util.regex.Pattern; import android.app.AlertDialog; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.graphics.Color; import android.os.Bundle; import android.os.Handler; import android.os.ParcelUuid; import android.os.Parcelable; import android.support.v4.app.FragmentActivity; import android.util.DisplayMetrics; import android.util.Log; import android.view.Surface; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; import android.widget.Toast; import cz.tomsuch.lampicka.R; import cz.tomsuch.lampicka.abstracts.CustomSeekBar; import cz.tomsuch.lampicka.enums.BluetoothLampBacklightMode; import cz.tomsuch.lampicka.enums.BluetoothLampColorSetMode; import cz.tomsuch.lampicka.enums.BluetoothLampCommand; import cz.tomsuch.lampicka.enums.BluetoothLampEffect; import cz.tomsuch.lampicka.impl.DefaultBluetoothLamp; import cz.tomsuch.lampicka.interfaces.BluetoothInputLineListener; import cz.tomsuch.lampicka.interfaces.BluetoothLampCommandListener; import cz.tomsuch.lampicka.interfaces.OnColorChangedListener; import cz.tomsuch.lampicka.interfaces.PalleteDialogColorListener; import cz.tomsuch.lampicka.pallete.PalleteDialog; import cz.tomsuch.lampicka.util.BluetoothDeviceWrapper; import cz.tomsuch.lampicka.util.BluetoothSocketListener; import cz.tomsuch.lampicka.util.ColorPickerView; import cz.tomsuch.lampicka.util.FixedBluetoothSocket; import cz.tomsuch.lampicka.util.Preferences; /** * Displays controls and status for selected BluetoothDevice (aka lamp). * * For now it only runs in portrait mode * * * @author Marek Sebera <marek@msebera.cz> * */ public final class LampActivity extends FragmentActivity { /** * Intent extra parameter, must contain BluetoothDevice * */ private BluetoothDeviceWrapper device; private ParcelUuid serviceUuid; private FixedBluetoothSocket socket; private BluetoothSocketListener bsl; private Handler handler = new Handler(); private boolean isReceiverRegistered = false; private BluetoothLampEffect currentEffect = BluetoothLampEffect.NO_EFFECT; private BluetoothLampBacklightMode currentBacklightEffect = BluetoothLampBacklightMode.ON; private BluetoothLampColorSetMode currentColorSetMode = BluetoothLampColorSetMode.CONTINUOUS; private DefaultBluetoothLamp lamp = null; private ColorPickerView colorPicker; private Button lamp_select, lamp_connect_disconnect, lamp_effects_select, lamp_backlight_select, lamp_pallet, lamp_turn_off, lamp_set_with_effect; private TextView lamp_name, lamp_humidity, lamp_lightness, lamp_intensity, lamp_temperature; private CustomSeekBar lamp_color_intensity; protected String lamp_version, lamp_serial_number; /** * If user clicks on software or hardware back button, it finished whole * application according to UI-flow * */ @Override public void onBackPressed() { setResult(RESULT_OK); finish(); } /** * Handles input from BluetoothSocket * */ private BluetoothInputLineListener bluetoothInputListener = new BluetoothInputLineListener() { @Override public void handleReceivedLine(String line) { handleInput(line); } }; /** * Listens for selected color, if dialog is not dismissed * */ private PalleteDialogColorListener palleteListener = new PalleteDialogColorListener() { @Override public void colorSelected(int color) { colorPicker.setColor(color); onColorChangedListener.colorChanged(color, true, true); } }; /** * Listener for various UI controls * */ private OnClickListener onClickListener = new OnClickListener() { @Override public void onClick(View v) { switch (v.getId()) { case R.id.LAMP_EFFECT_CHOOSER: displayEffectChooserDialog(); break; case R.id.LAMP_SET_COLOR_EFFECT_CHOOSER: displayLampColorSetModeChooserDialog(); break; case R.id.LAMP_PALLET_CHOOSER: displayColorPaletteChooserDialog(); break; case R.id.LAMP_BACKLIGHT_CHOOSER: displayBacklightChooserDialog(); break; case R.id.LAMP_TURN_OFF: lamp.setColorHard(Color.BLACK); setCurrentEffect(BluetoothLampEffect.NO_EFFECT); break; case R.id.LAMP_CONNECT_DISCONNECT: if (socket != null) { disconnect(); } else { discoverDevice(); } break; case R.id.LAMP_CHOOSER: finish(); break; } } }; /** * Helper method to set current effect * */ private void setCurrentEffect(BluetoothLampEffect effect) { currentEffect = effect; lamp_effects_select.setText(currentEffect.getName()); } /** * Displays color chooser pallete dialog * */ protected void displayColorPaletteChooserDialog() { PalleteDialog.attach(getSupportFragmentManager(), palleteListener); } /** * Listener for ColorPickerView widget * */ OnColorChangedListener onColorChangedListener = new OnColorChangedListener() { private long lastChange = 0; private long minDelta = 150; @Override public void colorChanged(int color, boolean up, boolean center) { switch (currentColorSetMode) { default: case CONTINUOUS: long now = System.currentTimeMillis(); if (now - lastChange > minDelta) { setCurrentEffect(BluetoothLampEffect.NO_EFFECT); lamp.setColorHard(color); lastChange = now; } break; case HARD: if (up) { setCurrentEffect(BluetoothLampEffect.NO_EFFECT); lamp.setColorHard(color); } break; case TRANSITION: if (up) { setCurrentEffect(BluetoothLampEffect.NO_EFFECT); lamp.setColorWithCrossFade(color); } break; } } }; /** * Listens to discovery of service UUIDs on given BluetoothDevice * */ private BroadcastReceiver uuidsReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(BluetoothDevice.ACTION_UUID)) { Parcelable[] uuids = intent.getParcelableArrayExtra(BluetoothDevice.EXTRA_UUID); if (uuids != null) { for (Parcelable u : uuids) { if (u instanceof ParcelUuid && serviceUuid == null) { serviceUuid = (ParcelUuid) u; Preferences.getInstance().saveLastServiceUuid(serviceUuid); connectToService(); } } } } } }; /** * Listener to consume commands and execute them on device * */ private BluetoothLampCommandListener bluetoothLampCommandListener = new BluetoothLampCommandListener() { private int errorCounter = 0; /** * Sends request to BluetoothDevice over socket. Does not fail, if the * socket is not yet initialized * * @param msg * Request string, must not contain CR/LF * */ @Override public void sendData(String msg) { if (socket != null && socket.isConnected()) { if (msg != null && msg.length() > 0) { OutputStream outStream; try { Log.d("Send Data", msg); msg = msg + "\n"; outStream = socket.getOutputStream(); byte[] byteString = msg.getBytes(); outStream.write(byteString); errorCounter = 0; } catch (Throwable e) { errorCounter++; if (errorCounter == 3) { showToast(R.string.toast_disconnected); disconnect(); } } } } } @Override public void sendData(BluetoothLampCommand command) { sendData(command.toString()); } }; /** * Matches info about lamp (returned data) * */ private static final Pattern LAMP_INFO = Pattern.compile( "^0 ([-]?[0-9]|[-]?[1-9][0-9]|[-]?100):([0-9]|[1-9][0-9]|100):(10[0-2][0-4]|[1-9][1-9][0-9]|[1-9][0-9]|[0-9])$"); private static final Pattern LAMP_NAME = Pattern.compile("^2 .*$"); private static final Pattern LAMP_VERSION = Pattern.compile("^3 .*$"); private static final Pattern LAMP_SERIAL = Pattern.compile("^1 [0-9]{8}$"); private static final Pattern LAMP_SETTINGS = Pattern.compile("^4 .*$"); /** * If there is discovered Service UUID, it will initialize connection, * creates BluetoothSocket and retrieves informations about device (X,i) * */ private void connectToService() { new Thread(new Runnable() { @Override public void run() { try { setStatus(R.string.lamp_connecting); if (socket != null) { socket.close(); } socket = new FixedBluetoothSocket( BluetoothAdapter.getDefaultAdapter().getRemoteDevice(device.getAddress()) .createRfcommSocketToServiceRecord(serviceUuid.getUuid())); BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (adapter.isDiscovering()) adapter.cancelDiscovery(); if (socket != null) { try { socket.connect(); } catch (Exception e) { e.printStackTrace(); disconnect(); showToast(R.string.toast_cannot_connect_to_bluetooth_lamp); return; } } if (socket.isConnected()) { afterSocketConnected(); bsl = new BluetoothSocketListener(socket, bluetoothInputListener); new Thread(bsl).start(); } else { showToast(R.string.toast_could_not_connect); disconnect(); } } catch (Throwable e) { e.printStackTrace(); } } }).start(); } /** * Lamp color set mode chooser dialog listener * * {@link BluetoothLampColorSetMode} * {@link #displayLampColorSetModeChooserDialog()} * */ private DialogInterface.OnClickListener lampColorSetModeListener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { currentColorSetMode = BluetoothLampColorSetMode.getEffectNo(which); lamp_set_with_effect.setText(currentColorSetMode.getName()); dialog.dismiss(); } }; /** * Lamp color set mode chooser dialog builder * * {@link BluetoothLampColorSetMode} * */ protected void displayLampColorSetModeChooserDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.dialog_title_select_color_set_mode); String[] items = new String[BluetoothLampColorSetMode.values().length]; int selected = 0; int index = 0; for (BluetoothLampColorSetMode effect : BluetoothLampColorSetMode.values()) { items[index] = getString(effect.getName()); if (currentColorSetMode.equals(effect)) { selected = index; } index++; } builder.setSingleChoiceItems(items, selected, lampColorSetModeListener); builder.setNeutralButton(R.string.dialog_cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); builder.create().show(); } /** * Effect chooser dialog listener * * {@link BluetoothLampEffect} {@link #displayEffectChooserDialog()} * */ private DialogInterface.OnClickListener effectSelectedListener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { currentEffect = BluetoothLampEffect.getEffectNo(which); lamp_effects_select.setText(currentEffect.getName()); if (currentEffect.equals(BluetoothLampEffect.NO_EFFECT)) { lamp.setColorHard(Color.BLACK); } else { lamp.setEffect(currentEffect); } dialog.dismiss(); } }; /** * Effect chooser dialog builder * * {@link BluetoothLampEffect} * */ protected void displayEffectChooserDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.lamp_select_effect); String[] items = new String[BluetoothLampEffect.values().length]; int selected = 0; int index = 0; for (BluetoothLampEffect effect : BluetoothLampEffect.values()) { items[index] = getString(effect.getName()); if (currentEffect.equals(effect)) { selected = index; } index++; } builder.setSingleChoiceItems(items, selected, effectSelectedListener); builder.setNeutralButton(R.string.dialog_cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); builder.create().show(); } /** * Backlight effect chooser dialog listener * * {@link BluetoothLampBacklightMode} * {@link #displayBacklightChooserDialog()} * */ private DialogInterface.OnClickListener backlightSelectedListener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { currentBacklightEffect = BluetoothLampBacklightMode.getEffectNo(which); lamp_backlight_select.setText(currentBacklightEffect.getName()); lamp.setBacklightEffect(currentBacklightEffect); dialog.dismiss(); } }; private OnSeekBarChangeListener colorIntensityListener = new OnSeekBarChangeListener() { private long lastChange = 0; private long minDelta = 50; @Override public void onStopTrackingTouch(SeekBar seekBar) { } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { long now = System.currentTimeMillis(); if (now - lastChange > minDelta) { progress++; lamp.setColorIntensity(progress); lamp_intensity.setText(String.format(getString(R.string.lamp_intensity), progress)); lastChange = now; } } }; /** * Backlight effect chooser dialog builder * * {@link BluetoothLampBacklightMode} * */ protected void displayBacklightChooserDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.lamp_select_backlight_effect); String[] items = new String[BluetoothLampBacklightMode.values().length]; int selected = 0; int index = 0; for (BluetoothLampBacklightMode effect : BluetoothLampBacklightMode.values()) { items[index] = getString(effect.getName()); if (currentBacklightEffect.equals(effect)) { selected = index; } index++; } builder.setSingleChoiceItems(items, selected, backlightSelectedListener); builder.setNeutralButton(R.string.dialog_cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); builder.create().show(); } /** * Helper method, can be called from background threads * * @param message * String to be displayed * */ protected void showToast(final int message) { runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(LampActivity.this, message, Toast.LENGTH_SHORT).show(); } }); } /** * Executes after the socket is connected * */ private void afterSocketConnected() { setRequestedOrientation(getScreenOrientation()); lamp.getCurrentSettings(); setLampIsConnected(true); runInfoLoop(); } private int getScreenOrientation() { int rotation = getWindowManager().getDefaultDisplay().getRotation(); DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); int width = dm.widthPixels; int height = dm.heightPixels; int orientation; // if the device's natural orientation is portrait: if ((rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) && height > width || (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) && width > height) { switch (rotation) { case Surface.ROTATION_0: orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; break; case Surface.ROTATION_90: orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; break; case Surface.ROTATION_180: orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT; break; case Surface.ROTATION_270: orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; break; default: Log.e("WTF", "Unknown screen orientation. Defaulting to " + "portrait."); orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; break; } } // if the device's natural orientation is landscape or if the device // is square: else { switch (rotation) { case Surface.ROTATION_0: orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; break; case Surface.ROTATION_90: orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; break; case Surface.ROTATION_180: orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; break; case Surface.ROTATION_270: orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT; break; default: Log.e("WTF", "Unknown screen orientation. Defaulting to " + "landscape."); orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; break; } } return orientation; } /** * Sets whole UI state according to lamp connect status * */ private void setLampIsConnected(final boolean isConnected) { setUIControlsState(isConnected); runOnUiThread(new Runnable() { @Override public void run() { lamp_connect_disconnect.setEnabled(true); lamp_connect_disconnect.setText(isConnected ? R.string.lamp_disconnect : R.string.lamp_connect); } }); } /** * Runs UUID discovery on device * */ private void discoverDevice() { lamp_connect_disconnect.setEnabled(false); lamp_name.setText(device.getName()); lamp_select.setEnabled(false); serviceUuid = Preferences.getInstance().getLastBluetoothServiceUuid(); if (serviceUuid == null) { setStatus(R.string.lamp_discovering); BluetoothAdapter.getDefaultAdapter().getRemoteDevice(device.getAddress()).fetchUuidsWithSdp(); } else { connectToService(); } } /** * Handles incoming line from BluetoothDevice * * @param string * incoming data, can be multiple lines * */ public void handleInput(final String string) { runOnUiThread(new Runnable() { @Override public void run() { String[] lines = string.split(System.getProperty("line.separator")); for (String line : lines) { line = line.trim(); Log.d("Handle Line", line); if (LAMP_INFO.matcher(line).matches()) { setLampInfo(line); lamp.getLampVersion(); } else if (LAMP_NAME.matcher(line).matches()) { if (line.length() > 2) lamp_name.setText(line.substring(2)); lamp.getLampInfo(); } else if (LAMP_VERSION.matcher(line).matches()) { lamp_version = line.substring(2); lamp.getLampSerial(); } else if (LAMP_SERIAL.matcher(line).matches()) { lamp_serial_number = line.substring(2); } else if (LAMP_SETTINGS.matcher(line).matches()) { applyLampSettings(line.substring(2)); lamp.getLampId(); } } } }); } /** * Parses response from lamp, setting remote settings to local UI controls * */ private void applyLampSettings(String substring) { String[] parts = substring.split(":"); if (parts == null || parts.length != 6) return; int counter = 0; int red = 0, green = 0, blue = 0; int currentEffect = 0, currentBacklightEffect = 0, currentColorIntensity = 0; for (String part : parts) { int value = Integer.parseInt(part); switch (counter) { case 0: red = value; break; case 1: green = value; break; case 2: blue = value; break; case 3: currentBacklightEffect = value; break; case 4: currentEffect = value; break; case 5: currentColorIntensity = value; break; } counter++; } this.lamp_color_intensity.setProgressAndThumb(currentColorIntensity); this.colorPicker.setColor(Color.rgb(red, green, blue)); this.currentEffect = BluetoothLampEffect.getEffectRawNo(currentEffect); this.currentBacklightEffect = BluetoothLampBacklightMode.getEffectRawNo(currentBacklightEffect); this.lamp_effects_select.setText(this.currentEffect.getName()); this.lamp_backlight_select.setText(this.currentBacklightEffect.getName()); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); lamp = new DefaultBluetoothLamp(bluetoothLampCommandListener); setContentView(R.layout.activity_lamp_controls); setupUIControls(); this.device = Preferences.getInstance().getLastBluetoothDevice(); setLampIsConnected(false); } /** * If user returns to this activity (or comes at first), we register * receiver, as it does nothing itself * */ @Override protected void onResume() { try { IntentFilter uuidsFilter = new IntentFilter(BluetoothDevice.ACTION_UUID); registerReceiver(uuidsReceiver, uuidsFilter); isReceiverRegistered = true; } catch (Throwable t) { t.printStackTrace(); } if (device != null && serviceUuid != null) { connectToService(); } super.onResume(); } /** * Handles activity LifeCycle, unregisters UUIDs listener and closes * BluetoothSocket * */ @Override protected void onPause() { disconnect(); super.onPause(); } /** * Sums whole process of disconnecting onPause, on manual disconnect, ... * */ private void disconnect() { setLampIsConnected(false); handler.postAtFrontOfQueue(new Runnable() { @Override public void run() { try { handler.removeCallbacksAndMessages(null); } catch (Throwable t) { t.printStackTrace(); } if (isReceiverRegistered) { unregisterReceiver(uuidsReceiver); isReceiverRegistered = false; } try { if (socket != null) socket.close(); socket = null; } catch (Throwable t) { t.printStackTrace(); } } }); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR); } /** * Runs loop of ping request-response system, to keep socket active and * informations about device up to date * */ private void runInfoLoop() { lamp.getLampInfo(); handler.postDelayed(new Runnable() { @Override public void run() { runInfoLoop(); } }, 30000); } /** * Helper method, to display current status of connection to device * * @param string * message to be displayed * */ protected void setStatus(final int string) { runOnUiThread(new Runnable() { @Override public void run() { lamp_connect_disconnect.setText(string); } }); } /** * Helper method, to display lamp informations below status line * * @param string * message to be parsed * */ protected void setLampInfo(final String string) { runOnUiThread(new Runnable() { @Override public void run() { Matcher m = LAMP_INFO.matcher(string); if (m.find()) { lamp_intensity.setText( String.format(getString(R.string.lamp_intensity), lamp_color_intensity.getProgress())); if (!"0".equals(m.group(2))) lamp_humidity.setText(String.format(getString(R.string.lamp_humidity), m.group(2))); if (!"0".equals(m.group(3))) lamp_lightness.setText(String.format(getString(R.string.lamp_lightness), m.group(3))); if (!"0".equals(m.group(3)) && !"0".equals(m.group(1))) lamp_temperature.setText(String.format(getString(R.string.lamp_temperature), m.group(1))); } } }); } /** * Binds UI controls to {@link #onClickListener} * */ private void setupUIControls() { lamp_backlight_select = (Button) findViewById(R.id.LAMP_BACKLIGHT_CHOOSER); colorPicker = (ColorPickerView) findViewById(R.id.LAMP_COLOR_PICKER); lamp_turn_off = (Button) findViewById(R.id.LAMP_TURN_OFF); lamp_set_with_effect = (Button) findViewById(R.id.LAMP_SET_COLOR_EFFECT_CHOOSER); lamp_effects_select = (Button) findViewById(R.id.LAMP_EFFECT_CHOOSER); lamp_connect_disconnect = (Button) findViewById(R.id.LAMP_CONNECT_DISCONNECT); lamp_select = (Button) findViewById(R.id.LAMP_CHOOSER); lamp_pallet = (Button) findViewById(R.id.LAMP_PALLET_CHOOSER); lamp_name = (TextView) findViewById(R.id.LAMP_NAME); lamp_humidity = (TextView) findViewById(R.id.LAMP_HUMIDITY); lamp_lightness = (TextView) findViewById(R.id.LAMP_LIGHTNESS); lamp_temperature = (TextView) findViewById(R.id.LAMP_TEMPERATURE); lamp_intensity = (TextView) findViewById(R.id.LAMP_INTENSITY); lamp_color_intensity = (CustomSeekBar) findViewById(R.id.LAMP_COLOR_INTENSITY); for (Button b : getAllButtons()) { b.setOnClickListener(onClickListener); } colorPicker.setOnColorChangedListener(onColorChangedListener); colorPicker.setChangeColorContinually(true); colorPicker.setColor(Color.WHITE); lamp_effects_select.setText(currentEffect.getName()); lamp_backlight_select.setText(currentBacklightEffect.getName()); lamp_set_with_effect.setText(currentColorSetMode.getName()); lamp_color_intensity.setOnSeekBarChangeListener(colorIntensityListener); setUIControlsState(false); } /** * Helper method, sums all buttons for UI controls and OnClickListener sets * */ private Button[] getAllButtons() { return new Button[] { lamp_connect_disconnect, lamp_effects_select, lamp_backlight_select, lamp_pallet, lamp_turn_off, lamp_set_with_effect, lamp_select }; } /** * Sets enabled/disabled state to all UI controls, according to connection * state * */ private void setUIControlsState(final boolean enabled) { runOnUiThread(new Runnable() { @Override public void run() { for (Button b : getAllButtons()) { b.setEnabled(enabled); } lamp_select.setEnabled(!enabled); colorPicker.setEnabled(enabled); lamp_color_intensity.setEnabled(enabled); if (!enabled) { if (device != null) lamp_name.setText(device.getName()); else lamp_name.setText(R.string.lamp_disconnected); lamp_humidity.setText(null); lamp_lightness.setText(null); lamp_temperature.setText(null); lamp_intensity.setText(null); } } }); } }