package com.safemobile.safedispatch; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.graphics.Typeface; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.view.View; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.GridView; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import com.safemobile.adapters.ConversationGridViewAdapter; import com.safemobile.adapters.MessagesGridViewAdapter; import com.safemobile.lib.AppParams; import com.safemobile.lib.Msg; import com.safemobile.lib.OperationCodes; import com.safemobile.lib.SM; import com.safemobile.lib.SMS; import com.safemobile.lib.Vehicle; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.Hashtable; import java.util.Locale; import java.util.Objects; /** * fix import */ public class MessagesActivity extends Activity { /** * Called when the activity is first created. */ private MessagesGridViewAdapter mAdapter; private ConversationGridViewAdapter convAdapter; private ArrayList listLastMessages = new ArrayList<>(); private ArrayList listSpecificConversation = new ArrayList<>(); private ArrayList dispatcherPositions = new ArrayList<>(); private GridView gridView; private Context context; private Activity activity; private final Hashtable> tableSMS = new Hashtable<>(); private final Hashtable seqIDSMSHash = new Hashtable<>(); // Need handler for callbacks to the UI thread private final Handler myHandler = new Handler(Looper.getMainLooper()); /* Visual resources */ private LinearLayout layoutSend; private LinearLayout layoutHeader; private LinearLayout layoutHeaderConversation; private TextView textViewSelectedContact; private ImageView imageViewSelectedContact; private Button imageButtonSend; private EditText editTextMsg; private TabLayoutActivity parentTab; /* Message args */ private int ACTION; private static final int MSG_UPDATE = 0; private ArrayList allVehicleNames = new ArrayList<>(); private ArrayList allVehicle = new ArrayList<>(); // tip of Messages and flag first load public boolean LASTMESSAGES = true; private boolean FIRST = true; // store selected scId and selected unitType private long scId = 0; private int unitType = 0; private Bundle savedInstanceState; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.setSavedInstanceState(savedInstanceState); // get parentTab parentTab = (TabLayoutActivity) getParent(); context = this; activity = this; Locale locale = new Locale(AppParams.LANGUAGETMP); Locale.setDefault(locale); Configuration config = new Configuration(); config.locale = locale; getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics()); setContentView(R.layout.tabtext); // get LayoutSend and hide layoutSend = findViewById(R.id.layoutSendMsg); layoutSend.setVisibility(View.GONE); // get header layout layoutHeader = findViewById(R.id.layoutHeader); layoutHeaderConversation = findViewById(R.id.layoutHeaderConversation); // show only header layout layoutHeaderConversation.setVisibility(View.GONE); // get SelectedContact TextView and ImageView textViewSelectedContact = findViewById(R.id.textViewSelectedContact); imageViewSelectedContact = findViewById(R.id.imageViewSelectedContact); ImageView imageBarcode = findViewById(R.id.imageBarcode); imageBarcode.setOnClickListener(v -> { try { Intent intent = new Intent("com.google.zxing.client.android.SCAN"); startActivityForResult(intent, 0); } catch (Exception e) { showErrorDialog(getResources().getString(R.string.barcodeError)); } }); // change tab header fontFace TextView textView1 = findViewById(R.id.textView1); textView1.setTypeface(Typeface.createFromAsset(getAssets(), "Sketch_Block.ttf")); textView1.setTextSize(24); // prepared arraylist and passed it to the Adapter class mAdapter = new MessagesGridViewAdapter(this, listLastMessages); convAdapter = new ConversationGridViewAdapter(this, listSpecificConversation, dispatcherPositions, new ArrayList<>()); // Set custom adapter to gridview gridView = findViewById(R.id.gridView1); gridView.setAdapter(mAdapter); // Implement On Item click listener gridView.setOnItemClickListener((arg0, arg1, position, arg3) -> { if (LASTMESSAGES) { // get position Msg item = mAdapter.getItem(position); // get Specific Conversation setScId(item.from.sc_id); SM.Debug("Selected scId: " + getScId()); // set Conversation type LASTMESSAGES = false; // call get SMS getSMS4unit(getScId()); // create crt_Vehicle setUnitType((int) item.from.driver_id); // save selected vehicle } if (AppParams.DEMO) { // modify UI ACTION = MSG_UPDATE; updateResultsInUi(); } }); /* Buttons and EditBoxes */ ImageButton imageButtonAdd = findViewById(R.id.imageButtonAdd); imageButtonAdd.setOnClickListener(v -> showDialog()); // button send message imageButtonSend = findViewById(R.id.imageButtonSend); imageButtonSend.setOnClickListener(v -> { sendSMS(getScId(), editTextMsg.getText().toString()); Toast.makeText(context, "Sending message...", Toast.LENGTH_SHORT).show(); // disable send button and editBox editTextMsg.setEnabled(false); imageButtonSend.setEnabled(false); new Thread(() -> { try { Thread.sleep(500); myHandler.post(enableButtonRUN); if (AppParams.DEMO) { Thread.sleep(5500); myHandler.post(demoReceivedSMSRUN); } } catch (InterruptedException e) { e.printStackTrace(); Thread.currentThread().interrupt(); } }).start(); }); // button back to conversations ImageButton imageButtonBack = findViewById(R.id.imageButtonBack); imageButtonBack.setOnClickListener(v -> { // set LastMessage conversation type LASTMESSAGES = true; // refresh Grid getLastSMS(); if (AppParams.DEMO) updateResultsInUi(); }); // get Message editText editTextMsg = findViewById(R.id.editTextMsg); gridView.setId(1); // id needed for IconContextMenu registerForContextMenu(gridView); parentTab.setMessageActivity(this); } // Create runnable for posting final Runnable demoReceivedSMSRUN = new Runnable() { public void run() { parentTab.setImei(getScId() + ""); parentTab.updateResultsInUi("realpha"); int timeGMT = (int) (System.currentTimeMillis() / 1000L); String sendSMSSeqID = "1." + timeGMT; // add mess to not ack list seqIDSMSHash.put(sendSMSSeqID, getScId()); // get scId conversation and add message ArrayList crtSmsList = tableSMS.get(getScId()); SMS sms = new SMS(0, 0, timeGMT, "i got your sms", 0, getScId()); sms.seq_idx = sendSMSSeqID; if (crtSmsList != null) crtSmsList.add(sms); // add message to listLast boolean exists = false; for (Msg msg : listLastMessages) // if conversation exists in lastMessages if (msg.from.sc_id == getScId()) { exists = true; msg.message = "i got your sms"; msg.received = Calendar.getInstance().getTime(); } // if last messages doesn't contain this conversation if (!exists) { Vehicle sentVehicle = null; for (Vehicle veh : getAllVehicle()) if (veh.sc_id == getScId()) sentVehicle = veh; listLastMessages.add(new Msg(sentVehicle, "i got your sms", Calendar.getInstance().getTime(), sendSMSSeqID)); } SM.Debug("time: " + timeGMT + " | " + Calendar.getInstance().getTime()); updateResultsInUi(); } }; @Override public void onBackPressed() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage(getString(R.string.exit)) .setCancelable(false) .setNeutralButton(getString(R.string.logout), (dialog, id) -> parentTab.whenBackPressed(AppParams.ActivityResult.logout)) .setPositiveButton(getString(R.string.ext), (dialog, id) -> parentTab.whenBackPressed(AppParams.ActivityResult.exit)) .setNegativeButton(getString(R.string.cancel), (dialog, id) -> dialog.cancel()); AlertDialog alert = builder.create(); alert.show(); } @Override public void onPause() { super.onPause(); SM.Debug("onPause"); } @Override public void onResume() { super.onResume(); if (parentTab.getTCPState() != null && FIRST) { updateVehicles(parentTab.getAllVehicle()); FIRST = false; if (LASTMESSAGES) parentTab.executeNetworkStuff(new String[]{OperationCodes.GetLastSMS + "", AppParams.USERID + ""}); } SM.Debug("onResume"); } @Override public void onActivityResult(int requestCode, int resultCode, Intent intent) { if (requestCode == 0 && resultCode == RESULT_OK) { String contents = intent.getStringExtra("SCAN_RESULT"); String format = intent.getStringExtra("SCAN_RESULT_FORMAT"); editTextMsg.setText(String.format("%s%s", editTextMsg.getText().toString(), contents)); // Handle successful scan Toast.makeText(this, getResources().getString(R.string.barcodeContent) + ":" + contents + " with format:" + format, Toast.LENGTH_LONG).show(); } } // Request SMS 4 Unit from AppServer private void getSMS4UnitWithTime(long scId, long time) { if (!AppParams.DEMO) { parentTab.executeNetworkStuff(new String[]{OperationCodes.GetRecentSMSs + "", scId + "", time + ""}); SM.Debug(" #### GetSMS4uni:" + scId); } } private void getSMS4unit(long scId) { if (!AppParams.DEMO) { SM.Debug("getSMS4unit : " + scId); ArrayList listSMS = tableSMS.get(scId); long timeGMT = 0; if (listSMS != null && !listSMS.isEmpty()) timeGMT = listSMS.get(listSMS.size() - 1).timeGMT; // error in DB if (String.valueOf(timeGMT).contains(".")) { try { // remove the dot and the parse it to String timeGMT = Long.parseLong(String.valueOf(timeGMT).split("\\.")[1]); } catch (Exception e) { timeGMT = Long.parseLong(String.valueOf(timeGMT).replace(".", "")); } } parentTab.executeNetworkStuff(new String[]{OperationCodes.GetRecentSMSs + "", scId + "", timeGMT + ""}); SM.Debug(" #### GetSMS4uni:" + scId); } } // Request Last SMS from AppServer public void getLastSMS() { if (!AppParams.DEMO) { if (LASTMESSAGES) parentTab.executeNetworkStuff(new String[]{OperationCodes.GetLastSMS + "", AppParams.USERID + ""}); else { ArrayList listSMS = tableSMS.get(getScId()); long timeGMT = 0; if (listSMS != null && !listSMS.isEmpty()) timeGMT = listSMS.get(listSMS.size() - 1).timeGMT; parentTab.executeNetworkStuff(new String[]{OperationCodes.GetRecentSMSs + "", getScId() + "", timeGMT + ""}); } } else updateResultsInUi(); } private void sendSMS(long scIdd, String txt) { if (!AppParams.DEMO) { int timeGMT = (int) (System.currentTimeMillis() / 1000L); String sendSMSSeqID = "1." + timeGMT; // add mess to not ack list seqIDSMSHash.put(sendSMSSeqID, scIdd); // get scId conversation and add message SMS sms = new SMS(0, 0, timeGMT, txt, scIdd, 0); sms.seq_idx = sendSMSSeqID; tableSMS.get(scIdd).add(sms); parentTab.executeNetworkStuff(new String[]{OperationCodes.SEND_TM + "", sendSMSSeqID, scIdd + "", txt}); updateResultsInUi(); } else { int timeGMT = (int) (System.currentTimeMillis() / 1000L); String sendSMSSeqID = "1." + timeGMT; // add mess to not ack list seqIDSMSHash.put(sendSMSSeqID, scIdd); // get scId conversation and add message ArrayList crtSmsList = tableSMS.get(scIdd); SMS sms = new SMS(0, 0, timeGMT, txt, scIdd, 0); sms.seq_idx = sendSMSSeqID; crtSmsList.add(sms); // add message to listLast boolean exists = false; for (Msg msg : listLastMessages) // if conversation exists in lastMessages if (msg.from.sc_id == scIdd) { exists = true; msg.message = txt; msg.received = Calendar.getInstance().getTime(); } // if last messages doesn't contain this conversation if (!exists) { Vehicle sentVehicle = null; for (Vehicle veh : getAllVehicle()) if (veh.sc_id == scIdd) sentVehicle = veh; listLastMessages.add(new Msg(sentVehicle, txt, Calendar.getInstance().getTime(), sendSMSSeqID)); } SM.Debug("time: " + timeGMT + " | " + Calendar.getInstance().getTime()); LASTMESSAGES = false; updateResultsInUi(); } } // Update Vehicles received from AppServer public void updateVehicles(ArrayList list) { SM.Debug("## updateVehicles: " + list.size()); setAllVehicle(list); allVehicleNames = new ArrayList<>(); for (Vehicle v : getAllVehicle()) allVehicleNames.add(v.name); if (tableSMS.size() == 0) { for (Vehicle veh : getAllVehicle()) { ArrayList smsList = new ArrayList<>(); // populate conversation list if demo if (AppParams.DEMO) smsList = getDemoConversation(veh.sc_id); tableSMS.put(veh.sc_id, smsList); } } } // gets DEMO conversations private ArrayList getDemoConversation(long scId) { ArrayList smsList = new ArrayList<>(); if (scId == 101) smsList.add(new SMS(1, 2, 1324016412, "Only one left", 101, 0)); else if (scId == 102) smsList.add(new SMS(1, 2, 1328060100, "i'm at the train station", 0, 102)); else if (scId == 103) { smsList.add(new SMS(1, 2, 1121016637, "Where are you now?", 103, 0)); smsList.add(new SMS(2, 2, 1121016693, "Near Elementary School 81", 0, 103)); smsList.add(new SMS(3, 2, 1121016693, "We have a client on Belmont Ave", 103, 0)); smsList.add(new SMS(4, 2, 1121016724, "It's only 4 blocks away", 103, 0)); smsList.add(new SMS(5, 2, 1121016693, "Can you take him?", 103, 0)); smsList.add(new SMS(6, 2, 1121016818, "I'll be right there", 0, 103)); } else if (scId == 105) smsList.add(new SMS(1, 2, 1328061660, "Thanks", 0, 105)); return smsList; } public void updateSMS(ArrayList list) { SM.Debug("## updateSMS: " + list.size() + " [LASTMESSAGES:" + LASTMESSAGES + "]"); // populate listLastMessages if (LASTMESSAGES) { listLastMessages = new ArrayList<>(); for (SMS sms : list) { // get for sender long senderId = sms.sc_id_dest; if (senderId == 0) senderId = sms.sc_id_sour; // get vehicle with sender id Vehicle messageVeh; messageVeh = getVehicleById(senderId); listLastMessages.add(0, new Msg(messageVeh, sms.mess, new Date((long) sms.timeGMT * 1000), sms.seq_idx)); } // update GridView mAdapter = new MessagesGridViewAdapter(activity, listLastMessages); } else { // add new values to hashTable for key = scId ArrayList listScId = tableSMS.get(getScId()); if (!list.isEmpty()) for (SMS sms : list) { // compare last item in hashList with first elem in arrived list // protect is listSc_Id size = 0 if (listScId != null && (listScId.isEmpty() || (sms.sc_id_dest != listScId.get(listScId.size() - 1).sc_id_dest || sms.sc_id_sour != listScId.get(listScId.size() - 1).sc_id_sour || !Objects.equals(sms.mess, listScId.get(listScId.size() - 1).mess)))) listScId.add(sms); } } // modify UI ACTION = MSG_UPDATE; myHandler.post(this::updateResultsInUi); } // Confirmation for sending message public void confirmSMS(String data, final String seqID) { SM.Debug("confirmSMS"); if (data.equals("0")) { SM.Debug("Error on sending SMS"); showErrorDialog("Error on sending message."); } else { SM.Debug("ACK received for text message"); //get scId for crt message long scId = seqIDSMSHash.get(seqID); // get SMS list for crt scId ArrayList crtSMSList = tableSMS.get(scId); if (crtSMSList != null) { for (SMS sms : crtSMSList) { if (sms.seq_idx.equals(seqID)) { SM.Debug("######### AM SCHIMBAT STATUSUL pt: " + sms.mess + " | " + scId + " | " + seqID + " || " + sms.seq_idx); // set ACK sms.status = 2; } } } // remove message from seqIDSMS Hash = don't wait confirmation for it seqIDSMSHash.remove(seqID); // store sms seqId to set to ACK in adapter myHandler.post(() -> { convAdapter.setACK(seqID); convAdapter.changeView(seqID); convAdapter.notifyDataSetChanged(); }); myHandler.post(() -> editTextMsg.setText("")); } } public void newSMS(String imei, String message, final long time) { SM.Debug(" ## newSMS: " + imei + " | " + message); if (!LASTMESSAGES) { // if received message from current conversation if (getVehicleByImei(imei).sc_id == getScId()) getSMS4UnitWithTime(getScId(), time); // refresh MSG List } else getLastSMS(); // get last SMS } // Create runnable for posting final Runnable enableButtonRUN = this::updateEnableButtonsUI; // enable buttons in UI after 200ms from send private void updateEnableButtonsUI() { // enable buttons imageButtonSend.setEnabled(true); editTextMsg.setEnabled(true); editTextMsg.setText(""); } private void updateResultsInUi() { if (getAllVehicle() == null) updateVehicles(parentTab.getAllVehicle()); if (ACTION == MSG_UPDATE) { if (LASTMESSAGES) { // show Header Layout layoutHeader.setVisibility(View.VISIBLE); // hide Conversation Header Layout layoutHeaderConversation.setVisibility(View.GONE); // hide Send Layout layoutSend.setVisibility(View.GONE); // change GridView adapter gridView.setAdapter(mAdapter); gridView.invalidate(); } else { SM.Debug(" #### Modify adapter for SMS4unit"); // populate specific conversation listSpecificConversation = new ArrayList<>(); dispatcherPositions = new ArrayList<>(); ArrayList ackPosition = new ArrayList<>(); ArrayList list; list = tableSMS.get(getScId()); if (list != null) { for (SMS sms : list) { // get for sender long senderId = sms.sc_id_dest; if (senderId == 0) senderId = sms.sc_id_sour; // get vehicle with sender id Vehicle messageVeh; messageVeh = getVehicleById(senderId); // flag dispatcher message when source is 0 dispatcherPositions.add(sms.sc_id_sour == 0); ackPosition.add(sms.status == 2); listSpecificConversation.add(new Msg(messageVeh, sms.mess, new Date((long) sms.timeGMT * 1000), sms.seq_idx)); } } convAdapter = new ConversationGridViewAdapter(activity, listSpecificConversation, dispatcherPositions, ackPosition); gridView.setAdapter(convAdapter); if (!listSpecificConversation.isEmpty()) gridView.setSelection(listSpecificConversation.size() - 1); // set unit name and image in Header Conversation textViewSelectedContact.setText(getVehicleByScId(getScId()).name); imageViewSelectedContact.setImageResource(getVehicleByScId(getScId()).getLargeIcon()); // clear editText editTextMsg.setText(""); // change layouts visibility layoutSend.setVisibility(View.VISIBLE); layoutHeader.setVisibility(View.GONE); layoutHeaderConversation.setVisibility(View.VISIBLE); } gridView.invalidate(); } } // gets Vehicle from id public Vehicle getVehicleById(long vehicleId) { for (Vehicle vehicle : getAllVehicle()) if (vehicle.sc_id == vehicleId) return vehicle; return null; } // get Vehicle from imei public Vehicle getVehicleByImei(String imei) { for (Vehicle vehicle : getAllVehicle()) if (vehicle.imei.equalsIgnoreCase(imei)) return vehicle; return null; } public Vehicle getVehicleByScId(long scId) { for (Vehicle vehicle : getAllVehicle()) if (vehicle.sc_id == scId) return vehicle; return null; } // show a dialog public void showDialog() { ArrayAdapter adapter = new ArrayAdapter<>(this, R.layout.template_simple_list_item, allVehicleNames); AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(getString(R.string.selectVehicle)); builder.setAdapter(adapter, (dialog, which) -> { // get position Vehicle item = getAllVehicle().get(which); // get Specific Conversation setScId(item.sc_id); SM.Debug("Selected scId: " + getScId()); // set Conversation type LASTMESSAGES = false; // call get SMS getSMS4unit(getScId()); // create crt_Vehicle setUnitType((int) item.driver_id); SM.Debug("AM SELECTAT: " + getScId() + " | " + item.name + " | " + getUnitType() + "\n\t " + item); if (AppParams.DEMO) updateResultsInUi(); }); AlertDialog alert = builder.create(); alert.show(); } public void showErrorDialog(String errorMsg) { Dialog dialog = new Dialog(context); dialog.setTitle(getString(R.string.sendingError)); dialog.setContentView(R.layout.dialog); dialog.setCancelable(true); dialog.setCanceledOnTouchOutside(true); TextView text = dialog.findViewById(R.id.text); ImageView image = dialog.findViewById(R.id.image); image.setImageResource(R.drawable.error); text.setText(errorMsg); dialog.show(); } public ArrayList getAllVehicle() { return allVehicle; } public void setAllVehicle(ArrayList allVehicle) { this.allVehicle = allVehicle; } public long getScId() { return scId; } public void setScId(long scId) { this.scId = scId; } public int getUnitType() { return unitType; } public void setUnitType(int unitType) { this.unitType = unitType; } public Bundle getSavedInstanceState() { return savedInstanceState; } public void setSavedInstanceState(Bundle savedInstanceState) { this.savedInstanceState = savedInstanceState; } }