Nous utilisons Sinch voip api. Il y a un service lié qui commence au démarrage de l'application, nous initialisons le client sinch dans le service et il fonctionne toujours en arrière-plan. J'ai essayé de mettre le code pour la notification dans l'activité de l'écran d'appel car cette activité s'affichera toujours pour accepter l'appel. Mon but est de pouvoir cliquer sur la notification et de rouvrir cette activité d'appel comme dans whatsapp.Notification pour reprendre l'activité qui est passé en arrière-plan en utilisant backpress
public class CallScreenActivity extends BaseActivity {
static final String TAG = CallScreenActivity.class.getSimpleName();
private AudioPlayer mAudioPlayer;
private Timer mTimer;
private UpdateCallDurationTask mDurationTask;
private String mCallId;
String mCaller, mReceiver;
String otherusername, myname;
private long mCallStart = 0;
private TextView mCallDuration;
private TextView mCallState;
private TextView mCallerName;
private ImageView mCallImg;
private String mk, mTimestamp;
private String mProfpic;
Button endCallButton;
Notification notification;
NotificationManager notificationManager;
private class UpdateCallDurationTask extends TimerTask {
@Override
public void run() {
CallScreenActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
updateCallDuration();
}
});
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+ WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
| +WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| +WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
setContentView(R.layout.activity_callscreen);
mAudioPlayer = new AudioPlayer(this);
mCallDuration = (TextView) findViewById(R.id.callDuration);
mCallerName = (TextView) findViewById(R.id.remoteUser);
mCallState = (TextView) findViewById(R.id.callState);
mCallImg = (ImageView) findViewById(R.id.imgotherusr);
endCallButton = (Button) findViewById(R.id.hangupButton);
endCallButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
endCall();
}
});
mCallStart = System.currentTimeMillis();
mCallId = getIntent().getStringExtra(SinchCallService.CALL_ID);
UserSession us = new UserSession(this);
mk = us.getUserKey();
myname = us.getUsername();
mCaller = getIntent().getStringExtra("calleruid");
mReceiver = getIntent().getStringExtra("receiveruid");
otherusername = getIntent().getStringExtra("otherusername");
mTimestamp = getIntent().getStringExtra("timestamp");
System.out.println(mCaller+"on create call screen activity ongoing call" + mReceiver + otherusername);
showNotification();
}
private void showNotification() {
System.out.println("show notification callscreenactivity");
Intent notificationIntent = new Intent(this, CallScreenActivity.class);
notificationIntent.setAction("ongoingcall");
notificationIntent.putExtra("calleruid", mCaller);
notificationIntent.putExtra("receiveruid", mReceiver);
notificationIntent.putExtra("otherusername", otherusername);
notificationIntent.putExtra("timestamp", mTimestamp);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Intent hangupintent = new Intent(this, CallScreenActivity.class);
hangupintent.setAction("hangupcall");
hangupintent.setAction("ongoingcall");
hangupintent.putExtra("calleruid", mCaller);
hangupintent.putExtra("receiveruid", mReceiver);
hangupintent.putExtra("otherusername", otherusername);
hangupintent.putExtra("timestamp", mTimestamp);
PendingIntent phangupintent = PendingIntent.getService(this, 0,
hangupintent, 0);
notification = new NotificationCompat.Builder(this)
.setContentTitle("In call with " + otherusername)
.setContentText("Duration " + VoiceCallHelper.formatTimespan(System.currentTimeMillis() - mCallStart))
.setSmallIcon(R.drawable.iconcall)
.setContentIntent(pendingIntent)
.addAction(R.drawable.ic_arrow_back, "Hangup",
phangupintent).build();
notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(111 /* ID of notification */, notification);
}
@Override
public void onServiceConnected() {
try {
doStuff();
} catch (NullPointerException e) {
//getSinchServiceInterface() in doStuff below throw null pointer error.
}
}
private void doStuff() {
final Call call = getSinchServiceInterface().getCall(mCallId);
if (call != null) {
call.addCallListener(new SinchCallListener());
mCallState.setText(call.getState().toString());
DBREF_USER_PROFILES.child(call.getRemoteUserId()).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
System.out.println("datasnapshot callscreenactivity otheruser" + dataSnapshot);
User u = User.parse(dataSnapshot);
mCallerName.setText(u.getName());
mProfpic = u.getProfpicurl();
Glide.with(CallScreenActivity.this).load(mProfpic).into(mCallImg);
} else {
mCallerName.setText(call.getHeaders().get("username"));
Glide.with(CallScreenActivity.this).load(R.drawable.whatsapplogo).into(mCallImg);
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
} else {
Log.e(TAG, "Started with invalid callId, aborting.");
finish();
}
}
@Override
public void onPause() {
super.onPause();
mDurationTask.cancel();
mTimer.cancel();
}
@Override
public void onResume() {
super.onResume();
mTimer = new Timer();
mDurationTask = new UpdateCallDurationTask();
mTimer.schedule(mDurationTask, 0, 500);
if (getIntent() != null && getIntent().getAction() != null) {
switch (getIntent().getAction()) {
case "ongoingcall":
System.out.println("on resume call screen activity ongoing call" + mCaller + mReceiver + otherusername);
mCaller = getIntent().getStringExtra("calleruid");
mReceiver = getIntent().getStringExtra("receiveruid");
otherusername = getIntent().getStringExtra("otherusername");
mTimestamp = getIntent().getStringExtra("timestamp");
break;
case "hangupcall":
System.out.println("on resume call screen activity hangup call");
mCaller = getIntent().getStringExtra("calleruid");
mReceiver = getIntent().getStringExtra("receiveruid");
otherusername = getIntent().getStringExtra("otherusername");
mTimestamp = getIntent().getStringExtra("timestamp");
endCallButton.performClick();
break;
}
}
}
@Override
public void onBackPressed() {
startActivity(new Intent(CallScreenActivity.this, MainAct.class));
}
private void endCall() {
if (notification != null) {
System.out.println("cancelling notification in endCAll callscreenactivity");
notificationManager.cancel(111);
}
mAudioPlayer.stopProgressTone();
Call call = getSinchServiceInterface().getCall(mCallId);
if (call != null) {
call.hangup();
}
finish();
}
private void updateCallDuration() {
if (mCallStart > 0) {
mCallDuration.setText(VoiceCallHelper.formatTimespan(System.currentTimeMillis() - mCallStart));
showNotification();
}
}
private class SinchCallListener implements CallListener {
@Override
public void onCallEnded(Call call) {
CallEndCause cause = call.getDetails().getEndCause();
Log.d(TAG, "Call ended. Reason: " + cause.toString() + mk + mCaller);
if (mk != null && mCaller != null && mk.matches(mCaller)) {
mAudioPlayer.stopProgressTone();
setVolumeControlStream(AudioManager.USE_DEFAULT_STREAM_TYPE);
String endMsg = "Call ended: " + call.getDetails().toString();
Long gt = GetTimeStamp.Id();
Toast.makeText(CallScreenActivity.this, endMsg, Toast.LENGTH_LONG).show();
System.out.println(endMsg + "mtimestamp" + mTimestamp);
String cau;
String oth;
if (call.getDetails().getDuration() > 0)
cau = "completed";
else
cau = cause.toString();
CallDetails cd1 = new CallDetails(String.valueOf(call.getDetails().getDuration()), mCaller, mReceiver, cau, String.valueOf(gt), mTimestamp, mProfpic, mCallerName.getText().toString());
CallDetails cd2 = new CallDetails(String.valueOf(call.getDetails().getDuration()), mCaller, mReceiver, cau, String.valueOf(gt), mTimestamp, mProfpic, myname);
System.out.println(mCaller + "end msg callscreenactivity" + mReceiver + " " + String.valueOf(gt));
System.out.println("end msg callscreenactivity" + mReceiver + " " + DBREF.child("VoiceCalls").child(mCaller).child(String.valueOf(gt)));
//setting in mCaller mykey node at voicecalls node firebase
DBREF_CALLS.child(mCaller).child(String.valueOf(gt)).setValue(cd1);
//setting in mReceiver otheruserkey node at voicecalls node firebase
DBREF_CALLS.child(mReceiver).child(String.valueOf(gt)).setValue(cd2);
}
endCall();
}
@Override
public void onCallEstablished(Call call) {
Log.d(TAG, "Call established");
mAudioPlayer.stopProgressTone();
mCallState.setText(call.getState().toString());
setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);
mCallStart = System.currentTimeMillis();
mTimestamp = GetTimeStamp.timeStamp();
}
@Override
public void onCallProgressing(Call call) {
Log.d(TAG, "Call progressing");
mAudioPlayer.playProgressTone();
}
@Override
public void onShouldSendPushNotification(Call call, List<PushPair> pushPairs) {
// Send a push through your push provider here, e.g. GCM
}
}
}
Ma classe SinchCallService est la suivante:
public class SinchCallService extends Service {
private static final String APP_KEY = SINCH_APPLICATION_KEY;
private static final String APP_SECRET = SINCH_SECRET_KEY;
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 = SinchCallService.class.getSimpleName();
private SinchServiceInterface mSinchServiceInterface = new SinchServiceInterface();
private SinchClient mSinchClient;
private String mUserId;
private StartFailedListener mListener;
@Override
public void onCreate() {
super.onCreate();
UserSession us = new UserSession(this);
System.out.println("From sinchcall oncreate" + us.getUserKey());
if (!isStarted()) {
System.out.println("sinch not started callservice oncreate " + us.getUserKey());
start(us.getUserKey());
}
}
@Override
public void onDestroy() {
if (mSinchClient != null && mSinchClient.isStarted()) {
mSinchClient.terminate();
}
super.onDestroy();
}
public void start(String userName) {
System.out.println("sinch call service start " + 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();
System.out.println(" sinch client started");
}
}
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 SinchCallService getService() {
return SinchCallService.this;
}
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) {
if(!isStarted()){
UserSession us = new UserSession(getApplicationContext());
startClient(us.getUserKey());
}
return mSinchClient.getCallClient().callUser(userId, headers);
}
public String getUserName() {
return mUserId;
}
public boolean isStarted() {
return SinchCallService.this.isStarted();
}
public void startClient(String userName) {
System.out.println("startClient called sinchcallservice" + userName);
if (!isStarted()) {
System.out.println("startClient not started callservice " + 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.e(TAG, "Incoming call");
Intent intent = new Intent(SinchCallService.this, IncomingCallScreenActivity.class);
intent.putExtra(CALL_ID, call.getCallId());
intent.putExtra(LOCATION, call.getHeaders().get("location"));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
SinchCallService.this.startActivity(intent);
}
}
}
Après est mon BaseActivity.java:
public abstract class BaseActivity extends FragmentActivity implements ServiceConnection {
private SinchCallService.SinchServiceInterface mSinchServiceInterface;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getApplicationContext().bindService(new Intent(this, SinchCallService.class), this,
BIND_AUTO_CREATE);
}
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
if (SinchCallService.class.getName().equals(componentName.getClassName())) {
mSinchServiceInterface = (SinchCallService.SinchServiceInterface) iBinder;
onServiceConnected();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
if (SinchCallService.class.getName().equals(componentName.getClassName())) {
mSinchServiceInterface = null;
onServiceDisconnected();
}
}
protected void onServiceConnected() {
// for subclasses
}
protected void onServiceDisconnected() {
// for subclasses
}
protected SinchCallService.SinchServiceInterface getSinchServiceInterface() {
return mSinchServiceInterface;
}
}
J'ai essayé des choses comme la mise en
android:launchMode="singleTop"
Si je backpress sur le CallScreenA ctivity et cliquez sur notification, il ouvre le MainAct pas le CallScreenActivity. Comment faire pour ouvrir CallScreenActivity?
J'ai essayé une solution avec la création d'un stackbuilder et le passage à l'intention dans l'attente comme suit:
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(CallScreenActivity.class);
stackBuilder.addNextIntent(notificationIntent);
PendingIntent pendingIntent =
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
Et aussi changé le manifeste comme suit:
<activity
android:launchMode="singleTop"
android:name=".activity.calls.CallScreenActivity"
android:screenOrientation="portrait"
android:parentActivityName=".activity.main.MainAct">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".activity.main.MainAct"/>
</activity>
Mais le changement ci-dessus conduit à l'application planter avec l'erreur suivante:
07-06 23:38:52.353 9182-9182/com.app E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.NullPointerException: Attempt to invoke interface method 'com.sinch.android.rtc.calling.CallClient com.sinch.android.rtc.SinchClient.getCallClient()' on a null object reference
at com.app.services.SinchCallService$SinchServiceInterface.getCall(SinchCallService.java:150)
at com.app.activity.calls.CallScreenActivity.endCall(CallScreenActivity.java:265)
at com.app.activity.calls.CallScreenActivity.access$100(CallScreenActivity.java:51)
at com.app.activity.calls.CallScreenActivity$1.onClick(CallScreenActivity.java:110)
at android.view.View.performClick(View.java:5207)
at android.view.View$PerformClick.run(View.java:21177)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5438)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:738)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:628)
Donc, si j'utilise le code sans le st ackbuilder et i appuyez sur le bouton d'accueil, puis appuyez sur la notification que mon CallSCreenACtivity ouvre, mais si j'appuie sur le bouton arrière dans le CAllSCreenACtivity et puis appuyez sur le bouton d'accueil puis j'appuie sur notification, il ouvre l'activité principale au lieu du CallSCreenACtivity. Mon appel est toujours actvity même après avoir appuyé sur le bouton back sur callscreenactivty.
J'ai également remarqué que la durée de l'appel affiché dans la notification a cessé de se rafraîchir après une pression sur le CallScreenActivity mais l'appel est toujours actif.
flux de l'application:
Pour l'appelant: - Lorsque l'application démarre, MainAct commence, d'où un utilisateur clique sur le profil de quelqu'un et est pris à ProfilesAct où il appuie sur le bouton d'appel pour appeler cette personne et est pris à la CallScreenActivity.
MainAct->ProfilesACt->CallScreenACt
Pour le récepteur: - App est en arrière-plan, l'appel vient, le SinchCallService fait l'IncomingCAllAct montrer, quand il accepte l'appel qu'il est pris au CallScreenActivity.
IncomingCallAct->CallSCreeenACtivity
ou pourrait être supposons que le récepteur utilise déjà l'application, puis
any activity(could be chat activity, main acitivty etc)->IncomingCallAct->CallSCreeenACtivity
Manifest de l'application: -
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.app.t">
<application
android:name=".TApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<activity
android:name=".SplashAct"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".activity.userprofile.UserProfileAct"
android:screenOrientation="portrait" />
<activity
android:name=".activity.videocalls.VideoCallScreenActivity"
android:screenOrientation="portrait"
android:launchMode="singleTop"/>
<activity
android:name=".activity.videocalls.IncomingVideoCallScreenActivity"
android:screenOrientation="portrait"
android:noHistory="true"/>
<activity
android:name=".activity.main.MainAct"
android:launchMode="singleTop"
android:screenOrientation="portrait"></activity>
<activity android:name=".activity.chat.ChatActivity" />
<service android:name=".services.MyFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service android:name=".services.MyFirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<activity android:name=".activity.settings.SettingsmainActivity" />
<service android:name=".services.SinchCallService"></service>
<activity
android:name=".activity.calls.CallScreenActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name=".activity.calls.IncomingCallScreenActivity"
android:noHistory="true"
android:screenOrientation="portrait" />
<activity android:name=".activity.chat.NewChatActivity" />
<activity android:name=".activity.chat.ChatActivity1"/>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
</application>
</manifest>
Vous remplacez 'onBackPressed()' dans 'CallScreenActivity' et le démarrez' MainAct'. Quelle est la raison? L'activité 'MainAct' est-elle déjà en cours (ie: sous 'CallScreenActivity'?) Vous devez expliquer la navigation entre vos activités, sachant que l'utilisation de' TaskStackBuilder' n'est probablement pas ce que vous voulez, car cela effacera toujours la tâche activités en cours (ce qui n'est probablement pas ce que vous voulez) –
@DavidWasser J'ai inclus le flux de l'application maintenant, pouvez-vous s'il vous plaît m'aider? – Ghanendra
Que devrait-il se passer lorsque l'utilisateur appuie sur BACK dans 'CallScreenActivity'? actif (non terminé) quand 'CallScreenActivity' est en cours d'exécution? Je ne comprends toujours pas votre problème –