Working with Sinch Instant Messaging System - java

I am using Sinch and Parse for my instant messaging system integrated in our application, and I have two concerns.
1) For some reason, I am receiving the following error when the messaging activity is displayed: The message client did not start". Furthermore, the message does not seem to go through in Sinch and not reflected visually in the application.
Below is the activity code (when the user clicks on the "quick chat" button, it takes them to the messaging activity page.
Below is the activity code for the messaging activity
public class MessagingActivity extends Activity implements ServiceConnection, MessageClientListener {
private String recipientId;
private Button sendButton;
private EditText messageBodyField;
private String messageBody;
private MessageService.MessageServiceInterface messageService;
private MessageAdapter messageAdapter;
private ListView messagesList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.messaging);
doBind();
messagesList = (ListView) findViewById(R.id.listMessages);
messageAdapter = new MessageAdapter(this);
messagesList.setAdapter(messageAdapter);
Intent intent = getIntent();
recipientId = intent.getStringExtra("Name");
messageBodyField = (EditText) findViewById(R.id.messageBodyField);
sendButton = (Button) findViewById(R.id.sendButton);
sendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
sendMessage();
}
});
}
private void sendMessage() {
messageBodyField = (EditText) findViewById(R.id.messageBodyField);
messageBody = messageBodyField.getText().toString();
if (messageBody.isEmpty()) {
Toast.makeText(this, "Please enter a message", Toast.LENGTH_LONG).show();
return;
}
//Here is where you will actually send the message throught Sinch
messageService.sendMessage(recipientId, messageBody);
messageBodyField.setText("");
}
private void doBind() {
Intent serviceIntent = new Intent(this, MessageService.class);
bindService(serviceIntent, this, BIND_AUTO_CREATE);
}
#Override
public void onDestroy() {
unbindService(this);
super.onDestroy();
}
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
//Define the messaging service and add a listener
messageService = (MessageService.MessageServiceInterface) iBinder;
messageService.addMessageClientListener(this);
if (!messageService.isSinchClientStarted()) {
Toast.makeText(this, "The message client did not start."
,Toast.LENGTH_LONG).show();
}
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
messageService = null;
}
#Override
public void onMessageDelivered(MessageClient client, MessageDeliveryInfo deliveryInfo) {
//Intentionally left blank
}
#Override
public void onMessageFailed(MessageClient client, Message message,
MessageFailureInfo failureInfo) {
//Notify the user if message fails to send
Toast.makeText(this, "Message failed to send.", Toast.LENGTH_LONG).show();
}
#Override
public void onIncomingMessage(MessageClient client, Message message) {
messageAdapter.addMessage(message, MessageAdapter.DIRECTION_INCOMING);
}
#Override
public void onMessageSent(MessageClient client, Message message, String recipientId) {
messageAdapter.addMessage(message, MessageAdapter.DIRECTION_OUTGOING);
}
#Override
public void onShouldSendPushData(MessageClient client, Message message, List<PushPair> pushPairs) {
//Intentionally left blank
}
}
I have verified that the APP_KEY, the APP_SECRET and ENVIRONMENT matches what was recorded on Sinch.
I have tried this both on the emulator, and on a physical device.
Thanks in advance
Code service
public class MessageService extends Service implements SinchClientListener {
private static final String APP_KEY = "XXXXX";
private static final String APP_SECRET = "YYYYY";
private static final String ENVIRONMENT = "sandbox.sinch.com";
private final MessageServiceInterface serviceInterface = new MessageServiceInterface();
private SinchClient sinchClient = null;
private MessageClient messageClient = null;
private String currentUserId;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
currentUserId = ParseUser.getCurrentUser().getObjectId().toString();
if (currentUserId != null && !isSinchClientStarted()) {
startSinchClient(currentUserId);
}
return super.onStartCommand(intent, flags, startId);
}
public void startSinchClient(String username) {
sinchClient = Sinch.getSinchClientBuilder().context(this).userId(username).applicationKey(APP_KEY)
.applicationSecret(APP_SECRET).environmentHost(ENVIRONMENT).build();
sinchClient.addSinchClientListener(this);
sinchClient.setSupportMessaging(true);
sinchClient.setSupportActiveConnectionInBackground(true);
sinchClient.checkManifest();
sinchClient.start();
}
private boolean isSinchClientStarted() {
return sinchClient != null && sinchClient.isStarted();
}
#Override
public void onClientFailed(SinchClient client, SinchError error) {
sinchClient = null;
}
#Override
public void onClientStarted(SinchClient client) {
client.startListeningOnActiveConnection();
messageClient = client.getMessageClient();
}
#Override
public void onClientStopped(SinchClient client) {
sinchClient = null;
}
public void stop() {
if (isSinchClientStarted()) {
sinchClient.stop();
sinchClient.removeSinchClientListener(this);
}
sinchClient = null;
}
#Override
public IBinder onBind(Intent intent) {
return serviceInterface;
}
#Override
public void onLogMessage(int level, String area, String message) {
//Intentionally left blank
}
#Override
public void onRegistrationCredentialsRequired(SinchClient client, ClientRegistration clientRegistration) {
//Intentionally left blank
}
public void sendMessage(String recipientUserId, String textBody) {
if (messageClient != null) {
WritableMessage message = new WritableMessage(recipientUserId, textBody);
messageClient.send(message);
}
}
public void addMessageClientListener(MessageClientListener listener) {
if (messageClient != null) {
messageClient.addMessageClientListener(listener);
}
}
public void removeMessageClientListener(MessageClientListener listener) {
if (messageClient != null) {
messageClient.removeMessageClientListener(listener);
}
}
public class MessageServiceInterface extends Binder {
public void sendMessage(String recipientUserId, String textBody) {
MessageService.this.sendMessage(recipientUserId, textBody);
}
public void addMessageClientListener(MessageClientListener listener) {
MessageService.this.addMessageClientListener(listener);
}
public void removeMessageClientListener(MessageClientListener listener) {
MessageService.this.removeMessageClientListener(listener);
}
public boolean isSinchClientStarted() {
return MessageService.this.isSinchClientStarted();
}
}
}
2) Limit: I would like to set a limit, where a only 25 messages would be available between a particular party.
Thanks in advance, and if you need any clarification, let me know.
Update 3
When user clicks on this button, he is taking to the MessagingActivity with the person he has been matched to based upon the below criteria
final Button ibutton = (Button) this.findViewById(R.id.btnQuickChat);
idrinks.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
openConversation();
}
private void openConversation() {
// TODO Auto-generated method stub
ParseQuery<ParseUser> query = ParseUser.getQuery();
query.whereNotEqualTo("objectId", ParseUser.getCurrentUser()
.getObjectId());
query.setLimit(1);
query.findInBackground(new FindCallback<ParseUser>() {
public void done(List<ParseUser> user, ParseException e) {
if (e == null) {
Intent intent = new Intent(getApplicationContext(), MessagingActivity.class);
intent.putExtra("RECIPIENT_ID", user.get(0).getObjectId());
startActivity(intent);
} else {
Toast.makeText(getApplicationContext(),
"Error finding that user",
Toast.LENGTH_SHORT).show();
}
}
});
}
});
MessagingActivity (nearly same as one provided in tutorial):
public class MessagingActivity extends Activity {
private String recipientId;
private EditText messageBodyField;
private String messageBody;
private MessageService.MessageServiceInterface messageService;
private MessageAdapter messageAdapter;
private ListView messagesList;
private String currentUserId;
private ServiceConnection serviceConnection = new MyServiceConnection();
private MessageClientListener messageClientListener = new MyMessageClientListener();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.messaging);
bindService(new Intent(this, MessageService.class), serviceConnection, BIND_AUTO_CREATE);
Intent intent = getIntent();
recipientId = intent.getStringExtra("RECIPIENT_ID");
currentUserId = ParseUser.getCurrentUser().getObjectId();
messagesList = (ListView) findViewById(R.id.listMessages);
messageAdapter = new MessageAdapter(this);
messagesList.setAdapter(messageAdapter);
populateMessageHistory();
messageBodyField = (EditText) findViewById(R.id.messageBodyField);
findViewById(R.id.sendButton).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
sendMessage();
}
});
}
//get previous messages from parse & display
private void populateMessageHistory() {
String[] userIds = {currentUserId, recipientId};
ParseQuery<ParseObject> query = ParseQuery.getQuery("ParseMessage");
query.whereContainedIn("senderId", Arrays.asList(userIds));
query.whereContainedIn("recipientId", Arrays.asList(userIds));
query.orderByAscending("createdAt");
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> messageList, com.parse.ParseException e) {
if (e == null) {
for (int i = 0; i < messageList.size(); i++) {
WritableMessage message = new WritableMessage(messageList.get(i).get("recipientId").toString(), messageList.get(i).get("messageText").toString());
if (messageList.get(i).get("senderId").toString().equals(currentUserId)) {
messageAdapter.addMessage(message, MessageAdapter.DIRECTION_OUTGOING);
} else {
messageAdapter.addMessage(message, MessageAdapter.DIRECTION_INCOMING);
}
}
}
}
});
}
private void sendMessage() {
messageBody = messageBodyField.getText().toString();
if (messageBody.isEmpty()) {
Toast.makeText(this, "Please enter a message", Toast.LENGTH_LONG).show();
return;
}
messageService.sendMessage(recipientId, messageBody);
messageBodyField.setText("");
}
#Override
public void onDestroy() {
messageService.removeMessageClientListener(messageClientListener);
unbindService(serviceConnection);
super.onDestroy();
}
private class MyServiceConnection implements ServiceConnection {
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
messageService = (MessageService.MessageServiceInterface) iBinder;
messageService.addMessageClientListener(messageClientListener);
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
messageService = null;
}
}
private class MyMessageClientListener implements MessageClientListener {
#Override
public void onMessageFailed(MessageClient client, Message message,
MessageFailureInfo failureInfo) {
Toast.makeText(MessagingActivity.this, "Message failed to send.", Toast.LENGTH_LONG).show();
}
#Override
public void onIncomingMessage(MessageClient client, Message message) {
if (message.getSenderId().equals(recipientId)) {
WritableMessage writableMessage = new WritableMessage(message.getRecipientIds().get(0), message.getTextBody());
messageAdapter.addMessage(writableMessage, MessageAdapter.DIRECTION_INCOMING);
}
}
#Override
public void onMessageSent(MessageClient client, Message message, String recipientId) {
final WritableMessage writableMessage = new WritableMessage(message.getRecipientIds().get(0), message.getTextBody());
//only add message to parse database if it doesn't already exist there
ParseQuery<ParseObject> query = ParseQuery.getQuery("ParseMessage");
query.whereEqualTo("sinchId", message.getMessageId());
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> messageList, com.parse.ParseException e) {
if (e == null) {
if (messageList.size() == 0) {
ParseObject parseMessage = new ParseObject("ParseMessage");
parseMessage.put("senderId", currentUserId);
parseMessage.put("recipientId", writableMessage.getRecipientIds().get(0));
parseMessage.put("messageText", writableMessage.getTextBody());
parseMessage.put("sinchId", writableMessage.getMessageId());
parseMessage.saveInBackground();
messageAdapter.addMessage(writableMessage, MessageAdapter.DIRECTION_OUTGOING);
}
}
}
});
}
#Override
public void onMessageDelivered(MessageClient client, MessageDeliveryInfo deliveryInfo) {}
#Override
public void onShouldSendPushData(MessageClient client, Message message, List<PushPair> pushPairs) {}
}
}
MessageService activity
public class MessageService extends Service implements SinchClientListener {
private static final String APP_KEY = "61b1bfc0-b82a-44f5-ab68-dedca69ead8c";
private static final String APP_SECRET = "jrFrLr8Adkm0Na4nLdASDw==";
private static final String ENVIRONMENT = "sandbox.sinch.com";
private final MessageServiceInterface serviceInterface = new MessageServiceInterface();
private SinchClient sinchClient = null;
private MessageClient messageClient = null;
private String currentUserId;
private LocalBroadcastManager broadcaster;
private Intent broadcastIntent = new Intent("com.dooba.beta.matchOptionActivity");
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
currentUserId = ParseUser.getCurrentUser().getObjectId();
if (currentUserId != null && !isSinchClientStarted()) {
startSinchClient(currentUserId);
}
broadcaster = LocalBroadcastManager.getInstance(this);
return super.onStartCommand(intent, flags, startId);
}
public void startSinchClient(String username) {
sinchClient = Sinch.getSinchClientBuilder().context(this).userId(username).applicationKey(APP_KEY)
.applicationSecret(APP_SECRET).environmentHost(ENVIRONMENT).build();
sinchClient.addSinchClientListener(this);
sinchClient.setSupportMessaging(true);
sinchClient.setSupportActiveConnectionInBackground(true);
sinchClient.checkManifest();
sinchClient.start();
}
private boolean isSinchClientStarted() {
return sinchClient != null && sinchClient.isStarted();
}
#Override
public void onClientFailed(SinchClient client, SinchError error) {
broadcastIntent.putExtra("success", false);
broadcaster.sendBroadcast(broadcastIntent);
sinchClient = null;
}
#Override
public void onClientStarted(SinchClient client) {
broadcastIntent.putExtra("success", true);
broadcaster.sendBroadcast(broadcastIntent);
client.startListeningOnActiveConnection();
messageClient = client.getMessageClient();
}
#Override
public void onClientStopped(SinchClient client) {
sinchClient = null;
}
#Override
public IBinder onBind(Intent intent) {
return serviceInterface;
}
#Override
public void onLogMessage(int level, String area, String message) {
}
#Override
public void onRegistrationCredentialsRequired(SinchClient client, ClientRegistration clientRegistration) {
}
public void sendMessage(String recipientUserId, String textBody) {
if (messageClient != null) {
WritableMessage message = new WritableMessage(recipientUserId, textBody);
messageClient.send(message);
}
}
public void addMessageClientListener(MessageClientListener listener) {
if (messageClient != null) {
messageClient.addMessageClientListener(listener);
}
}
public void removeMessageClientListener(MessageClientListener listener) {
if (messageClient != null) {
messageClient.removeMessageClientListener(listener);
}
}
public class MessageServiceInterface extends Binder {
public void sendMessage(String recipientUserId, String textBody) {
MessageService.this.sendMessage(recipientUserId, textBody);
}
public void addMessageClientListener(MessageClientListener listener) {
MessageService.this.addMessageClientListener(listener);
}
public void removeMessageClientListener(MessageClientListener listener) {
MessageService.this.removeMessageClientListener(listener);
}
public boolean isSinchClientStarted() {
return MessageService.this.isSinchClientStarted();
}
}
Message adapter activity:
public class MessageAdapter extends BaseAdapter {
public static final int DIRECTION_INCOMING = 0;
public static final int DIRECTION_OUTGOING = 1;
private List<Pair<WritableMessage, Integer>> messages;
private LayoutInflater layoutInflater;
public MessageAdapter(Activity activity) {
layoutInflater = activity.getLayoutInflater();
messages = new ArrayList<Pair<WritableMessage, Integer>>();
}
public void addMessage(WritableMessage message, int direction) {
messages.add(new Pair(message, direction));
notifyDataSetChanged();
}
#Override
public int getCount() {
return messages.size();
}
#Override
public Object getItem(int i) {
return messages.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public int getItemViewType(int i) {
return messages.get(i).second;
}
#Override
public View getView(int i, View convertView, ViewGroup viewGroup) {
int direction = getItemViewType(i);
//show message on left or right, depending on if
//it's incoming or outgoing
if (convertView == null) {
int res = 0;
if (direction == DIRECTION_INCOMING) {
res = R.layout.message_right;
} else if (direction == DIRECTION_OUTGOING) {
res = R.layout.message_left;
}
convertView = layoutInflater.inflate(res, viewGroup, false);
}
WritableMessage message = messages.get(i).first;
TextView txtMessage = (TextView) convertView.findViewById(R.id.txtMessage);
txtMessage.setText(message.getTextBody());
return convertView;
}
}

I wrote the tutorial you're following, and actually just updated it yesterday to fix your first problem. Check out http://tutorial.sinch.com/android-messaging-tutorial/#show-spinner to see the updates. Instead of showing a toast message when the service is not started, the new version will show a progress dialog (loading spinner) until the service has either started or failed to start.
Could you clarify your second question?

Just declare your service in manifest. I had the same problem and it solved it.

Related

How to delete messages from firebase Database?

I am working on a chat application connected to firebase. I am trying to add a future where I can delete a message. This is what I have tried but it's not working.
This is the code
...package com.sollie.ian.eunice.ui
public class ChatActivity extends AppCompatActivity {
private RecyclerView recyclerChat;
public static final int VIEW_TYPE_USER_MESSAGE = 0;
public static final int VIEW_TYPE_FRIEND_MESSAGE = 1;
private ListMessageAdapter adapter;
public String roomId;
private ArrayList<CharSequence> idFriend;
private Consersation consersation;
private MessageInput editWriteMessage;
private LinearLayoutManager linearLayoutManager;
public static HashMap<String, Bitmap> bitmapAvataFriend;
public Bitmap bitmapAvataUser;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
Intent intentData = getIntent();
idFriend = intentData.getCharSequenceArrayListExtra(StaticConfig.INTENT_KEY_CHAT_ID);
roomId = intentData.getStringExtra(StaticConfig.INTENT_KEY_CHAT_ROOM_ID);
String nameFriend = intentData.getStringExtra(StaticConfig.INTENT_KEY_CHAT_FRIEND);
consersation = new Consersation();
String base64AvataUser = SharedPreferenceHelper.getInstance(this).getUserInfo().avata;
if (!base64AvataUser.equals(StaticConfig.STR_DEFAULT_BASE64)) {
byte[] decodedString = Base64.decode(base64AvataUser, Base64.DEFAULT);
bitmapAvataUser = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
} else {
bitmapAvataUser = null;
}
editWriteMessage = findViewById(R.id.input);
if (idFriend != null && nameFriend != null) {
getSupportActionBar().setTitle(nameFriend);
linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
recyclerChat = findViewById(R.id.recyclerChat);
recyclerChat.setLayoutManager(linearLayoutManager);
adapter = new ListMessageAdapter(this, consersation, bitmapAvataFriend, bitmapAvataUser);
FirebaseDatabase.getInstance().getReference().child("message/" + roomId).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
if (dataSnapshot.getValue() != null) {
HashMap mapMessage = (HashMap) dataSnapshot.getValue();
Message newMessage = new Message();
newMessage.idSender = (String) mapMessage.get("idSender");
newMessage.idReceiver = (String) mapMessage.get("idReceiver");
newMessage.text = (String) mapMessage.get("text");
newMessage.timestamp = (long) mapMessage.get("timestamp");
consersation.getListMessageData().add(newMessage);
adapter.notifyDataSetChanged();
linearLayoutManager.scrollToPosition(consersation.getListMessageData().size() - 1);
}
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
recyclerChat.setAdapter(adapter);
}
editWriteMessage.setInputListener(input -> {
String content = input.toString().trim();
if (content.length() > 0) {
// editWriteMessage.setTex("");
Message newMessage = new Message();
newMessage.text = content;
newMessage.idSender = StaticConfig.UID;
newMessage.idReceiver = roomId;
newMessage.timestamp = System.currentTimeMillis();
FirebaseDatabase.getInstance().getReference().child("message/" + roomId).push().setValue(newMessage);
}
return true;
});
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId() == android.R.id.home){
Intent result = new Intent();
result.putExtra("idFriend", idFriend.get(0));
setResult(RESULT_OK, result);
this.finish();
}
return true;
}
#Override
public void onBackPressed() {
Intent result = new Intent();
result.putExtra("idFriend", idFriend.get(0));
setResult(RESULT_OK, result);
this.finish();
}
}
class ListMessageAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
private Consersation consersation;
private HashMap<String, Bitmap> bitmapAvata;
private HashMap<String, DatabaseReference> bitmapAvataDB;
private Bitmap bitmapAvataUser;
private String roomId;
public ListMessageAdapter(Context context, Consersation consersation, HashMap<String, Bitmap> bitmapAvata, Bitmap bitmapAvataUser) {
this.context = context;
this.consersation = consersation;
this.bitmapAvata = bitmapAvata;
this.bitmapAvataUser = bitmapAvataUser;
bitmapAvataDB = new HashMap<>();
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == ChatActivity.VIEW_TYPE_FRIEND_MESSAGE) {
View view = LayoutInflater.from(context).inflate(R.layout.rc_item_message_friend, parent, false);
return new ItemMessageFriendHolder(view);
} else if (viewType == ChatActivity.VIEW_TYPE_USER_MESSAGE) {
View view = LayoutInflater.from(context).inflate(R.layout.rc_item_message_user, parent, false);
return new ItemMessageUserHolder(view);
}
return null;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof ItemMessageFriendHolder) {
((ItemMessageFriendHolder) holder).txtContent.setText(consersation.getListMessageData().get(position).text);
Bitmap currentAvata = bitmapAvata.get(consersation.getListMessageData().get(position).idSender);
if (currentAvata != null) {
((ItemMessageFriendHolder) holder).avata.setImageBitmap(currentAvata);
} else {
final String id = consersation.getListMessageData().get(position).idSender;
if(bitmapAvataDB.get(id) == null){
bitmapAvataDB.put(id, FirebaseDatabase.getInstance().getReference().child("user/" + id + "/avata"));
bitmapAvataDB.get(id).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.getValue() != null) {
String avataStr = (String) dataSnapshot.getValue();
if(!avataStr.equals(StaticConfig.STR_DEFAULT_BASE64)) {
byte[] decodedString = Base64.decode(avataStr, Base64.DEFAULT);
ChatActivity.bitmapAvataFriend.put(id, BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length));
}else{
ChatActivity.bitmapAvataFriend.put(id, BitmapFactory.decodeResource(context.getResources(), R.drawable.default_avata));
}
notifyDataSetChanged();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
} else if (holder instanceof ItemMessageUserHolder) {
((ItemMessageUserHolder) holder).txtContent.setText(consersation.getListMessageData().get(position).text);
if (bitmapAvataUser != null) {
((ItemMessageUserHolder) holder).avata.setImageBitmap(bitmapAvataUser);
}
((ItemMessageUserHolder) holder).txtContent.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Delete Message");
builder.setMessage("Are You Sure To Delete This Messgae");
builder.setPositiveButton("Delete", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
deleteMsg(position);
}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.create().show();
return false;
}
});
}
}
private void deleteMsg(int position) {
final String myuid = FirebaseAuth.getInstance().getCurrentUser().getUid();
String msgtimestmp =String.valueOf(consersation.getListMessageData().get(position).timestamp);
String message=consersation.getListMessageData().get(position).text;
DatabaseReference roofRef=FirebaseDatabase.getInstance().getReference();
roofRef.child("message").child(message)
.removeValue().addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(task.isSuccessful())
{
Toast.makeText(context, "deleted", Toast.LENGTH_SHORT).show();
}else
{
Toast.makeText(context, "failed", Toast.LENGTH_SHORT).show();
}
}
});
}
#Override
public int getItemViewType(int position) {
return consersation.getListMessageData().get(position).idSender.equals(StaticConfig.UID) ? ChatActivity.VIEW_TYPE_USER_MESSAGE : ChatActivity.VIEW_TYPE_FRIEND_MESSAGE;
}
#Override
public int getItemCount() {
return consersation.getListMessageData().size();
}
}
class ItemMessageUserHolder extends RecyclerView.ViewHolder {
public TextView txtContent;
public CircleImageView avata;
public ItemMessageUserHolder(View itemView) {
super(itemView);
txtContent = itemView.findViewById(R.id.textContentUser);
avata = itemView.findViewById(R.id.imageView2);
}
}
class ItemMessageFriendHolder extends RecyclerView.ViewHolder {
public TextView txtContent;
public CircleImageView avata;
public ItemMessageFriendHolder(View itemView) {
super(itemView);
txtContent = itemView.findViewById(R.id.textContentFriend);
avata = itemView.findViewById(R.id.imageView3);
}
}
And this is what I have tried
private void deleteMsg(int position) {
final String myuid = FirebaseAuth.getInstance().getCurrentUser().getUid();
String msgtimestmp =String.valueOf(consersation.getListMessageData().get(position).timestamp);
String message=consersation.getListMessageData().get(position).text;
DatabaseReference roofRef=FirebaseDatabase.getInstance().getReference();
roofRef.child("message").child(message)
.removeValue().addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(task.isSuccessful())
{
Toast.makeText(context, "deleted", Toast.LENGTH_SHORT).show();
}else
{
Toast.makeText(context, "failed", Toast.LENGTH_SHORT).show();
}
}
});
}
What am I doing wrong?
The problem is here:
String message=consersation.getListMessageData().get(position).text;
DatabaseReference roofRef=FirebaseDatabase.getInstance().getReference();
roofRef.child("message").child(message).removeValue()
You're trying to delete the message based on its text, but to delete a node from Firebase you need to know its key.
This means that when you read the messages from the database, you'll need to store dataSnapshot.getKey() for each message (probably as a field in your Message class). Then when you are ready to delete the message, you can get the key from that class and pass it into the database call, with something like:
String key= consersation.getListMessageData().get(position).key; // 👈
DatabaseReference roofRef=FirebaseDatabase.getInstance().getReference();
roofRef.child("message").child(key).removeValue()... // 👈

Cannot get sinch call when app is clear from recent in android

Cannot get sinch call when app is clear from recent in android
public class SinchService extends Service {
private static final String APP_KEY = "";
private static final String APP_SECRET = "";
private static final String ENVIRONMENT = "clientapi.sinch.com";
public static final String CALL_ID = "CALL_ID";
static final String TAG = SinchService.class.getSimpleName();
private SinchServiceInterface mSinchServiceInterface = new SinchServiceInterface();
private SinchClient mSinchClient;
private String mUserId;
private StartFailedListener mListener;
#Override
public void onCreate() {
super.onCreate();
}
private void start(String userName) {
Log.d("start123", "start");
if (mSinchClient == null) {
mUserId = userName;
mSinchClient = Sinch.getSinchClientBuilder().context(getApplicationContext()).userId(userName)
.applicationKey(APP_KEY)
.applicationSecret(APP_SECRET)
.environmentHost(ENVIRONMENT).build();
mSinchClient.setSupportManagedPush(true);
mSinchClient.setSupportCalling(true);
mSinchClient.startListeningOnActiveConnection();
mSinchClient.setSupportActiveConnectionInBackground(true);
mSinchClient.addSinchClientListener(new MySinchClientListener());
mSinchClient.getCallClient().addCallClientListener(new SinchCallClientListener());
mSinchClient.start();
}
}
private void stop() {
if (mSinchClient != null) {
mSinchClient.terminate();
mSinchClient = null;
}
}
private boolean isStarted() {
return (mSinchClient != null && mSinchClient.isStarted());
}
#Override
public IBinder onBind(Intent intent) {
return mSinchServiceInterface;
}
public class SinchServiceInterface extends Binder {
public Call callUserVideo(String userId) {
return mSinchClient.getCallClient().callUser(userId);
}
public Call callUser(String userId) {
return mSinchClient.getCallClient().callUserVideo(userId);
}
public String getUserName() {
return mUserId;
}
public boolean isStarted() {
return SinchService.this.isStarted();
}
public void startClient(String userName) {
start(userName);
}
public void stopClient() {
stop();
}
public void setStartListener(StartFailedListener listener) {
mListener = listener;
}
public Call getCall(String callId) {
return mSinchClient.getCallClient().getCall(callId);
}
public VideoController getVideoController() {
if (!isStarted()) {
return null;
}
return mSinchClient.getVideoController();
}
public AudioController getAudioController() {
if (!isStarted()) {
return null;
}
return mSinchClient.getAudioController();
}
}
public interface StartFailedListener {
void onStartFailed(SinchError error);
void onStarted();
}
private class MySinchClientListener implements SinchClientListener {
#Override
public void onClientFailed(SinchClient client, SinchError error) {
if (mListener != null) {
mListener.onStartFailed(error);
}
mSinchClient.terminate();
mSinchClient = null;
}
#Override
public void onClientStarted(SinchClient client) {
Log.d(TAG, "SinchClient started");
if (mListener != null) {
mListener.onStarted();
}
}
#Override
public void onClientStopped(SinchClient client) {
Log.d(TAG, "SinchClient stopped");
}
#Override
public void onLogMessage(int level, String area, String message) {
switch (level) {
case Log.DEBUG:
Log.d(area, message);
break;
case Log.ERROR:
Log.e(area, message);
break;
case Log.INFO:
Log.i(area, message);
break;
case Log.VERBOSE:
Log.v(area, message);
break;
case Log.WARN:
Log.w(area, message);
break;
}
}
#Override
public void onRegistrationCredentialsRequired(SinchClient client,
ClientRegistration clientRegistration) {
}
}
private class SinchCallClientListener implements CallClientListener {
#Override
public void onIncomingCall(CallClient callClient, Call call) {
FirebaseAuth auth = FirebaseAuth.getInstance();
DatabaseReference cal = FirebaseDatabase.getInstance().getReference().child("call_detail").child(auth.getCurrentUser().getUid()).child(call.getCallId());
cal.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
String cl = dataSnapshot.child("callType").getValue(String.class);
if( cl.equals("audio") ){
Intent intent = new Intent(SinchService.this, IncomingVoiceCallActivity.class);
intent.putExtra(CALL_ID, call.getCallId());
intent.putExtra("callerUserId", call.getRemoteUserId());
Log.d("ABCD", call.getRemoteUserId());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
SinchService.this.startActivity(intent);
}if (cl.equals("video")){
Intent intent = new Intent(SinchService.this, IncomingVideoCallActivity.class);
intent.putExtra(CALL_ID, call.getCallId());
intent.putExtra("callerUserId", call.getRemoteUserId());
Log.d("ABCD", call.getRemoteUserId());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
SinchService.this.startActivity(intent);
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
}
}
I received call when app is in recent tray. but when i clear app from recent i cannot get call. this is my SinchService class. i also used forground service, with foreground service i get call on some devices on app close but not get call on some oppo and samsung mobiles.

ExoPlayer - playing multiple videos

I'm tying to play videos from a Firebase Listadapter. When the user clicks on the list they a video plays, and upon finishing the activity finishes, and they return to the original list.
When the click on the second video it starts the ExoPlayer activity, but won't play the video. If they press back and select the original video it will play fine.
public String mTastingWineID;
public String tastingWineId;
public String mWineVideoID;
public String tastingWineVideoId;
private DataSource.Factory mediaDataSourceFactory;
private boolean isPlaying = false;
public int mVideoResource;
public Uri videoUri;
private static final String TAG = "WineMediaActivity";
private static final DefaultBandwidthMeter BANDWIDTH_METER = new DefaultBandwidthMeter();
private SimpleExoPlayer player;
private SimpleExoPlayerView mVideoView;
private ComponentListener componentListener;
private long playbackPostiion;
private int currentWindow;
private boolean playWhenReady = true;
private BandwidthMeter bandwidthMeter;
public Firebase wineMediaUrl;
public ValueEventListener wineMediaUrlListener;
private MediaControllerCompat mediaControllerCompat;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.analytics_media_wine_information);
Bundle bundle = getIntent().getExtras();
mTastingWineID = bundle.getString(Constants.WINE_ID);
tastingWineId = mTastingWineID.toString();
mWineVideoID = bundle.getString(Constants.WINE_VIDEO_ID);
tastingWineVideoId = mWineVideoID.toString();
if (player != null){
player.release();
}
getCurrentVideo();
}
public void getCurrentVideo(){
wineMediaUrl = new Firebase(Constants.FIREBASE_URL).child(FIREBASE_LOCATION_WINE_DETAILS).child(tastingWineId).child(WINE_MEDIA).child(tastingWineVideoId).child("wineVideoUrl");
wineMediaUrlListener = wineMediaUrl.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
componentListener = new ComponentListener();
mVideoView = findViewById(R.id.videoView1);
mVideoView.requestFocus();
Object tempVideoFiles = dataSnapshot.getValue();
String str = tempVideoFiles.toString();
videoUri = Uri.parse(str);
if (videoUri != null) {
initializePlayer();
} else {
Toast.makeText(WineMediaActivity.this, "No Video Found", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
mediaDataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, "mediaPlayerSample"), (TransferListener<? super DataSource>) bandwidthMeter);
}
private class ComponentListener implements ExoPlayer.EventListener, VideoRendererEventListener, AudioRendererEventListener {
#Override
public void onTimelineChanged(Timeline timeline, Object manifest) {
}
#Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
}
#Override
public void onLoadingChanged(boolean isLoading) {
}
#Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
String stateString;
switch (playbackState) {
case ExoPlayer.STATE_IDLE:
stateString = "ExoPlayer.STATE_IDLE";
break;
case ExoPlayer.STATE_BUFFERING:
stateString = "ExoPlayer.STATE_IDLE";
break;
case ExoPlayer.STATE_READY:
stateString = "ExoPlayer.STATE_IDLE";
break;
case ExoPlayer.STATE_ENDED:
stateString = "ExoPlayer.STATE_IDLE";
releasePlayer();
finish();
break;
default:
stateString = "UNKNOWN_STATE";
break;
}
Log.d(TAG, "changed state to: " + stateString + " play when ready: " + playWhenReady);
}
#Override
public void onRepeatModeChanged(int repeatMode) {
}
#Override
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
}
#Override
public void onPlayerError(ExoPlaybackException error) {
}
#Override
public void onPositionDiscontinuity(int reason) {
}
#Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
}
#Override
public void onSeekProcessed() {
}
#Override
public void onAudioEnabled(DecoderCounters counters) {
}
#Override
public void onAudioSessionId(int audioSessionId) {
}
#Override
public void onAudioDecoderInitialized(String decoderName, long initializedTimestampMs, long initializationDurationMs) {
}
#Override
public void onAudioInputFormatChanged(Format format) {
}
#Override
public void onAudioSinkUnderrun(int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) {
}
#Override
public void onAudioDisabled(DecoderCounters counters) {
}
#Override
public void onVideoEnabled(DecoderCounters counters) {
}
#Override
public void onVideoDecoderInitialized(String decoderName, long initializedTimestampMs, long initializationDurationMs) {
}
#Override
public void onVideoInputFormatChanged(Format format) {
}
#Override
public void onDroppedFrames(int count, long elapsedMs) {
}
#Override
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
}
#Override
public void onRenderedFirstFrame(Surface surface) {
}
#Override
public void onVideoDisabled(DecoderCounters counters) {
}
}
private void initializePlayer() {
if (player == null) {
TrackSelection.Factory adaptiveTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
player = ExoPlayerFactory.newSimpleInstance(new DefaultRenderersFactory(this), new DefaultTrackSelector(adaptiveTrackSelectionFactory), new DefaultLoadControl());
player.addListener(componentListener);
player.setVideoDebugListener(componentListener);
player.setAudioDebugListener(componentListener);
mVideoView.setPlayer(player);
player.setPlayWhenReady(playWhenReady);
player.seekTo(currentWindow, playbackPostiion);
}
MediaSource mediaSource = new ExtractorMediaSource(videoUri, mediaDataSourceFactory, extractorsFactory, null, null);
player.prepare(mediaSource, true, false);
}
#SuppressLint("InlinedApi")
private void hideSystemUi() {
mVideoView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
}
private void releasePlayer() {
if (player != null) {
playbackPostiion = player.getCurrentPosition();
currentWindow = player.getCurrentWindowIndex();
playWhenReady = player.getPlayWhenReady();
player.removeListener(componentListener);
mVideoView.setPlayer(null);
player.setVideoListener(null);
player.setVideoDebugListener(null);
player.setAudioDebugListener(null);
player.release();
player = null;
if (wineMediaUrlListener != null) {
wineMediaUrl.removeEventListener(wineMediaUrlListener);
wineMediaUrlListener = null;
}
}
}
#Override
protected void onPause() {
super.onPause();
releasePlayer();
}
#Override
public void onStop() {
super.onStop();
releasePlayer();
}
#Override
public void onDestroy() {
super.onDestroy();
releasePlayer();
}
Apologies for the code, I'm newish to coding and hoping someone can help me.
Turns out the code is fine - the error was in the upload of videos, they were overwriting the previous video meaning the previous one wouldn't play.

Unable to instantiate Sinch client- NullPointerException Error

I am using a Sinch tutorial(https://github.com/sinch/android-app-app-calling-headers) as a framework for an app I am trying to develop. The following is the login class from the tutorial which I have updated and been successful in initializing the sinch client.
public class LoginActivity extends BaseActivity implements SinchService.StartFailedListener {
private Button mLoginButton;
private EditText mLoginName;
private static final int REQUEST_PERMISSION = 10;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
mLoginName = (EditText) findViewById(R.id.loginName);
mLoginButton = (Button) findViewById(R.id.loginButton);
mLoginButton.setEnabled(false);
requestAppPermissions(new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.ACCESS_FINE_LOCATION}, R.string.msg, REQUEST_PERMISSION);
mLoginButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
loginClicked();
}
});
}
#Override
public void onPermissionGranted(int requestCode) {
}
#Override
protected void onServiceConnected() {
mLoginButton.setEnabled(true);
getSinchServiceInterface().setStartListener(this);
}
#Override
protected void onPause() {
super.onPause();
}
#Override
public void onStartFailed(SinchError error) {
Toast.makeText(this, error.toString(), Toast.LENGTH_LONG).show();
}
#Override
public void onStarted() {
openPlaceCallActivity();
}
private void loginClicked() {
String userName = mLoginName.getText().toString();
if (userName.isEmpty()) {
Toast.makeText(this, "Please enter a name", Toast.LENGTH_LONG).show();
return;
}
if (!getSinchServiceInterface().isStarted()) {
getSinchServiceInterface().startClient(userName);
} else {
openPlaceCallActivity();
}
}
private void openPlaceCallActivity() {
Intent mainActivity = new Intent(this, PlaceCallActivity.class);
startActivity(mainActivity);
}
}
The instantiation of the client occurs in the SinchService Class which is as follows:
private static final String APP_KEY = "";
private static final String APP_SECRET = "";
private static final String ENVIRONMENT = "sandbox.sinch.com";
public static final String LOCATION = "LOCATION";
public static final String CALL_ID = "CALL_ID";
static final String TAG = SinchService.class.getSimpleName();
private SinchServiceInterface mSinchServiceInterface = new SinchServiceInterface();
private SinchClient mSinchClient;
private String mUserId;
private StartFailedListener mListener;
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
if (mSinchClient != null && mSinchClient.isStarted()) {
mSinchClient.terminate();
}
super.onDestroy();
}
private void start(String userName) {
if (mSinchClient == null) {
mUserId = userName;
mSinchClient = Sinch.getSinchClientBuilder().context(getApplicationContext()).userId(userName)
.applicationKey(APP_KEY)
.applicationSecret(APP_SECRET)
.environmentHost(ENVIRONMENT).build();
mSinchClient.setSupportCalling(true);
mSinchClient.startListeningOnActiveConnection();
mSinchClient.addSinchClientListener(new MySinchClientListener());
mSinchClient.getCallClient().addCallClientListener(new SinchCallClientListener());
mSinchClient.start();
}
}
private void stop() {
if (mSinchClient != null) {
mSinchClient.terminate();
mSinchClient = null;
}
}
private boolean isStarted() {
return (mSinchClient != null && mSinchClient.isStarted());
}
#Override
public IBinder onBind(Intent intent) {
return mSinchServiceInterface;
}
public class SinchServiceInterface extends Binder {
public Call callPhoneNumber(String phoneNumber) {
return mSinchClient.getCallClient().callPhoneNumber(phoneNumber);
}
public Call callUser(String userId) {
return mSinchClient.getCallClient().callUser(userId);
}
public Call callUser(String userId, Map<String, String> headers) {
return mSinchClient.getCallClient().callUser(userId, headers);
}
public String getUserName() {
return mUserId;
}
public boolean isStarted() {
return SinchService.this.isStarted();
}
public void startClient(String userName) {
start(userName);
}
public void stopClient() {
stop();
}
public void setStartListener(StartFailedListener listener) {
mListener = listener;
}
public Call getCall(String callId) {
return mSinchClient.getCallClient().getCall(callId);
}
}
public interface StartFailedListener {
void onStartFailed(SinchError error);
void onStarted();
}
private class MySinchClientListener implements SinchClientListener {
#Override
public void onClientFailed(SinchClient client, SinchError error) {
if (mListener != null) {
mListener.onStartFailed(error);
}
mSinchClient.terminate();
mSinchClient = null;
}
#Override
public void onClientStarted(SinchClient client) {
Log.d(TAG, "SinchClient started");
if (mListener != null) {
mListener.onStarted();
}
}
#Override
public void onClientStopped(SinchClient client) {
Log.d(TAG, "SinchClient stopped");
}
#Override
public void onLogMessage(int level, String area, String message) {
switch (level) {
case Log.DEBUG:
Log.d(area, message);
break;
case Log.ERROR:
Log.e(area, message);
break;
case Log.INFO:
Log.i(area, message);
break;
case Log.VERBOSE:
Log.v(area, message);
break;
case Log.WARN:
Log.w(area, message);
break;
}
}
#Override
public void onRegistrationCredentialsRequired(SinchClient client,
ClientRegistration clientRegistration) {
}
}
private class SinchCallClientListener implements CallClientListener {
#Override
public void onIncomingCall(CallClient callClient, Call call) {
Log.d(TAG, "Incoming call");
Intent intent = new Intent(SinchService.this, IncomingCallScreenActivity.class);
intent.putExtra(CALL_ID, call.getCallId());
intent.putExtra(LOCATION, call.getHeaders().get("location"));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
SinchService.this.startActivity(intent);
}
}
}
For my purposes, I need to derive the username for the client from my shared preferences folder. I made a dummy app that uses the same framework above with the addition of shared preferences but I always get a NullPointerException error. The following is my login class from my dummy app.
public class LoginActivity extends BaseActivity implements SinchService.StartFailedListener {
private EditText mLoginName, recipientName, coordinateA, coordinateB;
private Button loginButton;
private static final int REQUEST_PERMISSION = 10;
public static final String DEFAULT = "N/A";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
userName = (EditText) findViewById(R.id.userInput);
recipientName = (EditText) findViewById(R.id.recipientInput);
loginButton = (Button) findViewById(R.id.loginButton);
requestAppPermissions(new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.ACCESS_FINE_LOCATION}, R.string.msg, REQUEST_PERMISSION);
SharedPreferences sharedPreferences = getSharedPreferences("MyData", MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("user_name", mLoginName.getText().toString());
editor.putString("recipient_name", recipientName.getText().toString());
editor.commit();
loginButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
loginClicked();
}
});
}
#Override
public void onPermissionGranted(int requestCode) {
}
#Override
protected void onServiceConnected() {
getSinchServiceInterface().setStartListener(this);
}
#Override
protected void onPause() {
super.onPause();
}
#Override
public void onStartFailed(SinchError error) {
Toast.makeText(this, error.toString(), Toast.LENGTH_LONG).show();
}
#Override
public void onStarted() {
openPlaceCallActivity();
}
private void loginClicked() {
SharedPreferences sharedPreferences = getSharedPreferences("MyData", MODE_PRIVATE);
String userName = sharedPreferences.getString("user_name", DEFAULT);
if (userName.isEmpty()) {
Toast.makeText(this, "Please enter a name",
Toast.LENGTH_LONG).show();
return;
}
if (!getSinchServiceInterface().isStarted()) {
getSinchServiceInterface().startClient(userName);
} else {
openPlaceCallActivity();
}
}
private void openPlaceCallActivity() {
Intent mainActivity = new Intent(LoginActivity.this, PlaceCallActivity.class);
startActivity(mainActivity);
}
}
When comparing my login class with the tutorial's login class-- the only difference is where the variable "userName" is derived. We both have a value attached to the username; however, only one client is able to establish while the other throws a NullPointerException Error. Anyone know why?
EDIT: The error message is as follows:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.dejon_000.sinchtest2, PID: 32470
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean com.example.dejon_000.sinchtest2.SinchService$SinchServiceInterface.isStarted()' on a null object reference
at com.example.dejon_000.sinchtest2.LoginActivity.loginClicked(LoginActivity.java:83)
at com.example.dejon_000.sinchtest2.LoginActivity.access$000(LoginActivity.java:17)
at com.example.dejon_000.sinchtest2.LoginActivity$1.onClick(LoginActivity.java:47)
at android.view.View.performClick(View.java:4802)
at android.view.View$PerformClick.run(View.java:20059)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5422)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:914)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:707)
SECOND EDIT: The getSinchServiceInterface() method is found in the BaseActivity class. It is as follows:
public abstract class BaseActivity extends Activity implements ServiceConnection {
private SparseIntArray mErrorString;
public static final String DEFAULT = "N/A";
private SinchService.SinchServiceInterface mSinchServiceInterface;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getApplicationContext().bindService(new Intent(this, SinchService.class), this,
BIND_AUTO_CREATE);
mErrorString = new SparseIntArray();
}
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
if (SinchService.class.getName().equals(componentName.getClassName())) {
mSinchServiceInterface = (SinchService.SinchServiceInterface) iBinder;
onServiceConnected();
}
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
if (SinchService.class.getName().equals(componentName.getClassName())) {
mSinchServiceInterface = null;
onServiceDisconnected();
}
}
protected void onServiceConnected() {
// for subclasses
}
protected void onServiceDisconnected() {
// for subclasses
}
protected SinchService.SinchServiceInterface getSinchServiceInterface() {
return mSinchServiceInterface;
}
public abstract void onPermissionGranted(int requestCode);
public void requestAppPermissions(final String[] requestedPermissions, final int stringId, final int requestCode) {
mErrorString.put(requestCode, stringId);
int permissionCheck = PackageManager.PERMISSION_GRANTED;
boolean showRequestPermissions = false;
for (String permission : requestedPermissions) {
permissionCheck = permissionCheck + ContextCompat.checkSelfPermission(this, permission);
showRequestPermissions = showRequestPermissions || ActivityCompat.shouldShowRequestPermissionRationale(this, permission);
}
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
if (showRequestPermissions) {
Snackbar.make(findViewById(android.R.id.content), stringId, Snackbar.LENGTH_INDEFINITE).setAction("GRANT", new View.OnClickListener() {
#Override
public void onClick(View view) {
ActivityCompat.requestPermissions(BaseActivity.this, requestedPermissions, requestCode);
}
}).show();
} else {
ActivityCompat.requestPermissions(this, requestedPermissions, requestCode);
}
} else {
onPermissionGranted(requestCode);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
int permissionCheck = PackageManager.PERMISSION_GRANTED;
for(int permission : grantResults){
permissionCheck = permissionCheck + permission;
}
if((grantResults.length > 0)&& PackageManager.PERMISSION_GRANTED == permissionCheck ){
onPermissionGranted(requestCode);
}else{
Snackbar.make(findViewById(android.R.id.content), mErrorString.get(requestCode), Snackbar.LENGTH_INDEFINITE).setAction("ENABLE", new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent i = new Intent();
i.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
i.setData(Uri.parse("package:"+ getPackageName()));
i.addCategory(Intent.CATEGORY_DEFAULT);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
startActivity(i);
}
}).show();
}
}
}
Try this :
on your BaseActivity.java
instead of
protected void onServiceConnected() {
// for subclasses
}
put
protected void onServiceConnected(IBinder iBinder) {
mSinchServiceInterface = (SinchService.SinchServiceInterface) iBinder;
}
and in your LoginActivity.java
Override the function onServiceConnected(IBinder iBinder)
#Override
protected void onServiceConnected(IBinder iBinder) {
super.onServiceConnected(iBinder);
getSinchServiceInterface().setStartListener(this);
}

Service is returning null despite running in the background

I am trying to implement an Instant Messaging functionality into my app following this guide: https://www.sinch.com/tutorials/android-messaging-tutorial-using-sinch-and-parse/#start the sinch client
I have followed everything in the guide exactly, but when I attempt to send a message I get a NullPointerException. Here is the guilty code:
private void sendMessage() {
messageBody = messageBodyField.getText().toString();
if (messageBody.isEmpty()) {
Toast.makeText(getApplicationContext(), "Enter a message", Toast.LENGTH_LONG).show();
return;
}
Log.i(TAG, "messageService: " + messageService);
Log.i(TAG, "recipientId: " + recipientId);
Log.i(TAG, "messageBody: " + messageBody);
messageService.sendMessage(recipientId, messageBody);
messageBodyField.setText("");
}
From the logs, I see that the recipientId and messageBody are properly assigned, and that the messageService object is null. Below is the full code of the activity:
public class ChatActivity extends AppCompatActivity {
private static final String TAG = "ChatActivity";
private String recipientId;
private EditText messageBodyField;
private ListView messagesList;
private ChatAdapter chatAdapter;
private String messageBody;
private MessageService.MessageServiceInterface messageService;
private String currentUserId;
private ServiceConnection serviceConnection = new MyServiceConnection();
private MessageClientListener messageClientListener = new MyMessageClientListener();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chat);
bindService(new Intent(this, MessageService.class), serviceConnection, BIND_AUTO_CREATE);
//Log.i("Tag", "bindService(): " + bindService(new Intent(this, MessageService.class), serviceConnection, BIND_AUTO_CREATE));
Intent intent = getIntent();
recipientId = intent.getStringExtra("RECIPIENT_ID");
currentUserId = ParseUser.getCurrentUser().getObjectId();
messagesList = (ListView) findViewById(R.id.listview_chat);
chatAdapter = new ChatAdapter(this);
messagesList.setAdapter(chatAdapter);
loadMessageHistory();
messageBodyField = (EditText) findViewById(R.id.edittext_messageBodyField);
findViewById(R.id.button_send).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
sendMessage();
}
});
}
private void loadMessageHistory() {
String[] userIds = {currentUserId, recipientId};
ParseQuery<ParseObject> query = ParseQuery.getQuery("ParseMessage");
query.whereContainedIn("senderId", Arrays.asList(userIds));
query.whereContainedIn("recipientId", Arrays.asList(userIds));
query.orderByAscending("createdAt");
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> messageList, ParseException e) {
if (e == null) {
for (int i = 0; i < messageList.size(); i++) {
WritableMessage message = new WritableMessage(messageList.get(i).get("recipientId").toString(), messageList.get(i).get("messageText").toString());
if (messageList.get(i).get("senderId").toString().equals(currentUserId)) {
chatAdapter.addMessage(message, ChatAdapter.DIRECTION_OUTGOING);
} else {
chatAdapter.addMessage(message, ChatAdapter.DIRECTION_INCOMING);
}
}
}
}
});
}
private void sendMessage() {
messageBody = messageBodyField.getText().toString();
if (messageBody.isEmpty()) {
Toast.makeText(getApplicationContext(), "Enter a message", Toast.LENGTH_LONG).show();
return;
}
Log.i(TAG, "messageService: " + messageService);
Log.i(TAG, "recipientId: " + recipientId);
Log.i(TAG, "messageBody: " + messageBody);
messageService.sendMessage(recipientId, messageBody);
messageBodyField.setText("");
}
#Override
public void onDestroy() {
messageService.removeMessageClientListener(messageClientListener);
unbindService(serviceConnection);
super.onDestroy();
}
private class MyServiceConnection implements ServiceConnection {
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
messageService = (MessageService.MessageServiceInterface) iBinder;
Log.i(TAG, "messageService::onServiceConnected: " + messageService);
messageService.addMessageClientListener(messageClientListener);
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
messageService = null;
Log.i(TAG, "messageService::onServiceDisconnected: " + messageService);
}
}
private class MyMessageClientListener implements MessageClientListener {
#Override
public void onMessageFailed(MessageClient client, Message message, MessageFailureInfo failureInfo) {
Toast.makeText(ChatActivity.this, "Failed to send message", Toast.LENGTH_LONG).show();
}
#Override
public void onIncomingMessage(MessageClient client, final Message message) {
if (message.getSenderId().equals(recipientId)) {
final WritableMessage writableMessage = new WritableMessage(message.getRecipientIds().get(0), message.getTextBody());
ParseQuery<ParseObject> query = ParseQuery.getQuery("ParseMessage");
query.whereEqualTo("sinchId", message.getMessageId());
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> messageList, ParseException e) {
if (e == null) {
if (messageList.size() == 0) {
ParseObject parseMessage = new ParseObject("ParseMessage");
parseMessage.put("senderId", currentUserId);
parseMessage.put("recipientId", writableMessage.getRecipientIds().get(0));
parseMessage.put("messageText", writableMessage.getTextBody());
parseMessage.put("sinchId", message.getMessageId());
parseMessage.saveInBackground();
chatAdapter.addMessage(writableMessage, chatAdapter.DIRECTION_INCOMING);
}
}
}
});
}
}
#Override
public void onMessageSent(MessageClient client, Message message, String recipientId) {
final WritableMessage writableMessage = new WritableMessage(message.getRecipientIds().get(0), message.getTextBody());
chatAdapter.addMessage(writableMessage, ChatAdapter.DIRECTION_OUTGOING);
}
#Override
public void onMessageDelivered(MessageClient client, MessageDeliveryInfo deliveryInfo) {
}
#Override
public void onShouldSendPushData(MessageClient client, Message message, List<PushPair> pushPairs) {
}
}
}
And the MessageService class code:
package com.example.aes.ctf;
public class MessageService extends Service implements SinchClientListener {
private static final String APP_KEY = "app-key";
private static final String APP_SECRET = "secret";
private static final String ENVIRONMENT = "";
private final MessageServiceInterface serviceInterface = new MessageServiceInterface();
private SinchClient sinchClient = null;
private MessageClient messageClient = null;
private String currentUserId;
//private Intent broadcastIntent = new Intent("com.example.aes.ctf.ListUsersActivity");
//private LocalBroadcastManager broadcaster;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
currentUserId = ParseUser.getCurrentUser().getObjectId();
if (currentUserId != null && !isSinchClientStarted()) {
startSinchClient(currentUserId);
}
//broadcaster = LocalBroadcastManager.getInstance(this);
return super.onStartCommand(intent, flags, startId);
}
public void startSinchClient(String username) {
sinchClient = Sinch.getSinchClientBuilder().context(this).userId(username)
.applicationKey(APP_KEY).applicationSecret(APP_SECRET)
.environmentHost(ENVIRONMENT).build();
sinchClient.addSinchClientListener(this);
sinchClient.setSupportMessaging(true);
sinchClient.setSupportActiveConnectionInBackground(true);
sinchClient.checkManifest();
sinchClient.start();
}
private boolean isSinchClientStarted() {
return sinchClient != null && sinchClient.isStarted();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onClientStarted(SinchClient client) {
/*broadcastIntent.putExtra("success", true);
broadcaster.sendBroadcast(broadcastIntent);*/
client.startListeningOnActiveConnection();
messageClient = client.getMessageClient();
}
#Override
public void onClientStopped(SinchClient client) {
client = null;
}
#Override
public void onClientFailed(SinchClient client, SinchError sinchError) {
/*broadcastIntent.putExtra("success", false);
broadcaster.sendBroadcast(broadcastIntent);*/
client = null;
}
#Override
public void onRegistrationCredentialsRequired(SinchClient sinchClient, ClientRegistration clientRegistration) {
}
#Override
public void onLogMessage(int i, String s, String s1) {
}
public void sendMessage(String recipientUserId, String textBody) {
if (messageClient != null) {
WritableMessage message = new WritableMessage(recipientUserId, textBody);
messageClient.send(message);
}
}
public void addMessageClientListener(MessageClientListener listener) {
if (messageClient != null) {
messageClient.addMessageClientListener(listener);
}
}
public void removeMessageClientListener(MessageClientListener listener) {
if (messageClient != null) {
messageClient.removeMessageClientListener(listener);
}
}
#Override
public void onDestroy() {
sinchClient.stopListeningOnActiveConnection();
sinchClient.terminate();
}
public class MessageServiceInterface extends Binder {
public void sendMessage(String recipientUserId, String textBody) {
MessageService.this.sendMessage(recipientUserId, textBody);
}
public void addMessageClientListener(MessageClientListener listener) {
MessageService.this.addMessageClientListener(listener);
}
public void removeMessageClientListener(MessageClientListener listener) {
MessageService.this.removeMessageClientListener(listener);
}
public boolean isSinchClientStarted() {
return MessageService.this.isSinchClientStarted();
}
}
}
I can post more related code if needed. I've been stuck on this error for awhile.
EDIT:
I was able to fix it by changing
#Override
public IBinder onBind(Intent intent) {
return null;
}
to
#Override
public IBinder onBind(Intent intent) {
return serviceInterface;
}
Thanks guy!
well, this is because you never INITIALIZE the messageService object.
it seems like you wish to start a service and then - control it from your activity... are you sure you wish to send messages from a service rather from an AsyncTask?
AsyncTask also run in the background and much more easier to control for this purpose...
try to chek this link: http://developer.android.com/reference/android/os/AsyncTask.html
Your problem is here:
#Override
public IBinder onBind(Intent intent) {
return null;
}
You should implement a binder for your service and return it in the onBind method of your service, so in your MessageServiceInterface class declare following method:
public MessageService getService() {
Log.v("Serivce Bind", "Bind");
return MessageService.this;
}
}
And declare a field in MessageService class:
IBinder binder = new MessageSeviceInterface();
Return binder instance in onBind method and finally get the allocated instance of MessageService using following code:
Replace
messageService = (MessageService.MessageServiceInterface) iBinder;
With:
MessageService.MessageServiceInterface binder = (MessageService.MessageServiceInterface) iBinder;
messageService = binder.getService()`

Categories