/*
* This file is part of Domodroid.
*
* Domodroid is Copyright (C) 2011 Pierre LAINE, Maxime CHOFARDET
*
* Domodroid 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.
*
* Domodroid 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
* Domodroid. If not, see <http://www.gnu.org/licenses/>.
*/
package widgets;
import android.app.Activity;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.text.Html;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;
import com.github.curioustechizen.ago.RelativeTimeTextView;
import org.domogik.domodroid13.R;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
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.tracerengine;
import rinor.Rest_com;
import rinor.send_command;
import static activities.Activity_Main.SV_Main_ScrollView;
@SuppressWarnings("ALL")
public class Graphical_List extends Basic_Graphical_widget implements OnClickListener {
private ListView LV_listChoices = new ListView(activity);
;
private ListView LV_listCommands;
private ArrayList<HashMap<String, String>> listItem;
private LinearLayout featurePan2;
private TextView TV_Value;
private RelativeTimeTextView TV_Timestamp;
private Handler handler;
private Message msg;
private static String mytag = "Graphical_List";
public static FrameLayout container = null;
public static FrameLayout myself = null;
public Boolean with_list = true;
private Boolean realtime = false;
private String[] known_values;
private String[] real_values;
JSONObject Values = null;
private ArrayList<HashMap<String, String>> listItemCommands;
private TextView cmd_to_send = null;
private String cmd_requested = null;
private String address;
private String type;
private int id;
private Entity_Feature feature;
private String state_key;
private String parameters;
private int dev_id;
private final int session_type;
private String command_id = null;
private String command_type = null;
private final SharedPreferences params;
private String stateS;
private boolean isopen = false;
private int nb_item_for_history;
private int currentint;
private int sizeint;
public Graphical_List(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_List(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();
}
public void onCreate() {
this.state_key = feature.getState_key();
this.dev_id = feature.getDevId();
this.parameters = feature.getParameters();
this.id = feature.getId();
this.address = feature.getAddress();
this.isopen = false;
try {
String params_nb_item_for_history = params.getString("history_length", "5");
this.nb_item_for_history = Integer.valueOf(params_nb_item_for_history);
} catch (Exception e) {
Tracer.e(mytag, "Error getting number of item to display");
this.nb_item_for_history = 5;
}
String[] model = feature.getDevice_type_id().split("\\.");
this.type = model[0];
String packageName = activity.getPackageName();
this.myself = this;
setOnLongClickListener(this);
setOnClickListener(this);
mytag = "Graphical_List (" + dev_id + ")";
//state key
final TextView state_key_view = new TextView(activity);
try {
stateS = getResources().getString(translate.do_translate(activity, Tracer, state_key));
} catch (Exception e) {
stateS = state_key;
}
state_key_view.setText(stateS);
state_key_view.setTextColor(Color.parseColor("#333333"));
//value
TV_Value = new TextView(activity);
TV_Value.setTextSize(28);
TV_Value.setTextColor(Color.BLACK);
TV_Value.setGravity(Gravity.RIGHT);
Animation animation = new AlphaAnimation(0.0f, 1.0f);
animation.setDuration(1000);
TV_Timestamp = new RelativeTimeTextView(activity, null);
TV_Timestamp.setTextSize(10);
TV_Timestamp.setTextColor(Color.BLUE);
TV_Timestamp.setGravity(Gravity.RIGHT);
if (api_version >= 0.7f) {
//get values from json parameters
JSONObject jparam = null;
try {
jparam = new JSONObject(parameters.replaceAll(""", "\""));
String temp = jparam.getString("values");
Values = new JSONObject(temp.replaceAll(""", "\""));
Tracer.d(mytag, "Json Values :" + Values);
} catch (Exception e) {
Values = null;
Tracer.e(mytag, "Json Values error " + e.toString());
}
}
if (with_list) {
//Exploit parameters
JSONObject jparam = null;
String command;
JSONArray commandValues = null;
try {
jparam = new JSONObject(parameters.replaceAll(""", "\""));
if (api_version < 0.7f) {
command = jparam.getString("command");
commandValues = jparam.getJSONArray("commandValues");
Tracer.d(mytag, "Json command :" + commandValues);
} else if (api_version >= 0.7f) {
//get commands for domogik >= 0.4
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");
Tracer.d(mytag, "Json command_id :" + command_id + " & command_type :" + command_type);
}
}
} catch (Exception e) {
command = "";
commandValues = null;
Tracer.e(mytag, "Json command error " + e.toString());
}
//used in previous version of domogik until 0.3 if commands
if (commandValues != null) {
if (commandValues.length() > 0) {
if (known_values != null)
known_values = null;
known_values = new String[commandValues.length()];
for (int i = 0; i < commandValues.length(); i++) {
try {
known_values[i] = commandValues.getString(i);
} catch (Exception e) {
known_values[i] = "???";
}
}
}
}
// used after domogik 0.4 if commands need to display an open informations
if (command_id != null) {
TV_Value.setTypeface(typefaceawesome, Typeface.NORMAL);
//TV_Value.setRotation(180f);
TV_Value.setText(Html.fromHtml(""), TextView.BufferType.SPANNABLE);
//TV_Value.setText(R.string.open_show_command);
}
// used after domogik 0.4
if (Values != null) {
if (Values.length() > 0) {
if (known_values != null)
known_values = null;
known_values = new String[Values.length()];
real_values = new String[Values.length()];
Iterator<String> iter = Values.keys();
int i = 0;
while (iter.hasNext()) {
String key = iter.next();
try {
known_values[i] = Values.get(key).toString();
real_values[i] = key;
Tracer.d(mytag, "Json key :" + key);
Tracer.d(mytag, "Json value :" + known_values[i]);
} catch (JSONException e) {
known_values[i] = "N/A";
real_values[i] = "";
Tracer.e(mytag, "Json iteration ERROR:" + e.toString());
}
i++;
}
}
}
//list of choices
LV_listCommands = new ListView(activity);
listItemCommands = new ArrayList<HashMap<String, String>>();
//list_usable_choices = new Vector<String>();
for (int i = 0; i < known_values.length; i++) {
//list_usable_choices.add(getStringResourceByName(known_values[i]));
HashMap<String, String> map = new HashMap<String, String>();
try {
map.put("choice", getResources().getString(translate.do_translate(activity, Tracer, (known_values[i]))));
} catch (Exception e) {
map.put("choice", known_values[i]);
}
if (api_version >= 0.7f) {
map.put("cmd_to_send", real_values[i]);
} else {
map.put("cmd_to_send", known_values[i]);
}
listItemCommands.add(map);
}
SimpleAdapter adapter_map = new SimpleAdapter(getContext(), listItemCommands,
R.layout.item_choice, new String[]{"choice", "cmd_to_send"}, new int[]{R.id.choice, R.id.cmd_to_send});
LV_listCommands.setAdapter(adapter_map);
LV_listCommands.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if ((position < listItemCommands.size()) && (position > -1)) {
//process selected command
HashMap<String, String> map = new HashMap<String, String>();
map = listItemCommands.get(position);
cmd_requested = map.get("cmd_to_send");
Tracer.d(mytag, "command selected at Position = " + position + " Command = " + cmd_requested);
send_command.send_it(activity, Tracer, command_id, command_type, cmd_requested, api_version);
}
}
});
//LV_listCommands.setScrollingCacheEnabled(false);
//feature panel 2 which will contain list of selectable choices
featurePan2 = new LinearLayout(activity);
featurePan2.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
featurePan2.setGravity(Gravity.CENTER_VERTICAL);
featurePan2.setPadding(5, 10, 5, 10);
featurePan2.addView(LV_listCommands);
}
super.LL_infoPan.addView(state_key_view);
super.LL_featurePan.addView(TV_Value);
super.LL_featurePan.addView(TV_Timestamp);
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 2) {
Toast.makeText(getContext(), R.string.command_failed, Toast.LENGTH_SHORT).show();
} else if (msg.what == 9999) {
//Message from cache engine
//state_engine send us a signal to notify value changed
if (session == null)
return;
String new_val = session.getValue();
String Value_timestamp = session.getTimestamp();
Tracer.d(mytag, "Handler receives a new value <" + new_val + "> at " + Value_timestamp);
Long Value_timestamplong = null;
Value_timestamplong = Value_timestamplong.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_timestamp.toString(), activity));
} else {
TV_Timestamp.setReferenceTime(Value_timestamplong);
}
if (api_version > 0.7f) {
try {
display_sensor_info.display(Tracer, Values.getString(new_val), Value_timestamplong, mytag, parameters, TV_Value, TV_Timestamp, activity, LL_featurePan, typefaceweather, typefaceawesome, state_key, state_key_view, stateS, "");
} catch (Exception e) {
display_sensor_info.display(Tracer, new_val, Value_timestamplong, mytag, parameters, TV_Value, TV_Timestamp, activity, LL_featurePan, typefaceweather, typefaceawesome, state_key, state_key_view, stateS, "");
Tracer.e(mytag, "Can not convert new_val " + e.toString());
}
} else {
display_sensor_info.display(Tracer, new_val, Value_timestamplong, mytag, parameters, TV_Value, TV_Timestamp, activity, LL_featurePan, typefaceweather, typefaceawesome, state_key, state_key_view, stateS, "");
}
//To have the icon colored as it has no state
change_this_icon(2);
} else if (msg.what == 9998) {
// state_engine send us a signal to notify it'll die !
Tracer.d(mytag, "cache engine disappeared ===> Harakiri !");
session = null;
realtime = false;
removeView(LL_background);
myself.setVisibility(GONE);
if (container != null) {
container.removeView(myself);
container.recomputeViewAttributes(myself);
}
try {
finalize();
} catch (Throwable t) {
} //kill the handler thread itself
}
}
}; //End of handler
//================================================================================
/*
* 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(id, "", 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....
}
private void Hide(Boolean command) {
if (command_id != null) {
TV_Value.setTypeface(typefaceawesome, Typeface.NORMAL);
TV_Value.setText(Html.fromHtml(""), TextView.BufferType.SPANNABLE);
}
isopen = false;
super.LL_background.removeView(featurePan2);
super.LL_background.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
if (command) {
String text_to_display = activity.getResources().getString(R.string.command_sent) + " " + state_key;
Toast.makeText(getContext(), text_to_display, Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onWindowVisibilityChanged(int visibility) {
if (visibility == View.VISIBLE) {
}
}
public void onClick(View v) {
if (with_list) {
//Done correct 350px because it's the source of http://tracker.domogik.org/issues/1804
float size = 262.5f * activity.getResources().getDisplayMetrics().density + 0.5f;
sizeint = (int) size;
currentint = LL_background.getHeight();
if (!isopen) {
this.isopen = true;
Tracer.d(mytag, "on click");
try {
super.LL_background.removeView(featurePan2);
Tracer.d(mytag, "removeView(featurePan2)");
} catch (Exception e) {
}
super.LL_background.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, sizeint));
Tracer.d(mytag, "addView(featurePan2)");
super.LL_background.addView(featurePan2);
this.LV_listCommands.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
SV_Main_ScrollView.requestDisallowInterceptTouchEvent(true);
int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_UP:
SV_Main_ScrollView.requestDisallowInterceptTouchEvent(false);
break;
}
return false;
}
});
// used after domogik 0.4 if commands need to display an open informations
if (command_id != null) {
TV_Value.setTypeface(typefaceawesome, Typeface.NORMAL);
TV_Value.setText(Html.fromHtml(""), TextView.BufferType.SPANNABLE);
}
} else {
Hide(false);
}
} else {
//Done correct 350px because it's the source of http://tracker.domogik.org/issues/1804
float size = ((nb_item_for_history * 35) + 0.5f) * activity.getResources().getDisplayMetrics().density + 0.5f;
int sizeint = (int) size;
int currentint = LL_background.getHeight();
if (!isopen) {
Tracer.d(mytag, "on click");
try {
super.LL_background.removeView(LV_listChoices);
Tracer.d(mytag, "removeView(listeChoices)");
} catch (Exception e) {
e.printStackTrace();
}
Tracer.d(mytag, "getting history");
display_last_value sync = new display_last_value();
sync.execute();
} else {
isopen = false;
super.LL_background.removeView(LV_listChoices);
super.LL_background.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
}
}
}
private class display_last_value extends AsyncTask<Void, Integer, Void> {
@Override
protected void onPreExecute() {
super.onPreExecute();
Toast.makeText(activity, R.string.loading_data_from_rest, Toast.LENGTH_SHORT).show();
}
protected Void doInBackground(Void... params) {
JSONObject json_LastValues = null;
JSONArray itemArray = null;
try {
if (api_version <= 0.6f) {
Tracer.i(mytag, "UpdateThread (" + dev_id + ") : " + "stats/" + dev_id + "/" + state_key + "/last/" + nb_item_for_history + "/");
json_LastValues = Rest_com.connect_jsonobject(activity, Tracer, "stats/" + dev_id +
"/" + state_key +
"/last/" + nb_item_for_history +
"/", 30000);
} else if (api_version >= 0.7f) {
Tracer.i(mytag, "UpdateThread (" + id + ") : " + "sensorhistory/id/" + id + "/last/" + nb_item_for_history);
//Don't forget old "dev_id"+"state_key" is replaced by "id"
JSONArray json_LastValues_0_4 = Rest_com.connect_jsonarray(activity, Tracer, "sensorhistory/id/" + id +
"/last/" + nb_item_for_history + "", 30000);
json_LastValues = new JSONObject();
json_LastValues.put("stats", json_LastValues_0_4);
}
itemArray = json_LastValues.getJSONArray("stats");
if (api_version <= 0.6f) {
for (int i = itemArray.length(); i >= 0; i--) {
try {
HashMap<String, String> map = new HashMap<>();
try {
map.put("TV_Value", activity.getString(translate.do_translate(activity, Tracer, itemArray.getJSONObject(i).getString("TV_Value"))));
} catch (Exception e1) {
map.put("TV_Value", itemArray.getJSONObject(i).getString("TV_Value"));
}
map.put("date", itemArray.getJSONObject(i).getString("date"));
listItem.add(map);
Tracer.d(mytag, map.toString());
} catch (Exception e) {
Tracer.e(mytag, "Error getting json TV_Value");
}
}
} else if (api_version >= 0.7f) {
for (int i = 0; i < itemArray.length(); i++) {
try {
HashMap<String, String> map = new HashMap<>();
String temp_value_str = "";
try {
temp_value_str = Values.getString(itemArray.getJSONObject(i).getString("value_str").toLowerCase());
} catch (Exception e) {
temp_value_str = itemArray.getJSONObject(i).getString("value_str").toLowerCase();
}
try {
map.put("TV_Value", activity.getString(translate.do_translate(activity, Tracer, temp_value_str)));
} catch (Exception e1) {
map.put("TV_Value", temp_value_str);
}
if (api_version == 0.7f) {
map.put("date", itemArray.getJSONObject(i).getString("date"));
} else if (api_version >= 0.8f) {
String currenTimestamp = String.valueOf((long) (itemArray.getJSONObject(i).getInt("timestamp")) * 1000);
map.put("date", display_sensor_info.timestamp_convertion(currenTimestamp, activity));
}
listItem.add(map);
Tracer.d(mytag, map.toString());
} catch (Exception e) {
Tracer.e(mytag, "Error getting json TV_Value");
}
}
}
} catch (Exception e) {
//return null;
Tracer.e(mytag, "Error fetching json object");
}
return null;
}
protected void onPostExecute(Void result) {
SimpleAdapter adapter_feature = new SimpleAdapter(activity, listItem,
R.layout.item_history_in_graphical_history, new String[]{"TV_Value", "date"}, new int[]{R.id.value, R.id.date});
LV_listChoices.setAdapter(adapter_feature);
LV_listChoices.setScrollingCacheEnabled(false);
Tracer.d(mytag, "history is: " + listItem);
if (!listItem.isEmpty()) {
Tracer.d(mytag, "addView(listeChoices)");
LL_background.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, currentint + sizeint));
try {
LL_background.removeView(LV_listChoices);
} catch (Exception e) {
//to avoid #135
}
LL_background.addView(LV_listChoices);
isopen = true;
} else {
Tracer.d(mytag, "history is empty nothing to display");
}
}
}
}