Commit 95a288c3 by Simhachalam ch

added logs for chat freeze issue debugging

parent cafce5d8
...@@ -79,17 +79,13 @@ android { ...@@ -79,17 +79,13 @@ android {
dependencies { dependencies {
def appCenterSdkVersion = '2.3.0' def appCenterSdkVersion = '2.3.0'
implementation fileTree(include: ['*.jar'], dir: 'libs') implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.volley:volley:1.1.+' implementation 'com.android.volley:volley:1.1.+'
implementation('com.microsoft.aad:adal:1.14.+') { implementation('com.microsoft.aad:adal:1.14.+') {
exclude group: 'com.android.support' exclude group: 'com.android.support'
} }
implementation "com.microsoft.appcenter:appcenter-analytics:${appCenterSdkVersion}" implementation "com.microsoft.appcenter:appcenter-analytics:${appCenterSdkVersion}"
implementation "com.microsoft.appcenter:appcenter-crashes:${appCenterSdkVersion}" implementation "com.microsoft.appcenter:appcenter-crashes:${appCenterSdkVersion}"
implementation 'com.android.support:design:28.0.0' implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support:support-annotations:28.0.0' implementation 'com.android.support:support-annotations:28.0.0'
implementation 'android.arch.lifecycle:extensions:1.1.1' implementation 'android.arch.lifecycle:extensions:1.1.1'
...@@ -101,7 +97,6 @@ dependencies { ...@@ -101,7 +97,6 @@ dependencies {
implementation('com.google.android.gms:play-services-analytics:16.0.8') { implementation('com.google.android.gms:play-services-analytics:16.0.8') {
exclude group: 'com.google.firebase', module: 'firebase-iid' exclude group: 'com.google.firebase', module: 'firebase-iid'
} }
implementation 'com.googlecode.android-query:android-query:0.25.9' implementation 'com.googlecode.android-query:android-query:0.25.9'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1' annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
implementation('com.crashlytics.sdk.android:crashlytics:2.9.0@aar') { implementation('com.crashlytics.sdk.android:crashlytics:2.9.0@aar') {
...@@ -124,14 +119,14 @@ dependencies { ...@@ -124,14 +119,14 @@ dependencies {
implementation 'de.hdodenhof:circleimageview:3.0.0' implementation 'de.hdodenhof:circleimageview:3.0.0'
implementation 'com.github.bumptech.glide:glide:4.8.0' implementation 'com.github.bumptech.glide:glide:4.8.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
// implementation 'com.quickbirdstudios:opencv:4.1.0' // implementation 'com.quickbirdstudios:opencv:4.1.0'
implementation 'org.jsoup:jsoup:1.11.3' implementation 'org.jsoup:jsoup:1.11.3'
//static Reports Screen //static Reports Screen
implementation 'com.numetriclabz.numandroidcharts:numandroidcharts:1.0.9' implementation 'com.numetriclabz.numandroidcharts:numandroidcharts:1.0.9'
implementation 'info.hoang8f:android-segmented:1.0.6' implementation 'info.hoang8f:android-segmented:1.0.6'
implementation 'com.github.PhilJay:MPAndroidChart:v2.1.6' implementation 'com.github.PhilJay:MPAndroidChart:v2.1.6'
implementation 'com.android.support:multidex:1.0.3' implementation 'com.android.support:multidex:1.0.3'
implementation files('libs/opencsv-4.6.jar')
} }
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'
No preview for this file type
...@@ -157,10 +157,6 @@ public class CatalogueApplication extends MultiDexApplication { ...@@ -157,10 +157,6 @@ public class CatalogueApplication extends MultiDexApplication {
mSocket = IO.socket(Constants.CHAT_SERVER_URL,options); mSocket = IO.socket(Constants.CHAT_SERVER_URL,options);
mSocket.io().timeout(-1);
mSocket.io().reconnection(true);
mSocket.io().reconnectionDelay(0);
mSocket.io().reconnectionAttempts(2000);
} catch (URISyntaxException e) { } catch (URISyntaxException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
......
...@@ -2,6 +2,7 @@ package com.vsoft.vera.db; ...@@ -2,6 +2,7 @@ package com.vsoft.vera.db;
public interface DBConstants { public interface DBConstants {
//Tables //Tables
String TABLE_CHAT_LOG = "chat_log";
String TABLE_CATALOGUE = "catalogue_category"; String TABLE_CATALOGUE = "catalogue_category";
String TABLE_CATALOGUE_ITEM = "catalogue_category_item"; String TABLE_CATALOGUE_ITEM = "catalogue_category_item";
String TABLE_CATALOGUE_VARIABLES = "catalogue_variable"; String TABLE_CATALOGUE_VARIABLES = "catalogue_variable";
...@@ -41,6 +42,15 @@ public interface DBConstants { ...@@ -41,6 +42,15 @@ public interface DBConstants {
int SYNC_FLAG_DELETE = 3; int SYNC_FLAG_DELETE = 3;
/** /**
* Chat log table
*/
String CHAT_ID = "chat_id";
String CHAT_CLIENT_MESSAGE = "client_message";
String CHAT_SERVER__RESPONSE = "title";
String CHAT_TIMESTAMP = "description";
String CHAT_CONN_STATUS= "icon";
/**
* Catalogue table * Catalogue table
*/ */
String CATALOGUE_ID = ID; String CATALOGUE_ID = ID;
...@@ -405,6 +415,8 @@ public interface DBConstants { ...@@ -405,6 +415,8 @@ public interface DBConstants {
*/ */
int CHAT_BOT_HISTORY_COLUMN_COUNT = 5; int CHAT_BOT_HISTORY_COLUMN_COUNT = 5;
int CHAT_LOG__COLUMN_COUNT = 5;
/** /**
* ChatBot User table * ChatBot User table
*/ */
......
...@@ -40,6 +40,7 @@ public class DBManager extends SQLiteOpenHelper implements DBConstants { ...@@ -40,6 +40,7 @@ public class DBManager extends SQLiteOpenHelper implements DBConstants {
createCatalogueItemInputTable(db); createCatalogueItemInputTable(db);
createAttachmentTable(db); createAttachmentTable(db);
createIncidentInputTable(db); createIncidentInputTable(db);
createChatLogTable(db);
// if(Util.isNotificationsItemEnabled()) { // if(Util.isNotificationsItemEnabled()) {
// createNotificationsTable(db); // createNotificationsTable(db);
...@@ -76,6 +77,16 @@ public class DBManager extends SQLiteOpenHelper implements DBConstants { ...@@ -76,6 +77,16 @@ public class DBManager extends SQLiteOpenHelper implements DBConstants {
onCreate(db); onCreate(db);
} }
private void createChatLogTable(SQLiteDatabase db) {
db.execSQL("create table " + TABLE_CHAT_LOG + "("
+ CHAT_ID + " integer primary key autoincrement, "
+ CHAT_CLIENT_MESSAGE + " text, "
+ CHAT_SERVER__RESPONSE + " text, "
+ CHAT_TIMESTAMP + " text, "
+ CHAT_CONN_STATUS + " text"
+ ");");
}
private void createCatalogueTable(SQLiteDatabase db) { private void createCatalogueTable(SQLiteDatabase db) {
db.execSQL("create table " + TABLE_CATALOGUE + "(" db.execSQL("create table " + TABLE_CATALOGUE + "("
+ CATALOGUE_ID + " integer primary key autoincrement, " + CATALOGUE_ID + " integer primary key autoincrement, "
......
package com.vsoft.vera.db.managers;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import com.vsoft.vera.CatalogueApplication;
import com.vsoft.vera.db.DBConstants;
import com.vsoft.vera.db.models.ChatBotHistory;
import com.vsoft.vera.utils.ChatLog;
import com.vsoft.vera.utils.Util;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
*
* @author Kunj on 05-04-2018.
*/
public class ChatLogManager implements DBConstants {
public static long save(ChatLog chatLog) {
SQLiteDatabase db = CatalogueApplication.getDatabase();
if (db != null) {
long id = db.insert(TABLE_CHAT_LOG, null, getChatLogContentValues(chatLog));
chatLog.setChatId(id);
return id;
} else {
return -1;
}
}
public static List<ChatLog> getAllChatLogHistory() {
SQLiteDatabase db = CatalogueApplication.getDatabase();
if (db != null) {
String queryString = "select * from " + TABLE_CHAT_LOG +";";
Cursor c = db.rawQuery(queryString, null);
ArrayList<ChatLog> chatLogList;
if (c.getCount() > 0) {
chatLogList = new ArrayList<>(c.getCount());
while (c.moveToNext()) {
ChatLog chatLog = new ChatLog();
chatLog.setChatId(c.getLong(0));
chatLog.setClientMessage(c.getString(1));
chatLog.setServerResponse(c.getString(2));
chatLog.setTimestamp(c.getString(3));
chatLog.setConnStatus(c.getString(4));
chatLogList.add(chatLog);
}
} else {
chatLogList = new ArrayList<>(0);
}
c.close();
return chatLogList;
} else {
return new ArrayList<>(0);
}
}
public static int deleteAllRows() {
SQLiteDatabase db = CatalogueApplication.getDatabase();
if (db != null) {
return db.delete(TABLE_CHAT_LOG, null, null);
}
return -1;
}
public static void saveLogEvent(String clientMsg, String serverMsg, String connStatus, Date timestamp){
ChatLog chatLog = new ChatLog();
chatLog.setTimestamp(Util.getDateTime(timestamp.getTime()));
chatLog.setServerResponse(serverMsg);
chatLog.setClientMessage(clientMsg);
chatLog.setConnStatus(connStatus);
ChatLogManager.save(chatLog);
}
private static ContentValues getChatLogContentValues(ChatLog chatLog) {
ContentValues cv = new ContentValues(CHAT_LOG__COLUMN_COUNT - 1);
cv.put(CHAT_CLIENT_MESSAGE, chatLog.getClientMessage());
cv.put(CHAT_SERVER__RESPONSE, chatLog.getServerResponse());
cv.put(CHAT_TIMESTAMP, chatLog.getTimestamp());
cv.put(CHAT_CONN_STATUS, chatLog.getConnStatus());
return cv;
}
}
\ No newline at end of file
...@@ -55,6 +55,7 @@ import com.bumptech.glide.request.target.SimpleTarget; ...@@ -55,6 +55,7 @@ import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.transition.Transition; import com.bumptech.glide.request.transition.Transition;
import com.github.nkzawa.emitter.Emitter; import com.github.nkzawa.emitter.Emitter;
import com.github.nkzawa.socketio.client.Socket; import com.github.nkzawa.socketio.client.Socket;
import com.opencsv.CSVWriter;
import com.vsoft.vera.CatalogueApplication; import com.vsoft.vera.CatalogueApplication;
import com.vsoft.vera.R; import com.vsoft.vera.R;
import com.vsoft.vera.api.listeners.get.GetLiveAgentApiListener; import com.vsoft.vera.api.listeners.get.GetLiveAgentApiListener;
...@@ -70,6 +71,7 @@ import com.vsoft.vera.chat.Speaker; ...@@ -70,6 +71,7 @@ import com.vsoft.vera.chat.Speaker;
import com.vsoft.vera.db.DBConstants; import com.vsoft.vera.db.DBConstants;
import com.vsoft.vera.db.managers.ChatBotHistoryManager; import com.vsoft.vera.db.managers.ChatBotHistoryManager;
import com.vsoft.vera.db.managers.ChatBotUserManager; import com.vsoft.vera.db.managers.ChatBotUserManager;
import com.vsoft.vera.db.managers.ChatLogManager;
import com.vsoft.vera.db.models.ChatBotHistory; import com.vsoft.vera.db.models.ChatBotHistory;
import com.vsoft.vera.db.models.ChatBotUser; import com.vsoft.vera.db.models.ChatBotUser;
import com.vsoft.vera.db.models.UserApiValues; import com.vsoft.vera.db.models.UserApiValues;
...@@ -78,6 +80,7 @@ import com.vsoft.vera.speechRecognizer.DroidSpeech; ...@@ -78,6 +80,7 @@ import com.vsoft.vera.speechRecognizer.DroidSpeech;
import com.vsoft.vera.speechRecognizer.OnDSListener; import com.vsoft.vera.speechRecognizer.OnDSListener;
import com.vsoft.vera.speechRecognizer.OnDSPermissionsListener; import com.vsoft.vera.speechRecognizer.OnDSPermissionsListener;
import com.vsoft.vera.utils.CatalogueLog; import com.vsoft.vera.utils.CatalogueLog;
import com.vsoft.vera.utils.ChatLog;
import com.vsoft.vera.utils.Constants; import com.vsoft.vera.utils.Constants;
import com.vsoft.vera.utils.DialogUtils; import com.vsoft.vera.utils.DialogUtils;
import com.vsoft.vera.utils.GenerateRandomString; import com.vsoft.vera.utils.GenerateRandomString;
...@@ -94,6 +97,7 @@ import org.json.JSONObject; ...@@ -94,6 +97,7 @@ import org.json.JSONObject;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -395,6 +399,8 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD ...@@ -395,6 +399,8 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
}); });
mMessagesView.addOnItemTouchListener(mOnItemTouchListener); mMessagesView.addOnItemTouchListener(mOnItemTouchListener);
} }
private void readAndWriteCallsData() { private void readAndWriteCallsData() {
...@@ -588,16 +594,62 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD ...@@ -588,16 +594,62 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
finish(); finish();
return true; return true;
/*case R.id.voice_menu_icon: case R.id.export_log:
//get all logs
List<ChatLog> chatLogList = ChatLogManager.getAllChatLogHistory();
Log.i(TAG, "chat log list count = "+ chatLogList.size());
exportAndSaveLogs(chatLogList);
//delete all logs
ChatLogManager.deleteAllRows();
return true; return true;
case R.id.text_menu_icon: /* case R.id.text_menu_icon:
return true;*/ return true;*/
default: default:
return super.onOptionsItemSelected(menuItem); return super.onOptionsItemSelected(menuItem);
} }
} }
private void exportAndSaveLogs(List<ChatLog> chatLogList) {
String baseDir = android.os.Environment.getExternalStorageDirectory().getAbsolutePath();
String fileName = "chatlog.csv";
String filePath = baseDir + File.separator + fileName;
File f = new File(filePath);
CSVWriter writer;
// File exist
if (f.exists() && !f.isDirectory()) {
FileWriter mFileWriter = null;
try {
mFileWriter = new FileWriter(filePath, true);
writer = new CSVWriter(mFileWriter);
for (ChatLog chat: chatLogList) {
String[] line = {""+chat.getChatId(),chat.getClientMessage(), chat.getServerResponse(), chat.getConnStatus(), chat.getTimestamp() } ;
writer.writeNext(line);
}
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
} else {
try {
writer = new CSVWriter(new FileWriter(filePath));
String[] headerLine = {"Chat Id","Client Msg","Server Msg", "Conn Status" , "Time Stamp"} ;
writer.writeNext(headerLine);
for (ChatLog chat: chatLogList) {
String[] line = {""+chat.getChatId(),chat.getClientMessage(), chat.getServerResponse(), chat.getConnStatus(), chat.getTimestamp() } ;
writer.writeNext(line);
}
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/** /**
* this message calls when we will add send and receive message in chat screen. * this message calls when we will add send and receive message in chat screen.
*/ */
...@@ -666,26 +718,27 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD ...@@ -666,26 +718,27 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
*/ */
private void attemptSend() { private void attemptSend() {
if (NetworkConnectivity.haveNetworkConnection(ChatActivity.this)) { if (NetworkConnectivity.haveNetworkConnection(ChatActivity.this)) {
String message = mInputMessageView.getText().toString().trim(); String message = mInputMessageView.getText().toString().trim();
if (!TextUtils.isEmpty(message)){ if (!TextUtils.isEmpty(message)){
if (null == mLoggedInUsername) return; if (null == mLoggedInUsername) return;
if (!mSocket.connected())
return;
//Whenever we'll click on send button, running TTS speak should stop //Whenever we'll click on send button, running TTS speak should stop
if(speaker != null && speaker.isSpeaking()) { if(speaker != null && speaker.isSpeaking()) {
speaker.stop(); speaker.stop();
} }
textDotLoader.show();
if (TextUtils.isEmpty(message)) { /**
mInputMessageView.requestFocus(); * checking socket connection, if it is false,
* then we are reconnecting and send the message again
*/
if (!mSocket.connected()){
showSocketConnectError();
mSocket.connect();
return; return;
} }
textDotLoader.show();
mInputMessageView.setText(""); mInputMessageView.setText("");
addMessage(mLoggedInUsername, message,""); addMessage(mLoggedInUsername, message,"");
...@@ -701,9 +754,15 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD ...@@ -701,9 +754,15 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
} catch (JSONException e) { } catch (JSONException e) {
e.printStackTrace(); e.printStackTrace();
} }
Log.i("Print", jsonObject.toString());
mSocket.emit(NEW_MESSAGE, jsonObject); mSocket.emit(NEW_MESSAGE, jsonObject);
ChatLogManager.saveLogEvent(message,"","true",new Date().toString());
} else { } else {
mInputMessageView.requestFocus();
Toast toast = Toast.makeText(getApplicationContext(), "Please enter the message", Toast.LENGTH_LONG); Toast toast = Toast.makeText(getApplicationContext(), "Please enter the message", Toast.LENGTH_LONG);
View toastView = toast.getView(); // This'll return the default View of the Toast. View toastView = toast.getView(); // This'll return the default View of the Toast.
...@@ -741,6 +800,9 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD ...@@ -741,6 +800,9 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
@Override @Override
public void run() { public void run() {
// userAuthenticateTask(); // userAuthenticateTask();
Log.e(TAG, "socket got connected");
// Toast.makeText(getApplicationContext(),
// R.string.connect, Toast.LENGTH_LONG).show();
initChatMessage(INIT_MSG); initChatMessage(INIT_MSG);
} }
}); });
...@@ -773,7 +835,35 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD ...@@ -773,7 +835,35 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
} }
} }
private void showSocketConnectError(){
runOnUiThread(new Runnable() {
@Override
public void run() {
Log.e(TAG,"failed to connect");
Snackbar snackbar = Snackbar
.make(mMessagesView, R.string.error_connect, Snackbar.LENGTH_LONG)
.setAction("Dismiss", new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
snackbar.show();
// Changing message text color
snackbar.setActionTextColor(Color.RED);
// Changing action button text color
View sbView = snackbar.getView();
TextView textView = (TextView) sbView.findViewById(android.support.design.R.id.snackbar_text);
textView.setTextColor(Color.YELLOW);
snackbar.show();
}
});
}
/** /**
* Chat server calls this if we will disconnect from server. * Chat server calls this if we will disconnect from server.
...@@ -811,8 +901,9 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD ...@@ -811,8 +901,9 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
private Emitter.Listener onConnectTimeOut = new Emitter.Listener() { private Emitter.Listener onConnectTimeOut = new Emitter.Listener() {
@Override @Override
public void call(Object... args) { public void call(Object... args) {
Toast.makeText(getApplicationContext(), Log.e(TAG, "onConnectTimeOut Called");
"onConnectTimeOut Called", Toast.LENGTH_LONG).show(); // Toast.makeText(getApplicationContext(),
// "onConnectTimeOut Called", Toast.LENGTH_LONG).show();
//reconnect(); //reconnect();
} }
}; };
...@@ -823,8 +914,9 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD ...@@ -823,8 +914,9 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
private Emitter.Listener onReconnect = new Emitter.Listener() { private Emitter.Listener onReconnect = new Emitter.Listener() {
@Override @Override
public void call(Object... args) { public void call(Object... args) {
/*Toast.makeText(getApplicationContext(), Log.e(TAG, "Reconnection Called");
"Reconnection Called", Toast.LENGTH_LONG).show();*/ // Toast.makeText(getApplicationContext(),
// "Reconnection Called", Toast.LENGTH_LONG).show();
//reconnect(); //reconnect();
} }
...@@ -840,6 +932,7 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD ...@@ -840,6 +932,7 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
@Override @Override
public void run() { public void run() {
if(!isConnectError) { if(!isConnectError) {
Log.e(TAG,"failed to connect");
Snackbar snackbar = Snackbar Snackbar snackbar = Snackbar
.make(mMessagesView, R.string.error_connect, Snackbar.LENGTH_LONG) .make(mMessagesView, R.string.error_connect, Snackbar.LENGTH_LONG)
.setAction("Dismiss", new View.OnClickListener() { .setAction("Dismiss", new View.OnClickListener() {
...@@ -930,6 +1023,7 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD ...@@ -930,6 +1023,7 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
} }
if(!message.isEmpty()) { if(!message.isEmpty()) {
ChatLogManager.saveLogEvent("",message,"true",new Date().toString());
if(message.contains(Constants.RESET_PASSWORD_NAVIGATION_SCREEN)){ if(message.contains(Constants.RESET_PASSWORD_NAVIGATION_SCREEN)){
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
......
package com.vsoft.vera.utils;
public class ChatLog {
private Long chatId;
private String serverResponse;
private String timestamp;
/**
* socket connection status
* true or false
*/
private String connStatus;
private String clientMessage;
public Long getChatId() {
return chatId;
}
public void setChatId(Long chatId) {
this.chatId = chatId;
}
public String getClientMessage() {
return clientMessage;
}
public void setClientMessage(String clientMessage) {
this.clientMessage = clientMessage;
}
public String getServerResponse() {
return serverResponse;
}
public void setServerResponse(String serverResponse) {
this.serverResponse = serverResponse;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
public String getConnStatus() {
return connStatus;
}
public void setConnStatus(String connStatus) {
this.connStatus = connStatus;
}
}
...@@ -7,5 +7,9 @@ ...@@ -7,5 +7,9 @@
android:id="@+id/more_menu_clear" android:id="@+id/more_menu_clear"
android:icon="@drawable/ic_clear_black" android:icon="@drawable/ic_clear_black"
android:title="Clear Chat" /> android:title="Clear Chat" />
<item
android:id="@+id/export_log"
android:title="Export Log" />
</menu> </menu>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment