package widgets; import android.app.Activity; import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.os.AsyncTask; import android.os.Handler; import android.os.Message; import android.preference.PreferenceManager; import android.view.Gravity; import android.view.View; import android.view.View.OnClickListener; import android.view.animation.Animation; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; import android.widget.Toast; import com.github.curioustechizen.ago.RelativeTimeTextView; import org.domogik.domodroid13.R; import org.json.JSONException; import org.json.JSONObject; import java.util.TimerTask; import Abstract.display_sensor_info; import Abstract.translate; import Entity.Entity_Feature; import Entity.Entity_Map; import Entity.Entity_client; import database.WidgetUpdate; import misc.Color_Progress; import misc.Color_RGBField; import misc.Color_Result; import misc.tracerengine; import rinor.send_command; public class Graphical_Color extends Basic_Graphical_widget implements OnSeekBarChangeListener, OnClickListener { private int mInitialColor, mDefaultColor; private String mKey; private RelativeTimeTextView TV_Timestamp; private LinearLayout featurePan2; private Color_Progress seekBarHueBar; private Color_Progress seekBarRGBXBar; private Color_Progress seekBarRGBYBar; private Color_RGBField rgbView; private Color_Result resultView; private Animation animation; private boolean touching; private int updating = 0; private int argb = 0; private String argbS = ""; private Message msg; private static String mytag; public static FrameLayout container = null; private static FrameLayout myself = null; private Boolean switch_state = false; private TimerTask doAsynchronousTask; private Color currentColor; private SeekBar seekBarOnOff; private int[] mMainColors = new int[65536]; private float mCurrentHue = 0; public int rgbHue = 0; private int rgbX = 0; private int rgbY = 0; private int r, g, b; private TextView title7; private TextView title8; private TextView title9; private String t7s; private String t8s; private String t9s = ""; private final SharedPreferences params; private Boolean realtime = false; private JSONObject jparam; private final Entity_Feature feature; private String command_id = null; private String command_type = null; private final int session_type; public Graphical_Color(tracerengine Trac, final Activity activity, int widgetSize, int session_type, int place_id, String place_type, SharedPreferences params, final Entity_Feature feature, Handler handler) { super(params, activity, Trac, feature.getId(), feature.getDescription(), feature.getState_key(), feature.getIcon_name(), widgetSize, place_id, place_type, mytag, container, handler); this.feature = feature; this.params = params; this.session_type = session_type; onCreate(); } public Graphical_Color(tracerengine Trac, final Activity activity, int widgetSize, int session_type, int place_id, String place_type, SharedPreferences params, final Entity_Map feature_map, Handler handler) { super(params, activity, Trac, feature_map.getId(), feature_map.getDescription(), feature_map.getState_key(), feature_map.getIcon_name(), widgetSize, place_id, place_type, mytag, container, handler); this.feature = feature_map; this.session_type = session_type; this.params = params; onCreate(); } private void onCreate() { myself = this; int dev_id = feature.getDevId(); String parameters = feature.getParameters(); String state_key = feature.getState_key(); command_id = feature.getAddress(); mytag = "Graphical_Color(" + dev_id + ")"; String value0; String value1; try { jparam = new JSONObject(parameters.replaceAll(""", "\"")); value1 = jparam.getString("value1"); value0 = jparam.getString("value0"); } catch (Exception e) { Tracer.d(mytag, "no parameters for this device"); value0 = "0"; value1 = "1"; } setOnClickListener(this); String[] model = feature.getDevice_type_id().split("\\."); command_type = model[0]; Tracer.d(mytag, "model_id = <" + feature.getDevice_type_id() + "> command_type = <" + command_type + ">"); //state key TextView state_key_view = new TextView(activity); try { state_key_view.setText(activity.getResources().getString(translate.do_translate(getContext(), Tracer, state_key))); } catch (Exception e) { state_key_view.setText(state_key); } state_key_view.setTextColor(Color.parseColor("#333333")); //first seekbar on/off seekBarOnOff = new SeekBar(activity); seekBarOnOff.setProgress(0); seekBarOnOff.setMax(100); Bitmap bMap = BitmapFactory.decodeResource(getResources(), R.drawable.bgseekbaronoff); seekBarOnOff.setLayoutParams(new LayoutParams(bMap.getWidth(), bMap.getHeight())); seekBarOnOff.setProgressDrawable(getResources().getDrawable(R.drawable.bgseekbaronoff)); seekBarOnOff.setThumb(getResources().getDrawable(R.drawable.buttonseekbar)); seekBarOnOff.setThumbOffset(0); seekBarOnOff.setOnSeekBarChangeListener(this); seekBarOnOff.setTag("onoff"); //feature panel 2 featurePan2 = new LinearLayout(activity); featurePan2.setOrientation(LinearLayout.HORIZONTAL); //featurePan2.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT)); featurePan2.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); featurePan2.setGravity(Gravity.CENTER_VERTICAL); featurePan2.setPadding(20, 0, 0, 10); //left panel LinearLayout color_LeftPan = new LinearLayout(activity); color_LeftPan.setOrientation(LinearLayout.VERTICAL); //color_LeftPan.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.FILL_PARENT,1)); color_LeftPan.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 1)); color_LeftPan.setPadding(0, 0, 0, 10); TextView title1 = new TextView(activity); title1.setText(activity.getString(R.string.Hue)); title1.setTextSize(10); title1.setTextColor(Color.parseColor("#333333")); TextView title2 = new TextView(activity); title2.setText(activity.getString(R.string.Sat)); title2.setTextSize(10); title2.setTextColor(Color.parseColor("#333333")); TextView title3 = new TextView(activity); title3.setText(activity.getString(R.string.Bright)); title3.setTextSize(10); title3.setTextColor(Color.parseColor("#333333")); //TextView title4 = new TextView(activity); //title4.setText("Luminosity"); //title4.setTextSize(10); //title4.setTextColor(Color.parseColor("#333333")); TextView title5 = new TextView(activity); title5.setText(activity.getString(R.string.Field)); title5.setTextSize(10); title5.setTextColor(Color.parseColor("#333333")); TextView title6 = new TextView(activity); title6.setText(activity.getString(R.string.Curcolor)); title6.setTextSize(10); title6.setTextColor(Color.parseColor("#333333")); title7 = new TextView(activity); t7s = activity.getString(R.string.Red); title7.setText(t7s + " : 255"); title7.setTextSize(10); title7.setTextColor(Color.parseColor("#333333")); title8 = new TextView(activity); t8s = activity.getString(R.string.Green); title8.setText(t8s + " : 0"); title8.setTextSize(10); title8.setTextColor(Color.parseColor("#333333")); title9 = new TextView(activity); t9s = activity.getString(R.string.Blue); title9.setText(t9s + " : 0"); title9.setTextSize(10); title9.setTextColor(Color.parseColor("#333333")); //seekbar huebar seekBarHueBar = new Color_Progress(Tracer, activity, 0, 0); seekBarHueBar.setProgress(0); seekBarHueBar.setMax(255); seekBarHueBar.setProgressDrawable(null); seekBarHueBar.setOnSeekBarChangeListener(this); seekBarHueBar.setTag("hue"); //seekbar rgbbarX seekBarRGBXBar = new Color_Progress(Tracer, activity, 1, 0); seekBarRGBXBar.setProgress(0); seekBarRGBXBar.setMax(255); seekBarRGBXBar.setProgressDrawable(null); seekBarRGBXBar.setOnSeekBarChangeListener(this); seekBarRGBXBar.setTag("rgbx"); //seekbar rgbbarY seekBarRGBYBar = new Color_Progress(Tracer, activity, 2, 0); seekBarRGBYBar.setProgress(0); seekBarRGBYBar.setMax(255); seekBarRGBYBar.setProgressDrawable(null); seekBarRGBYBar.setOnSeekBarChangeListener(this); seekBarRGBYBar.setTag("rgby"); //seekbar powerbar Color_Progress seekBarPowerBar = new Color_Progress(Tracer, activity, 3, 0); seekBarPowerBar.setProgress(0); seekBarPowerBar.setMax(255); seekBarPowerBar.setProgressDrawable(null); seekBarPowerBar.setOnSeekBarChangeListener(this); seekBarPowerBar.setTag("power"); //RGBField rgbView = new Color_RGBField(getContext(), Color.RED, Color.RED); //rgbView.drawRGBField(); //right panel LinearLayout color_RightPan = new LinearLayout(activity); color_RightPan.setOrientation(LinearLayout.VERTICAL); color_RightPan.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, Gravity.RIGHT)); color_RightPan.setPadding(20, 0, 0, 10); //Color result resultView = new Color_Result(activity); //Timestamp TV_Timestamp = new RelativeTimeTextView(activity, null); TV_Timestamp.setTextSize(10); TV_Timestamp.setTextColor(Color.BLUE); TV_Timestamp.setGravity(Gravity.RIGHT); LL_featurePan.addView(seekBarOnOff); LL_featurePan.addView(TV_Timestamp); LL_infoPan.addView(state_key_view); color_LeftPan.addView(title1); color_LeftPan.addView(seekBarHueBar); color_LeftPan.addView(title2); color_LeftPan.addView(seekBarRGBXBar); color_LeftPan.addView(title3); color_LeftPan.addView(seekBarRGBYBar); //color_LeftPan.addView(title4); //color_LeftPan.addView(seekBarPowerBar); color_LeftPan.addView(title5); color_LeftPan.addView(rgbView); color_RightPan.addView(title6); color_RightPan.addView(resultView); color_RightPan.addView(title7); color_RightPan.addView(title8); color_RightPan.addView(title9); featurePan2.addView(color_LeftPan); featurePan2.addView(color_RightPan); featurePan2.setVisibility(INVISIBLE); if (api_version >= 0.7f) { try { int number_of_command_parameters = jparam.getInt("number_of_command_parameters"); if (number_of_command_parameters == 1) { command_id = jparam.getString("command_id"); command_type = jparam.getString("command_type1"); } } catch (JSONException e) { Tracer.d(mytag, "No command_id for this device"); seekBarOnOff.setEnabled(false); } } //LoadSelections(); Handler handler = new Handler() { @Override public void handleMessage(Message msg) { argbS = "?"; if (msg.what == 2) { Toast.makeText(getContext(), R.string.command_rejected, Toast.LENGTH_SHORT).show(); } else if (msg.what == 9998) { // state_engine send us a signal to notify it'll die ! Tracer.d(mytag, "state engine disappeared ===> Harakiri !"); session = null; realtime = false; removeView(LL_background); myself.setVisibility(GONE); try { finalize(); } catch (Throwable t) { t.printStackTrace(); } //kill the handler thread itself } else if (msg.what == 9999) { if (session != null) { argbS = session.getValue(); String Value_timestamp = session.getTimestamp(); Tracer.d(mytag, "Handler receives a new value <" + argbS + "> at " + Value_timestamp); Long Value_timestamplong = null; Value_timestamplong = Long.valueOf(Value_timestamp) * 1000; SharedPreferences SP_params = PreferenceManager.getDefaultSharedPreferences(activity); if (SP_params.getBoolean("widget_timestamp", false)) { TV_Timestamp.setText(display_sensor_info.timestamp_convertion(Value_timestamplong.toString(), activity)); } else { TV_Timestamp.setReferenceTime(Value_timestamplong); } } else return; } switch (argbS) { case "off": switch_state = false; argbS = "000000"; argb = 0; break; case "on": seekBarOnOff.setProgress(100); switch_state = true; LoadSelections(); //Recall last values known from shared preferences // argb and argbS will be set when seekBars will be changed return; default: try { argbS = argbS.substring(1); //It's the form #RRGGBB : ignore the # //Tracer.d(mytag,"Handler ==> argbS after extraction = <"+argbS+">" ); argb = Integer.parseInt(argbS, 16); //Tracer.d(mytag,"Handler ==> argb after parsing = <"+argb+">" ); } catch (Exception e) { argb = 1; } break; } int value_save = argb; r = ((argb >> 16) & 0xFF); g = ((argb >> 8) & 0xFF); b = ((argb) & 0xFF); if (argb == 0) { seekBarOnOff.setProgress(0); switch_state = false; } else { seekBarOnOff.setProgress(100); } //Convert RGB to HSV color, and set sliders float hsv[] = new float[3]; Color.colorToHSV(value_save, hsv); //Tracer.d(mytag,"Handler ==> RGB ("+value_save+") values after process = <"+r+"> <"+g+"> <"+b+">" ); //Tracer.d(mytag,"Handler ==> HSV values after process = <"+hsv[0]+"> <"+hsv[1]+"> <"+hsv[2]+">" ); //Seekbars are in range 0-255 : convert HSV values //Hue is an angle : convert it to linear seekBarHueBar.setProgress((int) (255f - (hsv[0] * 255f / 360))); seekBarRGBXBar.setProgress((int) (hsv[1] * 255f)); seekBarRGBYBar.setProgress((int) (hsv[2] * 255f)); title7.setText(t7s + " : " + r); title8.setText(t8s + " : " + g); title9.setText(t9s + " : " + b); if ((r != 0) || (g != 0) || (b != 0)) { SaveSelections(); } } }; updating = 0; //================================================================================ /* * New mechanism to be notified by widgetupdate engine when our value is changed * */ WidgetUpdate cache_engine = WidgetUpdate.getInstance(); if (cache_engine != null) { if (api_version <= 0.6f) { session = new Entity_client(dev_id, state_key, mytag, handler, session_type); } else if (api_version >= 0.7f) { session = new Entity_client(feature.getId(), "", mytag, handler, session_type); } try { if (Tracer.get_engine().subscribe(session)) { realtime = true; //we're connected to engine //each time our value change, the engine will call handler handler.sendEmptyMessage(9999); //Force to consider current value in session } } catch (Exception e) { e.printStackTrace(); } } //================================================================================ //updateTimer(); //Don't use anymore cyclic refresh.... } public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) { if (arg0.getTag().equals("onoff")) { //User is moving on/off object.... } else if (arg0.getTag().equals("hue")) { //rgb view mCurrentHue = (255 - arg0.getProgress()) * 360 / 255; rgbView.mCurrentHue = mCurrentHue; rgbView.invalidate(); //rgb X float[] hsv0 = {0, 0, (float) rgbY / 255f}; float[] hsv1 = {mCurrentHue, 1, (float) rgbY / 255f}; seekBarRGBXBar.hsv0 = hsv0; seekBarRGBXBar.hsv1 = hsv1; seekBarRGBXBar.invalidate(); //rgb Y float[] hsv2 = {0, 0, 0}; float[] hsv3 = {mCurrentHue, (float) rgbX / 255f, 1}; seekBarRGBYBar.hsv2 = hsv2; seekBarRGBYBar.hsv3 = hsv3; seekBarRGBYBar.invalidate(); } else if (arg0.getTag().equals("rgbx")) { rgbX = arg0.getProgress(); float[] hsv2 = {0, 0, 0}; float[] hsv3 = {mCurrentHue, (float) rgbX / 255f, 1}; seekBarRGBYBar.hsv2 = hsv2; seekBarRGBYBar.hsv3 = hsv3; seekBarRGBYBar.invalidate(); rgbView.mCurrentX = arg0.getProgress(); seekBarRGBYBar.invalidate(); rgbView.invalidate(); } else if (arg0.getTag().equals("rgby")) { rgbY = arg0.getProgress(); float[] hsv0 = {0, 0, (float) rgbY / 255f}; float[] hsv1 = {mCurrentHue, 1, (float) rgbY / 255f}; seekBarRGBXBar.hsv0 = hsv0; seekBarRGBXBar.hsv1 = hsv1; rgbView.mCurrentY = 255 - arg0.getProgress(); seekBarRGBXBar.invalidate(); rgbView.invalidate(); } float[] hsvCurrent = {mCurrentHue, (float) rgbX / 255f, (float) rgbY / 255f}; argb = Color.HSVToColor(hsvCurrent); resultView.hsvCurrent = hsvCurrent; argbS = Integer.toHexString((argb >> 16) & 0xFF) + Integer.toHexString((argb >> 8) & 0xFF) + Integer.toHexString((argb) & 0xFF); r = ((argb >> 16) & 0xFF); g = ((argb >> 8) & 0xFF); b = ((argb) & 0xFF); title7.setText(t7s + " : " + r); title8.setText(t8s + " : " + g); title9.setText(t9s + " : " + b); resultView.invalidate(); } public void onStartTrackingTouch(SeekBar seekBar) { touching = true; updating = 3; } public void onStopTrackingTouch(SeekBar seekBar) { String tag = (String) seekBar.getTag(); if (tag.equals("onoff")) { if (seekBar.getProgress() < 20) { seekBar.setProgress(0); switch_state = false; Tracer.i(mytag, "Change switch to OFF"); // Force color picker to black.... seekBarRGBYBar.setProgress(0); //No brightness => black ! } else { seekBar.setProgress(100); switch_state = true; LoadSelections(); //Recall last known value, till state engine refresh... Tracer.i(mytag, "Change switch to ON"); } new CommandeThread().execute(); //And send switch_state to Domogik } else { int state_progress = seekBar.getProgress(); SaveSelections(); Tracer.i(mytag, "End of change : new rgb value = #" + argbS); if (seekBarOnOff.getProgress() > 50) if (switch_state) new CommandeThread().execute(); //send new color } touching = false; } private class CommandeThread extends AsyncTask<Void, Integer, Void> { // TODO change this to use the send_commands method @Override protected Void doInBackground(Void... params) { Handler temphandler = new Handler(activity.getMainLooper()); temphandler.post(new Runnable() { public void run() { String state_progress = ""; if (api_version >= 0.7f) { if ((argb != 0) && switch_state) { if (feature.getDevice_feature_model_id().startsWith("DT_ColorRGBHexa.")) { String srgb = Integer.toHexString(argb); if (srgb.length() > 6) srgb = srgb.substring(2); state_progress = srgb; } else if (feature.getDevice_feature_model_id().startsWith("DT_ColorRGB.")) { state_progress = r + "," + g + "," + b; } else if (feature.getDevice_feature_model_id().startsWith("DT_ColorCMYK.")) { int computedC, computedM, computedY; int minCMY; computedC = 1 - (r / 255); computedM = 1 - (g / 255); computedY = 1 - (b / 255); if (r == 0 && g == 0 && b == 0) { minCMY = 1; } else { minCMY = Math.min(computedC, Math.min(computedM, computedY)); } computedC = (computedC - minCMY) / (1 - minCMY); computedM = (computedM - minCMY) / (1 - minCMY); computedY = (computedY - minCMY) / (1 - minCMY); state_progress = computedC + "," + computedM + "," + computedY + "," + minCMY; } } else { if (switch_state) { //To see state_progress = "000000"; } else { state_progress = "000000"; seekBarHueBar.setProgress(255); seekBarRGBXBar.setProgress(0); seekBarRGBYBar.setProgress(0); } } } else { // in 0.7 api // Url2send = "cmd/id/" + command_id + "?" + command_type + "=" + value; // in 0.6 api // Url2send = "command/" + type + "/" + address + "/setcolor/" + value; if ((argb != 0) && switch_state) { String srgb = Integer.toHexString(argb); if (srgb.length() > 6) srgb = srgb.substring(2); state_progress = "#" + srgb; } else { if (switch_state) { state_progress = "000000"; } else { state_progress = "000000"; seekBarHueBar.setProgress(255); seekBarRGBXBar.setProgress(0); seekBarRGBYBar.setProgress(0); } } } updating = 1; JSONObject json_Ack = null; try { //new CallUrl().execute(Url2send, login, password, "3000", String.valueOf(SSL)); send_command.send_it(activity, Tracer, command_id, command_type, String.valueOf(state_progress), api_version); //json_Ack = Rest_com.connect_jsonobject(Url2send, login, password,3000); } catch (Exception e) { Tracer.e(mytag, "Rinor exception sending command <" + e.getMessage() + ">"); } /* try { Boolean ack = JSONParser.Ack(json_Ack); if (!ack) { Tracer.i(mytag, "Received error from Rinor : <" + json_Ack.toString() + ">"); Toast.makeText(activity, "Received error from Rinor", Toast.LENGTH_LONG).show(); handler.sendEmptyMessage(2); } } catch (Exception e) { e.printStackTrace(); } */ } } ); return null; } } /* * Saving HSV parameters allow to restore them when Domogik server * only notify 'on' state (without any RGB parameters) * We've to know which was the last one, kept by Domogik */ private void SaveSelections() { SharedPreferences.Editor prefEditor = params.edit(); prefEditor.putInt("COLORHUE", seekBarHueBar.getProgress()); prefEditor.putInt("COLORSATURATION", seekBarRGBXBar.getProgress()); prefEditor.putInt("COLORBRIGHTNESS", seekBarRGBYBar.getProgress()); prefEditor.putString("COLORRGB", "#" + argbS); prefEditor.commit(); /* Tracer.i(mytag, "SaveSelections()"); Tracer.i(mytag,"Hue = "+params.getInt("COLORHUE",0)); Tracer.i(mytag,"Sat = "+params.getInt("COLORSATURATION",0)); Tracer.i(mytag,"Bright = "+params.getInt("COLORBRIGHTNESS",0)); */ } private void LoadSelections() { seekBarHueBar.setProgress(params.getInt("COLORHUE", 0)); seekBarRGBXBar.setProgress(params.getInt("COLORSATURATION", 255)); seekBarRGBYBar.setProgress(params.getInt("COLORBRIGHTNESS", 255)); /* Tracer.i(mytag, "LoadSelections()"); Tracer.i(mytag,"Hue = "+params.getInt("COLORHUE",0)); Tracer.i(mytag,"Sat = "+params.getInt("COLORSATURATION",0)); Tracer.i(mytag,"Bright = "+params.getInt("COLORBRIGHTNESS",0)); */ } public void onClick(View arg0) { Tracer.i(mytag, "Touch...."); if (featurePan2.getVisibility() == INVISIBLE) { try { LL_background.removeView(featurePan2); } catch (Exception e) { //to avoid #135 } LL_background.addView(featurePan2); featurePan2.setVisibility(VISIBLE); Tracer.i(mytag, "FeaturePan2 set to VISIBLE"); } else { LL_background.removeView(featurePan2); featurePan2.setVisibility(INVISIBLE); Tracer.i(mytag, "FeaturePan2 set to INVISIBLE"); } } }