I am working on a quiz app basically. In my app there are many questions getting datas from Firebase Database with those areas (question, optionA,optionB,optionC,optionD and correctANS) but I want to improve my project. I want to add image questions instead of text questions. For this I added an area(urlImage) to my database on Firebase. Normally I can get data from Firebase except urlImage but I didn't see Image in ImageView in my app. What should i do? Please someone help me?
those are my QuestionsActivity codes:
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_questions);
Toolbar toolbar=findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
question=findViewById(R.id.question);
urlImage=findViewById(R.id.urlImage);
noIndicator=findViewById(R.id.no_indicator);
bookmarkBtn=findViewById(R.id.bookmark_btn);
optionsContainer=findViewById(R.id.option_container);
shareBtn=findViewById(R.id.share_btn);
nextBtn=findViewById(R.id.next_btn);
preferences=getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
editor=preferences.edit();
gson=new Gson();
getBookmarks();
bookmarkBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (modelMatch()){
bookmarkslist.remove(matchedQuestionPosition);
bookmarkBtn.setImageDrawable(getDrawable(R.drawable.bookmark_border));
}else{
bookmarkslist.add(list.get(position));
bookmarkBtn.setImageDrawable(getDrawable(R.drawable.bookmark));
}
}
});
setId=getIntent().getStringExtra("setId");
loadingDialog=new Dialog(this);
loadingDialog.setContentView(R.layout.loading);
loadingDialog.getWindow().setBackgroundDrawable(getDrawable(R.drawable.rounded_corner2));
loadingDialog.getWindow().setLayout(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT);
loadingDialog.setCancelable(false);
list=new ArrayList<>();
loadingDialog.show();
myRef.child("SETS").child(setId).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot dataSnapshot1 :dataSnapshot.getChildren()){
String id=dataSnapshot1.getKey();
String question= dataSnapshot1.child("question").getValue().toString();
String a= dataSnapshot1.child("optionA").getValue().toString();
String b= dataSnapshot1.child("optionB").getValue().toString();
String c= dataSnapshot1.child("optionC").getValue().toString();
String d= dataSnapshot1.child("optionD").getValue().toString();
String correctANS= dataSnapshot1.child("correctANS").getValue().toString();
String urlImage= dataSnapshot1.child("urlImage").getValue().toString();
list.add(new QuestionModel(id,question,a,b,c,d,correctANS,urlImage,setId));
}
if (list.size() > 0){
for (int i=0;i<4;i++){
optionsContainer.getChildAt(i).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
checkhanswer(((Button)view));
}
});
}
playAnim(question,0,list.get(position).getQuestion());
nextBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
nextBtn.setEnabled(false);
nextBtn.setAlpha(0.7f);
enableOption(true);
position++;
if (position==list.size()){
Intent scoreIntent=new Intent(QuestionsActivity.this,ScoreActivity.class);
scoreIntent.putExtra("score",score);
scoreIntent.putExtra("total",list.size());
startActivity(scoreIntent);
finish();
return;
}
count=0;
playAnim(question,0,list.get(position).getQuestion());
}
});
}else{
finish();
Toast.makeText(QuestionsActivity.this, "There isn't any question.", Toast.LENGTH_SHORT).show();
}
loadingDialog.dismiss();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Toast.makeText(QuestionsActivity.this, error.getMessage(), Toast.LENGTH_SHORT).show();
loadingDialog.dismiss();
finish();
}
});
// playAnim(question,0,list.get(position).getQuestion());
}
#Override
protected void onPause() {
super.onPause();
storeBookmarks();
}
private void playAnim(final View view, final int value, final String data){
// for (int i=0;i<4;i++){
// optionsContainer.getChildAt(i).setBackgroundTintList(null);
// }
view.animate().alpha(value).scaleX(value).scaleY(value).setDuration(500).setStartDelay(100)
.setInterpolator(new DecelerateInterpolator()).setListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animator) {
if (value == 0 && count<4){
String option="";
if (count==0){
option=list.get(position).getA();
}
else if(count==1){
option=list.get(position).getB();
}
else if(count==2){
option=list.get(position).getC();
}
else if(count==3){
option=list.get(position).getD();
}
playAnim(optionsContainer.getChildAt(count),0,option);
count++;
}
}
#Override
public void onAnimationEnd(Animator animator) {
((TextView)view).setText(data);
if (value==0){
try {
((TextView)view).setText(data);
noIndicator.setText(position+1+"/"+list.size());
if (modelMatch()){
bookmarkBtn.setImageDrawable(getDrawable(R.drawable.bookmark));
}else{
bookmarkBtn.setImageDrawable(getDrawable(R.drawable.bookmark_border));
}
}catch (ClassCastException e){
((Button)view).setText(data);
}
view.setTag(data);
playAnim(view,1,data);
// playAnim(urlResim,0,list.get(position).getUrlResim());
}
}
#Override
public void onAnimationCancel(Animator animator) {
}
#Override
public void onAnimationRepeat(Animator animator) {
}
});
}
those are my QuestionModel codes:
public class QuestionModel {
private String id,question,A,B,C,D,answer,set,urlImage;
public QuestionModel(String id, String question, String a, String b, String c, String d, String answer,
String set,String urlImage) {
this.id = id;
this.question = question;
A = a;
B = b;
C = c;
D = d;
this.answer = answer;
this.set = set;
this.urlImage=urlImage;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
public String getA() {
return A;
}
public void setA(String a) {
A = a;
}
public String getB() {
return B;
}
public void setB(String b) {
B = b;
}
public String getC() {
return C;
}
public void setC(String c) {
C = c;
}
public String getD() {
return D;
}
public void setD(String d) {
D = d;
}
public String getAnswer() {
return answer;
}
public void setAnswer(String answer) {
this.answer = answer;
}
public String getSet() {
return set;
}
public void setSet(String set) {
this.set = set;
}
public String getUrlImage() {
return urlImage;
}
public void setUrlImage(String urlResim) {
this.urlImage = urlImage;
}
}
Related
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
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.
I am trying to use Google Nearby Connections API to connect two Android devices to exchange data but no success.
The devices can found eachother none of them can connect to the other. It always fails at onConnectionInitiated() with
STATUS_ENDPOINT_UNKNOWN when I try to accept the connection.
I tried it with Strategy.P2P_POINT_TO_POINT Strategy.CLUSTER and Strategy.STAR but I get the same result.
Anyone can help me what do I miss?
Both devices are physical and running on Android 9.0
This is the code:
public static ConnectionLifecycleCallback connectionLifecycleCallback;
public static EndpointDiscoveryCallback endpointDiscoveryCallback;
public static PayloadCallback payloadCallback;
public static String SERVICE_ID;
public Context ctx;
public static Strategy STRATEGY;
public NearbyHandler(Context ctx,Strategy STRATEGY){
this.ctx = ctx;
this.STRATEGY = STRATEGY;
SERVICE_ID = ctx.getPackageName();
payloadCallback = new PayloadCallback() {
#Override
public void onPayloadReceived(#NonNull String s, #NonNull Payload payload) {
Log.d("NEARBY_", "PAYLOAD RECEIVED " + s);
}
#Override
public void onPayloadTransferUpdate(#NonNull String s, #NonNull PayloadTransferUpdate payloadTransferUpdate) {
Log.d("NEARBY_", "PAYLOAD TRANSFER UPDATE " + s);
}
};
connectionLifecycleCallback = new ConnectionLifecycleCallback() {
#Override
public void onConnectionInitiated(#NonNull String s, #NonNull ConnectionInfo connectionInfo) {
Nearby.getConnectionsClient(ctx)
.acceptConnection(s, payloadCallback)
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d("NEARBY_", "SUCCESSFULLY CONNECTED");
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
e.printStackTrace();
}
});
}
#Override
public void onConnectionResult(#NonNull String s, #NonNull ConnectionResolution connectionResolution) {
switch (connectionResolution.getStatus().getStatusCode()) {
case ConnectionsStatusCodes.STATUS_OK:
Nearby.getConnectionsClient(ctx).stopAdvertising();
Nearby.getConnectionsClient(ctx).stopDiscovery();
break;
case ConnectionsStatusCodes.STATUS_CONNECTION_REJECTED:
break;
case ConnectionsStatusCodes.STATUS_ERROR:
break;
}
}
#Override
public void onDisconnected(#NonNull String s) {
Log.d("NEARBY_", "DISCONNECTED " + s);
}
};
endpointDiscoveryCallback = new EndpointDiscoveryCallback() {
#Override
public void onEndpointFound(#NonNull String s, #NonNull DiscoveredEndpointInfo discoveredEndpointInfo) {
Nearby.getConnectionsClient(ctx)
.requestConnection(
s,
ctx.getPackageName(),
connectionLifecycleCallback)
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d("NEARBY_", "ENDPOINT CONNECTED");
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.d("NEARBY_", "FAILED TO CONNECT ENDPOINT " + e.getMessage());
e.printStackTrace();
}
});
}
#Override
public void onEndpointLost(#NonNull String s) {
Log.d("NEARBY_", "ENDPOINT LOST: " + s);
}
};
}
public void startDiscovering() {
Nearby.getConnectionsClient(ctx)
.startDiscovery(
SERVICE_ID,
endpointDiscoveryCallback,
new DiscoveryOptions.Builder()
.setStrategy(CONSTANTS.PEERTOPEER_STRATEGY).build())
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d("NEARBY_DISCOVERER_", "onSuccess");
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
e.printStackTrace();
}
});
}
public void startAdvertising() {
Nearby.getConnectionsClient(ctx)
.startAdvertising(
Build.MODEL,
SERVICE_ID,
connectionLifecycleCallback,
new AdvertisingOptions.Builder()
.setStrategy(CONSTANTS.PEERTOPEER_STRATEGY).build())
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
e.printStackTrace();
}
});
}
}
NearbyHandler nearby = new NearbyHandler(getApplicationContext(), Strategy.P2P_POINT_TO_POINT);
if (IS_DEVICE_A) {
nearby.startAdvertising();
} else {
nearby.startDiscovering();
}
Update: Google's walkietalkie demo app works fine on both phones.
Finally I've managed to get it working but not sure about the problem.
I managed the connection lifecycle a bit different way than in the API Docs.
So I created a private helper class
class Endpoint {
#NonNull
private final String id;
#NonNull
private final String name;
public Endpoint(#NonNull String id, #NonNull String name) {
this.id = id;
this.name = name;
}
#NonNull
public String getId() {
return id;
}
#NonNull
public String getName() {
return name;
}
#Override
public boolean equals(Object obj) {
if (obj instanceof Endpoint) {
Endpoint other = (Endpoint) obj;
return id.equals(other.id);
}
return false;
}
#Override
public int hashCode() {
return id.hashCode();
}
#Override
public String toString() {
return String.format("Endpoint{id=%s, name=%s}", id, name);
}
}
The ConnectionLifecycleCallback() and EndpointDiscoveryCallback() should look like this:
endpointDiscoveryCallback = new EndpointDiscoveryCallback() {
#Override
public void onEndpointFound(#NonNull String s, #NonNull DiscoveredEndpointInfo discoveredEndpointInfo) {
Endpoint endpoint = new Endpoint(s, discoveredEndpointInfo.getEndpointName());
ConnectionsClient c = Nearby.getConnectionsClient(ctx);
c.requestConnection(endpoint.getName(), endpoint.getId(), connectionLifecycleCallback).addOnSuccessListener(new OnSuccessListener < Void > () {
#Override
public void onSuccess(Void aVoid) {}
});
}
#Override
public void onEndpointLost(#NonNull String s) {}
};
connectionLifecycleCallback = new ConnectionLifecycleCallback() {
#Override
public void onConnectionInitiated(#NonNull String s, #NonNull ConnectionInfo connectionInfo) {
Nearby.getConnectionsClient(ctx).stopAdvertising();
Nearby.getConnectionsClient(ctx).stopDiscovery();
Endpoint endpoint = new Endpoint(s, connectionInfo.getEndpointName());
ConnectionsClient c = Nearby.getConnectionsClient(ctx);
c.acceptConnection(endpoint.getId(), payloadCallback).addOnSuccessListener(new OnSuccessListener < Void > () {
#Override
public void onSuccess(Void aVoid) {}
});
}
#Override
public void onConnectionResult(#NonNull String s, #NonNull ConnectionResolution connectionResolution) {
switch (connectionResolution.getStatus().getStatusCode()) {
case ConnectionsStatusCodes.STATUS_OK:
Nearby.getConnectionsClient(ctx).stopAdvertising();
Nearby.getConnectionsClient(ctx).stopDiscovery();
break;
case ConnectionsStatusCodes.STATUS_CONNECTION_REJECTED:
// The connection was rejected by one or both sides.
break;
case ConnectionsStatusCodes.STATUS_ERROR:
// The connection broke before it was able to be accepted.
break;
}
}
#Override
public void onDisconnected(#NonNull String s) {}
};
FCM with agora Implementation
I have down agora part but have to implement firebase console.
I have configured cm. Previously I was using sinch to have called between two apps but now want to change to calling with agoro but with the same concept. In that, we were sending a token to the server and according to that sinch use to handle the call.
public class MainActivity extends AppCompatActivity {
private static final int PERMISSION_REQ_ID = 22;
private static final String[] REQUESTED_PERMISSIONS = {
Manifest.permission.RECORD_AUDIO,
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
private static final String TAG="Agora ";
private RtcEngine mRtcEmgine;
private FrameLayout mLocalContainer;
private RelativeLayout mRemoteContainer;
private SurfaceView mLocalView;
private SurfaceView mremoteView;
private ImageView mCallBtn;
private ImageView mMuteBtn;
private ImageView mSwitchCameraBtn;
private boolean mCallEnd;
private boolean mMuted;
private final IRtcEngineEventHandler mRtcHandler= new IRtcEngineEventHandler() {
#Override
public void onJoinChannelSuccess(String channel,final int uid, int elapsed) {
super.onJoinChannelSuccess(channel, uid, elapsed);
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.e("agora","Join channel success, uid "+(uid &0xFFFFFFFFL));
}
});
}
#Override
public void onUserOffline(final int uid, int reason) {
super.onUserOffline(uid, reason);
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.e("agora","User Offline, uid "+(uid &0xFFFFFFFFL));
removeRemoteVideo();
}
});
}
#Override
public void onRemoteVideoStateChanged(final int uid, int state, int reason, int elapsed) {
super.onRemoteVideoStateChanged(uid, state, reason, elapsed);
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.e("agora","First reomte video decoded, uid "+(uid &0xFFFFFFFFL));
setupRemoteVideo(uid);
}
});
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//initUI();
mLocalContainer=findViewById(R.id.local_video_view_container);
mRemoteContainer=findViewById(R.id.remote_video_view_container);
mCallBtn=findViewById(R.id.btn_call);
mCallBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mCallEnd){
startCall();
mCallEnd=false;
mCallBtn.setImageResource(R.drawable.btn_endcall);
}
else {
endCall();
mCallEnd=true;
mCallBtn.setImageResource(R.drawable.btn_startcall);
}
showButton(!mCallEnd);
}
});
mMuteBtn=findViewById(R.id.btn_mute);
mMuteBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mMuted = !mMuted;
mRtcEmgine.muteLocalAudioStream(mMuted);
int res = mMuted ? R.drawable.btn_mute : R.drawable.btn_unmute;
mMuteBtn.setImageResource(res);
}
});
mSwitchCameraBtn=findViewById(R.id.btn_switch_camera);
mSwitchCameraBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mRtcEmgine.switchCamera();
}
});
if (checkSelfpermission(REQUESTED_PERMISSIONS[0]) &&
checkSelfpermission(REQUESTED_PERMISSIONS[1]) &&
checkSelfpermission(REQUESTED_PERMISSIONS[2]))
{
Log.e(TAG," true ");
initEngineAndJoinChannel();
}
else {
Log.e(TAG," false ");
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if (requestCode == PERMISSION_REQ_ID) {
if (grantResults[0] != PackageManager.PERMISSION_GRANTED ||
grantResults[1] != PackageManager.PERMISSION_GRANTED ||
grantResults[2] != PackageManager.PERMISSION_GRANTED) {
Log.e(TAG,"Need permissions " + Manifest.permission.RECORD_AUDIO +
"/" + Manifest.permission.CAMERA + "/" + Manifest.permission.WRITE_EXTERNAL_STORAGE);
finish();
return;
}
initEngineAndJoinChannel();
}
}
#Override
protected void onDestroy(){
super.onDestroy();
if (!mCallEnd){
leaveChannel();
}
RtcEngine.destroy();
}
private void initUI() {
Log.e(TAG," UI ");
mLocalContainer=findViewById(R.id.local_video_view_container);
mRemoteContainer=findViewById(R.id.remote_video_view_container);
mCallBtn=findViewById(R.id.btn_call);
mMuteBtn=findViewById(R.id.btn_mute);
mSwitchCameraBtn=findViewById(R.id.btn_switch_camera);
}
private void initEngineAndJoinChannel() {
initializeEngine();
setupVideoConfig();
setupLocalVideo();
joinChannel();
}
private void setupVideoConfig() {
Log.e(TAG,"running 2");
mRtcEmgine.enableVideo();
mRtcEmgine.setVideoEncoderConfiguration(new VideoEncoderConfiguration(
VideoEncoderConfiguration.VD_640x360,
VideoEncoderConfiguration.FRAME_RATE.FRAME_RATE_FPS_15,
VideoEncoderConfiguration.STANDARD_BITRATE,
VideoEncoderConfiguration.ORIENTATION_MODE.ORIENTATION_MODE_FIXED_PORTRAIT
));
}
private void setupLocalVideo() {
Log.e(TAG,"running 3");
mRtcEmgine.enableVideo();
mLocalView=RtcEngine.CreateRendererView(getBaseContext());
mLocalView.setZOrderMediaOverlay(true);
mLocalContainer.addView(mLocalView);
VideoCanvas localVideoCanvas = new VideoCanvas(mLocalView, VideoCanvas.RENDER_MODE_HIDDEN,0);
mRtcEmgine.setupLocalVideo(localVideoCanvas);
}
private void setupRemoteVideo(int uid) {
int count = mRemoteContainer.getChildCount();
View view = null;
for(int i = 0; i < count; i++) {
View v= mRemoteContainer.getChildAt(i);
if (v.getTag() instanceof Integer && ((int)v.getTag()) == uid) {
view = v;
}
}
if (view != null) {
return;
}
mremoteView = RtcEngine.CreateRendererView(getBaseContext());
mRemoteContainer.addView(mremoteView);
mRtcEmgine.setupRemoteVideo(new VideoCanvas(mremoteView, VideoCanvas.RENDER_MODE_HIDDEN, uid));
mremoteView.setTag(uid);
}
private void initializeEngine() {
Log.e(TAG,"running 1");
try {
mRtcEmgine=RtcEngine.create(getBaseContext(),getString(R.string.agora_app_id),mRtcHandler);
}
catch (Exception e) {
Log.e(TAG,Log.getStackTraceString(e));
throw new RuntimeException("NEED TO check rtc sdk fatal error \n"+Log.getStackTraceString(e));
}
}
private void removeRemoteVideo() {
if (mremoteView != null) {
mRemoteContainer.removeView(mremoteView);
}
mremoteView = null;
}
private void joinChannel() {
Log.e(TAG,"running 4");
String token = getString(R.string.agora_access_token);
if (TextUtils.isEmpty(token)) {
token = null;
}
mRtcEmgine.joinChannel(token,"demochannel", "", 0);
}
private void leaveChannel() {
mRtcEmgine.leaveChannel();
}
/* public void onLocalAudioMuteClicked(View view) {
mMuted = !mMuted;
mRtcEmgine.muteLocalAudioStream(mMuted);
int res = mMuted ? R.drawable.btn_mute : R.drawable.btn_unmute;
mMuteBtn.setImageResource(res);
}*/
/* public void onSwitchClicked(View view) {
mRtcEmgine.switchCamera();
}*/
/* public void onCallClicked(View view) {
if (mCallEnd){
startCall();
mCallEnd = false;
mCallBtn.setImageResource(R.drawable.btn_endcall);
}
else {
endCall();
mCallEnd = true;
mCallBtn.setImageResource(R.drawable.btn_startcall);
}
showButton(!mCallEnd);
}*/
private void startCall() {
setupLocalVideo();
joinChannel();
}
private void endCall() {
removeLocalVideo();
removeRemoteVideo();
leaveChannel();
}
private void removeLocalVideo() {
if (mLocalView != null) {
mLocalContainer.removeView(mLocalView);
}
mLocalView = null;
}
private void showButton(boolean show) {
int visibilty = show ? View.VISIBLE : View.GONE;
mMuteBtn.setVisibility(visibilty);
mSwitchCameraBtn.setVisibility(visibilty);
}
private Boolean checkSelfpermission(String permission) {
if (ContextCompat.checkSelfPermission(this,permission) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, REQUESTED_PERMISSIONS, MainActivity.PERMISSION_REQ_ID);
return false;
}
return true;
}
}
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.