I write a ToastUtils to avoid duplicate toast:
public class ToastUtils {
private ToastUtils() {
//no instance
}
private static Toast toast = null;
public static void showToast(String message) {
if (toast == null) {
toast = Toast.makeText(Utils.getApp(), message, Toast.LENGTH_SHORT);
}
toast.setText(message);
toast.setDuration(Toast.LENGTH_SHORT);
toast.show();
}
public static void showToast(#StringRes int messageId) {
if (toast == null) {
toast = Toast.makeText(Utils.getApp(), messageId, Toast.LENGTH_SHORT);
}
toast.setText(messageId);
toast.setDuration(Toast.LENGTH_SHORT);
toast.show();
}
}
Utils.java is the following:
public class Utils {
private Utils() {
//no instance
}
/**
* 提供统一的 Context 接口给其他工具类
*
* #return Context 对象
*/
public static Context getApp() {
return App.getApplication();
}
}
App.java is my custom Application:
public class App extends Application {
private static App application;
#Override
public void onCreate() {
super.onCreate();
application = this;
String curProcessName = getCurProcessName();
if (!TextUtils.equals(curProcessName, getPackageName())) {
return;
}
// omit my business code...
}
public static App getApplication() {
return application;
}
private String getCurProcessName() {
int pid = android.os.Process.myPid();
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
if (am == null || am.getRunningAppProcesses() == null || am.getRunningAppProcesses().isEmpty()) {
return null;
}
for (ActivityManager.RunningAppProcessInfo appProcess : am.getRunningAppProcesses()) {
if (appProcess.pid == pid) {
return appProcess.processName;
}
}
return null;
}
}
What makes me frustrated is ToastUtils doesn't work sometimes, ie, I cannot see toast message show on the screen.
Toast.makeText(Utils.getApp().....
The first parameter should be filled with activity
how about put context in parameter?
public static void showToast(Context context, #StringRes int messageId) {
if (toast == null) {
toast = Toast.makeText(context, messageId, Toast.LENGTH_SHORT);
}
toast.setText(messageId);
toast.setDuration(Toast.LENGTH_SHORT);
toast.show();
}
in activity :
showToast(this, R.string.toast)
Related
I implemented Sinch video calling in my current app. When the app is in the foreground everything is OK for the incoming call. But when I closed the app and tried to receive an incoming call, it does not show any incoming call. How to do video Sinch calling when application is closed for incoming calls? following is my FCMMessageReceiverService class.
public class FCMMessageReceiverService extends FirebaseMessagingService implements ServiceConnection {
Context context;
private SinchService.SinchServiceInterface mSinchServiceInterface;
HashMap dataHashMap;
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
context = this;
if (SinchHelpers.isSinchPushPayload(remoteMessage.getData())) {
Map data = remoteMessage.getData();
dataHashMap = (data instanceof HashMap) ? (HashMap) data : new HashMap<>(data);
if (SinchHelpers.isSinchPushPayload(dataHashMap)) {
getApplicationContext().bindService(new Intent(getApplicationContext(), SinchService.class), this, Context.BIND_AUTO_CREATE);
}
} else {
Intent intent;
PendingIntent pendingIntent = null;
if (remoteMessage.getData().size() > 0) {
String identifier = remoteMessage.getData().get("identifier");
if (identifier.equals("0")) {
intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
}
}
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this);
notificationBuilder.setWhen(System.currentTimeMillis());
notificationBuilder.setContentTitle(remoteMessage.getNotification().getTitle());
notificationBuilder.setContentText(remoteMessage.getNotification().getBody());
notificationBuilder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
notificationBuilder.setDefaults(Notification.DEFAULT_ALL | Notification.DEFAULT_LIGHTS | Notification.FLAG_SHOW_LIGHTS | Notification.DEFAULT_SOUND);
notificationBuilder.setAutoCancel(true);
notificationBuilder.setSmallIcon(R.mipmap.ic_launcher);
notificationBuilder.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notificationBuilder.build());
}
}
public static boolean foregrounded() {
ActivityManager.RunningAppProcessInfo appProcessInfo = new ActivityManager.RunningAppProcessInfo();
ActivityManager.getMyMemoryState(appProcessInfo);
return (appProcessInfo.importance == appProcessInfo.IMPORTANCE_FOREGROUND || appProcessInfo.importance == appProcessInfo.IMPORTANCE_VISIBLE);
}
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
if (SinchService.class.getName().equals(componentName.getClassName())) {
mSinchServiceInterface = (SinchService.SinchServiceInterface) iBinder;
}
// it starts incoming call activity which does not show incoming caller name and picture
NotificationResult result = mSinchServiceInterface.relayRemotePushNotificationPayload(dataHashMap);
if (result.isValid() && result.isCall()) {
CallNotificationResult callResult = result.getCallResult();
if (callResult.isCallCanceled() || callResult.isTimedOut()) {
createNotification("Missed Call from : ", callResult.getRemoteUserId());
return;
} else {
if (callResult.isVideoOffered()) {
Intent intent = new Intent(this, IncomingCallScreenActivity.class);
intent.putExtra(SinchService.CALL_ID, callResult.getRemoteUserId());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(intent);
}
}
} else if (result.isValid() && result.isMessage()) {
//i want to get message content here
MessageNotificationResult notificationResult = result.getMessageResult();
createNotification("Received Message from : ", notificationResult.getSenderId());
}
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
unbindService(this);
}
private void createNotification(String contentTitle, String userId) {
PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, new Intent(getApplicationContext(), MainActivity.class), 0);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getApplicationContext()).setSmallIcon(R.mipmap.ic_launcher).setContentTitle(contentTitle).setContentText(userId);
mBuilder.setContentIntent(contentIntent);
mBuilder.setDefaults(Notification.DEFAULT_SOUND);
mBuilder.setAutoCancel(true);
NotificationManager mNotificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(1, mBuilder.build());
}
}
here is my since service code:
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 PersistedSettings mSettings;
private StartFailedListener mListener;
#Override
public void onCreate() {
super.onCreate();
mSettings = new PersistedSettings(getApplicationContext());
String userName = mSettings.getUsername();
if (!userName.isEmpty()) {
Intent intent=new Intent(this,placecallActvity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
start(userName);
}
}
#Override
public void onDestroy() {
if (mSinchClient != null && mSinchClient.isStarted()) {
mSinchClient.terminate();
}
super.onDestroy();
}
private void start(String userName) {
if (mSinchClient == null) {
mSettings.setUsername(userName);
mUserId = userName;
mSinchClient = Sinch.getSinchClientBuilder().context(getApplicationContext()).userId(userName).applicationKey(APP_KEY).applicationSecret(APP_SECRET).environmentHost(ENVIRONMENT).build();
mSinchClient.setSupportCalling(true);
mSinchClient.setSupportManagedPush(true);
mSinchClient.checkManifest();
mSinchClient.setSupportActiveConnectionInBackground(true);
mSinchClient.startListeningOnActiveConnection();
mSinchClient.addSinchClientListener(new MySinchClientListener());
mSinchClient.getCallClient().setRespectNativeCalls(false);
mSinchClient.getCallClient().addCallClientListener(new SinchCallClientListener());
mSinchClient.getVideoController().setResizeBehaviour(VideoScalingType.ASPECT_FILL);
mSinchClient.start();
}
}
private void stop() {
if (mSinchClient != null) {
mSinchClient.terminate();
mSinchClient = null;
}
mSettings.setUsername("");
}
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().callUserVideo(userId);
}
public NotificationResult relayRemotePushNotificationPayload(final Map payload) {
if (mSinchClient == null && !mSettings.getUsername().isEmpty()) {
start(mSettings.getUsername());
} else if (mSinchClient == null && mSettings.getUsername().isEmpty()) {
return null;
}
return mSinchClient.relayRemotePushNotificationPayload(payload);
}
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) {
Log.d(TAG, "Incoming call");
Intent intent = new Intent(SinchService.this, IncomingCallScreenActivity.class);
intent.putExtra(CALL_ID, call.getCallId());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
SinchService.this.startActivity(intent);
}
}
private class PersistedSettings {
private SharedPreferences mStore;
private static final String PREF_KEY = "Sinch";
public PersistedSettings(Context context) {
mStore = context.getSharedPreferences(PREF_KEY, MODE_PRIVATE);
}
public String getUsername() {
return mStore.getString("Username", "");
}
public void setUsername(String username) {
SharedPreferences.Editor editor = mStore.edit();
editor.putString("Username", username);
editor.commit();
}
}
}
add FCM to your project
add following code
public class SinchService extends Service {
static final String APP_KEY = "************";
static final String APP_SECRET = "***********";
static final String ENVIRONMENT = "clientapi.sinch.com";
public static final int MESSAGE_PERMISSIONS_NEEDED = 1;
public static final String REQUIRED_PERMISSION = "REQUIRED_PESMISSION";
public static final String MESSENGER = "MESSENGER";
private Messenger messenger;
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;
private PersistedSettings mSettings;
private AudioPlayer audioPlayer;
private Handler handler;
#Override
public void onCreate() {
super.onCreate();
super.onCreate();
mSettings = new PersistedSettings(getApplicationContext());
String userName = mSettings.getUsername();
if (!userName.isEmpty()) {
start(userName);
}
handler = new Handler();
}
private void createClient(String username) {
mSinchClient = Sinch.getSinchClientBuilder().context(getApplicationContext()).userId(username)
.applicationKey(APP_KEY)
.applicationSecret(APP_SECRET)
.environmentHost(ENVIRONMENT).build();
mSinchClient.setSupportCalling(true);
mSinchClient.setSupportManagedPush(true);
mSinchClient.addSinchClientListener(new MySinchClientListener());
mSinchClient.getCallClient().addCallClientListener(new SinchCallClientListener());
mSinchClient.setPushNotificationDisplayName("User " + username);
}
#Override
public void onDestroy() {
if (mSinchClient != null && mSinchClient.isStarted()) {
mSinchClient.terminateGracefully();
}
super.onDestroy();
}
private boolean hasUsername() {
if (mSettings.getUsername().isEmpty()) {
Log.e(TAG, "Can't start a SinchClient as no username is available!");
return false;
}
return true;
}
private void createClientIfNecessary() {
if (mSinchClient != null)
return;
if (!hasUsername()) {
throw new IllegalStateException("Can't create a SinchClient as no username is available!");
}
createClient(mSettings.getUsername());
}
private void start(String userName) {
boolean permissionsGranted = true;
if (mSinchClient == null) {
mSettings.setUsername(userName);
createClient(userName);
}
createClientIfNecessary();
try {
//mandatory checks
mSinchClient.checkManifest();
if (getApplicationContext().checkCallingOrSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
throw new MissingPermissionException(Manifest.permission.CAMERA);
}
} catch (MissingPermissionException e) {
permissionsGranted = false;
if (messenger != null) {
Message message = Message.obtain();
Bundle bundle = new Bundle();
bundle.putString(REQUIRED_PERMISSION, e.getRequiredPermission());
message.setData(bundle);
message.what = MESSAGE_PERMISSIONS_NEEDED;
try {
messenger.send(message);
} catch (RemoteException e1) {
e1.printStackTrace();
}
}
}
if (permissionsGranted) {
Log.d(TAG, "Starting SinchClient");
try {
mSinchClient.start();
} catch (IllegalStateException e) {
Log.w(TAG, "Can't start SinchClient - " + e.getMessage());
}
}
}
private void stop() {
if (mSinchClient != null) {
mSinchClient.terminateGracefully();
mSinchClient = null;
}
}
private boolean isStarted() {
return (mSinchClient != null && mSinchClient.isStarted());
}
#Override
public IBinder onBind(Intent intent) {
messenger = intent.getParcelableExtra(MESSENGER);
return mSinchServiceInterface;
}
public class SinchServiceInterface extends Binder {
public Call callUserVideo(String userId) {
return mSinchClient.getCallClient().callUserVideo(userId);
}
public String getUserName() {
return mSettings.getUsername();
}
public void setUsername(String username) {
mSettings.setUsername(username);
}
public void retryStartAfterPermissionGranted() {
SinchService.this.attemptAutoStart();
}
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 NotificationResult relayRemotePushNotificationPayload(final Map payload) {
if (!hasUsername()) {
Log.e(TAG, "Unable to relay the push notification!");
return null;
}
createClientIfNecessary();
return mSinchClient.relayRemotePushNotificationPayload(payload);
}
}
private void attemptAutoStart() {
}
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, "onIncomingCall: " + call.getCallId());
audioPlayer = AudioPlayer.getInstance(getApplicationContext());
call.addCallListener(new SinchCallListener());
Intent intent = new Intent(SinchService.this, IncomingCallScreenActivity.class);
intent.putExtra(EXTRA_ID, MESSAGE_ID);
intent.putExtra(CALL_ID, call.getCallId());
boolean inForeground = isAppOnForeground(getApplicationContext());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (inForeground) {
SinchService.this.startActivity(intent);
} else {
if (!audioPlayer.isPlayedRingtone()) {
audioPlayer.playRingtone();
}
((NotificationManager) Objects.requireNonNull(getSystemService(NOTIFICATION_SERVICE))).notify(MESSAGE_ID, createIncomingCallNotification(call.getRemoteUserId(), intent));
}
}
private boolean isAppOnForeground(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> appProcesses = null;
if (activityManager != null) {
appProcesses = activityManager.getRunningAppProcesses();
}
if (appProcesses == null) {
return false;
}
final String packageName = context.getPackageName();
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) {
return true;
}
}
return false;
}
private Bitmap getBitmap(Context context, int resId) {
int largeIconWidth = (int) context.getResources()
.getDimension(R.dimen.height);
int largeIconHeight = (int) context.getResources()
.getDimension(R.dimen.height);
Drawable d = context.getResources().getDrawable(resId);
Bitmap b = Bitmap.createBitmap(largeIconWidth, largeIconHeight, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
d.setBounds(0, 0, largeIconWidth, largeIconHeight);
d.draw(c);
return b;
}
private PendingIntent getPendingIntent(Intent intent, String action) {
intent.setAction(action);
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 111, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return pendingIntent;
}
#TargetApi(29)
private Notification createIncomingCallNotification(String userId, Intent fullScreenIntent) {
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 112, fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder =
new NotificationCompat.Builder(getApplicationContext(), FcmListenerService.CHANNEL_ID)
.setContentTitle("Incoming call")
.setContentText(userId)
.setLargeIcon(getBitmap(getApplicationContext(), R.drawable.call_normal))
.setSmallIcon(R.drawable.call_pressed)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setContentIntent(pendingIntent)
.setFullScreenIntent(pendingIntent, true)
.addAction(R.drawable.button_accept, "Answer", getPendingIntent(fullScreenIntent, ACTION_ANSWER))
.addAction(R.drawable.button_decline, "Ignore", getPendingIntent(fullScreenIntent, ACTION_IGNORE))
.setOngoing(true);
return builder.build();
}
}
private class SinchCallListener implements CallListener {
#Override
public void onCallEnded(Call call) {
cancelNotification();
if (audioPlayer != null && audioPlayer.isPlayedRingtone()) {
audioPlayer.stopRingtone();
}
}
#Override
public void onCallEstablished(Call call) {
Log.d(TAG, "Call established");
if (audioPlayer != null && audioPlayer.isPlayedRingtone()) {
audioPlayer.stopRingtone();
}
}
#Override
public void onCallProgressing(Call call) {
Log.d(TAG, "Call progressing");
}
#Override
public void onShouldSendPushNotification(Call call, List<PushPair> pushPairs) {
// no need to implement for managed push
}
}
public void cancelNotification() {
NotificationManager nMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (nMgr != null) {
nMgr.cancel(MESSAGE_ID);
}
}
private static class PersistedSettings {
private SharedPreferences mStore;
private static final String PREF_KEY = "Sinch";
public PersistedSettings(Context context) {
mStore = context.getSharedPreferences(PREF_KEY, MODE_PRIVATE);
}
public String getUsername() {
return mStore.getString("Username", "");
}
public void setUsername(String username) {
SharedPreferences.Editor editor = mStore.edit();
editor.putString("Username", username);
editor.apply();
}
}
}
and crete FcmListenerService and add following code
public class FcmListenerService extends FirebaseMessagingService {
public static String CHANNEL_ID = "Sinch Push Notification Channel";
private final String PREFERENCE_FILE = "com.sinch.android.rtc.sample.push.shared_preferences";
SharedPreferences sharedPreferences;
#Override
public void onMessageReceived(RemoteMessage remoteMessage){
Map data = remoteMessage.getData();
if (SinchHelpers.isSinchPushPayload(data)) {
new ServiceConnection() {
private Map payload;
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
Context context = getApplicationContext();
sharedPreferences = context.getSharedPreferences(PREFERENCE_FILE, Context.MODE_PRIVATE);
if (payload != null) {
SinchService.SinchServiceInterface sinchService = (SinchService.SinchServiceInterface) service;
if (sinchService != null) {
NotificationResult result = sinchService.relayRemotePushNotificationPayload(payload);
// handle result, e.g. show a notification or similar
// here is example for notifying user about missed/canceled call:
if (result!=null && result.isValid() && result.isCall()) {
CallNotificationResult callResult = result.getCallResult();
if (callResult != null && result.getDisplayName() != null) {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(callResult.getRemoteUserId(), result.getDisplayName());
editor.apply();
}
if (callResult != null && callResult.isCallCanceled()) {
String displayName = result.getDisplayName();
if (displayName == null) {
displayName = sharedPreferences.getString(callResult.getRemoteUserId(), "n/a");
}
createMissedCallNotification(!displayName.isEmpty() ? displayName : callResult.getRemoteUserId());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
context.deleteSharedPreferences(PREFERENCE_FILE);
}
}
}
}
}
payload = null;
}
#Override
public void onServiceDisconnected(ComponentName name) {}
public void relayMessageData(Map<String, String> data) {
payload = data;
createNotificationChannel(NotificationManager.IMPORTANCE_MAX);
getApplicationContext().bindService(new Intent(getApplicationContext(), SinchService.class), this, BIND_AUTO_CREATE);
}
}.relayMessageData(data);
}
}
private void createNotificationChannel(int importance) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "Amar LPG";
String description = "Incoming call notification";
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
NotificationManager notificationManager = getSystemService(NotificationManager.class);
if (notificationManager != null) {
notificationManager.createNotificationChannel(channel);
}
}
}
private void createMissedCallNotification(String userId) {
createNotificationChannel(NotificationManager.IMPORTANCE_DEFAULT);
PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0,
new Intent(getApplicationContext(), IncomingCallScreenActivity.class), 0);
NotificationCompat.Builder builder =
new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID)
.setSmallIcon(R.drawable.icon)
.setContentTitle("Missed call from ")
.setContentText(userId)
.setContentIntent(contentIntent)
.setDefaults(Notification.DEFAULT_SOUND)
.setAutoCancel(true);
NotificationManager mNotificationManager =
(NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
if (mNotificationManager != null) {
mNotificationManager.notify(1, builder.build());
}
}
}
in the incoming call screen add the following code
public class IncomingCallScreenActivity extends BaseActivity {
static final String TAG = IncomingCallScreenActivity.class.getSimpleName();
private String mCallId;
private AudioPlayer mAudioPlayer;
public static final String ACTION_ANSWER = "answer";
public static final String ACTION_IGNORE = "ignore";
public static final String EXTRA_ID = "id";
public static int MESSAGE_ID = 14;
private String mAction;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_incoming_call_screen);
Button answer = (Button) findViewById(R.id.answerButton);
answer.setOnClickListener(mClickListener);
Button decline = (Button) findViewById(R.id.declineButton);
decline.setOnClickListener(mClickListener);
mAudioPlayer = new AudioPlayer(this);
mAudioPlayer.playRingtone();
mCallId = getIntent().getStringExtra(SinchService.CALL_ID);
mAction = "";
}
#Override
protected void onResume() {
super.onResume();
Intent intent = getIntent();
if (intent != null) {
if (intent.getStringExtra(SinchService.CALL_ID) != null) {
mCallId = getIntent().getStringExtra(SinchService.CALL_ID);
}
final int id = intent.getIntExtra(EXTRA_ID, -1);
if (id > 0) {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(id);
}
mAction = intent.getAction();
}
}
#Override
protected void onServiceConnected() {
Call call = getSinchServiceInterface().getCall(mCallId);
if (call != null) {
call.addCallListener(new SinchCallListener());
TextView remoteUser = (TextView) findViewById(R.id.remoteUser);
remoteUser.setText(call.getRemoteUserId());
if (ACTION_ANSWER.equals(mAction)) {
mAction = "";
answerClicked();
} else if (ACTION_IGNORE.equals(mAction)) {
mAction = "";
declineClicked();
}
} else {
Log.e(TAG, "Started with invalid callId, aborting");
finish();
}
}
private void answerClicked() {
if (mAudioPlayer!=null && mAudioPlayer.isPlayedRingtone()){
mAudioPlayer.stopRingtone();
}
Call call = getSinchServiceInterface().getCall(mCallId);
if (call != null) {
Log.d(TAG, "Answering call");
call.answer();
Intent intent = new Intent(this, CallScreenActivity.class);
intent.putExtra(SinchService.CALL_ID, mCallId);
startActivity(intent);
} else {
finish();
}
}
private void declineClicked() {
if (mAudioPlayer!=null && mAudioPlayer.isPlayedRingtone()){
mAudioPlayer.stopRingtone();
}
Call call = getSinchServiceInterface().getCall(mCallId);
if (call != null) {
call.hangup();
}
finish();
}
private class SinchCallListener implements VideoCallListener {
#Override
public void onCallEnded(Call call) {
CallEndCause cause = call.getDetails().getEndCause();
Log.d(TAG, "Call ended, cause: " + cause.toString());
mAudioPlayer.stopRingtone();
finish();
}
#Override
public void onCallEstablished(Call call) {
Log.d(TAG, "Call established");
}
#Override
public void onCallProgressing(Call call) {
Log.d(TAG, "Call progressing");
}
#Override
public void onShouldSendPushNotification(Call call, List<PushPair> pushPairs) {
}
#Override
public void onVideoTrackAdded(Call call) {
// Display some kind of icon showing it's a video call
}
#Override
public void onVideoTrackPaused(Call call) {
}
#Override
public void onVideoTrackResumed(Call call) {
}
}
private View.OnClickListener mClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.answerButton:
answerClicked();
break;
case R.id.declineButton:
declineClicked();
break;
}
}
};
}
in the login activity add the following code.
public class MainActivity extends BaseActivity implements SinchService.StartFailedListener, PushTokenRegistrationCallback, UserRegistrationCallback {
private Button mLoginButton;
private EditText mLoginName;
private ProgressDialog mSpinner;
private String mUserId;
private long mSigningSequence = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA, Manifest.permission.ACCESS_NETWORK_STATE, Manifest.permission.READ_PHONE_STATE},100);
}
mLoginName = (EditText) findViewById(R.id.loginName);
mLoginButton = (Button) findViewById(R.id.loginButton);
mLoginButton.setEnabled(false);
mLoginButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
loginClicked();
}
});
}
#Override
protected void onResume() {
super.onResume();
}
#Override
protected void onServiceConnected() {
mLoginButton.setEnabled(true);
getSinchServiceInterface().setStartListener(this);
}
#Override
protected void onPause() {
if (mSpinner != null) {
mSpinner.dismiss();
}
super.onPause();
}
#Override
public void onStartFailed(SinchError error) {
Toast.makeText(this, error.toString(), Toast.LENGTH_LONG).show();
if (mSpinner != null) {
mSpinner.dismiss();
}
}
#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);
showSpinner();
} else {
openPlaceCallActivity();
}
mUserId = userName;
UserController uc = Sinch.getUserControllerBuilder()
.context(getApplicationContext())
.applicationKey(APP_KEY)
.userId(mUserId)
.environmentHost(ENVIRONMENT)
.build();
uc.registerUser(this, this);
}
private void openPlaceCallActivity() {
Intent mainActivity = new Intent(this, PlaceCallActivity.class);
startActivity(mainActivity);
finish();
}
private void showSpinner() {
mSpinner = new ProgressDialog(this);
mSpinner.setTitle("Logging in");
mSpinner.setMessage("Please wait...");
mSpinner.show();
}
private void dismissSpinner() {
if (mSpinner != null) {
mSpinner.dismiss();
mSpinner = null;
}
}
#Override
public void tokenRegistered() {
dismissSpinner();
startClientAndOpenPlaceCallActivity();
}
private void startClientAndOpenPlaceCallActivity() {
// start Sinch Client, it'll result onStarted() callback from where the place call activity will be started
if (!getSinchServiceInterface().isStarted()) {
getSinchServiceInterface().startClient("");
showSpinner();
}
}
#Override
public void tokenRegistrationFailed(SinchError sinchError) {
dismissSpinner();
Toast.makeText(this, "Push token registration failed - incoming calls can't be received!", Toast.LENGTH_LONG).show();
}
#Override
public void onCredentialsRequired(ClientRegistration clientRegistration) {
String toSign = mUserId + APP_KEY + mSigningSequence + APP_SECRET;
String signature;
MessageDigest messageDigest;
try {
messageDigest = MessageDigest.getInstance("SHA-1");
byte[] hash = messageDigest.digest(toSign.getBytes("UTF-8"));
signature = Base64.encodeToString(hash, Base64.DEFAULT).trim();
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e.getCause());
}
clientRegistration.register(signature, mSigningSequence++);
}
#Override
public void onUserRegistered() {
}
#Override
public void onUserRegistrationFailed(SinchError sinchError) {
dismissSpinner();
Toast.makeText(this, "Registration failed!", Toast.LENGTH_LONG).show();
}
}
on our SDK package you will find under the Samples folder multiple sample files, the one called sinch-rtc-sample-video-push does what you wnat.
You should also check our docs here:
https://developers.sinch.com/docs/voice-android-push-notifications
Best regards
i am implementing sinch in my project. I started testing sinch sample if its working. I found sinch push samples are not working on android 8.0 and higher and are working on lower versions. I tested my FCM implementation and is working fine but sinch push is not working when the app is not running.
Please help as i have tested all the solutions available on this site and none of the solutions worked.
public class SinchService extends Service {
private static final String APP_KEY = "my app key here";
private static final String APP_SECRET = "my app secret here";
private static final String ENVIRONMENT = "sandbox.sinch.com";
public static final int MESSAGE_PERMISSIONS_NEEDED = 1;
public static final String REQUIRED_PERMISSION = "REQUIRED_PESMISSION";
public static final String MESSENGER = "MESSENGER";
private Messenger messenger;
public static final String CALL_ID = "CALL_ID";
static final String TAG = SinchService.class.getSimpleName();
private PersistedSettings mSettings;
private SinchServiceInterface mSinchServiceInterface = new SinchServiceInterface();
private SinchClient mSinchClient;
private StartFailedListener mListener;
#Override
public void onCreate() {
super.onCreate();
mSettings = new PersistedSettings(getApplicationContext());
attemptAutoStart();
}
private void attemptAutoStart() {
String userName = mSettings.getUsername();
if (!userName.isEmpty() && messenger != null) {
start(userName);
}
}
private void createClient(String username) {
mSinchClient = Sinch.getSinchClientBuilder().context(getApplicationContext()).userId(username)
.applicationKey(APP_KEY)
.applicationSecret(APP_SECRET)
.environmentHost(ENVIRONMENT).build();
mSinchClient.setSupportCalling(true);
mSinchClient.setSupportManagedPush(true);
mSinchClient.setSupportActiveConnectionInBackground(true);
mSinchClient.startListeningOnActiveConnection();
mSinchClient.addSinchClientListener(new MySinchClientListener());
mSinchClient.getCallClient().addCallClientListener(new SinchCallClientListener());
}
#Override
public void onDestroy() {
if (mSinchClient != null && mSinchClient.isStarted()) {
mSinchClient.terminate();
}
super.onDestroy();
}
private void start(String username) {
boolean permissionsGranted = true;
if (mSinchClient == null) {
mSettings.setUsername(username);
createClient(username);
}
try {
//mandatory checks
mSinchClient.checkManifest();
} catch (MissingPermissionException e) {
permissionsGranted = false;
if (messenger != null) {
Message message = Message.obtain();
Bundle bundle = new Bundle();
bundle.putString(REQUIRED_PERMISSION, e.getRequiredPermission());
message.setData(bundle);
message.what = MESSAGE_PERMISSIONS_NEEDED;
try {
messenger.send(message);
} catch (RemoteException e1) {
e1.printStackTrace();
}
}
}
if (permissionsGranted) {
Log.d(TAG, "Starting SinchClient");
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) {
messenger = intent.getParcelableExtra(MESSENGER);
return mSinchServiceInterface;
}
public class SinchServiceInterface extends Binder {
public Call callUser(String userId) {
return mSinchClient.getCallClient().callUser(userId);
}
public String getUserName() {
return mSinchClient != null ? mSinchClient.getLocalUserId() : "";
}
public void retryStartAfterPermissionGranted() { SinchService.this.attemptAutoStart(); }
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 AudioController getAudioController() {
if (!isStarted()) {
return null;
}
return mSinchClient.getAudioController();
}
public NotificationResult relayRemotePushNotificationPayload(final Map payload) {
if (mSinchClient == null && !mSettings.getUsername().isEmpty()) {
createClient(mSettings.getUsername());
} else if (mSinchClient == null && mSettings.getUsername().isEmpty()) {
Log.e(TAG, "Can't start a SinchClient as no username is available, unable to relay push.");
return null;
}
return mSinchClient.relayRemotePushNotificationPayload(payload);
}
}
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, "onIncomingCall: " + call.getCallId());
Intent intent = new Intent(SinchService.this, IncomingCallScreenActivity.class);
intent.putExtra(CALL_ID, call.getCallId());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
SinchService.this.startActivity(intent);
}
}
private class PersistedSettings {
private SharedPreferences mStore;
private static final String PREF_KEY = "Sinch";
public PersistedSettings(Context context) {
mStore = context.getSharedPreferences(PREF_KEY, MODE_PRIVATE);
}
public String getUsername() {
return mStore.getString("Username", "");
}
public void setUsername(String username) {
SharedPreferences.Editor editor = mStore.edit();
editor.putString("Username", username);
editor.commit();
}
}
}
public class FcmListenerService extends FirebaseMessagingService {
private final String PREFERENCE_FILE = "com.sinch.android.rtc.sample.push.shared_preferences";
SharedPreferences sharedPreferences;
#Override
public void onMessageReceived(RemoteMessage remoteMessage){
Map data = remoteMessage.getData();
if (SinchHelpers.isSinchPushPayload(data)) {
new ServiceConnection() {
private Map payload;
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
Context context = getApplicationContext();
sharedPreferences = context.getSharedPreferences(PREFERENCE_FILE, Context.MODE_PRIVATE);
if (payload != null) {
SinchService.SinchServiceInterface sinchService = (SinchService.SinchServiceInterface) service;
if (sinchService != null) {
NotificationResult result = sinchService.relayRemotePushNotificationPayload(payload);
// handle result, e.g. show a notification or similar
// here is example for notifying user about missed/canceled call:
if (result.isValid() && result.isCall()) {
CallNotificationResult callResult = result.getCallResult();
if (callResult != null && result.getDisplayName() != null) {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(callResult.getRemoteUserId(), result.getDisplayName());
editor.commit();
}
if (callResult.isCallCanceled()) {
String displayName = result.getDisplayName();
if (displayName == null) {
displayName = sharedPreferences.getString(callResult.getRemoteUserId(),"n/a");
}
createNotification(displayName != null && !displayName.isEmpty() ? displayName : callResult.getRemoteUserId());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
context.deleteSharedPreferences(PREFERENCE_FILE);
}
}
}
}
}
payload = null;
}
#Override
public void onServiceDisconnected(ComponentName name) {}
public void relayMessageData(Map<String, String> data) {
payload = data;
getApplicationContext().bindService(new Intent(getApplicationContext(), SinchService.class), this, BIND_AUTO_CREATE);
}
}.relayMessageData(data);
}
}
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "Sinch";
String description = "Incoming Sinch Push Notifications.";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(getResources().getString(R.string.default_notification_channel_id), name, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
private void createNotification(String userId) {
createNotificationChannel();
PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0,
new Intent(getApplicationContext(), LoginActivity.class), 0);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(getApplicationContext(), getResources().getString(R.string.default_notification_channel_id))
.setSmallIcon(R.drawable.icon)
.setContentTitle("Missed call from:")
.setContentText(userId);
mBuilder.setContentIntent(contentIntent);
mBuilder.setDefaults(Notification.DEFAULT_SOUND);
mBuilder.setAutoCancel(true);
NotificationManager mNotificationManager =
(NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(1, mBuilder.build());
}
}
I am developing an app that connects to a Chromecast, everything works fine when I do it from one activity, the problem is, that I want that activity to be fullscreen with no action bar, and no soft buttons. I am achiving that, hiding them when the users connects to the Chromecast, but it would be better if the users connect from the first activity (with action bar) and then goes to the second activity and the magic occurs there. But I can't pass the session between the activities. I have follow this tutorial to make the communication with the chromecast but tried to change a little to make the 2 acitivites communication.
Of course I have tested it and it returns a NullPointerException.
ConnectionFailedListener.java
public class ConnectionFailedListener implements GoogleApiClient.OnConnectionFailedListener {
private String TAG;
private MyConnectionCallbacks myConnectionCB;
public ConnectionFailedListener(String _TAG)
{
this.TAG=_TAG;
}
private void setMyConnectionCallBack(MyConnectionCallbacks _ConnectionCallbacks)
{
this.myConnectionCB = _ConnectionCallbacks;
}
#Override
public void onConnectionFailed(ConnectionResult result)
{
Log.e(TAG, "onConnectionFailed ");
myConnectionCB.teardown();
}
}
Channel.java
public class EventChannel implements Cast.MessageReceivedCallback
{
private Context myContext;
private String TAG;
/**
* #return custom namespace
*/
public EventChannel(Context _context, String _TAG)
{
this.myContext = _context;
this.TAG = _TAG;
}
public String getNamespace()
{
return myContext.getString(R.string.namespace);
}
/*
* Receive message from the receiver app
*/
#Override
public void onMessageReceived(CastDevice castDevice, String namespace,String message)
{
Log.d(TAG, "onMessageReceived: " + message);
}
}
ConnectionCallbacks.java
public class MyConnectionCallbacks implements GoogleApiClient.ConnectionCallbacks
{
private String TAG;
private Context myContext;
public CastDevice mSelectedDevice;
private GoogleApiClient mApiClient;
private boolean mWaitingForReconnect;
private EventChannel mEventChannel;
private String mSessionId;
private boolean mApplicationStarted;
private EventChannel myChannel;
public MyConnectionCallbacks(Context _context, String _TAG)
{
this.myContext=_context;
this.TAG = _TAG;
}
public void setApiClient(GoogleApiClient _newApiClient)
{
this.mApiClient = _newApiClient;
}
#Override
public void onConnected(Bundle connectionHint)
{
Log.d(TAG, "onConnected");
if (mApiClient == null)
{
// We got disconnected while this runnable was pending execution.
return;
}
try
{
if (mWaitingForReconnect)
{
mWaitingForReconnect = false;
// Check if the receiver app is still running
if ((connectionHint != null) && connectionHint.getBoolean(Cast.EXTRA_APP_NO_LONGER_RUNNING))
{
Log.d(TAG, "App is no longer running");
teardown();
}
else
{// Re-create the custom message channel
try
{
Cast.CastApi.setMessageReceivedCallbacks(mApiClient,mEventChannel.getNamespace(),mEventChannel);
}
catch (IOException e)
{
Log.e(TAG, "Exception while creating channel", e);
}
}
}
else
{// Launch the receiver app because is connected
Cast.CastApi.launchApplication(mApiClient,myContext.getString(R.string.app_id), false).setResultCallback(
new ResultCallback<Cast.ApplicationConnectionResult>()
{
#Override
public void onResult(Cast.ApplicationConnectionResult result) {
Status status = result.getStatus();
Log.d(TAG,"ApplicationConnectionResultCallback.onResult: statusCode"+ status.getStatusCode());
if (status.isSuccess())
{
ApplicationMetadata applicationMetadata = result.getApplicationMetadata();
mSessionId = result.getSessionId();
String applicationStatus = result.getApplicationStatus();
boolean wasLaunched = result.getWasLaunched();
Log.d(TAG,"application name: "+ applicationMetadata.getName()
+ ", status: "+ applicationStatus
+ ", sessionId: "+ mSessionId
+ ", wasLaunched: "+ wasLaunched);
mApplicationStarted = true;
// Create the custom message channel
mEventChannel = new EventChannel(myContext,TAG);
try
{
Cast.CastApi.setMessageReceivedCallbacks(mApiClient,mEventChannel.getNamespace(),mEventChannel);
}
catch (IOException e)
{
Log.e(TAG,"Exception while creating channel",e);
}
// set the initial instructions on the receiver
sendMessage("starting from mobile");
}
else
{
Log.e(TAG,"application could not launch");
teardown();
}
}
});
}
}
catch (Exception e)
{
Log.e(TAG, "Failed to launch application", e);
}
}
#Override
public void onConnectionSuspended(int cause)
{
Log.d(TAG, "onConnectionSuspended");
mWaitingForReconnect = true;
}
public void sendMessage(String message)
{
if (mApiClient != null && mEventChannel != null)
{
try
{
Cast.CastApi.sendMessage(mApiClient,mEventChannel.getNamespace(), message)
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status result)
{
if (!result.isSuccess())
{
Log.e(TAG, "Sending message failed");
}
}
});
}
catch (Exception e)
{
Log.e(TAG, "Exception while sending message", e);
}
}
else
{
Toast.makeText(myContext, message, Toast.LENGTH_SHORT).show();
}
}
public void teardown()
{
Log.d(TAG, "teardown");
if (mApiClient != null)
{
if (mApplicationStarted)
{
if (mApiClient.isConnected() || mApiClient.isConnecting())
{
try
{
Cast.CastApi.stopApplication(mApiClient, mSessionId);
if (myChannel != null)
{
Cast.CastApi.removeMessageReceivedCallbacks(mApiClient,myChannel.getNamespace());
myChannel = null;
}
}
catch (IOException e)
{
Log.e(TAG, "Exception while removing channel", e);
}
mApiClient.disconnect();
}
mApplicationStarted = false;
}
mApiClient = null;
}
mSelectedDevice = null;
mWaitingForReconnect = false;
mSessionId = null;
}
}
MediaRouterCallback.java
public class MyMediaRouterCallback extends MediaRouter.Callback {
private GoogleApiClient mApiClient;
private Cast.Listener mCastListener;
private Context myContext;
private ConnectionFailedListener mConnectionFailedListener;
public MyConnectionCallbacks mConnectionCallbacks;
public String TAG;
//private String mSessionId;
public MyMediaRouterCallback(Context _context, String _TAG)
{
this.myContext = _context;
this.TAG = _TAG;
mConnectionCallbacks = new MyConnectionCallbacks(myContext,TAG);
}
#Override
public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) {
Log.d(TAG, "onRouteSelected");
mConnectionCallbacks.mSelectedDevice = CastDevice.getFromBundle(info.getExtras());
launchReceiver();
}
#Override
public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) {
Log.d(TAG, "onRouteUnselected: info=" + info);
mConnectionCallbacks.teardown();
mConnectionCallbacks.mSelectedDevice = null;
}
private void launchReceiver()
{
try
{
mCastListener = new Cast.Listener() {
#Override
public void onApplicationDisconnected(int errorCode) {
Log.d(TAG, "application has stopped");
mConnectionCallbacks.teardown();
}
};
//Constructors for Google Play Services Connection
//mConnectionCallbacks = new MyConnectionCallbacks(myContext,TAG);
mConnectionFailedListener = new ConnectionFailedListener(TAG);
Cast.CastOptions.Builder apiOptionsBuilder =
Cast.CastOptions.builder(mConnectionCallbacks.mSelectedDevice, mCastListener);
// ApiClient to Connect to Google Play services
mApiClient = new GoogleApiClient.Builder(myContext)
.addApi(Cast.API, apiOptionsBuilder.build())
.addConnectionCallbacks(mConnectionCallbacks)
.addOnConnectionFailedListener(mConnectionFailedListener)
.build();
mConnectionCallbacks.setApiClient(mApiClient);//setting ApiClient to achieve sendMessage
//Connect to Google Play services
mApiClient.connect();
}
catch (Exception e)
{
Log.e(TAG, "Failed launchReceiver", e);
}
}
}
FirstActivity (where the chromecast is connected)
public class ConnectCastActivity extends ActionBarActivity {
private static final String TAG = ConnectCastActivity.class.getSimpleName();
private MediaRouter mMediaRouter;
private MediaRouteSelector mMediaRouteSelector;
private MediaRouter.Callback mMediaRouterCallback;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActionBar actionBar = getSupportActionBar();
actionBar.setBackgroundDrawable(new ColorDrawable(android.R.color.transparent));
setContentView(R.layout.activity_connect_cast);
// Configure Cast device discovery
mMediaRouter = MediaRouter.getInstance(getApplicationContext());
mMediaRouteSelector = new MediaRouteSelector.Builder().addControlCategory(CastMediaControlIntent.categoryForCast(getResources().getString(R.string.app_id))).build();
mMediaRouterCallback = new MyMediaRouterCallback(getApplicationContext(),TAG);
TextView myTextView = (TextView)findViewById(R.id.txt_helloworld);
myTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(getApplicationContext(),MainActivity.class);
startActivity(i);
}
});
}
#Override
protected void onStart() {
super.onStart();
// Start media router discovery
mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
}
#Override
protected void onStop() {
// End media router discovery
Log.w(TAG, "onStop");
//mMediaRouter.removeCallback(mMediaRouterCallback);
super.onStop();
}
#Override
public void onDestroy() {
Log.w(TAG, "onDestroy");
// mMediaRouterCallback.onRouteUnselected(mMediaRouter,null);
super.onDestroy();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.menu_connect_cast, menu);
MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item);
MediaRouteActionProvider mediaRouteActionProvider = (MediaRouteActionProvider) MenuItemCompat.getActionProvider(mediaRouteMenuItem);
// Set the MediaRouteActionProvider selector for device discovery.
mediaRouteActionProvider.setRouteSelector(mMediaRouteSelector);
return true;
}
}
SecondActivity (the one that will send the message)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MediaRouter mMediaRouter = MediaRouter.getInstance(getApplicationContext());
mConnectionCallbacks = new MyConnectionCallbacks(getApplicationContext(),TAG);
setContentView(R.layout.activity_main);
//What should I put here?
}
If you have an application with multiple activities, you are better off if you do not tie the cast connectivity and related states to any of those activities, instead you can have a singleton, or use your Application instance or use a background service or ... to maintain the connection and access the required pieces that are maintained in that global place. If it fits your requirement, you might want to use the CastCompanionLibrary that already does most of the routine stuff for you; if not, you can take a look at it and the see how the CastVideos sample app uses that and try to do something similar for your application.
This is a Google Chat application. When I get a message from Google Chat I want to show it in the status bar as a notification when the activity is in background.
I tried setting boolean values in the onPause() method but it did not work.
public void addMessage(String chatid, String msg) {
// I want to the execute this line only when the activity is in background
notify.getCurrentActivity(getApplicationContext(), msg, fromName, chatid);
}
public void getCurrentActivity(Context context, String msg){
showNotification(context, msg, fromName, fromChatID);
}
try to do below
try{
boolean foregroud = new ForegroundCheckTask().execute(context).get();
if(foregroud)
{
//app is foreground
}
else
{
//app is not foreground }
}catch(Exception e)
{
e.toString();
}
add below async
//Foreground check
class ForegroundCheckTask extends AsyncTask<Context, Void, Boolean> {
#Override
protected Boolean doInBackground(Context... params) {
final Context context = params[0].getApplicationContext();
return isAppOnForeground(context);
}
private boolean isAppOnForeground(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
if (appProcesses == null) {
return false;
}
final String packageName = context.getPackageName();
for (RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) {
return true;
}
}
return false;
}
}
I find out solution myself
private int key; // Declare as global
protected void onPause
{
key=1;
super.onpause();
}
protected void onResume{
key=0;
super.onResume();
}
public void addMessage(String chatid, String msg) {
if(key==1)
{
notify.getCurrentActivity(getApplicationContext(), msg, fromName, chatid);
}
}
I have been able to run TTS from an activity but when I try to execute the same code from a service, it's giving me message that TTS engine is initialised but not speaking anything.
Has anybody encountered the same issue anytime?
public void onCreate() {
super.onCreate();
tts = new TextToSpeech(this, this //TextToSpeech.OnInitListener);
timer.scheduleAtFixedRate( new TimerTask()
{ // In timer
public void run() {
//On some condition
tts.speak("thank you", TextToSpeech.QUEUE_ADD, null);
}, 0, 60000);
}
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
Toast.makeText(BackgroundProcessforTimecheck.this,
"Text-To-Speech engine is initialized", Toast.LENGTH_LONG).show();
}
else if (status == TextToSpeech.ERROR) {
Toast.makeText(BackgroundProcessforTimecheck.this,
"Error occurred while initializing Text-To-Speech engine", Toast.LENGTH_LONG).show();
}
}
I had the same problem and solved it this way:
Instantiate TextToSpeech Object in a separate Class (in my case I furthermore use a Factory to check if the Android Version is at least Donut) and reuse it (see method init(Context context)). Please notice that the onInit(int status) is far from being ready to release.
Service:
#Override
public void onStart(Intent intent, int startId) {
Context context = getApplicationContext();
TtsProviderFactory ttsProviderImpl = TtsProviderFactory.getInstance();
if (ttsProviderImpl != null) {
ttsProviderImpl.init(context);
ttsProviderImpl.say("hope that helps);
}}
Factory:
public abstract class TtsProviderFactory {
public abstract void say(String sayThis);
public abstract void init(Context context);
public abstract void shutdown();
private static TtsProviderFactory sInstance;
public static TtsProviderFactory getInstance() {
if (sInstance == null) {
int sdkVersion = Integer.parseInt(Build.VERSION.SDK);
if (sdkVersion < Build.VERSION_CODES.DONUT) {
return null;
}
try {
String className = "TtsProviderImpl";
Class<? extends TtsProviderFactory> clazz =
Class.forName(TtsProviderFactory.class.getPackage().getName() + "." + className)
.asSubclass(TtsProviderFactory.class);
sInstance = clazz.newInstance();
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
return sInstance;
}}
Implementation:
public class TtsProviderImpl extends TtsProviderFactory implements TextToSpeech.OnInitListener {
private TextToSpeech tts;
public void init(Context context) {
if (tts == null) {
tts = new TextToSpeech(context, this);
}
}
#Override
public void say(String sayThis) {
tts.speak(sayThis, TextToSpeech.QUEUE_FLUSH, null);
}
#Override
public void onInit(int status) {
Locale loc = new Locale("de", "", "");
if (tts.isLanguageAvailable(loc) >= TextToSpeech.LANG_AVAILABLE) {
tts.setLanguage(loc);
}
}
public void shutdown() {
tts.shutdown();
}}
Did you installed the TTS engine in your device. I too faced the same problem with the same message. But later I found that I have to install the TTS engine to my real device also and it is available in the play store.