diff --git a/app/build.gradle b/app/build.gradle index 1f60baf08443ee4c3f2eed8276e58e99be7fc40d..a42015c366c5e26777f11d63cfa4916cb3affb3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -682,8 +682,8 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" // Conference, Calls mobile SDK - implementation 'com.nynja.sdk:NynjaSdk:1.21@aar' - //implementation(name: 'NynjaSdk-1.21', ext: 'aar') + implementation 'com.nynja.sdk:NynjaSdk:1.21.5@aar' + //implementation(name: 'NynjaSdk-1.21.5', ext: 'aar') //ExoPlayer implementation 'com.google.android.exoplayer:exoplayer-core:2.9.6' diff --git a/app/src/main/java/com/nynja/mobile/communicator/data/FireBaseMessagingService.java b/app/src/main/java/com/nynja/mobile/communicator/data/FireBaseMessagingService.java index 48a6b942d100aa91d5cf9ed689392468610819e5..03626d70d237c2ccbc8bdbb1abfb044abd9a4356 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/data/FireBaseMessagingService.java +++ b/app/src/main/java/com/nynja/mobile/communicator/data/FireBaseMessagingService.java @@ -107,7 +107,7 @@ public class FireBaseMessagingService extends FirebaseMessagingService { if(model == null) break; Timber.i(model.toString()); if (mDataManager.getSettingNotifications().isCallNotifications()) { - boolean isMainActivityIsActive = !mDataManager.isInBackground();//isMainActivityIsActive(); + boolean isMainActivityIsActive = mDataManager.isMainActivityIsActive();//!mDataManager.isInBackground();// if (!isMainActivityIsActive) { mDataManager.reconnectConference(); } @@ -260,30 +260,32 @@ public class FireBaseMessagingService extends FirebaseMessagingService { public void sendCallPush(Context context, boolean isMainActivityIsActive, boolean hasActiveCall ) { Timber.i("Push.CALLING: sendCallPush() isMainActivityIsActive=" + (isMainActivityIsActive?"true": "false")); - Timber.i("Push.CALLING: handleConferencePushNotification(): handleCallPush XXX"); + Timber.i("Push.CALLING: sendCallPush(): check XX1"); String from = mDataManager.getConferenceSDK().getActiveConference().getCallerName(); String callId = mDataManager.getConferenceSDK().getActiveConference().mConference.callId(); boolean isInBackground = mDataManager.isInBackground(); Notification notification = mNotificationHelper.createCallPushNotification(context, from, callId, - isInBackground, //isMainActivityIsActive, - mDataManager.getSettingNotifications()); - Timber.i("Push.CALLING: handleConferencePushNotification(): handleCallPush XXXX" + + isMainActivityIsActive || isInBackground, + mDataManager.getSettingNotifications(), + true); + Timber.i("Push.CALLING: sendCallPush(): check XX2" + "; hasActiveCall=" + (hasActiveCall?"true": "false")); - if (notification != null && !hasActiveCall && !isMainActivityIsActive - && context instanceof FireBaseMessagingService) { - Timber.i("Push.CALLING: handleConferencePushNotification(): handleCallPush XXXXX"); + if (notification != null && !hasActiveCall && context instanceof FireBaseMessagingService) { + Timber.i("Push.CALLING: sendCallPush(): check XX3"); ((FireBaseMessagingService)context).startForeground(ActiveConferenceCall.ANDROID_10_PUSH_CALL_NTFN_ID, notification); } } private synchronized void handleCallPush(byte[] decoded, boolean isMainActivityIsActive) { + Timber.i("Push.CALLING: handleCallPush() isMainActivityIsActive=" + (isMainActivityIsActive?"true": "false")); boolean hasActiveCall = mDataManager.getConferenceSDK().hasCreatedActiveCall(); boolean startActivity = !(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q); boolean result = mDataManager.handleConferencePushNotification(decoded, isMainActivityIsActive, startActivity); boolean isCallRinging = mDataManager.getConferenceSDK().isCallRinging(); - Timber.i("Push.CALLING: handleConferencePushNotification()=" + (result?"true": "false") + "; isCallRinging="+ - (isCallRinging?"true": "false") + "; startActivity=" + (startActivity?"true": "false")); - if (result && !startActivity && isCallRinging && !hasActiveCall) { + Timber.i("Push.CALLING: handleCallPush()=" + (result?"true": "false") + "; isCallRinging="+ + (isCallRinging?"true": "false") + "; startActivity=" + (startActivity?"true": "false") + + "; hasActiveCall=" + (hasActiveCall?"true": "false")); + if (result && !startActivity && isCallRinging && !hasActiveCall){ sendCallPush(this, isMainActivityIsActive, hasActiveCall); } } diff --git a/app/src/main/java/com/nynja/mobile/communicator/data/conference/ConferenceVideoModule.java b/app/src/main/java/com/nynja/mobile/communicator/data/conference/ConferenceVideoModule.java index bf856e2b93332c0dc9fa952904291d57ee56aef3..21c32cc16055c1af1ebbd8fcd2ac57aa22ba7195 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/data/conference/ConferenceVideoModule.java +++ b/app/src/main/java/com/nynja/mobile/communicator/data/conference/ConferenceVideoModule.java @@ -12,9 +12,14 @@ import org.webrtc.SurfaceViewRenderer; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Map; import java.util.Set; import kotlin.jvm.Synchronized; +import timber.log.Timber; public class ConferenceVideoModule { @@ -28,7 +33,7 @@ public class ConferenceVideoModule { private ActiveConferenceCall mCurrentActiveCall; public int mActiveVideoParticipantsCount = 0; - public HashMap mActiveVideoParticipantsMap= new HashMap<>(); + public LinkedHashSet mActiveVideoParticipants= new LinkedHashSet<>(); private ConferenceVideoModule() { @@ -51,7 +56,7 @@ public class ConferenceVideoModule { public void reset() { // ToDo:... - mActiveVideoParticipantsMap.clear(); + mActiveVideoParticipants.clear(); mCurrentActiveCall = null; } @@ -85,38 +90,110 @@ public class ConferenceVideoModule { return trackId; } - @Synchronized - public ArrayList getConferenceVideoMembers(ActiveConferenceCall activeConferenceCall) { + public synchronized ArrayList getConferenceVideoMembers(ActiveConferenceCall activeConferenceCall) { if (activeConferenceCall == null) return new ArrayList<>(); - Set participatIds = mActiveVideoParticipantsMap.keySet(); - mActiveVideoParticipantsMap.clear(); - synchronized (activeConferenceCall.mData.mParticipantArray) { + HashSet mTempActiveVideoParticipants= new HashSet<>(); + HashSet tempParticipants= new HashSet<>(); + synchronized (activeConferenceCall.mData) { if (activeConferenceCall.mData.mParticipantArray != null) { for (int index = 0; index < activeConferenceCall.mData.mParticipantArray.size(); index++) { NYNCallParticipant participant = activeConferenceCall.mData.mParticipantArray.get(index); - if (participant.hasVideo() || (participant.isMe() && activeConferenceCall.mData.isOwnStreamActive)) { - ConferenceListItem item = conferenceParticipant(participant, participant.isOwner(), activeConferenceCall.mData.isOwnStreamActive); - mActiveVideoParticipantsMap.put(item.participantId, item); + ConferenceListItem item = conferenceParticipant(participant, participant.isOwner(), activeConferenceCall.mData.isOwnStreamActive); + tempParticipants.add(item); + if (//participant.hasVideo() || + activeConferenceCall.mData.mActiveParticipanTracks.containsValue(participant.getParticipantId())) { + ////////////////////////////////////////////////////////////////////////////////////////////////// + // WORKAROUND !!!!!!!!!! + item.hasVideo = true; + item.isMe = false; + ////////////////////////////////////////////////////////////////////////////////////////////////// + Timber.d("ConferenceVideoModule::getConferenceVideoMembers(): updated video feed item participant name=%s; ID=%s", item.name, item.participantId); + mTempActiveVideoParticipants.add(item); + } else if (//participant.hasVideo() && + participant.getParticipantId().contentEquals(activeConferenceCall.mConference.participantId()) && + participant.isMe() && + activeConferenceCall.mData.isOwnStreamActive) { + ////////////////////////////////////////////////////////////////////////////////////////////////// + // WORKAROUND !!!!!!!!!! + item.hasVideo = true; + item.isMe = true; + ////////////////////////////////////////////////////////////////////////////////////////////////// + Timber.d("ConferenceVideoModule::getConferenceVideoMembers(): updated video feed item participant name=%s; ID=%s", item.name, item.participantId); + mTempActiveVideoParticipants.add(item); } } } - } - - for (String participantId : participatIds) { - if (!mActiveVideoParticipantsMap.containsKey(participantId)) { - enableVideoForTrack(participantId, false); - String trackId = getTrackIdByParticipantId(participantId); - setVideoRendererForTrack(null, trackId, StringUtils.isEmpty(trackId)); +// if (activeConferenceCall.mData.mActiveParticipanTracks != null) { +// for (Map.Entry set : activeConferenceCall.mData.mActiveParticipanTracks.entrySet()) { +// NYNCallParticipant participant = activeConferenceCall.mConference.getParticipantByTrackId(set.getKey()); +// if (participant == null) participant = activeConferenceCall.mConference.getParticipantById(set.getValue()); +// if (participant != null && +// (participant.hasVideo() || +// (participant.isMe() && activeConferenceCall.mData.isOwnStreamActive) || +// activeConferenceCall.mData.mActiveParticipanTracks.containsKey(participant.getParticipantId()))) { +// ConferenceListItem item = conferenceParticipant(participant, participant.isOwner(), activeConferenceCall.mData.isOwnStreamActive); +// item.hasVideo = true; +// item.participantId = set.getValue(); +// mActiveVideoParticipantsMap.put(item.participantId, item); +// } +// } +// } + Iterator itr = mActiveVideoParticipants.iterator(); + while(itr.hasNext()) { + ConferenceListItem item = itr.next(); + if (!mTempActiveVideoParticipants.contains(item)) { + Timber.d("ConferenceVideoModule::getConferenceVideoMembers(): removed participant with ID=%s", item.participantId); + enableVideoForTrack(item.participantId, false); + if (item.isMe) { + setVideoRendererForTrack(null, "", true); + } else { + String trackId = getTrackIdByParticipantId(item.participantId); + if (StringUtils.isNotEmpty(trackId)) { + setVideoRendererForTrack(null, trackId, false); + } + } + itr.remove(); + } else if (tempParticipants.contains(item)) { + Iterator itr2 = tempParticipants.iterator(); + while(itr2.hasNext()) { + ConferenceListItem item2 = itr2.next(); + if (item2.equals(item)) { + item.update(item2); + break; + } + } + } + } + Iterator itr2 = mTempActiveVideoParticipants.iterator(); + while(itr2.hasNext()) { + ConferenceListItem item = itr2.next(); + if (!mActiveVideoParticipants.contains(item)) { + Timber.d("ConferenceVideoModule::getConferenceVideoMembers(): added participant with ID=%s", item.participantId); + mActiveVideoParticipants.add(item); + } } } - ArrayList items = new ArrayList<>(mActiveVideoParticipantsMap.values()); + mTempActiveVideoParticipants.clear(); + ArrayList items = new ArrayList<>(mActiveVideoParticipants); mActiveVideoParticipantsCount = items.size(); + Timber.d("ConferenceVideoModule::getConferenceVideoMembers(): items new size=%d", mActiveVideoParticipantsCount); return items; } - @Synchronized - public ArrayList getUpdatedActiveSpeakersParticipants(ArrayList participantIds) { - ArrayList items = new ArrayList<>(mActiveVideoParticipantsMap.values()); + public synchronized void participantRemoved(String participantId) { + Iterator itr = mActiveVideoParticipants.iterator(); + while(itr.hasNext()) { + ConferenceListItem item = itr.next(); + if (!participantId.contentEquals(item.participantId)) { + itr.remove(); + break; + } + } + mActiveVideoParticipantsCount = mActiveVideoParticipants.size(); + } + + public synchronized ArrayList getUpdatedActiveSpeakersParticipants(ArrayList participantIds) { + ArrayList items = new ArrayList<>(mActiveVideoParticipants); for (ConferenceListItem item : items) { item.isSpeaking = false; for (String participandId : participantIds) { @@ -134,8 +211,11 @@ public class ConferenceVideoModule { } public int getWidthDividerLength(int position) { - if (mActiveVideoParticipantsCount/MAX_VIDEO_FEEDS_COLUIMN_SIZE <= MAX_VIDEO_FEEDS_ROW_SIZE) { - return mActiveVideoParticipantsCount / MAX_VIDEO_FEEDS_COLUIMN_SIZE + 1; //MAX_VIDEO_FEEDS_ROW_SIZE + 1; + if (mActiveVideoParticipantsCount <= MAX_VIDEO_FEEDS_COUNT_PER_PAGE) { + if (mActiveVideoParticipantsCount/MAX_VIDEO_FEEDS_COLUIMN_SIZE <= MAX_VIDEO_FEEDS_ROW_SIZE) { + if (mActiveVideoParticipantsCount <= MAX_VIDEO_FEEDS_COLUIMN_SIZE) return 0; + return MAX_VIDEO_FEEDS_ROW_SIZE + 1; + } } int lastPageBeginer = ((mActiveVideoParticipantsCount / MAX_VIDEO_FEEDS_COUNT_PER_PAGE) * MAX_VIDEO_FEEDS_COUNT_PER_PAGE); if (mActiveVideoParticipantsCount == lastPageBeginer) { @@ -143,15 +223,16 @@ public class ConferenceVideoModule { } if (position < lastPageBeginer) { - return MAX_VIDEO_FEEDS_COUNT_PER_PAGE / MAX_VIDEO_FEEDS_COLUIMN_SIZE - 1; + return MAX_VIDEO_FEEDS_COUNT_PER_PAGE / MAX_VIDEO_FEEDS_COLUIMN_SIZE; } int row = (mActiveVideoParticipantsCount - lastPageBeginer)/MAX_VIDEO_FEEDS_COLUIMN_SIZE; if (row <= MAX_VIDEO_FEEDS_ROW_SIZE) { int rest = (mActiveVideoParticipantsCount - lastPageBeginer)%MAX_VIDEO_FEEDS_COLUIMN_SIZE; if (rest == 0) { + if ((position + 1 - lastPageBeginer)/MAX_VIDEO_FEEDS_COLUIMN_SIZE == MAX_VIDEO_FEEDS_ROW_SIZE) return MAX_VIDEO_FEEDS_ROW_SIZE + 1; + if (row == 1) return row; if (row < MAX_VIDEO_FEEDS_ROW_SIZE) return row; - if (position/lastPageBeginer == 1) return row + 1; return row - 1; } return row + 1; @@ -194,7 +275,7 @@ public class ConferenceVideoModule { } private int lastPageWidthDivider2(int lastPageCount) { - if (lastPageCount < MAX_VIDEO_FEEDS_COLUIMN_SIZE) return 1; + //if (lastPageCount < MAX_VIDEO_FEEDS_COLUIMN_SIZE) return 1; return MAX_VIDEO_FEEDS_ROW_SIZE; } @@ -216,6 +297,15 @@ public class ConferenceVideoModule { return MAX_VIDEO_FEEDS_COLUIMN_SIZE; } + public int getItemsPageCount() { + if (mActiveVideoParticipantsCount <= MAX_VIDEO_FEEDS_COLUIMN_SIZE) { + return 1; + } + int count = (mActiveVideoParticipantsCount / MAX_VIDEO_FEEDS_COUNT_PER_PAGE); + if ((mActiveVideoParticipantsCount - count*MAX_VIDEO_FEEDS_COUNT_PER_PAGE) % MAX_VIDEO_FEEDS_COUNT_PER_PAGE > 0) count++; + return count; + } + protected ConferenceListItem conferenceParticipant(NYNCallParticipant participant, boolean isModerator, boolean isOwnStreamActive) { diff --git a/app/src/main/java/com/nynja/mobile/communicator/data/sdk/ConferenceSDKPresenter.java b/app/src/main/java/com/nynja/mobile/communicator/data/sdk/ConferenceSDKPresenter.java index 9c1ae7305cc79a10464f28039f47b09147fe0dd1..cf1044ccef8dc33743aa5c15334d1e6950a4d736 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/data/sdk/ConferenceSDKPresenter.java +++ b/app/src/main/java/com/nynja/mobile/communicator/data/sdk/ConferenceSDKPresenter.java @@ -63,7 +63,7 @@ public abstract class ConferenceSDKPresenter extends Bas @Override public void onRemoteVideoTrackAdded(ActiveConferenceCall activeConferenceCall, String trackId) {} - @Override public void onRemoteVideoTrackRemoved(ActiveConferenceCall activeConferenceCall, String trackId) {} + @Override public void onRemoteVideoTrackRemoved(ActiveConferenceCall activeConferenceCall, String trackId, String participantId) {} @Override public void onLocalVideoCapturerStarted(ActiveConferenceCall activeConferenceCall) {} diff --git a/app/src/main/java/com/nynja/mobile/communicator/data/sdk/calls/ConferenceCallData.java b/app/src/main/java/com/nynja/mobile/communicator/data/sdk/calls/ConferenceCallData.java index 8f4042828852457c7412b222bb685a3a82509465..5fac62702aada9b24aad3a438ac3c028e1f06bc6 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/data/sdk/calls/ConferenceCallData.java +++ b/app/src/main/java/com/nynja/mobile/communicator/data/sdk/calls/ConferenceCallData.java @@ -5,6 +5,7 @@ import com.nynja.sdk.NYNCallParticipant; import com.nynja.sdk.NYNCallParticipantArray; import java.util.HashMap; +import java.util.Map; /** * Created by Ergyun Syuleyman on 04/03/2020. @@ -19,8 +20,8 @@ public class ConferenceCallData { public String mRemoteSSTrackId; public String mRemoteVideoTrackId; public HashMap mActiveTracks; - public HashMap mActiveParticipanTracks; - public HashMap mActiveParticipanSSTracks; + public HashMap mActiveParticipanTracks; + public HashMap mActiveParticipanSSTracks; public boolean hasRemoteVideoTrack; public boolean hasRemoteScreenShareTrack; public boolean mIsConference; @@ -51,13 +52,13 @@ public class ConferenceCallData { public void onRemoteVideoAdded(String trackId, String participantId) { hasRemoteVideoTrack = true; mActiveTracks.put(trackId, participantId); - mActiveParticipanTracks.put(participantId, trackId); + mActiveParticipanTracks.put(trackId, participantId); mRemoteVideoTrackId = trackId; } public void onRemoteVideoRemoved(String trackId, String participantId) { mActiveTracks.remove(trackId); - mActiveParticipanTracks.remove(participantId); + mActiveParticipanTracks.remove(trackId); hasRemoteVideoTrack = !isRemoteVideoTracksEmpty(); mRemoteVideoTrackId = ""; } @@ -65,14 +66,14 @@ public class ConferenceCallData { public void onRemoteSSAdded(String trackId, String participantId) { hasRemoteScreenShareTrack = true; mActiveTracks.put(trackId, participantId); - mActiveParticipanSSTracks.put(participantId, trackId); + mActiveParticipanSSTracks.put(trackId, participantId); mRemoteSSTrackId = trackId; } public void onRemoteSSRemoved(String trackId, String participantId) { hasRemoteScreenShareTrack = false; mActiveTracks.remove(trackId); - mActiveParticipanSSTracks.remove(participantId); + mActiveParticipanSSTracks.remove(trackId); mRemoteSSTrackId = ""; } @@ -96,12 +97,16 @@ public class ConferenceCallData { protected String getTrackIdForParticipant(String participantId, boolean isVideo) { if (StringUtils.isEmpty(participantId)) return ""; if (isVideo) { - if (mActiveParticipanTracks.containsKey(participantId)) { - return mActiveParticipanTracks.get(participantId); + for (Map.Entry set : mActiveParticipanTracks.entrySet()) { + if (set.getValue().contentEquals(participantId)) { + return set.getKey(); + } } } else { - if (mActiveParticipanSSTracks.containsKey(participantId)) { - return mActiveParticipanSSTracks.get(participantId); + for (Map.Entry set : mActiveParticipanSSTracks.entrySet()) { + if (set.getValue().contentEquals(participantId)) { + return set.getKey(); + } } } diff --git a/app/src/main/java/com/nynja/mobile/communicator/data/sdk/calls/ConferenceListItem.java b/app/src/main/java/com/nynja/mobile/communicator/data/sdk/calls/ConferenceListItem.java index e44ee8610cdb0882da1e30bde6e954d364740698..7b3b85da4e44c3f9c26382d05020509593c7b5ed 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/data/sdk/calls/ConferenceListItem.java +++ b/app/src/main/java/com/nynja/mobile/communicator/data/sdk/calls/ConferenceListItem.java @@ -135,12 +135,10 @@ public class ConferenceListItem extends Object { this.hasScreen = participant.hasScreen; this.isVideoPaused = participant.isVideoPaused; this.isScreenPaused = participant.isScreenPaused; - this.isTrackActive = 0; - this.isMe = participant.isMe; +// this.isMe = participant.isMe; this.isFriend = participant.isFriend; this.isMuted = participant.isMuted; this.isSpeaking = participant.isSpeaking; - this.isVideoFullScreen = false; } private void setActions(ArrayList itemActions) { diff --git a/app/src/main/java/com/nynja/mobile/communicator/data/sdk/calls/ConferenceSDKListener.java b/app/src/main/java/com/nynja/mobile/communicator/data/sdk/calls/ConferenceSDKListener.java index 4710d6de072de19ab699bc03f4a91bb56dd74d0b..b6bbde5325b77787f8013b45603db66497af91da 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/data/sdk/calls/ConferenceSDKListener.java +++ b/app/src/main/java/com/nynja/mobile/communicator/data/sdk/calls/ConferenceSDKListener.java @@ -48,7 +48,7 @@ public interface ConferenceSDKListener { void onRemoteVideoTrackAdded(ActiveConferenceCall activeConferenceCall, String trackId) ; - void onRemoteVideoTrackRemoved(ActiveConferenceCall activeConferenceCall, String trackId) ; + void onRemoteVideoTrackRemoved(ActiveConferenceCall activeConferenceCall, String trackId, String participantId) ; void onLocalVideoCapturerStarted(ActiveConferenceCall activeConferenceCall) ; diff --git a/app/src/main/java/com/nynja/mobile/communicator/data/sdk/calls/ConferenceSDKModule.java b/app/src/main/java/com/nynja/mobile/communicator/data/sdk/calls/ConferenceSDKModule.java index 3af7bfeabc63ba1fd2f5ede65cf4e3bff572e90e..791a9ce7c18f10fc6e92ed5b23934c69f3b5eb41 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/data/sdk/calls/ConferenceSDKModule.java +++ b/app/src/main/java/com/nynja/mobile/communicator/data/sdk/calls/ConferenceSDKModule.java @@ -144,6 +144,7 @@ public class ConferenceSDKModule extends BaseSDKModule { private HashMap mConferenceWaitingRoomLNames = new HashMap<>(); private HashMap mMyAcceptedElsewhereCalls = new HashMap<>(); + private int mLastPhoneCallState = TelephonyManager.CALL_STATE_IDLE; private enum States { Connecting, Connected, Disconnecting, Disconnected @@ -468,39 +469,19 @@ public class ConferenceSDKModule extends BaseSDKModule { boolean isLoggedIn, boolean startActivity) { Timber.i("ConferenceSDKModule::handlePushNotification(): " + payload); if (isLoggedIn) { - boolean handled = false; - if (!startActivity) { - boolean result = (!hasCreatedActiveCall()); - NYNCall iConference = mCallManager.handleCallNotification(payload); - if (iConference != null) { - if (iConference.isRinging()) { - if (result) { - createIncomingConference(iConference, false); - mActiveConference.isRinging = true; - } - return true; + boolean result = (!hasCreatedActiveCall()); + NYNCall iConference = mCallManager.handleCallNotification(payload); + if (iConference != null) { + if (iConference.isRinging()) { + if (result) { + Timber.i("ConferenceSDKModule::handlePushNotification(): check 1 "); + createIncomingConference(iConference, startActivity); + mActiveConference.isRinging = true; } - } - return false; - } - if (!isMainActivityIsActive || !hasCreatedActiveCall()) { - handled = mCallManager.handleNotification(payload); - } - if (handled) { - Timber.i("ConferenceSDKModule::handlePushNotification(): will try to catch it - core handling: " + payload); - if (!isMainActivityIsActive) { - Timber.i("ConferenceSDKModule::handlePushNotification(): push isMainActivityIsActive=" - + isMainActivityIsActive + ", start Application"); - Timber.i("ConferenceSDKModule::handlePushNotification(): push mStateDevice.isDeviceActive()=" - + mStateDevice.isDeviceActive() + ", start Application"); - startApplicationActivityForced(); - return true; - } else if (!hasCreatedActiveCall()) { - Timber.i("ConferenceSDKModule::handlePushNotification(): push mActiveConference=null"); - startApplicationActivity(); return true; } } + return false; } return false; } @@ -570,6 +551,10 @@ public class ConferenceSDKModule extends BaseSDKModule { } public void setSpeakerState(boolean on, boolean forced) { + setSpeakerState(on, forced, true); + } + + public void setSpeakerState(boolean on, boolean forced, boolean event) { if (mConferenceAudioManager == null) { mConferenceAudioManager = AppRTCAudioManager.create(getContext()); } @@ -586,38 +571,37 @@ public class ConferenceSDKModule extends BaseSDKModule { } + if (!event) return; for (ConferenceSDKListener conferenceSDKListener : mConferenceSDKListener) { conferenceSDKListener.onSpeakerStateChanged(on); } } public void setAudioRoute(ActiveCallBase.AudioRouteType routeType) { - AudioManager audioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); - if (audioManager == null) { - return; - } + setAudioRoute(routeType, true); + } - boolean isSpeakerOn = false; + public void setAudioRoute(ActiveCallBase.AudioRouteType routeType, boolean updateWith) { + if (mConferenceAudioManager == null) { + mConferenceAudioManager = AppRTCAudioManager.create(getContext()); + } switch (routeType) { case SPEAKER: - isSpeakerOn = true; - audioManager.setSpeakerphoneOn(true); - audioManager.setBluetoothScoOn(false); + setSpeakerState(true, true, false); + mConferenceAudioManager.selectAudioDevice(AppRTCAudioManager.AudioDevice.SPEAKER_PHONE); break; case EARPIECE: - audioManager.setBluetoothScoOn(false); - audioManager.setSpeakerphoneOn(false); + setSpeakerState(false, true, false); + mConferenceAudioManager.selectAudioDevice(AppRTCAudioManager.AudioDevice.EARPIECE); break; case BLUETOOTH: - audioManager.setBluetoothScoOn(true); - audioManager.setSpeakerphoneOn(false); + mConferenceAudioManager.selectAudioDevice(AppRTCAudioManager.AudioDevice.BLUETOOTH); break; } - if (hasCreatedActiveCall()) { + if (updateWith && hasCreatedActiveCall()) { mActiveConference.mAudioRouteType = routeType; - mActiveConference.isSpeakerOn = isSpeakerOn; } for (ConferenceSDKListener conferenceSDKListener : mConferenceSDKListener) @@ -1481,19 +1465,7 @@ public class ConferenceSDKModule extends BaseSDKModule { @Override public void replaceCall(String oldCallId, NYNCall newCall) { - if (oldCallId != null) { - Timber.d("replaceCall old call \'CallId\'=\'" + - oldCallId + "\' with new \'CallId\'=\'" + newCall!=null? newCall.callId(): "null"+ "\'"); - if (hasCreatedActiveCall() && mActiveConference.mConference != null - && mActiveConference.mConference.callId().contentEquals(oldCallId)) { - mActiveConference.mConference.setListener(null); - final String callId = newCall.callId(); - onReplaceCall(callId); - } else if (newCall != null && !hasCreatedActiveCall() && oldCallId.contentEquals(newCall.replaceRef())) { - final String callId = newCall.callId(); - replaceNewCall(callId); - } - } + trySwitchP2pToConferenceCall(oldCallId, newCall); } @Override @@ -1603,6 +1575,24 @@ public class ConferenceSDKModule extends BaseSDKModule { } } + private synchronized void trySwitchP2pToConferenceCall(String oldCallId, NYNCall newCall) { + if (oldCallId != null) { + Timber.d("replaceCall old call \'CallId\'=\'" + + oldCallId + "\' with new \'CallId\'=\'" + newCall!=null? newCall.callId(): "null"+ "\'"); + if (hasCreatedActiveCall() && mActiveConference.mConference != null + && mActiveConference.mConference.callId().contentEquals(oldCallId)) { + Timber.d("replaceCall::trySwitchP2pToConferenceCall(): check 1"); + mActiveConference.mConference.setListener(null); + final String callId = newCall.callId(); + onReplaceCall(callId); + } else if (newCall != null && !hasCreatedActiveCall() && oldCallId.contentEquals(newCall.replaceRef())) { + Timber.d("replaceCall::trySwitchP2pToConferenceCall(): check 2"); + final String callId = newCall.callId(); + replaceNewCall(callId); + } + } + } + private void onScreenShareState(String callId, boolean active) { // not need twice for active call or not!!! for (ConferenceSDKListener conferenceListener : mConferenceSDKListener) { @@ -1678,7 +1668,7 @@ public class ConferenceSDKModule extends BaseSDKModule { if (mActiveConference.mConference == null) return; if (mActiveConference.mConference.callId().contentEquals(callId)) { for (ConferenceSDKListener conferenceSDKListener : mConferenceSDKListener) { - conferenceSDKListener.onRemoteVideoTrackRemoved(mActiveConference, trackId); + conferenceSDKListener.onRemoteVideoTrackRemoved(mActiveConference, trackId, participantId); } } // if (isConference) { @@ -1916,24 +1906,14 @@ public class ConferenceSDKModule extends BaseSDKModule { if (!hasCreatedActiveCall() || StringUtils.isEmpty(conferenceId)) return; if (isP2P()) { if (replaceRef.contentEquals(mActiveConference.mConference.callId())) { - NYNCall conference = mCallManager.getCallById(conferenceId); - if (conference != null && conference.isConference()) { - // Escalate call to Conference - new Handler(Looper.getMainLooper()).post(() -> { - boolean isVideoConference = false;//NOT SUPPORTING VIDEO CONFERENCING YET!!!! mActiveConference.isVideoEnabled; - String subject = conference.getSubject(); - //conferenceHangUp(true); - mActiveConference.mConference.setListener(null); - endConference(false, false); - if (makeConferenceEx(conference, subject, roomId, null, isVideoConference, true)) { - mConferenceDetails.mCallId = conferenceId; - initConferenceCall(); - if (mHandler != null) mHandler.post( () -> { - onConferenceParticipantsUpdated(conferenceId); - }); - } - }); - } + // Escalate call to Conference + final NYNCall conference = mCallManager.getCallById(conferenceId); + if (conference == null || !conference.isConference()) return; + //////////////////////////////////////////////////////////////////////////////// + // !!!!!!!!!!! after that comes REPLACE event too ... + // so no needs to Recreate 2 time the new conference call !!! + trySwitchP2pToConferenceCall(replaceRef, conference); + //////////////////////////////////////////////////////////////////////////////// } } } @@ -2780,9 +2760,12 @@ public class ConferenceSDKModule extends BaseSDKModule { public boolean startIncommingConferenceActivity(boolean delayed, String callId, String screenKey) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && callId != null) { + Timber.d("startIncommingConferenceActivity with \'ConferenceId\'=\'" + callId + + "; delayed=" + (delayed?"true": "false")); + final String name = mActiveConference.getCallerName(); new Handler(Looper.getMainLooper()).post(() -> { - mNotificationHelper.createCallPushNotification(getContext(), mActiveConference.getCallerName(), callId, true, - mSettingNotifications); + mNotificationHelper.createCallPushNotification(getContext(), name, callId, true, + mSettingNotifications, false); }); return true; } else if (!mStateDevice.isDeviceActive()) { @@ -2916,11 +2899,13 @@ public class ConferenceSDKModule extends BaseSDKModule { if (!hasCreatedActiveCall()) return false; mActiveConference.mData.isOwnStreamActive = false; initConferenceCall(startActivity); + Timber.d("createIncomingCallAndStartRinging with \'ConferenceId\'=\'" + callId + + "; startActivity=" + (startActivity?"true": "false")); if (startActivity) { if (Consts.SHOW_INCOMING_CALLS_AS_POPUP_NOTIFICATIONS) { new Handler(Looper.getMainLooper()).post(() -> { mNotificationHelper.createCallPushNotification(getContext(), mActiveConference.getCallerName(), callId, true, - mSettingNotifications); + mSettingNotifications, false); }); } else if (!startIncommingConferenceActivity(delayed, callId, null)) { startIncommingActivity(delayed, NynjaNavigator.MAIN_NEW_CALL); @@ -2932,6 +2917,8 @@ public class ConferenceSDKModule extends BaseSDKModule { private synchronized boolean createIncomingConference(NYNCall iConference, boolean startActivity) { if (iConference == null) return false; if (iConference.isOutgoing()) return false; + Timber.d("createIncomingConference with \'ConferenceId\'=\'" + iConference.callId() + + "; startActivity=" + (startActivity?"true": "false")); boolean isCallAccess = mSettingNotifications.isCallNotifications() || mStateDevice.isDeviceActive(); if (!hasCreatedActiveCall() && iConference != null && isCallAccess) { return createIncomingCallAndStartRinging(iConference, false, startActivity); @@ -3095,17 +3082,22 @@ public class ConferenceSDKModule extends BaseSDKModule { final String callId = iConference.callId(); mActiveConference.isRinging = false; new Handler(Looper.getMainLooper()).post(() -> { - onCallReady(callId, videoEnabled); - if (mActiveConference.mInitialStartCapturer && - mActiveConference.mData.isOwnStreamActive && - mActiveConference.isOutgoingCall && - mActiveConference.mConference.isModerator()) { - mActiveConference.mConference.startCamera(); - mActiveConference.mInitialStartCapturer = false; - } + onConferenceConnectedInternal(callId, videoEnabled); }); } } + private synchronized void onConferenceConnectedInternal(String callId, boolean videoEnabled) { + onCallReady(callId, videoEnabled); + if (mActiveConference != null && + mActiveConference.mInitialStartCapturer && + mActiveConference.mData.isOwnStreamActive && + mActiveConference.isOutgoingCall && + mActiveConference.mConference != null && + mActiveConference.mConference.isModerator()) { + mActiveConference.mConference.startCamera(); + mActiveConference.mInitialStartCapturer = false; + } + } private void onCallReady(String callId, boolean videoEnabled) { onCallReady(callId, videoEnabled, false); @@ -3277,7 +3269,7 @@ public class ConferenceSDKModule extends BaseSDKModule { if (mActiveConference.mConference == null) return false; return (mActiveConference.mConference.hasRemoteScreenShare() - || !mActiveConference.mData.mActiveTracks.isEmpty()); + || !mActiveConference.mData.mActiveParticipanSSTracks.isEmpty()); } public boolean isScreenSharing() { @@ -3479,12 +3471,23 @@ public class ConferenceSDKModule extends BaseSDKModule { Timber.d("ConferenceModule::onReceive(): Telephony service event"); String action = intent.getAction(); if (action != null && action.equals(PHONE_STATE)) { + TelephonyManager tm = (TelephonyManager) context.getSystemService(Service.TELEPHONY_SERVICE); if (isConferenceActive()) { - TelephonyManager tm = (TelephonyManager) context.getSystemService(Service.TELEPHONY_SERVICE); - if (tm != null && tm.getCallState() == TelephonyManager.CALL_STATE_OFFHOOK) { - endActiveCall(); + if (tm != null) { + if (tm.getCallState() == TelephonyManager.CALL_STATE_OFFHOOK) { + endActiveCall(); + } else if (tm.getCallState() == TelephonyManager.CALL_STATE_RINGING) { + setAudioRoute(ActiveCallBase.AudioRouteType.EARPIECE, false); + //setSpeakerState(false, true, true); + } else if (mLastPhoneCallState == TelephonyManager.CALL_STATE_RINGING + && tm.getCallState() == TelephonyManager.CALL_STATE_IDLE) { + setAudioRoute(mActiveConference.mAudioRouteType, true); + } } } + if (tm != null) { + mLastPhoneCallState = tm.getCallState();//TelephonyManager.CALL_STATE_IDLE; + } } } } diff --git a/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/CallActivityPresenter.java b/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/CallActivityPresenter.java index aedd916dd5d24d2ad1f9930db4f193191997a98b..23b74d341ee06dbda76456e36180dee56a05fec7 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/CallActivityPresenter.java +++ b/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/CallActivityPresenter.java @@ -43,7 +43,7 @@ public class CallActivityPresenter extends ConferenceSDKPresenter return contact; } - private ArrayList getOriginParticipantContacts(List items) { - return getOriginParticipantContacts(items, false); + private ArrayList getOriginParticipantContacts(List items, + ContactModel me) { + return getOriginParticipantContacts(items, me, false); } - private ArrayList getOriginParticipantContacts(List items, boolean isEscalateCall) { + private ArrayList getOriginParticipantContacts(List items, + ContactModel me, + boolean isEscalateCall) { ArrayList contacts = new ArrayList<>(); if (items != null) { if (mNewAllContacts != null) { for (int i = 0; i < items.size(); i++) { ContactModel contact = getOriginParticipantContact(mNewAllContacts, items.get(i)); if (isEscalateCall) { - contact.isMe = false; // check with real MY contact!!! + if (me.equals(contact)) continue; + contact.isMe = false; } contacts.add(contact); } @@ -845,8 +849,8 @@ public class ChooseUserPresenter extends ConferenceSDKPresenter String roomName; String roomId = null; if (mRoom != null) { - contacts = getOriginParticipantContacts(items); ContactModel me = mDataManager.getMyConferenceContact(); + contacts = getOriginParticipantContacts(items, me); if (me != null) { MemberModel memberMe = mRoom.findMemberById(me.phoneId); if (memberMe != null) { @@ -860,8 +864,8 @@ public class ChooseUserPresenter extends ConferenceSDKPresenter roomName = mRoom.name; roomId = mRoom.id; } else { - contacts = getOriginParticipantContacts(items, isEscalateCall); ContactModel me = mDataManager.getMyConferenceContact(); + contacts = getOriginParticipantContacts(items, me, isEscalateCall); if (me != null) { me.isMe = true; contacts.add(0, me); diff --git a/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/ConferenceCallPresenter.java b/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/ConferenceCallPresenter.java index f4bb992891edc05a899a794d3e695f626c802ae3..57fd65d47961e3ef37c439b56f61254df91b3112 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/ConferenceCallPresenter.java +++ b/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/ConferenceCallPresenter.java @@ -64,10 +64,6 @@ public class ConferenceCallPresenter extends ConferenceSDKPresenter } - public void bluetoothDisconnected() { - mDataManager.getConferenceSDK().setSpeakerState(getActiveConference().isSpeakerOn); - } - public void switchCamera() { if (getAttachedViews().size() == 0) return; ActiveConferenceCall activeConferenceCall = mDataManager.getConferenceSDK(). @@ -373,7 +369,7 @@ public class ConferenceCallPresenter extends ConferenceSDKPresenter @Override public void onRemoteVideoTrackRemoved(ActiveConferenceCall activeConferenceCall, - String trackId) { + String trackId, String participantId) { if (getAttachedViews().size() == 0) return; if (activeConferenceCall == null) return; if (activeConferenceCall.isConference()) return; @@ -445,8 +441,12 @@ public class ConferenceCallPresenter extends ConferenceSDKPresenter public void onClickScreenShare(boolean isShareOn) { if (getAttachedViews().size() == 0) return; ActiveConferenceCall call = mDataManager.getConferenceSDK().getActiveConference(); - if (call != null && !call.isModerator() && !mDataManager.getConferenceSDK().isP2P()) { - if (!isScreenSharing() && hasRemoteScreenShare()) { + if (call != null && !mDataManager.getConferenceSDK().isP2P()) { + if (isCameraRunning()) { + getViewState().showStopOwnCameraFirstgAlert(); + return; + } + if (/*!call.isModerator() &&*/ !isScreenSharing() && hasRemoteScreenShare()) { getViewState().showFirstStopScreenSharingWarning(call); return; } @@ -464,12 +464,30 @@ public class ConferenceCallPresenter extends ConferenceSDKPresenter } } + public void stopCameraAndContinueWithScreenshare() { + if (getAttachedViews().size() == 0) return; + if (!isScreenSharing()) { + stopCameraCapture(); + //startScreenCapture(); + getViewState().continueWithScreenshare(); + } + } + + public void continueWithScreenshare() { + if (getAttachedViews().size() == 0) return; + if (!isScreenSharing()) { + startScreenCapture(); + getViewState().setScreenShareOn(true); + } + } + public String getInvitationLink() { return mDataManager.getConferenceSDK().getActiveConferenceJoinLink(); } @Nullable private ArrayList getConferenceParticipants() { + if (isP2PCall()) return null; if (mDataManager.getConferenceSDK(). getActiveConference().mData.mParticipantArray != null) { ArrayList currentContacts = new ArrayList<>(); @@ -555,11 +573,22 @@ public class ConferenceCallPresenter extends ConferenceSDKPresenter } } + public void tryStartCameraCapture() { + if (getAttachedViews().size() == 0) return; + ActiveConferenceCall call = mDataManager.getConferenceSDK().getActiveConference(); + if (call != null && !mDataManager.getConferenceSDK().isP2P()) { + if (isScreenSharing()) { + getViewState().showStopScreenShareFirstAlert(); + return; + } + } + startCameraCapture(); + } + public void startCameraCapture() { mDataManager.getConferenceSDK().startCameraCapture(); } - public void stopCameraCapture() { mDataManager.getConferenceSDK().stopCameraCapture(); } diff --git a/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/ConferenceVideoPresenter.java b/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/ConferenceVideoPresenter.java index 93ff6234b0e3ebb4d30a1f03899aace87af3a940..c1e6df26d1cac0eed419d56da022dfbc715b7d05 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/ConferenceVideoPresenter.java +++ b/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/ConferenceVideoPresenter.java @@ -135,8 +135,9 @@ public class ConferenceVideoPresenter extends ConferenceSDKPresenter() { mDataManager.getConferenceSDK().declineConference() } + fun setContactForP2P() { + val activeConferenceCall = mDataManager.conferenceSDK.activeConference + val peerId = mDataManager.conferenceSDK.activeConferencePeerName // getConferenceRoomId() + if (mDataManager.conferenceSDK.isP2P) { + val contact = mDataManager.getContactByChatId(peerId) + if (contact != null) { + activeConferenceCall?.addMember(contact) + } + } + } } diff --git a/app/src/main/java/com/nynja/mobile/communicator/mvp/view/CallView.java b/app/src/main/java/com/nynja/mobile/communicator/mvp/view/CallView.java index d718d095ffe79e3494a69ddd827a6afee6314c79..da0f547e22d730515d0130f017329be5d1f04ef0 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/mvp/view/CallView.java +++ b/app/src/main/java/com/nynja/mobile/communicator/mvp/view/CallView.java @@ -44,13 +44,13 @@ public interface CallView extends ErrorMvpView { void onStartCapturerFailed(int msgResId, boolean isCamera); - void onRemoteVideoTrackAdded(ActiveConferenceCall activeConferenceCall, String trackId) ; + void onRemoteVideoTrackAdded(ActiveConferenceCall activeConferenceCall, String trackId); - void onRemoteVideoTrackRemoved(ActiveConferenceCall activeConferenceCall, String trackId) ; + void onRemoteVideoTrackRemoved(ActiveConferenceCall activeConferenceCall, String trackId); - void onLocalVideoCapturerStarted(ActiveConferenceCall activeConferenceCall) ; + void onLocalVideoCapturerStarted(ActiveConferenceCall activeConferenceCall); - void onLocalVideoCapturerStopped(ActiveConferenceCall activeConferenceCall) ; + void onLocalVideoCapturerStopped(ActiveConferenceCall activeConferenceCall); void onScreenShareStateChanged(boolean isSharing); @@ -83,4 +83,11 @@ public interface CallView extends ErrorMvpView { void setScreenShareOn(boolean shareOn); void showFirstStopScreenSharingWarning(ActiveConferenceCall call); + + void showStopOwnCameraFirstgAlert(); + + void showStopScreenShareFirstAlert(); + + void continueWithScreenshare(); + } diff --git a/app/src/main/java/com/nynja/mobile/communicator/mvp/view/ConferenceVideoView.java b/app/src/main/java/com/nynja/mobile/communicator/mvp/view/ConferenceVideoView.java index 50d0d40f89a6e81ba154fdc38b068836ccdf2538..d3f88871efb72f91937cbebff1ce9d2c07ab2536 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/mvp/view/ConferenceVideoView.java +++ b/app/src/main/java/com/nynja/mobile/communicator/mvp/view/ConferenceVideoView.java @@ -13,7 +13,7 @@ public interface ConferenceVideoView extends ErrorMvpView { void onRemoteVideoTrackAdded(ActiveConferenceCall activeConferenceCall, String trackId) ; - void onRemoteVideoTrackRemoved(ActiveConferenceCall activeConferenceCall, String trackId) ; + void onRemoteVideoTrackRemoved(ActiveConferenceCall activeConferenceCall, String trackId, String participantId) ; void onLocalVideoCapturerStarted(ActiveConferenceCall activeConferenceCall) ; diff --git a/app/src/main/java/com/nynja/mobile/communicator/ui/activities/MainActivity.java b/app/src/main/java/com/nynja/mobile/communicator/ui/activities/MainActivity.java index c11eb28521e568d4483671d3eb9c8a1fa615b991..d3ec2a1c170d69e573b0ffc25313171dccef8c2c 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/ui/activities/MainActivity.java +++ b/app/src/main/java/com/nynja/mobile/communicator/ui/activities/MainActivity.java @@ -402,6 +402,7 @@ public class MainActivity extends BaseActivity implements MainActivityView, if (permission.granted) { Timber.d("All permission(s) requests finished"); if (incomming) { + mPresenter.setContactForP2P(); mPresenter.navigateToActiveCall(); mPresenter.clearIncomingCallNotification(); } else { diff --git a/app/src/main/java/com/nynja/mobile/communicator/ui/adapters/conference/ConferenceVideoAdapter.java b/app/src/main/java/com/nynja/mobile/communicator/ui/adapters/conference/ConferenceVideoAdapter.java index 0956d049d755aed605485fe7afe2ad6796d11640..f078dee5d9e8c443be56165c7fad92acf04f33f0 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/ui/adapters/conference/ConferenceVideoAdapter.java +++ b/app/src/main/java/com/nynja/mobile/communicator/ui/adapters/conference/ConferenceVideoAdapter.java @@ -18,8 +18,14 @@ import com.nynja.mobile.communicator.ui.adapters.viewholders.conference.Conferen import com.nynja.mobile.communicator.ui.base.BaseAdapter; import com.nynja.mobile.communicator.ui.base.BaseVH; +import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Set; + +import timber.log.Timber; import static com.nynja.mobile.communicator.data.conference.ConferenceVideoModule.MAX_VIDEO_FEEDS_COLUIMN_SIZE; import static com.nynja.mobile.communicator.data.conference.ConferenceVideoModule.MAX_VIDEO_FEEDS_ROW_SIZE; @@ -31,13 +37,13 @@ public class ConferenceVideoAdapter> exten private DisplayMetrics mDisplayMetrics = new DisplayMetrics(); private int mScreenWidth = 0; private int mScreenHeight = 0; - HashSet mHoldersSet; + LinkedHashSet< ConferenceVideoItemVh> mHolders; public ConferenceVideoAdapter(List list, OnConferenceVideoFeedClickListener onConferenceItemClickListener) { super(list); this.mOnConferenceVideoFeedClickListener = onConferenceItemClickListener; - mHoldersSet = new HashSet<>(); + mHolders = new LinkedHashSet<>(); setHasStableIds(true); } @@ -48,9 +54,21 @@ public class ConferenceVideoAdapter> exten @Override public long getItemId(int position) { if (position < getItemCount()) { - return getItem(position).hashCode(); + Timber.d("ConferenceVideoAdapter::getItemId(): participantId=%s; feedID=%d, position=%d", getItem(position).participantId, + getItem(position).participantId.hashCode(), position); + return getItem(position).participantId.hashCode(); } - return -1L; + return position; + } + + @Override + public int getItemsPageCount() { + return ConferenceVideoModule.getInstance().getItemsPageCount(); + } + + @Override + public int getMaxItemsPerPage() { + return ConferenceVideoModule.MAX_VIDEO_FEEDS_COUNT_PER_PAGE; } public void setIsModerator(boolean isModerator) { @@ -61,13 +79,53 @@ public class ConferenceVideoAdapter> exten return this.mIsModerator; } - public void releaseVideoCallRrenderers() { - for (ConferenceVideoItemVh vh : mHoldersSet) { + public void releaseVideoCallRrenderer(String participantId, boolean pause, boolean notify) { + Iterator itr = mHolders.iterator(); + while(itr.hasNext()) { + ConferenceVideoItemVh vh = itr.next(); + if (vh.getItem().participantId.contentEquals(participantId)) { + if (pause) { + onViewRecycled((T)vh); + } else { + releaseVideoCallRrenderer(vh, notify); + itr.remove(); + } + break; + } + } + } + + private void releaseVideoCallRrenderer(ConferenceVideoItemVh vh, boolean notify) { + String participantId = null; + if (vh != null) { + participantId = vh.getItem().participantId; vh.onViewRecycled(); vh.releaseVideoCallRrenderers(); } - mHoldersSet.clear(); + if (participantId == null) return; + int pos = 0; + for (ConferenceListItem item : mList) { + if (item.participantId.contentEquals(participantId)) { + mList.remove(participantId); + ConferenceVideoModule.getInstance().participantRemoved(participantId); + if (notify) notifyItemRemoved(pos); + break; + } + pos++; + } + } + + public void releaseVideoCallRrenderer(ConferenceVideoItemVh vh) { + } + public void releaseVideoCallRrenderers() { + Iterator itr = mHolders.iterator(); + while(itr.hasNext()) { + ConferenceVideoItemVh vh = itr.next(); + releaseVideoCallRrenderer(vh, false); + itr.remove(); + } + mHolders.clear(); clear(); } @@ -83,6 +141,7 @@ public class ConferenceVideoAdapter> exten @NonNull @Override public T onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { + Timber.d("ConferenceVideoAdapter::onBindViewHolder():"); ConferenceVideoItemVh viewHolder = new ConferenceVideoItemVh(viewGroup, mIsModerator); viewHolder.setOnClickListener(mOnConferenceVideoFeedClickListener); if (viewGroup.getContext() instanceof CallActivity) { @@ -92,12 +151,13 @@ public class ConferenceVideoAdapter> exten mScreenWidth = mDisplayMetrics.widthPixels; mScreenHeight = (int) (mDisplayMetrics.heightPixels - mDisplayMetrics.densityDpi/mDisplayMetrics.density); } - mHoldersSet.add(viewHolder); + mHolders.add(viewHolder); return (T) viewHolder; } @Override public void onBindViewHolder(T holder, int position) { + Timber.d("ConferenceVideoAdapter::onBindViewHolder(): item ID=%d; pos=%s", holder.getItemId(), position); super.onBindViewHolder(holder, position); if (mScreenWidth > 0) { float divWidth = ConferenceVideoModule.getInstance().getWidthDiv(position); @@ -121,7 +181,9 @@ public class ConferenceVideoAdapter> exten } else { layoutParams.width = itemWidth - ConferenceVideoModule.getInstance().getWidthDividerLength(position); } + holder.itemView.setBottom(itemHeight - 32); holder.itemView.setLayoutParams(layoutParams); + holder.itemView.requestLayout(); } } diff --git a/app/src/main/java/com/nynja/mobile/communicator/ui/adapters/viewholders/conference/ConferenceVideoItemVh.java b/app/src/main/java/com/nynja/mobile/communicator/ui/adapters/viewholders/conference/ConferenceVideoItemVh.java index 8c4e0165619eed1659081743eda384ac3ee6596f..cd14239e360aac822dbb7ec2efa39d6e54884914 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/ui/adapters/viewholders/conference/ConferenceVideoItemVh.java +++ b/app/src/main/java/com/nynja/mobile/communicator/ui/adapters/viewholders/conference/ConferenceVideoItemVh.java @@ -40,6 +40,7 @@ public class ConferenceVideoItemVh extends BaseVH { private OnConferenceVideoFeedClickListener mListener; private boolean mIsModerator; private boolean mIsRenderersInitialized = false; + private String mTrackId = ""; public ConferenceVideoItemVh(ViewGroup parent, boolean isModerator) { super(parent, R.layout.li_conference_video); @@ -51,19 +52,20 @@ public class ConferenceVideoItemVh extends BaseVH { } - @Override public void bind() { - //mUnbinder = ButterKnife.bind(this, itemView); - } - - @Override public void bind(ConferenceListItem item, int position) { - mPosition = position; - if (mUnbinder != null) { - //mUnbinder.unbind(); - } else { - mUnbinder = ButterKnife.bind(this, itemView); - } - setData(item); - } +// @Override public void bind() { +// //mUnbinder = ButterKnife.bind(this, itemView); +// } +// +// @Override public void bind(ConferenceListItem item, int position) { +// Timber.d("ConferenceVideoItemVh::bind(): item participant ID=%s, position=%d", item.participantId, position); +// mPosition = position; +// if (mUnbinder != null) { +// //mUnbinder.unbind(); +// } else { +// mUnbinder = ButterKnife.bind(this, itemView); +// } +// setData(item); +// } public SurfaceViewRenderer getVideoFeed() { return mVideoFeed; @@ -74,6 +76,11 @@ public class ConferenceVideoItemVh extends BaseVH { } @Override public void setData(ConferenceListItem item) { + if (!item.equals(this.mItem) && this.mItem != null) { + enableVideoForTrack(false); + removeVideoRendererForTrack(); + hideSwithCamera(); + } this.mItem = item; mSS.setAutoToggle(false); mActiveVideo.setAutoToggle(false); @@ -86,39 +93,39 @@ public class ConferenceVideoItemVh extends BaseVH { itemView.setOnLongClickListener(v -> mListener.onItemLongClick(item, mPosition)); } itemView.setTag(this); + mTrackId = ConferenceVideoModule.getInstance().getTrackIdByParticipantId(mItem.participantId); if (item.type == ConferenceListItem.ConferenceItemType.Plus) { // mPhoto.setImageResource(R.drawable.v_add_member_voice_call); } else { - // item.type == ConferenceListItem.ConferenceItemType.Participant - if (item.memberId == null || item.memberId.isEmpty()) { -// mPhoto.setImageResource(R.drawable.participant_placeholder_grey); - } else { - // in Conference - setupInConference(item); - onViewAttachedToWindow(); - } + // in Conference + setupInConference(item); + onViewAttachedToWindow(); } + Timber.d("ConferenceVideoItemVh::setData(): item participant name=%s; ID=%s", item.name, item.participantId); } public void onViewAttachedToWindow() { initVideoCallRenderer(); setVideoRendererForTrack(); enableVideoForTrack(true); + Timber.d("ConferenceVideoItemVh::onViewAttachedToWindow(): item participant name=%s; ID=%s", mItem.name, mItem.participantId); } public void onViewDetachedFromWindow() { enableVideoForTrack(false); - //removeVideoRendererForTrack(); + Timber.d("ConferenceVideoItemVh::onViewDetachedFromWindow(): item participant name=%s; ID=%s", mItem.name, mItem.participantId); } public void onViewRecycled() { enableVideoForTrack(false); + Timber.d("ConferenceVideoItemVh::onViewRecycled(): item participant name=%s; ID=%s", mItem.name, mItem.participantId); } @Synchronized public void releaseVideoCallRrenderers() { - removeVideoRendererForTrack(); + Timber.d("ConferenceVideoItemVh::releaseVideoCallRrenderers(): item participant name=%s; ID=%s", mItem.name, mItem.participantId); if (!mIsRenderersInitialized) return; + removeVideoRenderer(); if (mVideoFeed != null) { mVideoFeed.release(); } @@ -128,19 +135,21 @@ public class ConferenceVideoItemVh extends BaseVH { ///////////////////////////////////////////////////////////////////////////////////// // Internal Helpers private void setupInConference(ConferenceListItem item) { + Timber.d("ConferenceVideoItemVh::setupInConference(): item participant name=%s; ID=%s", mItem.name, mItem.participantId); initVideoCallRenderer(); if (item.participantId == null || !item.isActive) { // in Conference - but not joined yet mMutedIndicator.setVisibility(View.GONE); -// mPhoto.setImageResource(R.drawable.participant_placeholder_grey); + hideSwithCamera(); } else { // already joined in Conference drawIsMutedIfNeeded(item); drawIsScfreenSharingIfNeeded(item); // drawIsActiveVideoIfNeeded(item); - drawIsFeedVideoIfNeeded(item.hasVideo); +// drawIsFeedVideoIfNeeded(item.hasVideo); if (mItem != null) { if (mItem != null && mItem.isMe) { + mName.setText(R.string.call_me); mFeedFrameLayout.setBackgroundResource(R.drawable.video_feed_square_stroke_red); mSwithCamera.setOnClickListener(null); if (mListener != null) { @@ -149,21 +158,28 @@ public class ConferenceVideoItemVh extends BaseVH { } } else if (mItem != null && mItem.isSpeaking) { mFeedFrameLayout.setBackgroundResource(R.drawable.video_feed_square_stroke_green); + hideSwithCamera(); } else { mFeedFrameLayout.setBackgroundColor(Color.TRANSPARENT); + hideSwithCamera(); } } else { mFeedFrameLayout.setBackgroundColor(Color.TRANSPARENT); + hideSwithCamera(); } } } + private void hideSwithCamera() { + mSwithCamera.setOnClickListener(null); + mSwithCamera.setVisibility(View.GONE); + } + private void drawIsMutedIfNeeded(ConferenceListItem item) { if(item.isMuted) { mMutedIndicator.setVisibility(View.VISIBLE); } else { mMutedIndicator.setVisibility(View.GONE); -// ImageUtils.loadAvatarImage(item.avatar, mPhoto); } } @@ -186,6 +202,7 @@ public class ConferenceVideoItemVh extends BaseVH { } private void drawIsFeedVideoIfNeeded(boolean visible) { + Timber.d("ConferenceVideoItemVh::drawIsFeedVideoIfNeeded(): item participant ID=%s; visible=%s", mItem.participantId, visible? "true":"false"); if (visible) { mVideoFeed.setVisibility(View.VISIBLE); } else { @@ -194,9 +211,10 @@ public class ConferenceVideoItemVh extends BaseVH { refreshFeedVideo(); } - private void refreshFeedVideo() { + public void refreshFeedVideo() { + Timber.d("ConferenceVideoItemVh::refreshFeedVideo(): item participant name=%s; ID=%s", mItem.name, mItem.participantId); if (mVideoFeed != null) { - mVideoFeed.invalidate(); + mVideoFeed.postInvalidate(); mVideoFeed.refreshDrawableState(); } } @@ -212,10 +230,13 @@ public class ConferenceVideoItemVh extends BaseVH { @Synchronized private void initVideoCallRenderer() { + Timber.d("ConferenceVideoItemVh::initVideoCallRenderer(): item participant ID=%s; mIsRenderersInitialized=%s", mItem.participantId, mIsRenderersInitialized? "true":"false"); if (mIsRenderersInitialized) return; + Timber.d("ConferenceVideoItemVh::initVideoCallRenderer():2"); try { mVideoFeed.init(createRootEglBase().getEglBaseContext(), null); mVideoFeed.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT); + mVideoFeed.setWillNotDraw(false); mVideoFeed.setEnableHardwareScaler(true); if (mItem != null && mItem.isMe) { mVideoFeed.setMirror(true); @@ -228,30 +249,33 @@ public class ConferenceVideoItemVh extends BaseVH { @Synchronized private void setVideoRendererForTrack() { + Timber.d("setVideoRendererForTrack::setVideoRendererForTrack(): item participant name=%s; ID=%s", mItem.name, mItem.participantId); if (!mIsRenderersInitialized) return; if (mItem == null) return; - if (mItem.isTrackActive == 1) return; - String trackId = ConferenceVideoModule.getInstance().getTrackIdByParticipantId(mItem.participantId); - if (StringUtils.isNotEmpty(trackId) || mItem.isMe) { + //if (mItem.isTrackActive == 1) return; + Timber.d("setVideoRendererForTrack::setVideoRendererForTrack(): item participant ID=%s; trackId=%s", mItem.participantId, mTrackId); + if (StringUtils.isNotEmpty(mTrackId) || mItem.isMe) { mItem.isTrackActive = 1; - ConferenceVideoModule.getInstance().setVideoRendererForTrack(mVideoFeed, trackId, mItem.isMe); + Timber.d("setVideoRendererForTrack::setVideoRendererForTrack(): item participant ID=%s; isMe=%s", mItem.participantId, mItem.isMe? "true":"false"); + ConferenceVideoModule.getInstance().setVideoRendererForTrack(mVideoFeed, mTrackId, mItem.isMe); + refreshFeedVideo(); } } @Synchronized private void removeVideoRendererForTrack() { + Timber.d("setVideoRendererForTrack::removeVideoRendererForTrack(): item participant name=%s; ID=%s", mItem.name, mItem.participantId); if (!mIsRenderersInitialized) return; if (mItem == null) return; if (mItem.isTrackActive == 0) return; - String trackId = ConferenceVideoModule.getInstance().getTrackIdByParticipantId(mItem.participantId); - if (StringUtils.isNotEmpty(trackId) || mItem.isMe) { - ConferenceVideoModule.getInstance().setVideoRendererForTrack(null, trackId, mItem.isMe); - mItem.isTrackActive = 0; - } + Timber.d("setVideoRendererForTrack::removeVideoRendererForTrack(): item participant ID=%s; trackId=%s", mItem.participantId, mTrackId); + removeVideoRenderer(); } @Synchronized private void enableVideoForTrack(boolean enable) { + Timber.d("setVideoRendererForTrack::enableVideoForTrack(): item participant name=%s; ID=%s", mItem.name, mItem.participantId); + Timber.d("ConferenceVideoItemVh::enableVideoForTrack(): item participant ID=%s; enable=%s", mItem.participantId, enable? "true":"false"); if (!mIsRenderersInitialized) return; if (mItem == null) return; if (StringUtils.isNotEmpty(mItem.participantId)) { @@ -259,4 +283,13 @@ public class ConferenceVideoItemVh extends BaseVH { refreshFeedVideo(); } } + + private void removeVideoRenderer() { + if (StringUtils.isNotEmpty(mTrackId) || mItem.isMe) { + Timber.d("setVideoRendererForTrack::removeVideoRenderer(): item participant ID=%s; isMe=%s", mItem.participantId, mItem.isMe? "true":"false"); + ConferenceVideoModule.getInstance().setVideoRendererForTrack(null, mTrackId, mItem.isMe); + mItem.isTrackActive = 0; + refreshFeedVideo(); + } + } } diff --git a/app/src/main/java/com/nynja/mobile/communicator/ui/base/BaseAdapter.java b/app/src/main/java/com/nynja/mobile/communicator/ui/base/BaseAdapter.java index fe33b3d069c80db66bad8104fff0acc37d53fa23..c88465c9a120bcaae4c80c4f4a0922340006509f 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/ui/base/BaseAdapter.java +++ b/app/src/main/java/com/nynja/mobile/communicator/ui/base/BaseAdapter.java @@ -44,6 +44,14 @@ public abstract class BaseAdapter> extends RecyclerVie } } + public int getItemsPageCount() { + return getItemCount(); + } + + public int getMaxItemsPerPage() { + return 1; + } + public List getItems() { return mList; } diff --git a/app/src/main/java/com/nynja/mobile/communicator/ui/fragments/conference/ConferenceCallFragment.java b/app/src/main/java/com/nynja/mobile/communicator/ui/fragments/conference/ConferenceCallFragment.java index 216afa43a91da889b1d112be0d54988db98a1c58..3441886a6b38f1b7c9bd73ad3fdc2ecbc3d541ad 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/ui/fragments/conference/ConferenceCallFragment.java +++ b/app/src/main/java/com/nynja/mobile/communicator/ui/fragments/conference/ConferenceCallFragment.java @@ -373,7 +373,7 @@ public class ConferenceCallFragment extends BaseFragment implements CallView, .subscribe(permission -> { if (permission.granted) { videoOnOf.setChecked(true); - mConferencePresenter.startCameraCapture(); + mConferencePresenter.tryStartCameraCapture(); } else if (!permission.shouldShowRequestPermissionRationale) { PermissionHelper.getInstance().showPermissionDialog(getActivity(), mConferencePresenter.getPermissionDialogListener(), Manifest.permission.CAMERA); @@ -1602,17 +1602,48 @@ public class ConferenceCallFragment extends BaseFragment implements CallView, @Override public void showFirstStopScreenSharingWarning(ActiveConferenceCall call){ - if (call == null) return; - String message = getString(R.string.call_ask_to_stop_ss_first, call.getConferenceSSOwner()); - if (call.isConference() && call.mData.hasRemoteVideoTrack) { - message = getString(R.string.call_ask_to_stop_camera_first, call.getConferenceSSOwner()); + if (getActivity() == null || !isAdded() || audioSpeaker == null) { + return; } - final String msg = message; + if (call == null) return; + final String msg = getString(R.string.call_ask_to_stop_ss_first, call.getConferenceSSOwner()); getActivity().runOnUiThread(() -> DialogFactory.showAlert(getActivity(), msg, getString(R.string.call_conference_alert_title), null)); } + + @Override + public void showStopOwnCameraFirstgAlert() { + if (getActivity() == null || !isAdded() || audioSpeaker == null) { + return; + } + DialogFactory.showAlert(getActivity(), getString(R.string.call_conference_alert_title), + getString(R.string.call_start_conference_ss_alert), + getString(R.string.call_continue_button), getString(R.string.cancel), + (dialog, which) -> mConferencePresenter.stopCameraAndContinueWithScreenshare(), + null); + } + + @Override + public void showStopScreenShareFirstAlert() { + if (getActivity() == null || !isAdded() || audioSpeaker == null) { + return; + } + videoOnOf.setChecked(false); + DialogFactory.showAlert(getActivity(), + getString(R.string.call_start_conference_camera_alert), + getString(R.string.call_conference_alert_title), null); + } + + @Override + public void continueWithScreenshare() { + new Handler(Looper.getMainLooper()).postDelayed(() -> { + videoOnOf.setChecked(false); + mConferencePresenter.continueWithScreenshare(); + }, Consts.DELAY_300); + } + @Override public void onBluetoothDeviceDisconnected() { //mConferencePresenter.bluetoothDisconnected(); diff --git a/app/src/main/java/com/nynja/mobile/communicator/ui/fragments/conference/ConferenceVideoFragment.java b/app/src/main/java/com/nynja/mobile/communicator/ui/fragments/conference/ConferenceVideoFragment.java index eaad10fb5cf52701faa81bdb171b3b389f0a756d..af28f6a56fc9f9f077a8fd803c0d2e2d2ccf51d0 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/ui/fragments/conference/ConferenceVideoFragment.java +++ b/app/src/main/java/com/nynja/mobile/communicator/ui/fragments/conference/ConferenceVideoFragment.java @@ -4,6 +4,7 @@ import android.os.Bundle; import android.os.Handler; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.v4.content.ContextCompat; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.DividerItemDecoration; import android.support.v7.widget.GridLayoutManager; @@ -30,6 +31,7 @@ import com.nynja.mobile.communicator.ui.activities.calls.CallActivity; import com.nynja.mobile.communicator.ui.adapters.conference.ConferenceVideoAdapter; import com.nynja.mobile.communicator.ui.adapters.viewholders.conference.ConferenceVideoItemVh; import com.nynja.mobile.communicator.ui.base.BaseFragment; +import com.nynja.mobile.communicator.ui.views.CirclePagerIndicatorDecoration; import com.nynja.mobile.communicator.utils.ActionSheetDialog; import com.nynja.mobile.communicator.utils.DialogFactory; import com.nynja.mobile.communicator.utils.StringUtils; @@ -38,6 +40,7 @@ import org.webrtc.ContextUtils; import org.webrtc.EglBase; import java.util.ArrayList; +import java.util.List; import butterknife.BindView; import timber.log.Timber; @@ -166,23 +169,17 @@ public class ConferenceVideoFragment extends BaseFragment implements ConferenceV MAX_VIDEO_FEEDS_COLUIMN_SIZE, LinearLayoutManager.HORIZONTAL, false); -// mGridLayoutManager.setSpanCount(2); -// mGridLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); -// mGridLayoutManager.setReverseLayout(false); -// mGridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { -// @Override -// public int getSpanSize(int position) { -// return (int)ConferenceVideoModule.getInstance().getSpanSize(position); -// } -// }); mGridLayoutManager.setItemPrefetchEnabled(true); mRecyclerView.setLayoutManager(mGridLayoutManager); mRecyclerView.setHasFixedSize(true); mRecyclerView.setAdapter(mConfParticipantsAdapter); - SnapHelper snapHelper = new LinearSnapHelper(); - snapHelper.attachToRecyclerView(mRecyclerView); + mRecyclerView.addItemDecoration(new CirclePagerIndicatorDecoration(12, 24, 64, + ContextCompat.getColor(getActivity(), R.color.icon_spreadsheet_files), + ContextCompat.getColor(getActivity(), R.color.active_call_bg))); mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.HORIZONTAL)); mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL)); + SnapHelper snapHelper = new LinearSnapHelper(); + snapHelper.attachToRecyclerView(mRecyclerView); // mRecyclerView.addOnChildAttachStateChangeListener(new RecyclerView.OnChildAttachStateChangeListener() { // @Override // public void onChildViewAttachedToWindow(View view) { @@ -259,10 +256,10 @@ public class ConferenceVideoFragment extends BaseFragment implements ConferenceV } @Override - public void onRemoteVideoTrackRemoved(ActiveConferenceCall activeConferenceCall, String trackId) { + public void onRemoteVideoTrackRemoved(ActiveConferenceCall activeConferenceCall, String trackId, String participantId) { if (getActivity() == null || !isAdded()) return; getActivity().runOnUiThread(() -> { - removeRemoteVideoRenderer(activeConferenceCall, trackId); + removeRemoteVideoRenderer(activeConferenceCall, trackId, participantId); setConferenceState(activeConferenceCall); }); } @@ -280,7 +277,7 @@ public class ConferenceVideoFragment extends BaseFragment implements ConferenceV public void onLocalVideoCapturerStopped(ActiveConferenceCall activeConferenceCall) { if (getActivity() == null || !isAdded()) return; mHandler.post(() -> { - removeLocalVideoRenderer(activeConferenceCall); + removeLocalVideoRenderer(activeConferenceCall, false); setConferenceState(activeConferenceCall); }); } @@ -300,7 +297,6 @@ public class ConferenceVideoFragment extends BaseFragment implements ConferenceV @Override public void onSpeakerStateChanged(boolean isSpeakerOn) { if (getActivity() == null || !isAdded()) return; -// getActivity().runOnUiThread(() -> updateSpeakerState(isSpeakerOn)); } @Override @@ -347,6 +343,7 @@ public class ConferenceVideoFragment extends BaseFragment implements ConferenceV } public void setActiveState(boolean active) { + Timber.d("ConferenceVideoFragment::setActiveState(): active=%s", active? "true" : "false"); ActiveConferenceCall activeConferenceCall = mConferencePresenter.getActiveConference(); isActive = active; if (activeConferenceCall == null) return; @@ -365,10 +362,9 @@ public class ConferenceVideoFragment extends BaseFragment implements ConferenceV if (activeConferenceCall.isVideoEnabled) { if (activeConferenceCall.mData.isOwnStreamActive) { mConferencePresenter.pauseCallVideoCapturer(); - removeLocalVideoRenderer(mConferencePresenter.getActiveConference()); + removeLocalVideoRenderer(mConferencePresenter.getActiveConference(), true); } removeRemoteVideoRenderers(mConferencePresenter.getActiveConference()); - setConferenceState(activeConferenceCall); } } } @@ -493,7 +489,9 @@ public class ConferenceVideoFragment extends BaseFragment implements ConferenceV } private void loadConferenceMembers(ArrayList members) { + Timber.d("ConferenceVideoFragment::loadConferenceMembers()"); mConfParticipantsAdapter.setItems(members); + mConfParticipantsAdapter.notifyDataSetChanged(); } private void setRemoteVideoRenderer(ActiveConferenceCall activeConferenceCall) { @@ -503,10 +501,11 @@ public class ConferenceVideoFragment extends BaseFragment implements ConferenceV if (!activeConferenceCall.mConference.isConference()) return; if (!activeConferenceCall.isVideoEnabled) return; + Timber.d("ConferenceVideoFragment::setRemoteVideoRenderer()"); mConferencePresenter.loadConferenceParticipants(activeConferenceCall); } - private void removeRemoteVideoRenderer(ActiveConferenceCall activeConferenceCall, String trackId) { + private void removeRemoteVideoRenderer(ActiveConferenceCall activeConferenceCall, String trackId, String participantId) { if (activeConferenceCall == null) return; if (activeConferenceCall.mConference == null) return; if (!activeConferenceCall.mConference.isConference()) return; @@ -514,20 +513,23 @@ public class ConferenceVideoFragment extends BaseFragment implements ConferenceV if (!activeConferenceCall.isVideoEnabled) return; if (StringUtils.isNotEmpty(trackId)) { - ConferenceVideoModule.getInstance().setVideoRendererForTrack(null, trackId, false); + Timber.d("ConferenceVideoFragment::removeRemoteVideoRenderer()"); + if (StringUtils.isNotEmpty(participantId)) { + mConfParticipantsAdapter.releaseVideoCallRrenderer(participantId, false, true); + } } - mConfParticipantsAdapter.notifyDataSetChanged(); } private void removeRemoteVideoRenderers(ActiveConferenceCall activeConferenceCall) { if (activeConferenceCall == null) return; - ArrayList members = mConferencePresenter.getConferenceVideoMembers(activeConferenceCall); - for (ConferenceListItem item : members) { + Timber.d("ConferenceVideoFragment::removeRemoteVideoRenderers()"); + List list = mConfParticipantsAdapter.getItems(); + Timber.d("ConferenceVideoFragment::removeRemoteVideoRenderers(): list size=%d", list.size()); + for (ConferenceListItem item : list) { //members) { String trackId = ConferenceVideoModule.getInstance().getTrackIdByParticipantId(item.participantId); - if (StringUtils.isNotEmpty(trackId) || item.isMe) { - ConferenceVideoModule.getInstance().setVideoRendererForTrack(null, trackId, item.isMe); - } + Timber.d("ConferenceVideoFragment::removeRemoteVideoRenderers(): participantID=%s", item.participantId); + mConfParticipantsAdapter.releaseVideoCallRrenderer(item.participantId, true, true); } } @@ -535,17 +537,25 @@ public class ConferenceVideoFragment extends BaseFragment implements ConferenceV if (activeConferenceCall == null) return; if (activeConferenceCall.mConference == null) return; if (!activeConferenceCall.isVideoEnabled) return; + Timber.d("ConferenceVideoFragment::setLocalVideoRenderer()"); mConferencePresenter.loadConferenceParticipants(activeConferenceCall); } - private void removeLocalVideoRenderer(ActiveConferenceCall activeConferenceCall) { + private void removeLocalVideoRenderer(ActiveConferenceCall activeConferenceCall, boolean pause) { if (activeConferenceCall == null) return; if (activeConferenceCall.mConference == null) return; if (!activeConferenceCall.mConference.isRunning()) return; if (!activeConferenceCall.isVideoEnabled) return; - - mConferencePresenter.loadConferenceParticipants(activeConferenceCall); + Timber.d("ConferenceVideoFragment::removeLocalVideoRenderer()"); + List list = mConfParticipantsAdapter.getItems(); + for (ConferenceListItem item : list) { + if (item.participantId.contentEquals(activeConferenceCall.mConference.participantId()) && + item.isMe) { + Timber.d("ConferenceVideoFragment::removeLocalVideoRenderer(): participantID=%s", item.participantId); + mConfParticipantsAdapter.releaseVideoCallRrenderer(item.participantId, pause,true); + } + } } private void setConferenceState(ActiveConferenceCall activeConferenceCall) { diff --git a/app/src/main/java/com/nynja/mobile/communicator/ui/views/CirclePagerIndicatorDecoration.java b/app/src/main/java/com/nynja/mobile/communicator/ui/views/CirclePagerIndicatorDecoration.java index 898677c168a01a441789bfca58e738252a37ee38..0caaba0297ce22891a20170efef15edab6f445fc 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/ui/views/CirclePagerIndicatorDecoration.java +++ b/app/src/main/java/com/nynja/mobile/communicator/ui/views/CirclePagerIndicatorDecoration.java @@ -2,14 +2,19 @@ package com.nynja.mobile.communicator.ui.views; import android.content.res.Resources; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; +import android.graphics.drawable.Drawable; import android.support.annotation.ColorInt; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; +import com.nynja.mobile.communicator.R; +import com.nynja.mobile.communicator.ui.base.BaseAdapter; + import org.jetbrains.annotations.NotNull; /** @@ -48,29 +53,35 @@ public class CirclePagerIndicatorDecoration extends RecyclerView.ItemDecoration public void onDrawOver(@NotNull Canvas c, @NotNull RecyclerView parent, @NotNull RecyclerView.State state) { super.onDrawOver(c, parent, state); - final RecyclerView.Adapter adapter = parent.getAdapter(); + final BaseAdapter adapter = (BaseAdapter) parent.getAdapter(); if (adapter == null) { return; } - int itemCount = adapter.getItemCount(); + int pageCount = adapter.getItemsPageCount(); + if (pageCount <= 1) { + return; + } + + int maxItemsPerPage = adapter.getMaxItemsPerPage(); // center horizontally, calculate width and subtract half from center - float totalLength = this.radius * 2 * itemCount; - float paddingBetweenItems = Math.max(0, itemCount - 1) * indicatorItemPadding; + float totalLength = this.radius * 2 * pageCount; + float paddingBetweenItems = Math.max(0, pageCount - 1) * indicatorItemPadding; float indicatorTotalWidth = totalLength + paddingBetweenItems; float indicatorStartX = (parent.getWidth() - indicatorTotalWidth) / 2f; // center vertically in the allotted space float indicatorPosY = parent.getHeight() - indicatorHeight / 2f; - drawInactiveDots(c, indicatorStartX, indicatorPosY, itemCount); + drawInactiveDots(c, indicatorStartX, indicatorPosY, pageCount); - final int activePosition; + int activePosition; if (parent.getLayoutManager() instanceof GridLayoutManager) { - activePosition = ((GridLayoutManager) parent.getLayoutManager()).findFirstVisibleItemPosition(); + activePosition = ((GridLayoutManager) parent.getLayoutManager()).findFirstCompletelyVisibleItemPosition(); +// activePosition = ((GridLayoutManager) parent.getLayoutManager()).findFirstVisibleItemPosition(); } else if (parent.getLayoutManager() instanceof LinearLayoutManager) { activePosition = ((LinearLayoutManager) parent.getLayoutManager()).findFirstVisibleItemPosition(); } else { @@ -87,6 +98,7 @@ public class CirclePagerIndicatorDecoration extends RecyclerView.ItemDecoration if (activeChild == null) { return; } + activePosition = activePosition/maxItemsPerPage; drawActiveDot(c, indicatorStartX, indicatorPosY, activePosition); } @@ -107,7 +119,7 @@ public class CirclePagerIndicatorDecoration extends RecyclerView.ItemDecoration // width of item indicator including padding final float itemWidth = this.radius * 2 + indicatorItemPadding; float highlightStart = indicatorStartX + radius + itemWidth * highlightPosition; - c.drawCircle(highlightStart, indicatorPosY, radius, activePaint); + c.drawCircle(highlightStart, indicatorPosY, radius+2, activePaint); } @Override diff --git a/app/src/main/java/com/nynja/mobile/communicator/utils/NotificationHelper.java b/app/src/main/java/com/nynja/mobile/communicator/utils/NotificationHelper.java index 47aa822853a8c9243630de4228ee72e669cbd485..2d7f33a946f28d6295bf8c09cb5fafcd9ba9e959 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/utils/NotificationHelper.java +++ b/app/src/main/java/com/nynja/mobile/communicator/utils/NotificationHelper.java @@ -18,6 +18,7 @@ import android.support.annotation.ColorInt; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.NotificationCompat; +import android.support.v4.app.NotificationManagerCompat; import com.nynja.mobile.communicator.R; import com.nynja.mobile.communicator.data.DescManager; @@ -195,37 +196,35 @@ public class NotificationHelper extends ContextWrapper { return mManager; } - public Notification createCallPushNotification(String from, + public Notification createCallPushNotification(Context context, + String from, Intent intent, PendingIntent answerPendingIntent, PendingIntent rejectPendingIntent, boolean isMainActivityIsActive, SettingNotifications settingNotifications) { Uri notificationSoundUri = getNotificationSoundUri(settingNotifications.getDefaultNotificationSound()); - Timber.i("Push.CALLING: handleConferencePushNotification(): handleCallPush XXX1"); - - Timber.i("Push.CALLING: handleConferencePushNotification(): handleCallPush XXX2"); + Timber.i("Push.CALLING: createCallPushNotification(): check XXX1"); + Notification notification = buildCallNotification(intent, answerPendingIntent, rejectPendingIntent, + settingNotifications, from, isMainActivityIsActive, notificationSoundUri); if (isMainActivityIsActive) { - Notification notification = buildCallNotification(intent, answerPendingIntent, rejectPendingIntent, - settingNotifications, from, isMainActivityIsActive, notificationSoundUri); - Timber.i("Push.CALLING: handleConferencePushNotification(): handleCallPush XXX3"); + Timber.i("Push.CALLING: createCallPushNotification(): check XXX2"); // clearCallPush(ActiveConferenceCall.ANDROID_10_PUSH_CALL_NTFN_ID); -// Timber.i("Push.CALLING: handleConferencePushNotification(): handleCallPush XXX4"); - sendRingingNotify(notification, ActiveConferenceCall.ANDROID_10_PUSH_CALL_NTFN_ID, +// Timber.i("Push.CALLING: createCallPushNotification(): check XXX3"); + sendRingingNotify(context, notification, ActiveConferenceCall.ANDROID_10_PUSH_CALL_NTFN_ID, settingNotifications); - Timber.i("Push.CALLING: handleConferencePushNotification(): handleCallPush XXX5"); + Timber.i("Push.CALLING: createCallPushNotification(): check XXX4"); return null; } - return buildCallNotification(intent, answerPendingIntent, rejectPendingIntent, - settingNotifications, from, isMainActivityIsActive, notificationSoundUri); + return notification; } public synchronized Notification createCallPushNotification(Context context, String from, String callId, boolean isMainActivityIsActive, - SettingNotifications settingNotifications) { - Timber.i("Push.CALLING: sendCallPush() isMainActivityIsActive=" + (isMainActivityIsActive?"true": "false")); - Timber.i("Push.CALLING: handleConferencePushNotification(): handleCallPush XXX"); + SettingNotifications settingNotifications, + boolean isPush) { + Timber.i((isPush?"Push.CALLING": "Grpc.CALLING")+"Push.CALLING: createCallPushNotification() isMainActivityIsActive=" + (isMainActivityIsActive?"true": "false")); Intent fullScreenIntent = MainActivity.getLaunchIntent(context, false, true); fullScreenIntent.putExtra(MainActivity.INTENT_FROM_CALL_NOTIFICATION, true); fullScreenIntent.putExtra(MainActivity.INTENT_NOTIFICATION_CALL_ID, callId); @@ -248,7 +247,8 @@ public class NotificationHelper extends ContextWrapper { context, 1, rejectIntent, PendingIntent.FLAG_UPDATE_CURRENT); - return createCallPushNotification(from, + return createCallPushNotification(context, + from, fullScreenIntent, answerPendingIntent, rejectPendingIntent, @@ -415,7 +415,7 @@ public class NotificationHelper extends ContextWrapper { int iconRes = (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) ? R.mipmap.ic_launcher : R.drawable.ic_notification; PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(this, 0, - fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_CANCEL_CURRENT); + fullScreenIntent, 0);// | PendingIntent.FLAG_CANCEL_CURRENT); String contentText = getString(R.string.call_notification_incoming_from, from); Bundle args = new Bundle(); args.putInt(MainActivity.INTENT_CALL_NOTIFICATION_ID, ActiveConferenceCall.ANDROID_10_PUSH_CALL_NTFN_ID); @@ -447,13 +447,15 @@ public class NotificationHelper extends ContextWrapper { notificationBuilder.setFullScreenIntent(fullScreenPendingIntent, true); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { notificationBuilder.setFullScreenIntent(fullScreenPendingIntent, true); + notificationBuilder.setPriority(NotificationManager.IMPORTANCE_MAX); + //notificationBuilder.setPriority(NotificationManager.IMPORTANCE_HIGH); } else { notificationBuilder.setContentIntent(fullScreenPendingIntent); } Notification notification = notificationBuilder.build(); - if (!(isMainActivityIsActive && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)) { + if (!(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)) { if (settingNotifications.isSound() && mNynjaSoundManager.canPlayRingingSound()) { notification.sound = notificationSoundUri; notification.flags |= (Notification.FLAG_SHOW_LIGHTS | Notification.FLAG_INSISTENT | Notification.FLAG_NO_CLEAR); @@ -497,22 +499,39 @@ public class NotificationHelper extends ContextWrapper { } } - public void sendRingingNotify(Notification notification, + public void sendRingingNotify(Context context, + Notification notification, int id, SettingNotifications settingNotifications) { - NotificationManager notificationManager = getManager(); - if (notificationManager != null) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + boolean playSound = false; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + Timber.i("Push.CALLING: sendRingingNotify(): check 1"); + NotificationManager notificationManager = getManager(); + if (notificationManager != null) { + boolean isSoundEnabled = settingNotifications.isIncomingSoundInMutedChat(); + mNynjaSoundManager.updateShouldPlayRingingSound(isSoundEnabled, + settingNotifications.isInAppVibrate(), false); + Timber.i("Push.CALLING: sendRingingNotify(): mNynjaSoundManager.canPlayRingingSound="+(mNynjaSoundManager.canPlayRingingSound()? "true":"false")); + playSound = (areNotificationsEnabled(context, notificationManager, handleChannelIdToLatestOne(Push.CONFERENCE)) + // && settingNotifications.isSound() + && mNynjaSoundManager.canPlayRingingSound() + ); notificationManager.notify(getString(R.string.app_name), id, notification); - } else { - notificationManager.notify(id, notification); } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - Timber.i("Push.CALLING: handleConferencePushNotification(): handleCallPush XXX7"); - mNynjaSoundManager.playCallRinging(settingNotifications.getRingerSound(), false); - Timber.i("Push.CALLING: handleConferencePushNotification(): handleCallPush XXX8"); + } else { + Timber.i("Push.CALLING: sendRingingNotify(): check 2"); + NotificationManager notificationManager = getManager(); + if (notificationManager != null) { + playSound = (areNotificationsEnabled(context, notificationManager, handleChannelIdToLatestOne(Push.CONFERENCE))); + notificationManager.notify(id, notification); } } + Timber.i("Push.CALLING: sendRingingNotify(): playSound="+(playSound? "true":"false")); + if (playSound) { + Timber.i("Push.CALLING: sendRingingNotify(): check XXXX1"); + mNynjaSoundManager.playCallRinging(settingNotifications.getRingerSound(), false); + Timber.i("Push.CALLING: sendRingingNotify(): check XXXX2"); + } } public void clearPushMessageForChat(int notificationId) { @@ -603,4 +622,50 @@ public class NotificationHelper extends ContextWrapper { return Uri.parse(path); } + + private Uri getCallNotificationSoundUri(Context context, String soundName) { + soundName = soundName == null ? "" : soundName; + if (Consts.NOTIFICATION_SOUND_NO_SOUND.equalsIgnoreCase(soundName)) { + return null; + } + + String basePath = context.getResources().getAssets().toString() + "/"; + if (soundName.isEmpty()) { + soundName = Consts.NotificationSounds.NYNJA.getDisplayName(); + } + String path = basePath + soundName; + if (path == null) { + path = basePath + R.raw.nynja; + } + + return Uri.parse(path); + } + + public boolean areNotificationsEnabled(Context context, NotificationManager manager, String channelId) { + Timber.i("Push.CALLING: areNotificationsEnabled(): check 1"); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + if (!manager.areNotificationsEnabled()) { + Timber.i("Push.CALLING: areNotificationsEnabled(): check 2"); + return false; + } + if(StringUtils.isNotEmpty(channelId)) { + Timber.i("Push.CALLING: areNotificationsEnabled(): check 3"); + NotificationChannel channel = manager.getNotificationChannel(channelId); + if (channel != null) { + Timber.i("Push.CALLING: areNotificationsEnabled(): check 4"); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + Timber.i("Push.CALLING: areNotificationsEnabled(): check 5"); + return channel.getImportance() == NotificationManager.IMPORTANCE_HIGH; + } else { + Timber.i("Push.CALLING: areNotificationsEnabled(): check 6"); + return channel.getImportance() != NotificationManager.IMPORTANCE_NONE; + } + } + } + return false; + } else { + Timber.i("Push.CALLING: areNotificationsEnabled(): check 7"); + return NotificationManagerCompat.from(context).areNotificationsEnabled(); + } + } } diff --git a/app/src/main/res/layout/li_conference_video.xml b/app/src/main/res/layout/li_conference_video.xml index dfc71020c7ab73ee665675b31ec300a784088dd1..e3efcbbe913caafcc3016c04c11d7300a01e2fbf 100644 --- a/app/src/main/res/layout/li_conference_video.xml +++ b/app/src/main/res/layout/li_conference_video.xml @@ -6,7 +6,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" - android:padding="@dimen/padding_small"> + android:padding="@dimen/margin_tiniest"> + android:padding="2dp"> - - - - - - - + + + diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index 7c4abf80194ca6538139e2bf5e7c2c5c067a9a00..4b8c7a2ef62afcd0871ab972d4c5234d6ba40b44 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -1337,4 +1337,8 @@ Cannot start screen share because it has been already started by another participant Start camera is not available for groups + To share your screen, you need to stop your camera first. Tap \"Continue\" below and we will stop your camera for you and start screen sharing. + To start your camera, you need to stop screen sharing first. + Continue + diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index bf1a90442a94532e32da8e8818de54b21a222cc4..a93d6de9c0065509c19642db2785d60894cecef2 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -1336,4 +1336,8 @@ Cannot start screen share because it has been already started by another participant Start camera is not available for groups + To share your screen, you need to stop your camera first. Tap \"Continue\" below and we will stop your camera for you and start screen sharing. + To start your camera, you need to stop screen sharing first. + Continue + diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index c13526f956d6aaf5007e71a5a85c4057d135df5e..3fb29a0c692d48716fa723198251cb3c45944326 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -1336,4 +1336,8 @@ Cannot start screen share because it has been already started by another participant Start camera is not available for groups + To share your screen, you need to stop your camera first. Tap \"Continue\" below and we will stop your camera for you and start screen sharing. + To start your camera, you need to stop screen sharing first. + Continue + diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 355a75c596315f1d028833774587c7d919f9ae17..4716478128cd8713aa676fa53c4df514a509cfac 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -1336,4 +1336,8 @@ Cannot start screen share because it has been already started by another participant Start camera is not available for groups + To share your screen, you need to stop your camera first. Tap \"Continue\" below and we will stop your camera for you and start screen sharing. + To start your camera, you need to stop screen sharing first. + Continue + diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 355a75c596315f1d028833774587c7d919f9ae17..4716478128cd8713aa676fa53c4df514a509cfac 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -1336,4 +1336,8 @@ Cannot start screen share because it has been already started by another participant Start camera is not available for groups + To share your screen, you need to stop your camera first. Tap \"Continue\" below and we will stop your camera for you and start screen sharing. + To start your camera, you need to stop screen sharing first. + Continue + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 398d5866d8d849f76f925c7fa576a6b013f35ed5..d18544ed30fecdf3ed420eb97e5ff3aae882f39b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1338,4 +1338,8 @@ Cannot start screen share because it has been already started by another participant Start camera is not available for groups + To share your screen, you need to stop your camera first. Tap \"Continue\" below and we will stop your camera for you and start screen sharing. + To start your camera, you need to stop screen sharing first. + Continue +