-
Notifications
You must be signed in to change notification settings - Fork 45
Native android code that handles incoming calls
I'm quickly adding a sample of our native Android Activity that handles incoming calls. If you have some specific questions you can ask them here and we'll get back at you ASAP :)
package your.apps.id;
import android.app.Activity;
import android.app.KeyguardManager;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.os.Bundle;
import android.os.Vibrator;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.google.android.gms.tasks.Continuation;
import com.google.android.gms.tasks.Task;
import com.google.firebase.firestore.DocumentReference;
import com.google.firebase.firestore.DocumentSnapshot;
import com.google.firebase.firestore.EventListener;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.FirebaseFirestoreException;
import com.google.firebase.functions.FirebaseFunctions;
import com.google.firebase.functions.HttpsCallableResult;
import java.util.HashMap;
import static android.os.Build.VERSION.SDK_INT;
import static android.os.Build.VERSION_CODES;
import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
public class IncomingCallActivity extends Activity {
String callId;
String callUuid;
String callerHandle;
int notificationId;
Ringtone ringtone;
`Application application;`
`final private static String TAG = "IncomingCallActivity";`
`final private static long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};`
`@Override`
`protected void onCreate(Bundle savedInstanceState) {`
`super.onCreate(savedInstanceState);`
`try {`
`Log.d("done", "Done, IncomingCallActivity, onCreate();");`
`application = (Application)getApplication();`
`Intent intent = getIntent();`
`callId = intent.getStringExtra("your.apps.id.CALL_ID");`
`callUuid = intent.getStringExtra("your.apps.id.CALL_UUID");`
`callerHandle = intent.getStringExtra("your.apps.id.CALLER_HANDLE");`
`notificationId = intent.getIntExtra("your.notification.callkeep.NOTIFICATION_ID", 0);`
`if (SDK_INT >= VERSION_CODES.O_MR1) {`
`setShowWhenLocked(true);`
`setTurnScreenOn(true);`
`} else {`
`getWindow().addFlags(FLAG_SHOW_WHEN_LOCKED | FLAG_TURN_SCREEN_ON);`
`}`
`// Note that this shouldn't be needed on O_MR1 and higher, but `setTurnScreenOn` doesn't`
`// seem to have any effect on our Samsung Galaxy A40.`
`getWindow().addFlags(FLAG_TURN_SCREEN_ON);`
`getWindow().addFlags(FLAG_KEEP_SCREEN_ON | FLAG_FULLSCREEN);`
`String action = intent.getStringExtra("your.notification.callkeep.ACTION");`
`switch (action != null ? action : "") {`
`case "answer":`
`onAnswer(null);`
`break;`
`case "decline":`
`onDecline(null);`
`break;`
`default:`
`setup();`
`}`
`} catch (Exception e){`
`Log.d("done", "Done, IncomingCallActivity, onCreate " + e.toString());`
`}`
`}`
`@Override`
`protected void onStart() {`
`super.onStart();`
`startRinging();`
`}`
`@Override`
`protected void onStop() {`
`super.onStop();`
`stopRinging();`
`}`
`@Override`
`public void onWindowFocusChanged(boolean hasFocus) {`
`super.onWindowFocusChanged(hasFocus);`
`if (hasFocus) {`
`hideSystemUI();`
`}`
`}`
`private void hideSystemUI() {`
`try {`
`// Enables regular immersive mode.`
`// For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE.`
`// Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY`
`Log.d("done", "done, IncomingCallActivity, hideSystemUI");`
`View decorView = getWindow().getDecorView();`
`decorView.setSystemUiVisibility(`
`View.SYSTEM_UI_FLAG_IMMERSIVE`
`// Set the content to appear under the system bars so that the`
`// content doesn't resize when the system bars hide and show.`
`| View.SYSTEM_UI_FLAG_LAYOUT_STABLE`
`| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION`
`| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN`
`// Hide the nav bar and status bar`
`| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION`
`| View.SYSTEM_UI_FLAG_FULLSCREEN);`
`}catch (Exception e){`
`Log.e("done", "done, IncomingCallActivity, hidesystemui " + e.toString() );`
`}`
`}`
`private void setup() {`
`try {`
`Log.d("done", "done, IncomingCallActivity, setup");`
`setContentView(R.layout.activity_incoming_call);`
`TextView caller = (TextView) findViewById(R.id.txt_caller);`
`caller.setText(callerHandle);`
`FirebaseFirestore db = FirebaseFirestore.getInstance();`
`DocumentReference ref = db.collection("yourCallsCollection").document(callId);`
`ref.addSnapshotListener(new EventListener<DocumentSnapshot>() {`
`@Override`
`public void onEvent(DocumentSnapshot snapshot, FirebaseFirestoreException e) {`
`if (e != null) {`
`Log.e(TAG, "Listen to call snapshots failed", e);`
`return;`
`}`
`if (snapshot == null || !snapshot.exists() || snapshot.contains("answer")) {`
`dismissNotification();`
`finish();`
`}`
`}`
`});`
`} catch (Exception e){`
`Log.e("done", "done, IncomingCallActivity, setup " + e.toString() );`
`}`
`}`
`private void startRinging() {`
`try {`
`Log.d("done", "done, IncomingCallActivity, setup ");`
`android.net.Uri toneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);`
`ringtone = RingtoneManager.getRingtone(getApplicationContext(), toneUri);`
`ringtone.play();`
`Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);`
`v.vibrate(DEFAULT_VIBRATE_PATTERN, 0);`
`} catch (Exception e) {`
`e.printStackTrace();`
`}`
`}`
`private void stopRinging() {`
`try {`
`Log.d("done", "done, IncomingCallActivity, stopRinging ");`
`if (ringtone != null) {`
`ringtone.stop();`
`}`
`Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);`
`v.cancel();`
`} catch (Exception e){`
`Log.e("done", "done, IncomingCallActivity, stop ringing " + e.toString() );`
`}`
`}`
`private void dismissNotification() {`
`try {`
`Log.d("done", "done, IncomingCallActivity, dismissNotification ");`
`NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);`
`notificationManager.cancel(notificationId);`
`} catch (Exception e){`
`Log.e("done", "done, IncomingCallActivity, dismissNotification " + e.toString() );`
`}`
`}`
`private void launchMainActivity() {`
`try {`
`Log.d("done", "done, IncomingCallActivity, dismissNotification ");`
`SharedPreferences preferences = getApplicationContext().getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE);`
`preferences.edit().putBoolean("flutter." + callUuid + ":answer", true).commit();`
`Log.d("Done", "SharedPreferences committed");`
`String packageName = getApplicationContext().getPackageName();`
`Intent launchIntent = getApplicationContext().getPackageManager().getLaunchIntentForPackage(packageName).cloneFilter();`
`launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);`
`Log.d("Done", "Starting activity");`
`getApplicationContext().startActivity(launchIntent);`
`Log.d("Done", "Activity started");`
`} catch (Exception e){`
`Log.e("done", "done, IncomingCallActivity, launchMainActivity " + e.toString() );`
`}`
`}`
`public void onAnswer(View view) {`
`try {`
`Log.d("Done", "done, IncomingCallActivity, onAnswer started");`
`dismissNotification();`
`//1) check if MainActivity already present in stack`
`//* if the app is already running it means we've answered trough notification`
`if(application.isAppRunning()){`
`CallAnsweredTroughNotification call = new CallAnsweredTroughNotification(this.callId, this.callUuid, this.callerHandle, this.notificationId);`
`application.setCallAnsweredTroughNotification(call);`
`Log.d("done", "IncomingCallActivity about to finish with call");`
`finish();`
`return;`
`}`
`KeyguardManager manager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);`
`if (!manager.isKeyguardLocked()) {`
`Log.d("Done", "Keyguard not locked, launch main activity");`
`launchMainActivity();`
`return;`
`}`
`if (SDK_INT >= VERSION_CODES.O) {`
`manager.requestDismissKeyguard(this, new KeyguardManager.KeyguardDismissCallback() {`
`@Override`
`public void onDismissSucceeded() {`
`super.onDismissSucceeded();`
`launchMainActivity();`
`}`
`@Override`
`public void onDismissError() {`
`launchMainActivity();`
`super.onDismissError();`
`}`
`@Override`
`public void onDismissCancelled() {`
`launchMainActivity();`
`super.onDismissCancelled();`
`}`
`});`
`} else {`
`// Just launch the activity and rely on it setting `FLAG_DISMISS_KEYGUARD` to trigger keyguard unlock`
`launchMainActivity();`
`}`
`} catch (Exception e){`
`Log.e("done", "done, IncomingCallActivity, onAnswer " + e.toString() );`
`}`
`}`
`public void onDecline(View view) {`
`endCallOnFirebase();`
`dismissNotification();`
`finish();`
`}`
`void endCallOnFirebase(){`
`FirebaseFunctions functions = FirebaseFunctions.getInstance("europe-west1");`
`HashMap<String, Object> data = new HashMap();`
`data.put("callId", callId);`
`//* backend logic, we call cloud functions to end call`
`}`
}