diff --git a/README.md b/README.md index 4cf2791..d71063d 100644 --- a/README.md +++ b/README.md @@ -61,14 +61,22 @@ In `AndroidManifest.xml`: - + android:exported="true" + android:showWhenLocked="true" + android:turnScreenOn="true" + /> + = Build.VERSION_CODES.O_MR1) { setShowWhenLocked(true); setTurnScreenOn(true); @@ -69,10 +73,6 @@ protected void onCreate(Bundle savedInstanceState) { } } setContentView(R.layout.activity_call_incoming); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { - setShowWhenLocked(true); - setTurnScreenOn(true); - } getWindow().addFlags( WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD @@ -84,11 +84,12 @@ protected void onCreate(Bundle savedInstanceState) { ivAvatar = findViewById(R.id.ivAvatar); tvDecline=findViewById(R.id.tvDecline); tvAccept=findViewById(R.id.tvAccept); + lnDeclineCall = findViewById(R.id.lnDeclineCall); + lnAcceptCall = findViewById(R.id.lnAcceptCall); Bundle bundle = getIntent().getExtras(); if (bundle != null) { if (bundle.containsKey("uuid")) { uuid = bundle.getString("uuid"); - } if (bundle.containsKey("name")) { String name = bundle.getString("name"); @@ -114,8 +115,7 @@ protected void onCreate(Bundle savedInstanceState) { } } - LottieAnimationView acceptCallBtn = findViewById(R.id.ivAcceptCall); - acceptCallBtn.setOnClickListener(new View.OnClickListener() { + lnAcceptCall.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { try { @@ -129,8 +129,7 @@ public void onClick(View view) { } }); - LottieAnimationView rejectCallBtn = findViewById(R.id.ivDeclineCall); - rejectCallBtn.setOnClickListener(new View.OnClickListener() { + lnDeclineCall.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { dismissDialing(Constants.ACTION_REJECTED_CALL); @@ -159,21 +158,7 @@ public void destroyActivity(Boolean isReject) { private void acceptDialing() { active=false; WritableMap params = Arguments.createMap(); - params.putBoolean("accept", true); params.putString("callUUID", uuid); - KeyguardManager mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { - if (mKeyguardManager.isDeviceLocked()) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - mKeyguardManager.requestDismissKeyguard(this, new KeyguardManager.KeyguardDismissCallback() { - @Override - public void onDismissSucceeded() { - super.onDismissSucceeded(); - } - }); - } - } - } FullScreenNotificationIncomingCallModule.sendEventToJs(Constants.RNNotificationAnswerAction, params); stopService(new Intent(this, IncomingCallService.class)); if (Build.VERSION.SDK_INT >= 21) { @@ -186,7 +171,6 @@ public void onDismissSucceeded() { private void dismissDialing(String action) { active=false; WritableMap params = Arguments.createMap(); - params.putBoolean("accept", false); params.putString("callUUID", uuid); params.putString("endAction",action); FullScreenNotificationIncomingCallModule.sendEventToJs(Constants.RNNotificationEndCallAction, params); diff --git a/android/src/main/java/com/reactnativefullscreennotificationincomingcall/IncomingCallService.java b/android/src/main/java/com/reactnativefullscreennotificationincomingcall/IncomingCallService.java index 27c0d28..ce0fa01 100644 --- a/android/src/main/java/com/reactnativefullscreennotificationincomingcall/IncomingCallService.java +++ b/android/src/main/java/com/reactnativefullscreennotificationincomingcall/IncomingCallService.java @@ -6,24 +6,19 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.content.res.Resources; import android.graphics.Color; import android.media.AudioAttributes; -import android.media.AudioManager; -import android.media.Ringtone; import android.media.RingtoneManager; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; -import android.os.VibrationEffect; -import android.os.Vibrator; import android.util.Log; + import androidx.annotation.Nullable; import androidx.core.app.NotificationCompat; import androidx.core.content.ContextCompat; @@ -37,15 +32,15 @@ public class IncomingCallService extends Service { public static Handler callhandle; private String uuid = ""; private Integer timeoutNumber=0; + private boolean isRegistered = false; + // you can perform a click only once time + private Bundle bundleData; private static final String TAG = "FullscreenSevice"; public int onStartCommand(Intent intent, int flags, int startId) { String action = intent.getAction(); if (action != null) { if (action.equals(Constants.ACTION_SHOW_INCOMING_CALL)) { - IntentFilter filter = new IntentFilter(); - filter.addAction(Constants.ACTION_PRESS_ANSWER_CALL); - filter.addAction(Constants.ACTION_PRESS_DECLINE_CALL); - getApplicationContext().registerReceiver(mReceiver, filter); + NotificationReceiverHandler.updateCanClick(true); Bundle bundle = intent.getExtras(); uuid= bundle.getString("uuid"); if(bundle.containsKey("timeout")){ @@ -78,24 +73,25 @@ public void onTaskRemoved(Intent rootIntent) { stopSelf(); } - private PendingIntent onButtonNotificationClick(int id, String action) { - Intent buttonIntent= new Intent(); - buttonIntent.setAction(action); - return PendingIntent.getBroadcast(this,id , buttonIntent, PendingIntent.FLAG_IMMUTABLE); + + private PendingIntent onButtonNotificationClick(int id, String action,String eventName) { + Intent emptyScreenIntent = new Intent(this, NotificationReceiverActivity.class); + emptyScreenIntent.setAction(action); + emptyScreenIntent.putExtras(bundleData); + emptyScreenIntent.putExtra("eventName",eventName); + return PendingIntent.getActivity(this, 0, emptyScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); } private Notification buildNotification(Context context, Intent intent) { - Intent fullScreenIntent = new Intent(context, IncomingCallActivity.class); + + Intent emptyScreenIntent = new Intent(context, NotificationReceiverActivity.class); Bundle bundle = intent.getExtras(); - fullScreenIntent.putExtra("uuid", uuid); - fullScreenIntent.putExtra("name", bundle.getString("name")); - fullScreenIntent.putExtra("avatar", bundle.getString("avatar")); - fullScreenIntent.putExtra("info", bundle.getString("info")); - fullScreenIntent.putExtra("declineText", bundle.getString("declineText")); - fullScreenIntent.putExtra("answerText", bundle.getString("answerText")); + bundleData=bundle; + emptyScreenIntent.putExtras(bundle); + emptyScreenIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + emptyScreenIntent.setAction(Constants.onPressNotification); String channelId=bundle.getString("channelId"); - fullScreenIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(context, 0, fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); + PendingIntent emptyPendingIntent = PendingIntent.getActivity(context, 0, emptyScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel notificationChannel=new NotificationChannel(channelId, bundle.getString("channelName"), NotificationManager.IMPORTANCE_HIGH); @@ -117,16 +113,16 @@ private Notification buildNotification(Context context, Intent intent) { .setContentText(bundle.getString("info")) .setPriority(NotificationCompat.PRIORITY_MAX) .setCategory(NotificationCompat.CATEGORY_CALL) - .setContentIntent(fullScreenPendingIntent) + .setContentIntent(emptyPendingIntent) .addAction( 0, bundle.getString("declineText"), - onButtonNotificationClick(0,Constants.ACTION_PRESS_DECLINE_CALL) + onButtonNotificationClick(0,Constants.ACTION_PRESS_DECLINE_CALL,Constants.RNNotificationEndCallAction) ) .addAction( 0, bundle.getString("answerText"), - onButtonNotificationClick(1,Constants.ACTION_PRESS_ANSWER_CALL) + onButtonNotificationClick(1,Constants.ACTION_PRESS_ANSWER_CALL,Constants.RNNotificationAnswerAction) ) .setAutoCancel(true) .setOngoing(true) @@ -138,7 +134,7 @@ private Notification buildNotification(Context context, Intent intent) { // interacts with the notification. Also, if your app targets Android 10 // or higher, you need to request the USE_FULL_SCREEN_INTENT permission in // order for the platform to invoke this notification. - .setFullScreenIntent(fullScreenPendingIntent, true); + .setFullScreenIntent(emptyPendingIntent, true); if(bundle.getString("notificationColor")!=null){ notificationBuilder.setColor(getColorForResourceName(context,bundle.getString("notificationColor"))); } @@ -164,6 +160,7 @@ public void onDestroy() { cancelTimer(); stopForeground(true); } + public void setTimeOutEndCall(String uuid) { callhandle=new Handler(); handleTimeout=new Runnable() { @@ -186,39 +183,7 @@ public void cancelTimer(){ callhandle.removeCallbacks(handleTimeout); } } - private BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (action != null) { - if (action.equals(Constants.ACTION_PRESS_ANSWER_CALL)) { - cancelTimer(); - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { - Intent it = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); - context.sendBroadcast(it); - } - if (IncomingCallActivity.active) { - IncomingCallActivity.getInstance().destroyActivity(false); - } - WritableMap params = Arguments.createMap(); - params.putString("callUUID", uuid); - FullScreenNotificationIncomingCallModule.sendEventToJs(Constants.RNNotificationAnswerAction,params); - stopForeground(true); - }else if(action.equals(Constants.ACTION_PRESS_DECLINE_CALL)){ - cancelTimer(); - if (IncomingCallActivity.active) { - IncomingCallActivity.getInstance().destroyActivity(false); - } - WritableMap params = Arguments.createMap(); - params.putString("callUUID", uuid); - params.putString("endAction", Constants.ACTION_REJECTED_CALL); - FullScreenNotificationIncomingCallModule.sendEventToJs(Constants.RNNotificationEndCallAction,params); - stopForeground(true); - } - } - } - }; private int getResourceIdForResourceName(Context context, String resourceName) { int resourceId = context.getResources().getIdentifier(resourceName, "drawable", context.getPackageName()); if (resourceId == 0) { diff --git a/android/src/main/java/com/reactnativefullscreennotificationincomingcall/NotificationReceiverActivity.java b/android/src/main/java/com/reactnativefullscreennotificationincomingcall/NotificationReceiverActivity.java new file mode 100644 index 0000000..4282ac0 --- /dev/null +++ b/android/src/main/java/com/reactnativefullscreennotificationincomingcall/NotificationReceiverActivity.java @@ -0,0 +1,21 @@ +package com.reactnativefullscreennotificationincomingcall; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; + +public class NotificationReceiverActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + NotificationReceiverHandler.handleNotification(this, getIntent()); + finish(); + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + NotificationReceiverHandler.handleNotification(this, intent); + finish(); + } +} diff --git a/android/src/main/java/com/reactnativefullscreennotificationincomingcall/NotificationReceiverHandler.java b/android/src/main/java/com/reactnativefullscreennotificationincomingcall/NotificationReceiverHandler.java new file mode 100644 index 0000000..c327d36 --- /dev/null +++ b/android/src/main/java/com/reactnativefullscreennotificationincomingcall/NotificationReceiverHandler.java @@ -0,0 +1,80 @@ +package com.reactnativefullscreennotificationincomingcall; + + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; +import android.os.Build; +import android.os.Bundle; +import android.util.Log; +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.WritableMap; + +public class NotificationReceiverHandler { + private static final String TAG = "NotificationReceiverHandler"; + private static boolean canClick = true; + private static boolean openedInComing = true; + static void handleNotification(Context context, Intent intent) { + handleNotificationIntent(context, intent); + } + + static void updateCanClick(Boolean status){ + canClick=status; + openedInComing=status; + } + + private static void handleNotificationIntent(Context context, Intent intent) { + if(!canClick) return; + String action= intent.getAction(); + switch (action) { + case Constants.onPressNotification: + if(!openedInComing) return; + canClick=false; + handleNotificationPressIntent(context, intent); + break; + case Constants.ACTION_PRESS_DECLINE_CALL: + case Constants.ACTION_PRESS_ANSWER_CALL: + canClick=false; + handleNotificationActionIntent(context,intent); + break; + } + } + + private static void handleNotificationActionIntent(Context context, Intent intent) { + Bundle bundle = intent.getExtras(); + String uuid=""; + String eventName=""; + if (bundle != null) { + if (bundle.containsKey("uuid")) { + uuid = bundle.getString("uuid"); + } + if(bundle.containsKey("eventName")){ + eventName=bundle.getString("eventName"); + } + } + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { + Intent it = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + context.sendBroadcast(it); + } + if (IncomingCallActivity.active) { + IncomingCallActivity.getInstance().destroyActivity(false); + } + WritableMap params = Arguments.createMap(); + params.putBoolean("accept", true); + params.putString("callUUID", uuid); + FullScreenNotificationIncomingCallModule.sendEventToJs(eventName, params); + context.stopService(new Intent(context, IncomingCallService.class)); + } + + @SuppressLint("LongLogTag") + private static void handleNotificationPressIntent(Context context, Intent intent) { + Intent newIntent = new Intent(context, IncomingCallActivity.class); + Log.d(TAG, "Handle press notification content"); + Bundle bundle = intent.getExtras(); + if (bundle != null) { + newIntent.putExtras(bundle); + } + newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(newIntent); + } +} diff --git a/android/src/main/res/layout/activity_call_incoming.xml b/android/src/main/res/layout/activity_call_incoming.xml index ff6e191..524e6cc 100644 --- a/android/src/main/res/layout/activity_call_incoming.xml +++ b/android/src/main/res/layout/activity_call_incoming.xml @@ -74,13 +74,13 @@ android:layout_marginEnd="140dp" > - + - + @@ -30,18 +32,26 @@ + android:showWhenLocked="true" + android:turnScreenOn="true" + /> + - + diff --git a/example/android/build.gradle b/example/android/build.gradle index 11a8a86..a67d055 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -21,6 +21,20 @@ buildscript { allprojects { repositories { + exclusiveContent { + // We get React Native's Android binaries exclusively through npm, + // from a local Maven repo inside node_modules/react-native/. + // (The use of exclusiveContent prevents looking elsewhere like Maven Central + // and potentially getting a wrong version.) + filter { + includeGroup "com.facebook.react" + } + forRepository { + maven { + url "$rootDir/../node_modules/react-native/android" + } + } + } mavenLocal() maven { // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index 7665b0f..beb888e 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -3,3 +3,4 @@ distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-6.9-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists +org.gradle.jvmargs=-Xmx4096M diff --git a/example/package.json b/example/package.json index cd1e792..940d283 100644 --- a/example/package.json +++ b/example/package.json @@ -10,7 +10,8 @@ }, "dependencies": { "react": "17.0.2", - "react-native": "0.65.1" + "react-native": "0.65.1", + "uuid-random": "^1.3.2" }, "devDependencies": { "@babel/core": "^7.12.10", diff --git a/example/src/App.tsx b/example/src/App.tsx index 193570e..1a009b6 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,22 +1,33 @@ import * as React from 'react'; import RNNotificationCall from '../../src/index' import { StyleSheet, View, Text, TouchableOpacity } from 'react-native'; +import ramdomUuid from 'uuid-random'; + export default function App() { React.useEffect(() => { - RNNotificationCall.addEventListener("answer", () => { - console.log('press answer') + + RNNotificationCall.addEventListener("answer", (payload) => { + console.log('press answer', payload.callUUID) + }) - RNNotificationCall.addEventListener("endCall", () => { - console.log('press endCall') + RNNotificationCall.addEventListener("endCall", (payload) => { + console.log('press endCall', payload.callUUID) }) return () => { RNNotificationCall.removeEventListener("answer") RNNotificationCall.removeEventListener("endCall") }; + + }, []); + const getCurrentCallId = () => { + return ramdomUuid().toLowerCase(); + }; const display = () => { + const uid = getCurrentCallId() + console.log('uid', uid) RNNotificationCall.displayNotification( - "22221a97-8eb4-4ac2-b2cf-0a3c0b9100ad", + uid, null, 30000, { @@ -31,6 +42,9 @@ export default function App() { } ) } + const onHide = () => { + RNNotificationCall.hideNotification() + } return ( Display + + Hide + ); } diff --git a/package.json b/package.json index 719813f..e9805bb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-full-screen-notification-incoming-call", - "version": "0.1.3", + "version": "0.1.4", "description": "Android full screen notification incoming call for React Native", "main": "lib/commonjs/index", "module": "lib/module/index",