diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 69a9acbdadcfb0868dd0688b1e3df9d7ad5f5bb1..5e99f4fae60c032919d3515bd7274da9de5390bb 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,7 +20,7 @@ - + diff --git a/app/src/main/java/com/nynja/mobile/communicator/data/AudioModule.java b/app/src/main/java/com/nynja/mobile/communicator/data/AudioModule.java index 2555878866817b756f880f8a621e0dfe4bb7a310..9c8463e2839dd430764c52629084f0b98dcbc391 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/data/AudioModule.java +++ b/app/src/main/java/com/nynja/mobile/communicator/data/AudioModule.java @@ -193,14 +193,12 @@ public class AudioModule { (frameGains[0] / 2.0) + (frameGains[1] / 2.0)); for (int i = 1; i < numFrames - 1; i++) { - smoothedGains[i] = (double) ( - (frameGains[i - 1] / 3.0) + - (frameGains[i] / 3.0) + - (frameGains[i + 1] / 3.0)); + smoothedGains[i] = (frameGains[i - 1] / 3.0) + + (frameGains[i] / 3.0) + + (frameGains[i + 1] / 3.0); } - smoothedGains[numFrames - 1] = (double) ( - (frameGains[numFrames - 2] / 2.0) + - (frameGains[numFrames - 1] / 2.0)); + smoothedGains[numFrames - 1] = (frameGains[numFrames - 2] / 2.0) + + (frameGains[numFrames - 1] / 2.0); } // Make sure the range is no more than 0 - 255 diff --git a/app/src/main/java/com/nynja/mobile/communicator/data/DataManager.java b/app/src/main/java/com/nynja/mobile/communicator/data/DataManager.java index 3e9072e311452080928740adaa1e7f5d80e7ac61..bd87b0d7e0632c22f203a60c263422cce69cc97a 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/data/DataManager.java +++ b/app/src/main/java/com/nynja/mobile/communicator/data/DataManager.java @@ -44,7 +44,6 @@ import com.nynja.mobile.communicator.data.voximplant.VoxImplantModule; import com.nynja.mobile.communicator.injection.ApplicationContext; import com.nynja.mobile.communicator.utils.ContactsUtil; import com.nynja.mobile.communicator.utils.ImageUtils; -import com.voximplant.sdk.call.ICall; import java.io.File; import java.util.ArrayList; @@ -431,13 +430,6 @@ public class DataManager { mVoxClientManager.videoCall(userId); } - public ICall getCall() { - return mVoxClientManager.getActiveCall(); - } - - public void callEnd() { - mVoxClientManager.endCall(); - } //VoxImplant end public List getChats() { @@ -552,7 +544,7 @@ public class DataManager { } public double[] getAudioData2(String filePath) { - return mAudioModule.getData(filePath); + return AudioModule.getData(filePath); } public void playRecord(@NonNull String filePath, @Nullable AudioModule.OnPositionChangedListener listener) { @@ -562,4 +554,8 @@ public class DataManager { public void stopPlayRecord() { mAudioModule.stopPlay(); } + + public VoxImplantModule getVoxImlant() { + return mVoxClientManager; + } } diff --git a/app/src/main/java/com/nynja/mobile/communicator/data/audio/MP4Header.java b/app/src/main/java/com/nynja/mobile/communicator/data/audio/MP4Header.java index adf3f4a2bdd577e3b765b02743b02a262262aef4..fa0379cc0a67770a92127e5c4d32c582cdadc06c 100755 --- a/app/src/main/java/com/nynja/mobile/communicator/data/audio/MP4Header.java +++ b/app/src/main/java/com/nynja/mobile/communicator/data/audio/MP4Header.java @@ -67,10 +67,10 @@ class Atom { // note: latest versions of spec simply call it 'box' instead of ' private int getTypeInt(String type_str) { int type = 0; - type |= (byte)(type_str.charAt(0)) << 24; - type |= (byte)(type_str.charAt(1)) << 16; - type |= (byte)(type_str.charAt(2)) << 8; - type |= (byte)(type_str.charAt(3)); + type |= (byte) (type_str.charAt(0)) << 24; + type |= (byte) (type_str.charAt(1)) << 16; + type |= (byte) (type_str.charAt(2)) << 8; + type |= (byte) (type_str.charAt(3)); return type; } @@ -80,10 +80,10 @@ class Atom { // note: latest versions of spec simply call it 'box' instead of ' public String getTypeStr() { String type = ""; - type += (char)((byte)((mType >> 24) & 0xFF)); - type += (char)((byte)((mType >> 16) & 0xFF)); - type += (char)((byte)((mType >> 8) & 0xFF)); - type += (char)((byte)(mType & 0xFF)); + type += (char) ((byte) ((mType >> 24) & 0xFF)); + type += (char) ((byte) ((mType >> 16) & 0xFF)); + type += (char) ((byte) ((mType >> 8) & 0xFF)); + type += (char) ((byte) (mType & 0xFF)); return type; } @@ -145,19 +145,19 @@ class Atom { // note: latest versions of spec simply call it 'box' instead of ' byte[] atom_bytes = new byte[mSize]; int offset = 0; - atom_bytes[offset++] = (byte)((mSize >> 24) & 0xFF); - atom_bytes[offset++] = (byte)((mSize >> 16) & 0xFF); - atom_bytes[offset++] = (byte)((mSize >> 8) & 0xFF); - atom_bytes[offset++] = (byte)(mSize & 0xFF); - atom_bytes[offset++] = (byte)((mType >> 24) & 0xFF); - atom_bytes[offset++] = (byte)((mType >> 16) & 0xFF); - atom_bytes[offset++] = (byte)((mType >> 8) & 0xFF); - atom_bytes[offset++] = (byte)(mType & 0xFF); + atom_bytes[offset++] = (byte) ((mSize >> 24) & 0xFF); + atom_bytes[offset++] = (byte) ((mSize >> 16) & 0xFF); + atom_bytes[offset++] = (byte) ((mSize >> 8) & 0xFF); + atom_bytes[offset++] = (byte) (mSize & 0xFF); + atom_bytes[offset++] = (byte) ((mType >> 24) & 0xFF); + atom_bytes[offset++] = (byte) ((mType >> 16) & 0xFF); + atom_bytes[offset++] = (byte) ((mType >> 8) & 0xFF); + atom_bytes[offset++] = (byte) (mType & 0xFF); if (mVersion >= 0) { atom_bytes[offset++] = mVersion; - atom_bytes[offset++] = (byte)((mFlags >> 16) & 0xFF); - atom_bytes[offset++] = (byte)((mFlags >> 8) & 0xFF); - atom_bytes[offset++] = (byte)(mFlags & 0xFF); + atom_bytes[offset++] = (byte) ((mFlags >> 16) & 0xFF); + atom_bytes[offset++] = (byte) ((mFlags >> 8) & 0xFF); + atom_bytes[offset++] = (byte) (mFlags & 0xFF); } if (mData != null) { System.arraycopy(mData, 0, atom_bytes, offset, mData.length); @@ -178,7 +178,7 @@ class Atom { // note: latest versions of spec simply call it 'box' instead of ' byte[] atom_bytes = getBytes(); for (int i = 0; i < atom_bytes.length; i++) { - if(i % 8 == 0 && i > 0) { + if (i % 8 == 0 && i > 0) { str += '\n'; } str += String.format("0x%02X", atom_bytes[i]); @@ -218,7 +218,7 @@ public class MP4Header { mBitrate = bitrate; mMaxFrameSize = mFrameSize[0]; mTotSize = mFrameSize[0]; - for (int i=1; i> 24) & 0xFF); - mTime[1] = (byte)((time >> 16) & 0xFF); - mTime[2] = (byte)((time >> 8) & 0xFF); - mTime[3] = (byte)(time & 0xFF); + mTime[0] = (byte) ((time >> 24) & 0xFF); + mTime[1] = (byte) ((time >> 16) & 0xFF); + mTime[2] = (byte) ((time >> 8) & 0xFF); + mTime[3] = (byte) (time & 0xFF); int numSamples = 1024 * (frame_size.length - 1); // 1st frame does not contain samples. int durationMS = (numSamples * 1000) / mSampleRate; if ((numSamples * 1000) % mSampleRate > 0) { // round the duration up. durationMS++; } - mNumSamples= new byte[] { - (byte)((numSamples >> 26) & 0XFF), - (byte)((numSamples >> 16) & 0XFF), - (byte)((numSamples >> 8) & 0XFF), - (byte)(numSamples & 0XFF) + mNumSamples = new byte[]{ + (byte) ((numSamples >> 26) & 0XFF), + (byte) ((numSamples >> 16) & 0XFF), + (byte) ((numSamples >> 8) & 0XFF), + (byte) (numSamples & 0XFF) }; - mDurationMS = new byte[] { - (byte)((durationMS >> 26) & 0XFF), - (byte)((durationMS >> 16) & 0XFF), - (byte)((durationMS >> 8) & 0XFF), - (byte)(durationMS & 0XFF) + mDurationMS = new byte[]{ + (byte) ((durationMS >> 26) & 0XFF), + (byte) ((durationMS >> 16) & 0XFF), + (byte) ((durationMS >> 8) & 0XFF), + (byte) (durationMS & 0XFF) }; setHeader(); } @@ -288,7 +288,7 @@ public class MP4Header { Atom a_ftyp = getFTYPAtom(); Atom a_moov = getMOOVAtom(); Atom a_mdat = new Atom("mdat"); // create an empty atom. The AAC stream data should follow - // immediately after. The correct size will be set later. + // immediately after. The correct size will be set later. // set the correct chunk offset in the stco atom. Atom a_stco = a_moov.getChild("trak.mdia.minf.stbl.stco"); @@ -299,15 +299,15 @@ public class MP4Header { byte[] data = a_stco.getData(); int chunk_offset = a_ftyp.getSize() + a_moov.getSize() + a_mdat.getSize(); int offset = data.length - 4; // here stco should contain only one chunk offset. - data[offset++] = (byte)((chunk_offset >> 24) & 0xFF); - data[offset++] = (byte)((chunk_offset >> 16) & 0xFF); - data[offset++] = (byte)((chunk_offset >> 8) & 0xFF); - data[offset++] = (byte)(chunk_offset & 0xFF); + data[offset++] = (byte) ((chunk_offset >> 24) & 0xFF); + data[offset++] = (byte) ((chunk_offset >> 16) & 0xFF); + data[offset++] = (byte) ((chunk_offset >> 8) & 0xFF); + data[offset++] = (byte) (chunk_offset & 0xFF); // create the header byte array based on the previous atoms. byte[] header = new byte[chunk_offset]; // here chunk_offset is also the size of the header offset = 0; - for (Atom atom : new Atom[] {a_ftyp, a_moov, a_mdat}) { + for (Atom atom : new Atom[]{a_ftyp, a_moov, a_mdat}) { byte[] atom_bytes = atom.getBytes(); System.arraycopy(atom_bytes, 0, header, offset, atom_bytes.length); offset += atom_bytes.length; @@ -316,17 +316,17 @@ public class MP4Header { //set the correct size of the mdat atom int size = 8 + mTotSize; offset -= 8; - header[offset++] = (byte)((size >> 24) & 0xFF); - header[offset++] = (byte)((size >> 16) & 0xFF); - header[offset++] = (byte)((size >> 8) & 0xFF); - header[offset++] = (byte)(size & 0xFF); + header[offset++] = (byte) ((size >> 24) & 0xFF); + header[offset++] = (byte) ((size >> 16) & 0xFF); + header[offset++] = (byte) ((size >> 8) & 0xFF); + header[offset++] = (byte) (size & 0xFF); mHeader = header; } private Atom getFTYPAtom() { Atom atom = new Atom("ftyp"); - atom.setData(new byte[] { + atom.setData(new byte[]{ 'M', '4', 'A', ' ', // Major brand 0, 0, 0, 0, // Minor version 'M', '4', 'A', ' ', // compatible brands @@ -344,11 +344,11 @@ public class MP4Header { } private Atom getMVHDAtom() { - Atom atom = new Atom("mvhd", (byte)0, 0); - atom.setData(new byte[] { + Atom atom = new Atom("mvhd", (byte) 0, 0); + atom.setData(new byte[]{ mTime[0], mTime[1], mTime[2], mTime[3], // creation time. mTime[0], mTime[1], mTime[2], mTime[3], // modification time. - 0, 0, 0x03, (byte)0xE8, // timescale = 1000 => duration expressed in ms. + 0, 0, 0x03, (byte) 0xE8, // timescale = 1000 => duration expressed in ms. mDurationMS[0], mDurationMS[1], mDurationMS[2], mDurationMS[3], // duration in ms. 0, 1, 0, 0, // rate = 1.0 1, 0, // volume = 1.0 @@ -377,8 +377,8 @@ public class MP4Header { } private Atom getTKHDAtom() { - Atom atom = new Atom("tkhd", (byte)0, 0x07); // track enabled, in movie, and in preview. - atom.setData(new byte[] { + Atom atom = new Atom("tkhd", (byte) 0, 0x07); // track enabled, in movie, and in preview. + atom.setData(new byte[]{ mTime[0], mTime[1], mTime[2], mTime[3], // creation time. mTime[0], mTime[1], mTime[2], mTime[3], // modification time. 0, 0, 0, 1, // track ID @@ -408,12 +408,12 @@ public class MP4Header { } private Atom getMDHDAtom() { - Atom atom = new Atom("mdhd", (byte)0, 0); - atom.setData(new byte[] { + Atom atom = new Atom("mdhd", (byte) 0, 0); + atom.setData(new byte[]{ mTime[0], mTime[1], mTime[2], mTime[3], // creation time. mTime[0], mTime[1], mTime[2], mTime[3], // modification time. - (byte)(mSampleRate >> 24), (byte)(mSampleRate >> 16), // timescale = Fs => - (byte)(mSampleRate >> 8), (byte)(mSampleRate), // duration expressed in samples. + (byte) (mSampleRate >> 24), (byte) (mSampleRate >> 16), // timescale = Fs => + (byte) (mSampleRate >> 8), (byte) (mSampleRate), // duration expressed in samples. mNumSamples[0], mNumSamples[1], mNumSamples[2], mNumSamples[3], // duration 0, 0, // languages 0, 0 // pre-defined @@ -422,8 +422,8 @@ public class MP4Header { } private Atom getHDLRAtom() { - Atom atom = new Atom("hdlr", (byte)0, 0); - atom.setData(new byte[] { + Atom atom = new Atom("hdlr", (byte) 0, 0); + atom.setData(new byte[]{ 0, 0, 0, 0, // pre-defined 's', 'o', 'u', 'n', // handler type 0, 0, 0, 0, // reserved @@ -445,8 +445,8 @@ public class MP4Header { } private Atom getSMHDAtom() { - Atom atom = new Atom("smhd", (byte)0, 0); - atom.setData(new byte[] { + Atom atom = new Atom("smhd", (byte) 0, 0); + atom.setData(new byte[]{ 0, 0, // balance (center) 0, 0 // reserved }); @@ -460,7 +460,7 @@ public class MP4Header { } private Atom getDREFAtom() { - Atom atom = new Atom("dref", (byte)0, 0); + Atom atom = new Atom("dref", (byte) 0, 0); byte[] url = getURLAtom().getBytes(); byte[] data = new byte[4 + url.length]; data[3] = 0x01; // entry count = 1 @@ -470,7 +470,7 @@ public class MP4Header { } private Atom getURLAtom() { - Atom atom = new Atom("url ", (byte)0, 0x01); // flags = 0x01: data is self contained. + Atom atom = new Atom("url ", (byte) 0, 0x01); // flags = 0x01: data is self contained. return atom; } @@ -485,7 +485,7 @@ public class MP4Header { } private Atom getSTSDAtom() { - Atom atom = new Atom("stsd", (byte)0, 0); + Atom atom = new Atom("stsd", (byte) 0, 0); byte[] mp4a = getMP4AAtom().getBytes(); byte[] data = new byte[4 + mp4a.length]; data[3] = 0x01; // entry count = 1 @@ -497,16 +497,16 @@ public class MP4Header { // See also Part 14 section 5.6.1 of ISO/IEC 14496 for this atom. private Atom getMP4AAtom() { Atom atom = new Atom("mp4a"); - byte[] ase = new byte[] { // Audio Sample Entry data + byte[] ase = new byte[]{ // Audio Sample Entry data 0, 0, 0, 0, 0, 0, // reserved 0, 1, // data reference index 0, 0, 0, 0, // reserved 0, 0, 0, 0, // reserved - (byte)(mChannels >> 8), (byte)mChannels, // channel count + (byte) (mChannels >> 8), (byte) mChannels, // channel count 0, 0x10, // sample size 0, 0, // pre-defined 0, 0, // reserved - (byte)(mSampleRate >> 8), (byte)(mSampleRate), 0, 0, // sample rate + (byte) (mSampleRate >> 8), (byte) (mSampleRate), 0, 0, // sample rate }; byte[] esds = getESDSAtom().getBytes(); byte[] data = new byte[ase.length + esds.length]; @@ -517,7 +517,7 @@ public class MP4Header { } private Atom getESDSAtom() { - Atom atom = new Atom("esds", (byte)0, 0); + Atom atom = new Atom("esds", (byte) 0, 0); atom.setData(getESDescriptor()); return atom; } @@ -526,16 +526,16 @@ public class MP4Header { // 1024 samples per frame per channel. The decoder buffer size is set so that it can contain at // least 2 frames. (See section 7.2.6.5 of ISO/IEC 14496-1 for more details). private byte[] getESDescriptor() { - int[] samplingFrequencies = new int[] {96000, 88200, 64000, 48000, 44100, 32000, 24000, + int[] samplingFrequencies = new int[]{96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350}; // First 5 bytes of the ES Descriptor. - byte[] ESDescriptor_top = new byte[] {0x03, 0x19, 0x00, 0x00, 0x00}; + byte[] ESDescriptor_top = new byte[]{0x03, 0x19, 0x00, 0x00, 0x00}; // First 4 bytes of Decoder Configuration Descriptor. Audio ISO/IEC 14496-3, AudioStream. - byte[] decConfigDescr_top = new byte[] {0x04, 0x11, 0x40, 0x15}; + byte[] decConfigDescr_top = new byte[]{0x04, 0x11, 0x40, 0x15}; // Audio Specific Configuration: AAC LC, 1024 samples/frame/channel. // Sampling frequency and channels configuration are not set yet. - byte[] audioSpecificConfig = new byte[] {0x05, 0x02, 0x10, 0x00}; - byte[] slConfigDescr = new byte[] {0x06, 0x01, 0x02}; // specific for MP4 file. + byte[] audioSpecificConfig = new byte[]{0x05, 0x02, 0x10, 0x00}; + byte[] slConfigDescr = new byte[]{0x06, 0x01, 0x02}; // specific for MP4 file. int offset; int bufferSize = 0x300; while (bufferSize < 2 * mMaxFrameSize) { @@ -548,19 +548,19 @@ public class MP4Header { byte[] decConfigDescr = new byte[2 + decConfigDescr_top[1]]; System.arraycopy(decConfigDescr_top, 0, decConfigDescr, 0, decConfigDescr_top.length); offset = decConfigDescr_top.length; - decConfigDescr[offset++] = (byte)((bufferSize >> 16) & 0xFF); - decConfigDescr[offset++] = (byte)((bufferSize >> 8) & 0xFF); - decConfigDescr[offset++] = (byte)(bufferSize & 0xFF); - decConfigDescr[offset++] = (byte)((mBitrate >> 24) & 0xFF); - decConfigDescr[offset++] = (byte)((mBitrate >> 16) & 0xFF); - decConfigDescr[offset++] = (byte)((mBitrate >> 8) & 0xFF); - decConfigDescr[offset++] = (byte)(mBitrate & 0xFF); - decConfigDescr[offset++] = (byte)((mBitrate >> 24) & 0xFF); - decConfigDescr[offset++] = (byte)((mBitrate >> 16) & 0xFF); - decConfigDescr[offset++] = (byte)((mBitrate >> 8) & 0xFF); - decConfigDescr[offset++] = (byte)(mBitrate & 0xFF); + decConfigDescr[offset++] = (byte) ((bufferSize >> 16) & 0xFF); + decConfigDescr[offset++] = (byte) ((bufferSize >> 8) & 0xFF); + decConfigDescr[offset++] = (byte) (bufferSize & 0xFF); + decConfigDescr[offset++] = (byte) ((mBitrate >> 24) & 0xFF); + decConfigDescr[offset++] = (byte) ((mBitrate >> 16) & 0xFF); + decConfigDescr[offset++] = (byte) ((mBitrate >> 8) & 0xFF); + decConfigDescr[offset++] = (byte) (mBitrate & 0xFF); + decConfigDescr[offset++] = (byte) ((mBitrate >> 24) & 0xFF); + decConfigDescr[offset++] = (byte) ((mBitrate >> 16) & 0xFF); + decConfigDescr[offset++] = (byte) ((mBitrate >> 8) & 0xFF); + decConfigDescr[offset++] = (byte) (mBitrate & 0xFF); int index; - for (index=0; index> 1) & 0x07); - audioSpecificConfig[3] |= (byte)(((index & 1) << 7) | ((mChannels & 0x0F) << 3)); + audioSpecificConfig[2] |= (byte) ((index >> 1) & 0x07); + audioSpecificConfig[3] |= (byte) (((index & 1) << 7) | ((mChannels & 0x0F) << 3)); System.arraycopy( audioSpecificConfig, 0, decConfigDescr, offset, audioSpecificConfig.length); @@ -586,34 +586,34 @@ public class MP4Header { } private Atom getSTTSAtom() { - Atom atom = new Atom("stts", (byte)0, 0); + Atom atom = new Atom("stts", (byte) 0, 0); int numAudioFrames = mFrameSize.length - 1; - atom.setData(new byte[] { + atom.setData(new byte[]{ 0, 0, 0, 0x02, // entry count 0, 0, 0, 0x01, // first frame contains no audio 0, 0, 0, 0, - (byte)((numAudioFrames >> 24) & 0xFF), (byte)((numAudioFrames >> 16) & 0xFF), - (byte)((numAudioFrames >> 8) & 0xFF), (byte)(numAudioFrames & 0xFF), + (byte) ((numAudioFrames >> 24) & 0xFF), (byte) ((numAudioFrames >> 16) & 0xFF), + (byte) ((numAudioFrames >> 8) & 0xFF), (byte) (numAudioFrames & 0xFF), 0, 0, 0x04, 0, // delay between frames = 1024 samples (cf. timescale = Fs) }); return atom; } private Atom getSTSCAtom() { - Atom atom = new Atom("stsc", (byte)0, 0); + Atom atom = new Atom("stsc", (byte) 0, 0); int numFrames = mFrameSize.length; - atom.setData(new byte[] { + atom.setData(new byte[]{ 0, 0, 0, 0x01, // entry count 0, 0, 0, 0x01, // first chunk - (byte)((numFrames >> 24) & 0xFF), (byte)((numFrames >> 16) & 0xFF), // samples per - (byte)((numFrames >> 8) & 0xFF), (byte)(numFrames & 0xFF), // chunk + (byte) ((numFrames >> 24) & 0xFF), (byte) ((numFrames >> 16) & 0xFF), // samples per + (byte) ((numFrames >> 8) & 0xFF), (byte) (numFrames & 0xFF), // chunk 0, 0, 0, 0x01, // sample description index }); return atom; } private Atom getSTSZAtom() { - Atom atom = new Atom("stsz", (byte)0, 0); + Atom atom = new Atom("stsz", (byte) 0, 0); int numFrames = mFrameSize.length; byte[] data = new byte[8 + 4 * numFrames]; int offset = 0; @@ -621,27 +621,27 @@ public class MP4Header { data[offset++] = 0; data[offset++] = 0; data[offset++] = 0; - data[offset++] = (byte)((numFrames >> 24) & 0xFF); // sample count - data[offset++] = (byte)((numFrames >> 16) & 0xFF); - data[offset++] = (byte)((numFrames >> 8) & 0xFF); - data[offset++] = (byte)(numFrames & 0xFF); + data[offset++] = (byte) ((numFrames >> 24) & 0xFF); // sample count + data[offset++] = (byte) ((numFrames >> 16) & 0xFF); + data[offset++] = (byte) ((numFrames >> 8) & 0xFF); + data[offset++] = (byte) (numFrames & 0xFF); for (int size : mFrameSize) { - data[offset++] = (byte)((size >> 24) & 0xFF); - data[offset++] = (byte)((size >> 16) & 0xFF); - data[offset++] = (byte)((size >> 8) & 0xFF); - data[offset++] = (byte)(size & 0xFF); + data[offset++] = (byte) ((size >> 24) & 0xFF); + data[offset++] = (byte) ((size >> 16) & 0xFF); + data[offset++] = (byte) ((size >> 8) & 0xFF); + data[offset++] = (byte) (size & 0xFF); } atom.setData(data); return atom; } private Atom getSTCOAtom() { - Atom atom = new Atom("stco", (byte)0, 0); - atom.setData(new byte[] { + Atom atom = new Atom("stco", (byte) 0, 0); + atom.setData(new byte[]{ 0, 0, 0, 0x01, // entry count 0, 0, 0, 0 // chunk offset. Set to 0 here. Must be set later. Here it should be - // the size of the complete header, as the AAC stream will follow - // immediately. + // the size of the complete header, as the AAC stream will follow + // immediately. }); return atom; } diff --git a/app/src/main/java/com/nynja/mobile/communicator/data/audio/SoundFile.java b/app/src/main/java/com/nynja/mobile/communicator/data/audio/SoundFile.java index fcb59e80afe902f11e8a8250aefb321d1c4e3696..4adf9dfb6a55edb39c1da763c9c5138298992d01 100755 --- a/app/src/main/java/com/nynja/mobile/communicator/data/audio/SoundFile.java +++ b/app/src/main/java/com/nynja/mobile/communicator/data/audio/SoundFile.java @@ -77,6 +77,7 @@ public class SoundFile { public class InvalidInputException extends Exception { // Serial version ID generated by Eclipse. private static final long serialVersionUID = -2505698991597837165L; + public InvalidInputException(String message) { super(message); } @@ -84,12 +85,12 @@ public class SoundFile { // TODO(nfaralli): what is the real list of supported extensions? Is it device dependent? public static String[] getSupportedExtensions() { - return new String[] {"mp3", "wav", "3gpp", "3gp", "amr", "aac", "m4a", "ogg"}; + return new String[]{"mp3", "wav", "3gpp", "3gp", "amr", "aac", "m4a", "ogg"}; } public static boolean isFilenameSupported(String filename) { String[] extensions = getSupportedExtensions(); - for (int i=0; i= Build.VERSION_CODES.N && - Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1) { + Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1) { // Hack for Nougat where asReadOnlyBuffer fails to respect byte ordering. // See https://code.google.com/p/android/issues/detail?id=223824 return mDecodedSamples; @@ -196,8 +197,8 @@ public class SoundFile { } private void ReadFile(File inputFile) - throws java.io.FileNotFoundException, - IOException, InvalidInputException { + throws + IOException, InvalidInputException { MediaExtractor extractor = new MediaExtractor(); MediaFormat format = null; int i; @@ -205,11 +206,11 @@ public class SoundFile { mInputFile = inputFile; String[] components = mInputFile.getPath().split("\\."); mFileType = components[components.length - 1]; - mFileSize = (int)mInputFile.length(); + mFileSize = (int) mInputFile.length(); extractor.setDataSource(mInputFile.getPath()); int numTracks = extractor.getTrackCount(); // find and select the first audio track present in the file. - for (i=0; i 0) { + while (retry > 0) { try { newDecodedBytes = ByteBuffer.allocate(newSize); break; @@ -356,7 +357,7 @@ public class SoundFile { mDecodedBytes.rewind(); mDecodedBytes.order(ByteOrder.LITTLE_ENDIAN); mDecodedSamples = mDecodedBytes.asShortBuffer(); - mAvgBitRate = (int)((mFileSize * 8) * ((float)mSampleRate / mNumSamples) / 1000); + mAvgBitRate = (int) ((mFileSize * 8) * ((float) mSampleRate / mNumSamples) / 1000); extractor.release(); extractor = null; @@ -366,7 +367,7 @@ public class SoundFile { // Temporary hack to make it work with the old version. mNumFrames = mNumSamples / getSamplesPerFrame(); - if (mNumSamples % getSamplesPerFrame() != 0){ + if (mNumSamples % getSamplesPerFrame() != 0) { mNumFrames++; } mFrameGains = new int[mNumFrames]; @@ -374,13 +375,13 @@ public class SoundFile { mFrameOffsets = new int[mNumFrames]; int j; int gain, value; - int frameLens = (int)((1000 * mAvgBitRate / 8) * - ((float)getSamplesPerFrame() / mSampleRate)); - for (i=0; i 0) { value += Math.abs(mDecodedSamples.get()); } @@ -390,17 +391,17 @@ public class SoundFile { gain = value; } } - mFrameGains[i] = (int)Math.sqrt(gain); // here gain = sqrt(max value of 1st channel)... + mFrameGains[i] = (int) Math.sqrt(gain); // here gain = sqrt(max value of 1st channel)... mFrameLens[i] = frameLens; // totally not accurate... - mFrameOffsets[i] = (int)(i * (1000 * mAvgBitRate / 8) * // = i * frameLens - ((float)getSamplesPerFrame() / mSampleRate)); + mFrameOffsets[i] = (int) (i * (1000 * mAvgBitRate / 8) * // = i * frameLens + ((float) getSamplesPerFrame() / mSampleRate)); } mDecodedSamples.rewind(); // DumpSamples(); // Uncomment this line to dump the samples in a TSV file. } private void RecordAudio() { - if (mProgressListener == null) { + if (mProgressListener == null) { // A progress listener is mandatory here, as it will let us know when to stop recording. return; } @@ -422,7 +423,7 @@ public class SoundFile { AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize - ); + ); // Allocate memory for 20 seconds first. Reallocate later if more is needed. mDecodedBytes = ByteBuffer.allocate(20 * mSampleRate * 2); @@ -455,7 +456,7 @@ public class SoundFile { // Let the progress listener know how many seconds have been recorded. // The returned value tells us if we should keep recording or stop. if (!mProgressListener.reportProgress( - (float)(mDecodedSamples.position()) / mSampleRate)) { + (float) (mDecodedSamples.position()) / mSampleRate)) { break; } } @@ -468,7 +469,7 @@ public class SoundFile { // Temporary hack to make it work with the old version. mNumFrames = mNumSamples / getSamplesPerFrame(); - if (mNumSamples % getSamplesPerFrame() != 0){ + if (mNumSamples % getSamplesPerFrame() != 0) { mNumFrames++; } mFrameGains = new int[mNumFrames]; @@ -476,9 +477,9 @@ public class SoundFile { mFrameOffsets = null; // not needed for recorded audio int i, j; int gain, value; - for (i=0; i 0) { value = Math.abs(mDecodedSamples.get()); } else { @@ -488,7 +489,7 @@ public class SoundFile { gain = value; } } - mFrameGains[i] = (int)Math.sqrt(gain); // here gain = sqrt(max value of 1st channel)... + mFrameGains[i] = (int) Math.sqrt(gain); // here gain = sqrt(max value of 1st channel)... } mDecodedSamples.rewind(); // DumpSamples(); // Uncomment this line to dump the samples in a TSV file. @@ -497,15 +498,15 @@ public class SoundFile { // should be removed in the near future... public void WriteFile(File outputFile, int startFrame, int numFrames) throws IOException { - float startTime = (float)startFrame * getSamplesPerFrame() / mSampleRate; - float endTime = (float)(startFrame + numFrames) * getSamplesPerFrame() / mSampleRate; + float startTime = (float) startFrame * getSamplesPerFrame() / mSampleRate; + float endTime = (float) (startFrame + numFrames) * getSamplesPerFrame() / mSampleRate; WriteFile(outputFile, startTime, endTime); } public void WriteFile(File outputFile, float startTime, float endTime) throws IOException { - int startOffset = (int)(startTime * mSampleRate) * 2 * mChannels; - int numSamples = (int)((endTime - startTime) * mSampleRate); + int startOffset = (int) (startTime * mSampleRate) * 2 * mChannels; + int numSamples = (int) ((endTime - startTime) * mSampleRate); // Some devices have problems reading mono AAC files (e.g. Samsung S3). Making it stereo. int numChannels = (mChannels == 1) ? 2 : mChannels; @@ -518,7 +519,7 @@ public class SoundFile { codec.start(); // Get an estimation of the encoded data based on the bitrate. Add 10% to it. - int estimatedEncodedSize = (int)((endTime - startTime) * (bitrate / 8) * 1.1); + int estimatedEncodedSize = (int) ((endTime - startTime) * (bitrate / 8) * 1.1); ByteBuffer encodedBytes = ByteBuffer.allocate(estimatedEncodedSize); ByteBuffer[] inputBuffers = codec.getInputBuffers(); ByteBuffer[] outputBuffers = codec.getOutputBuffers(); @@ -536,7 +537,7 @@ public class SoundFile { } int[] frame_sizes = new int[tot_num_frames]; int num_out_frames = 0; - int num_frames=0; + int num_frames = 0; int num_samples_left = numSamples; int encodedSamplesSize = 0; // size of the output buffer containing the encoded samples. byte[] encodedSamples = null; @@ -558,7 +559,7 @@ public class SoundFile { // bufferSize is a hack to create a stereo file from a mono stream. int bufferSize = (mChannels == 1) ? (buffer.length / 2) : buffer.length; if (mDecodedBytes.remaining() < bufferSize) { - for (int i=mDecodedBytes.remaining(); i < bufferSize; i++) { + for (int i = mDecodedBytes.remaining(); i < bufferSize; i++) { buffer[i] = 0; // pad with extra 0s to make a full frame. } mDecodedBytes.get(buffer, 0, mDecodedBytes.remaining()); @@ -566,11 +567,11 @@ public class SoundFile { mDecodedBytes.get(buffer, 0, bufferSize); } if (mChannels == 1) { - for (int i=bufferSize - 1; i >= 1; i -= 2) { - buffer[2*i + 1] = buffer[i]; - buffer[2*i] = buffer[i-1]; - buffer[2*i - 1] = buffer[2*i + 1]; - buffer[2*i - 2] = buffer[2*i]; + for (int i = bufferSize - 1; i >= 1; i -= 2) { + buffer[2 * i + 1] = buffer[i]; + buffer[2 * i] = buffer[i - 1]; + buffer[2 * i - 1] = buffer[2 * i + 1]; + buffer[2 * i - 2] = buffer[2 * i]; } } num_samples_left -= frame_size; @@ -583,7 +584,7 @@ public class SoundFile { // Get the encoded samples from the encoder. int outputBufferIndex = codec.dequeueOutputBuffer(info, 100); - if (outputBufferIndex >= 0 && info.size > 0 && info.presentationTimeUs >=0) { + if (outputBufferIndex >= 0 && info.size > 0 && info.presentationTimeUs >= 0) { if (num_out_frames < frame_sizes.length) { frame_sizes[num_out_frames++] = info.size; } @@ -595,7 +596,7 @@ public class SoundFile { outputBuffers[outputBufferIndex].clear(); codec.releaseOutputBuffer(outputBufferIndex, false); if (encodedBytes.remaining() < info.size) { // Hopefully this should not happen. - estimatedEncodedSize = (int)(estimatedEncodedSize * 1.2); // Add 20%. + estimatedEncodedSize = (int) (estimatedEncodedSize * 1.2); // Add 20%. ByteBuffer newEncodedBytes = ByteBuffer.allocate(estimatedEncodedSize); int position = encodedBytes.position(); encodedBytes.rewind(); @@ -669,15 +670,15 @@ public class SoundFile { // should be removed in the near future... public void WriteWAVFile(File outputFile, int startFrame, int numFrames) throws IOException { - float startTime = (float)startFrame * getSamplesPerFrame() / mSampleRate; - float endTime = (float)(startFrame + numFrames) * getSamplesPerFrame() / mSampleRate; + float startTime = (float) startFrame * getSamplesPerFrame() / mSampleRate; + float endTime = (float) (startFrame + numFrames) * getSamplesPerFrame() / mSampleRate; WriteWAVFile(outputFile, startTime, endTime); } public void WriteWAVFile(File outputFile, float startTime, float endTime) throws IOException { - int startOffset = (int)(startTime * mSampleRate) * 2 * mChannels; - int numSamples = (int)((endTime - startTime) * mSampleRate); + int startOffset = (int) (startTime * mSampleRate) * 2 * mChannels; + int numSamples = (int) ((endTime - startTime) * mSampleRate); // Start by writing the RIFF header. FileOutputStream outputStream = new FileOutputStream(outputFile); @@ -752,7 +753,7 @@ public class SoundFile { try { writer = new BufferedWriter(new FileWriter(outFile)); for (int sampleIndex = 0; sampleIndex < mNumSamples; sampleIndex++) { - presentationTime = (float)(sampleIndex) / mSampleRate; + presentationTime = (float) (sampleIndex) / mSampleRate; row = Float.toString(presentationTime); for (int channelIndex = 0; channelIndex < mChannels; channelIndex++) { row += "\t" + mDecodedSamples.get(); diff --git a/app/src/main/java/com/nynja/mobile/communicator/data/audio/WAVHeader.java b/app/src/main/java/com/nynja/mobile/communicator/data/audio/WAVHeader.java index d52c026cbc46f777e71b4d9caab62a5be30dab08..986e4d521b4b5a8561d520f6a74d34fecc52d034 100755 --- a/app/src/main/java/com/nynja/mobile/communicator/data/audio/WAVHeader.java +++ b/app/src/main/java/com/nynja/mobile/communicator/data/audio/WAVHeader.java @@ -69,47 +69,47 @@ public class WAVHeader { int size; // set the RIFF chunk - System.arraycopy(new byte[] {'R', 'I', 'F', 'F'}, 0, header, offset, 4); + System.arraycopy(new byte[]{'R', 'I', 'F', 'F'}, 0, header, offset, 4); offset += 4; size = 36 + mNumSamples * mNumBytesPerSample; - header[offset++] = (byte)(size & 0xFF); - header[offset++] = (byte)((size >> 8) & 0xFF); - header[offset++] = (byte)((size >> 16) & 0xFF); - header[offset++] = (byte)((size >> 24) & 0xFF); - System.arraycopy(new byte[] {'W', 'A', 'V', 'E'}, 0, header, offset, 4); + header[offset++] = (byte) (size & 0xFF); + header[offset++] = (byte) ((size >> 8) & 0xFF); + header[offset++] = (byte) ((size >> 16) & 0xFF); + header[offset++] = (byte) ((size >> 24) & 0xFF); + System.arraycopy(new byte[]{'W', 'A', 'V', 'E'}, 0, header, offset, 4); offset += 4; // set the fmt chunk - System.arraycopy(new byte[] {'f', 'm', 't', ' '}, 0, header, offset, 4); + System.arraycopy(new byte[]{'f', 'm', 't', ' '}, 0, header, offset, 4); offset += 4; - System.arraycopy(new byte[] {0x10, 0, 0, 0}, 0, header, offset, 4); // chunk size = 16 + System.arraycopy(new byte[]{0x10, 0, 0, 0}, 0, header, offset, 4); // chunk size = 16 offset += 4; - System.arraycopy(new byte[] {1, 0}, 0, header, offset, 2); // format = 1 for PCM + System.arraycopy(new byte[]{1, 0}, 0, header, offset, 2); // format = 1 for PCM offset += 2; - header[offset++] = (byte)(mChannels & 0xFF); - header[offset++] = (byte)((mChannels >> 8) & 0xFF); - header[offset++] = (byte)(mSampleRate & 0xFF); - header[offset++] = (byte)((mSampleRate >> 8) & 0xFF); - header[offset++] = (byte)((mSampleRate >> 16) & 0xFF); - header[offset++] = (byte)((mSampleRate >> 24) & 0xFF); + header[offset++] = (byte) (mChannels & 0xFF); + header[offset++] = (byte) ((mChannels >> 8) & 0xFF); + header[offset++] = (byte) (mSampleRate & 0xFF); + header[offset++] = (byte) ((mSampleRate >> 8) & 0xFF); + header[offset++] = (byte) ((mSampleRate >> 16) & 0xFF); + header[offset++] = (byte) ((mSampleRate >> 24) & 0xFF); int byteRate = mSampleRate * mNumBytesPerSample; - header[offset++] = (byte)(byteRate & 0xFF); - header[offset++] = (byte)((byteRate >> 8) & 0xFF); - header[offset++] = (byte)((byteRate >> 16) & 0xFF); - header[offset++] = (byte)((byteRate >> 24) & 0xFF); - header[offset++] = (byte)(mNumBytesPerSample & 0xFF); - header[offset++] = (byte)((mNumBytesPerSample >> 8) & 0xFF); - System.arraycopy(new byte[] {0x10, 0}, 0, header, offset, 2); + header[offset++] = (byte) (byteRate & 0xFF); + header[offset++] = (byte) ((byteRate >> 8) & 0xFF); + header[offset++] = (byte) ((byteRate >> 16) & 0xFF); + header[offset++] = (byte) ((byteRate >> 24) & 0xFF); + header[offset++] = (byte) (mNumBytesPerSample & 0xFF); + header[offset++] = (byte) ((mNumBytesPerSample >> 8) & 0xFF); + System.arraycopy(new byte[]{0x10, 0}, 0, header, offset, 2); offset += 2; // set the beginning of the data chunk - System.arraycopy(new byte[] {'d', 'a', 't', 'a'}, 0, header, offset, 4); + System.arraycopy(new byte[]{'d', 'a', 't', 'a'}, 0, header, offset, 4); offset += 4; size = mNumSamples * mNumBytesPerSample; - header[offset++] = (byte)(size & 0xFF); - header[offset++] = (byte)((size >> 8) & 0xFF); - header[offset++] = (byte)((size >> 16) & 0xFF); - header[offset++] = (byte)((size >> 24) & 0xFF); + header[offset++] = (byte) (size & 0xFF); + header[offset++] = (byte) ((size >> 8) & 0xFF); + header[offset++] = (byte) ((size >> 16) & 0xFF); + header[offset++] = (byte) ((size >> 24) & 0xFF); mHeader = header; } diff --git a/app/src/main/java/com/nynja/mobile/communicator/data/voximplant/CallToPresenter.java b/app/src/main/java/com/nynja/mobile/communicator/data/voximplant/CallToPresenter.java new file mode 100644 index 0000000000000000000000000000000000000000..ddafd970660ba4ce08676e81a9a22b3e8e00df73 --- /dev/null +++ b/app/src/main/java/com/nynja/mobile/communicator/data/voximplant/CallToPresenter.java @@ -0,0 +1,35 @@ +package com.nynja.mobile.communicator.data.voximplant; + +import com.voximplant.sdk.call.ICall; +import com.voximplant.sdk.call.IVideoStream; + +public interface CallToPresenter { + void videoCall(ICall Call); + + void audioCall(ICall call); + + void activeVideoCall(ICall Call); + + void activeAudioCall(ICall call); + + void remoteVideoStreamAdded(IVideoStream iVideoStream); + + void remoteVideoStreamRemoved(IVideoStream iVideoStream); + + void timeTicksTicksAway(String time); //duration of call + + void callEnded(); + + // TO DETAILED CALL ACTIVITY +// void onSpeaker(boolean on); + + void onMute(boolean audioOn); + + void onCallRinging(); + + void onCallConnected(); + + void onCallFailed(String reason); + + void onLocalVideoStreamAdded(IVideoStream iVideoStream, boolean added); +} diff --git a/app/src/main/java/com/nynja/mobile/communicator/data/voximplant/VoxImplantModule.java b/app/src/main/java/com/nynja/mobile/communicator/data/voximplant/VoxImplantModule.java index e15a0af852d20857b0d14cd6a0e0758a4cccdb62..481e36dfb704667d15cf71fe25a0c1d839ff3e9e 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/data/voximplant/VoxImplantModule.java +++ b/app/src/main/java/com/nynja/mobile/communicator/data/voximplant/VoxImplantModule.java @@ -7,7 +7,14 @@ import com.nynja.mobile.communicator.data.models.mqtt.Person; import com.nynja.mobile.communicator.ui.activities.calls.CallActivity; import com.nynja.mobile.communicator.ui.activities.calls.IncomeCallActivity; import com.voximplant.sdk.Voximplant; +import com.voximplant.sdk.call.CallException; import com.voximplant.sdk.call.ICall; +import com.voximplant.sdk.call.ICallCompletionHandler; +import com.voximplant.sdk.call.ICallListener; +import com.voximplant.sdk.call.IEndpoint; +import com.voximplant.sdk.call.IEndpointListener; +import com.voximplant.sdk.call.IVideoStream; +import com.voximplant.sdk.call.RenderScaleType; import com.voximplant.sdk.client.AuthParams; import com.voximplant.sdk.client.ClientConfig; import com.voximplant.sdk.client.IClient; @@ -18,6 +25,8 @@ import com.voximplant.sdk.client.LoginError; import java.util.ArrayList; import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; import java.util.concurrent.Executors; import timber.log.Timber; @@ -27,14 +36,22 @@ import timber.log.Timber; **/ public class VoxImplantModule implements IClientLoginListener, IClientSessionListener, - IClientIncomingCallListener { + IClientIncomingCallListener, IEndpointListener, ICallListener { + public static final RenderScaleType RENDER_TYPE = RenderScaleType.SCALE_FILL; + private static final int SECOND = 1000; + private static final int SECOND_IN_MINUTE = 60; private static final String POSTFIX = "@videoconf.nynja.voximplant.com"; private final Context mContext; - private Person mPerson; + private Person mPerson; //person is me private IClient mVoxClient; private ICall mCall; private ArrayList mServers = new ArrayList<>(); + private IVideoStream mVideoStream; + private Timer mTimer; + private CallToPresenter mCallToPresenter; + private boolean connected; + private IVideoStream localVideoStream; public VoxImplantModule(Context context) { mContext = context; @@ -51,8 +68,29 @@ public class VoxImplantModule implements IClientLoginListener, IClientSessionLis mVoxClient.connect(true, mServers); } - public ICall getActiveCall() { - return mCall; + public void attachCallback(CallToPresenter callToPresenter) { + this.mCallToPresenter = callToPresenter; + if (mCallToPresenter == null) return; + + if (mCall == null) { + mCallToPresenter.callEnded(); + return; + } + + mCall.addCallListener(this); + if (!mCall.getEndpoints().isEmpty()) { + IEndpoint mEndpoint = mCall.getEndpoints().get(0); + mEndpoint.setEndpointListener(this); + } + if (connected) { + enableCall(mCall); + } else { + if (mCall.isVideoEnabled()) { + mCallToPresenter.videoCall(mCall); + } else { + mCallToPresenter.audioCall(mCall); + } + } } public void videoCall(String userId) { @@ -64,17 +102,72 @@ public class VoxImplantModule implements IClientLoginListener, IClientSessionLis } private void makeCall(String to, boolean isVideoCall) { - mCall = mVoxClient.callTo(to, isVideoCall, null); - if (mCall != null) { - onStartCall(to); + if (mCall == null) { + mCall = mVoxClient.callTo(to, isVideoCall, null); + } + onStartCallActivity(to, isVideoCall); + } + + public void startCall(boolean mIsIncomingCall) { + if (connected) return; + if (mIsIncomingCall) { + try { + if (mCall != null) { + mCall.answer(null, null); + } + } catch (CallException e) { + Timber.e(e); + } + } else { + if (mCall != null) { + mCall.start(null); + } } } - private void onStartCall(String to) { - Intent intent = CallActivity.getLaunchIntent(mContext, to); + + private void onStartCallActivity(String to, boolean withVideo) { + Intent intent = CallActivity.getLaunchIntent(mContext, to, withVideo, false); mContext.startActivity(intent); } + private void startTimer() { + mTimer = new Timer(); + mTimer.scheduleAtFixedRate(new TimerTask() { + @Override public void run() { + if (mCall != null && mCallToPresenter != null) { + mCallToPresenter.timeTicksTicksAway(getTime()); + } else { + mTimer.cancel(); + } + } + }, SECOND, SECOND); + } + + private String getTime() { + long milliseconds; + try { + milliseconds = mCall.getCallDuration(); + } catch (NullPointerException e) { //sometimes vox sdk can throw null pointer exception from here + e.printStackTrace(); + return ""; + } + if (milliseconds > SECOND * SECOND_IN_MINUTE * 60 * 24) + return ""; //sometimes voximplant returns current time milis or something like that + int seconds = (int) milliseconds / SECOND; + int minutes = seconds / SECOND_IN_MINUTE; + + String time; + if (seconds % SECOND_IN_MINUTE >= 10) { + time = minutes + ":" + seconds % SECOND_IN_MINUTE; + } else { + time = minutes + ":0" + seconds % SECOND_IN_MINUTE; + } + + return time; + + } + //Client Login @Override public void onLoginSuccessful(String s, AuthParams authParams) { Timber.i("VoxImplant login success"); @@ -117,7 +210,138 @@ public class VoxImplantModule implements IClientLoginListener, IClientSessionLis } } - public void endCall() { + private void endCall() { mCall = null; + mCallToPresenter = null; + connected = false; + } + + + @Override public void onRemoteVideoStreamAdded(IEndpoint iEndpoint, IVideoStream iVideoStream) { + this.mVideoStream = iVideoStream; + if (mCallToPresenter != null) mCallToPresenter.remoteVideoStreamAdded(iVideoStream); + } + + @Override + public void onRemoteVideoStreamRemoved(IEndpoint iEndpoint, IVideoStream iVideoStream) { + mVideoStream = null; + } + + public void reloadSurfaceRenderer() { + if (mVideoStream != null && mCallToPresenter != null) { + mCallToPresenter.remoteVideoStreamAdded(mVideoStream); + } + + if (localVideoStream != null && mCallToPresenter != null) { + mCallToPresenter.onLocalVideoStreamAdded(localVideoStream, true); + } + } + + @Override public void onCallConnected(ICall iCall, Map map) { + connected = true; + if (mCallToPresenter != null) { + mCallToPresenter.onCallConnected(); + startTimer(); + enableCall(iCall); + } + } + + private void enableCall(ICall iCall) { + if (iCall.isVideoEnabled()) { + mCallToPresenter.activeVideoCall(iCall); + } else { + mCallToPresenter.activeAudioCall(iCall); + } + } + + @Override public void onCallDisconnected(ICall iCall, Map map, boolean b) { + if (mTimer != null) mTimer.cancel(); + mCall = null; + if (mCallToPresenter != null) mCallToPresenter.callEnded(); + endCall(); + } + + @Override public void onCallRinging(ICall iCall, Map map) { + if (mCallToPresenter != null) mCallToPresenter.onCallRinging(); + } + + @Override public void onCallFailed(ICall iCall, int i, String s, Map map) { + if (mCallToPresenter != null) { //reason can be empty + mCallToPresenter.onCallFailed(s); + } + endCall(); + } + + @Override public void onCallAudioStarted(ICall iCall) { + + } + + @Override + public void onSIPInfoReceived(ICall iCall, String s, String s1, Map map) { + + } + + @Override public void onMessageReceived(ICall iCall, String s) { + + } + + @Override public void onLocalVideoStreamAdded(ICall iCall, IVideoStream iVideoStream) { + this.localVideoStream = iVideoStream; + if (mCallToPresenter != null) mCallToPresenter.onLocalVideoStreamAdded(iVideoStream, true); + } + + @Override public void onLocalVideoStreamRemoved(ICall iCall, IVideoStream iVideoStream) { + this.localVideoStream = null; + if (mCallToPresenter != null) mCallToPresenter.onLocalVideoStreamAdded(iVideoStream, false); + } + + @Override public void onICETimeout(ICall iCall) { + endCall(); + } + + @Override public void onICECompleted(ICall iCall) { + + } + + public void mute(boolean audioOn) { + mCall.sendAudio(audioOn); + if (mCallToPresenter != null) mCallToPresenter.onMute(audioOn); + } + + public void hangUp() { + if (mCall != null) mCall.hangup(null); + } + + public void switchToAudio() { + if (mCall != null) + mCall.sendVideo(false, new ICallCompletionHandler() { + @Override public void onComplete() { + if (mCallToPresenter != null) mCallToPresenter.audioCall(mCall); + } + + @Override public void onFailure(CallException e) { + Timber.e(e); + } + }); + } + + public void declineCall() { + try { + if (mCall != null) { + mCall.reject(null); + mCall.removeCallListener(this); + } + } catch (CallException e) { + Timber.e("VoxImplantSDKDemo", "exception on reject call ", e); + } + endCall(); + } + + public String getAnotherUsername() { + if (mCall == null || mCall.getEndpoints().isEmpty() || mCall.getEndpoints().get(0) == null) { + return null; + } else { + return mCall.getEndpoints().get(0).getUserName(); + } } } diff --git a/app/src/main/java/com/nynja/mobile/communicator/data/voximplant/VoxPresenter.java b/app/src/main/java/com/nynja/mobile/communicator/data/voximplant/VoxPresenter.java new file mode 100644 index 0000000000000000000000000000000000000000..1e8447601af3f5f25c304410e2cdf5eabae87bff --- /dev/null +++ b/app/src/main/java/com/nynja/mobile/communicator/data/voximplant/VoxPresenter.java @@ -0,0 +1,41 @@ +package com.nynja.mobile.communicator.data.voximplant; + +import com.nynja.mobile.communicator.mvp.presenters.BaseErrorPresenter; +import com.nynja.mobile.communicator.mvp.view.ErrorMvpView; +import com.voximplant.sdk.call.ICall; +import com.voximplant.sdk.call.IVideoStream; + +public abstract class VoxPresenter extends BaseErrorPresenter implements + CallToPresenter { + + @Override public void attachView(T view) { + super.attachView(view); + mDataManager.getVoxImlant().attachCallback(this); + } + + @Override public void videoCall(ICall Call) { } + + @Override public void audioCall(ICall call) { } + + @Override public void activeVideoCall(ICall Call) { } + + @Override public void activeAudioCall(ICall call) { } + + @Override public void remoteVideoStreamAdded(IVideoStream iVideoStream) { } + + @Override public void remoteVideoStreamRemoved(IVideoStream iVideoStream) { } + + @Override public void timeTicksTicksAway(String time) { } + + @Override public void callEnded() { } + + @Override public void onMute(boolean audioOn) { } + + @Override public void onCallRinging() { } + + @Override public void onCallConnected() { } + + @Override public void onCallFailed(String reason) { } + + @Override public void onLocalVideoStreamAdded(IVideoStream iVideoStream, boolean added) { } +} diff --git a/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/BasePresenter.java b/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/BasePresenter.java index d1d1e850b572fe6834e8bc005dcef385b85d957b..2417c2ce716cad09ab6f806fce9f23aaa42b6527 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/BasePresenter.java +++ b/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/BasePresenter.java @@ -23,7 +23,7 @@ import timber.log.Timber; public abstract class BasePresenter extends MvpPresenter { protected DataManager mDataManager; - Router mRouter; + protected Router mRouter; private CompositeDisposable mCompositeDisposable; diff --git a/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/CallPresenter.java b/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/CallPresenter.java index 5bc762b0750ae08d0b97ee5dea186155ca92caf9..3e59ed693a9c55efcff4b0fcc2775d1517ad1622 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/CallPresenter.java +++ b/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/CallPresenter.java @@ -1,27 +1,18 @@ package com.nynja.mobile.communicator.mvp.presenters; import com.arellomobile.mvp.InjectViewState; +import com.nynja.mobile.communicator.data.models.ChatModel; +import com.nynja.mobile.communicator.data.models.mqtt.Contact; import com.nynja.mobile.communicator.data.models.mqtt.Response; +import com.nynja.mobile.communicator.data.voximplant.CallToPresenter; +import com.nynja.mobile.communicator.data.voximplant.VoxPresenter; import com.nynja.mobile.communicator.mvp.view.CallView; -import com.voximplant.sdk.call.CallException; +import com.nynja.mobile.communicator.ui.fragments.chats.ChatFragment; import com.voximplant.sdk.call.ICall; -import com.voximplant.sdk.call.ICallCompletionHandler; -import com.voximplant.sdk.call.ICallListener; import com.voximplant.sdk.call.IVideoStream; -import java.util.Map; -import java.util.Timer; -import java.util.TimerTask; - -import timber.log.Timber; - @InjectViewState -public class CallPresenter extends BasePresenter implements ICallListener { - - private static final int SECOND = 1000; - private static final int SECOND_IN_MINUTE = 60; - private ICall mCall; - private Timer mTimer; +public class CallPresenter extends VoxPresenter implements CallToPresenter { @Override protected Class[] getFilter() { return new Class[0]; @@ -30,156 +21,95 @@ public class CallPresenter extends BasePresenter implements ICallListe @Override protected void handleResponse(Response response) { } - public void getCall() { - mCall = mDataManager.getCall(); - if (mCall != null) { - mCall.addCallListener(this); - getViewState().onCallSet(mCall); - } - } - public void switchCamera() { getViewState().onCameraSwitch(); } - public void sendVideo(boolean sendVideo) { - //// TODO: 10.08.17 switch audio-video - mCall.sendVideo(sendVideo, new ICallCompletionHandler() { - @Override public void onComplete() { - getViewState().switchUi(sendVideo); - } - - @Override public void onFailure(CallException e) { - Timber.e(e); - } - }); + public void switchToAudio() { + mDataManager.getVoxImlant().switchToAudio(); } - public void hanUp() { - if (mCall != null) mCall.hangup(null); - getViewState().fatality(); + public void hangUp() { + mDataManager.getVoxImlant().hangUp(); + getViewState().onCallEnded(); } public void mute(boolean on) { - mCall.sendAudio(on); - getViewState().onMute(on); + mDataManager.getVoxImlant().mute(on); } public void speaker(boolean on) { getViewState().onSpeaker(on); } - public void text() { - //TODO transfer to chat, oh, wait we have no chat + public void startCall(boolean mIsIncomingCall) { + mDataManager.getVoxImlant().startCall(mIsIncomingCall); } - public void startCall(boolean mIsIncomingCall) { - if (mIsIncomingCall) { - try { - if (mCall != null) { - mCall.answer(null, null); - } - } catch (CallException e) { - Timber.e(e); - } - } else { - if (mCall != null) { - mCall.start(null); - Timber.e("VOX", "start call " + mCall); - } - } - } - - private void startTimer() { - mTimer = new Timer(); - mTimer.scheduleAtFixedRate(new TimerTask() { - @Override public void run() { - if (mCall != null) { - getViewState().callTimeUpdated(getTime()); - } else { - mTimer.cancel(); - } - } - }, SECOND, SECOND); - } - - private String getTime() { - try { - long milliseconds = mCall.getCallDuration(); - if (milliseconds > SECOND * SECOND_IN_MINUTE * 60 * 24) - return ""; //sometimes voximplant returns current time milis or something like that - int seconds = (int) milliseconds / SECOND; - int minutes = seconds / SECOND_IN_MINUTE; - - String time; - if (seconds % SECOND_IN_MINUTE >= 10) { - time = minutes + ":" + seconds % SECOND_IN_MINUTE; - } else { - time = minutes + ":0" + seconds % SECOND_IN_MINUTE; - } - - return time; - } catch (NullPointerException e) { - e.printStackTrace(); - return ""; - } - } - - @Override public void onCallConnected(ICall iCall, Map map) { - Timber.i("Call connected"); - startTimer(); - getViewState().onCallConnected(); + public void openChat(Contact item) { + ChatModel chatModel = mDataManager.getChatWith(item.phoneId); + mRouter.replaceScreen(ChatFragment.class.getSimpleName(), chatModel); + getViewState().onCallEnded(); } - @Override public void onCallDisconnected(ICall iCall, Map map, boolean b) { - Timber.i("Call disconnected"); - getViewState().onCallDisconnected(); - getViewState().fatality(); - if (mTimer != null) mTimer.cancel(); - mDataManager.callEnd(); + public void loadUser(String username) { + getViewState().setUser(mDataManager.getProfile().getRoster().getContactByVoxUser(username)); } - @Override public void onCallRinging(ICall iCall, Map map) { - Timber.i("Call ringing..."); - getViewState().onCallRinging(); + public void reloadVideo() { + mDataManager.getVoxImlant().reloadSurfaceRenderer(); } - @Override public void onCallFailed(ICall iCall, int i, String s, Map map) { - Timber.i("Call failed"); - getViewState().onCallFailed(s); - mDataManager.callEnd(); + @Override public void videoCall(ICall Call) { + getViewState().videoCall(); } - @Override public void onCallAudioStarted(ICall iCall) { + @Override public void audioCall(ICall call) { + getViewState().audioCall(); + } + @Override public void remoteVideoStreamAdded(IVideoStream iVideoStream) { + getViewState().onRemoteVideoStreamAdded(iVideoStream); } - @Override - public void onSIPInfoReceived(ICall iCall, String s, String s1, Map map) { + @Override public void remoteVideoStreamRemoved(IVideoStream iVideoStream) { + getViewState().onRemoteVideoStreamRemoved(iVideoStream); + } + @Override public void timeTicksTicksAway(String time) { + getViewState().callTimeUpdated(time); } - @Override public void onMessageReceived(ICall iCall, String s) { + @Override public void callEnded() { + getViewState().onCallEnded(); + } + @Override public void onMute(boolean audioOn) { + getViewState().onMute(audioOn); } - @Override public void onLocalVideoStreamAdded(ICall iCall, IVideoStream iVideoStream) { - getViewState().onLocalVideoStreamAdded(iVideoStream, true); + @Override public void onCallRinging() { + getViewState().onCallRinging(); } - @Override public void onLocalVideoStreamRemoved(ICall iCall, IVideoStream iVideoStream) { - getViewState().onLocalVideoStreamAdded(iVideoStream, false); + @Override public void onCallConnected() { + getViewState().onCallConnected(); } - @Override public void onICETimeout(ICall iCall) { - mDataManager.callEnd(); + @Override public void onCallFailed(String reason) { + getViewState().onCallFailed(reason); } - @Override public void onICECompleted(ICall iCall) { + @Override public void onLocalVideoStreamAdded(IVideoStream iVideoStream, boolean added) { + getViewState().onLocalVideoStreamAdded(iVideoStream, added); + } + @Override public void activeVideoCall(ICall Call) { + getViewState().activeVideoCall(); } - public void getUser(String username) { - getViewState().setUser(mDataManager.getProfile().getRoster().getContactByVoxUser(username)); + @Override public void activeAudioCall(ICall call) { + getViewState().activeAudioCall(); } + } diff --git a/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/ChatPresenter.java b/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/ChatPresenter.java index e7139123735a40c59afe9d62c9d719db807472c3..be9af24b15e9432359c65b8f93cac50759e5263c 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/ChatPresenter.java +++ b/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/ChatPresenter.java @@ -281,4 +281,6 @@ public class ChatPresenter extends BaseErrorPresenter { } }); } + + } diff --git a/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/HomePresenter.java b/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/HomePresenter.java index 86f25b2e1b8f55ef57f4faf49366bb7ea4b75188..263b8974724980525d6e755b4cdf6ae6cb4af319 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/HomePresenter.java +++ b/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/HomePresenter.java @@ -2,23 +2,25 @@ package com.nynja.mobile.communicator.mvp.presenters; import com.arellomobile.mvp.InjectViewState; import com.nynja.mobile.communicator.data.models.events.LocalMessage; +import com.nynja.mobile.communicator.data.models.mqtt.Contact; import com.nynja.mobile.communicator.data.models.mqtt.Response; +import com.nynja.mobile.communicator.data.voximplant.VoxPresenter; import com.nynja.mobile.communicator.mvp.view.HomeView; import com.nynja.mobile.communicator.ui.views.wheel.WheelIconModel; +import com.voximplant.sdk.call.ICall; +import com.voximplant.sdk.call.IVideoStream; /** * Created by dmitro.boiko on 21/07/2017. **/ @InjectViewState -public class HomePresenter extends BaseErrorPresenter { +public class HomePresenter extends VoxPresenter { @Override protected Class[] getFilter() { return new Class[0]; } - @Override protected void handleResponse(Response response) { - - } + @Override protected void handleResponse(Response response) {} @Override protected void onFirstViewAttach() { super.onFirstViewAttach(); @@ -27,20 +29,57 @@ public class HomePresenter extends BaseErrorPresenter { .subscribe(localMessage -> getViewState().setLetter(localMessage.selectedLetter))); } - public void onWheelItemClick(WheelIconModel wheelIconModel) { + public void onWheelItemClick(WheelIconModel wheelIconModel){ mDataManager.sendLocalEvent(new LocalMessage(wheelIconModel.action)); } - void showContacts() { + public void onLetterSelected(char selectedLetter) { + mDataManager.sendLocalEvent(new LocalMessage(selectedLetter, LocalMessage.Types.Scroll)); } - void showMyProfile() { + public void reloadVideo() { + mDataManager.getVoxImlant().reloadSurfaceRenderer(); } - void showHistory() { + public void openCall(boolean video) { + if (video) { + //TODO WHERE TO GET PERSON ID? + mDataManager.videoCall(mDataManager.getVoxImlant().getAnotherUsername()); + } else { + mDataManager.audioCall(mDataManager.getVoxImlant().getAnotherUsername()); + } } - public void onLetterSelected(char selectedLetter) { - mDataManager.sendLocalEvent(new LocalMessage(selectedLetter, LocalMessage.Types.Scroll)); + public void requestPhoto() { + String username = mDataManager.getVoxImlant().getAnotherUsername(); + if (username != null) { + Contact contact = mDataManager.getProfile().getRoster().getContactByVoxUser(username); + getViewState().onAudioCallPhoto(contact.avatar); + } + } + + //CALL CALlBACKS + @Override public void remoteVideoStreamAdded(IVideoStream iVideoStream) { + getViewState().onVideoStreamAdded(iVideoStream); + } + + @Override public void remoteVideoStreamRemoved(IVideoStream iVideoStream) { + getViewState().onVideoStreamRemoved(iVideoStream); + } + + @Override public void timeTicksTicksAway(String time) { + getViewState().onCallTimeChange(time); + } + + @Override public void callEnded() { + getViewState().onCallEnded(); + } + + @Override public void activeVideoCall(ICall Call) { + getViewState().onActiveVideoCall(); + } + + @Override public void activeAudioCall(ICall call) { + getViewState().onActiveAudioCall(); } } diff --git a/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/IncomeCallPresenter.java b/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/IncomeCallPresenter.java index e2caa1c31f75995eeed5c753a2881c10f72b6341..50ad850906d08aa0731346be3b4cecdd0b73f0df 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/IncomeCallPresenter.java +++ b/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/IncomeCallPresenter.java @@ -3,20 +3,12 @@ package com.nynja.mobile.communicator.mvp.presenters; import com.arellomobile.mvp.InjectViewState; import com.nynja.mobile.communicator.data.models.mqtt.Contact; import com.nynja.mobile.communicator.data.models.mqtt.Response; +import com.nynja.mobile.communicator.data.voximplant.VoxPresenter; import com.nynja.mobile.communicator.mvp.view.IncomeCallView; -import com.voximplant.sdk.call.CallException; import com.voximplant.sdk.call.ICall; -import com.voximplant.sdk.call.ICallListener; -import com.voximplant.sdk.call.IVideoStream; - -import java.util.Map; - -import timber.log.Timber; @InjectViewState -public class IncomeCallPresenter extends BasePresenter implements ICallListener { - - private ICall mCall; +public class IncomeCallPresenter extends VoxPresenter { @Override protected Class[] getFilter() { return new Class[0]; @@ -29,78 +21,27 @@ public class IncomeCallPresenter extends BasePresenter implement } public void declineCall() { - try { - if (mCall != null) { - mCall.reject(null); - mCall.removeCallListener(this); - } - } catch (CallException e) { - Timber.e("VoxImplantSDKDemo", "exception on reject call ", e); - } - mDataManager.callEnd(); + mDataManager.getVoxImlant().declineCall(); getViewState().onCallDisconnected(); } - public void geCall() { - mCall = mDataManager.getCall(); - if (mCall != null && mCall.getEndpoints() != null) { - String userName = mCall.getEndpoints().get(0).getUserName(); - Contact contact = mDataManager.getProfile().getRoster().getContactByVoxUser(userName); - getViewState().setCall(mCall, contact); - mCall.addCallListener(this); - getViewState().hasVideo(mCall.isVideoEnabled()); - } - } - - @Override public void onCallConnected(ICall iCall, Map map) { - - } - - @Override public void onCallDisconnected(ICall mCall, Map map, boolean b) { - mCall.removeCallListener(this); + @Override public void callEnded() { getViewState().onCallDisconnected(); - mDataManager.callEnd(); - } - - @Override public void onCallRinging(ICall iCall, Map map) { - - } - - @Override public void onCallFailed(ICall iCall, int i, String s, Map map) { - mDataManager.callEnd(); - } - - @Override public void onCallAudioStarted(ICall iCall) { - } - @Override - public void onSIPInfoReceived(ICall iCall, String s, String s1, Map map) { - - } - - @Override public void onMessageReceived(ICall iCall, String s) { - - } - - @Override public void onLocalVideoStreamAdded(ICall iCall, IVideoStream iVideoStream) { - - } - - @Override public void onLocalVideoStreamRemoved(ICall iCall, IVideoStream iVideoStream) { - - } - - @Override public void onICETimeout(ICall iCall) { - mDataManager.callEnd(); - } - - @Override public void onICECompleted(ICall iCall) { - + @Override public void videoCall(ICall call) { + getViewState().hasVideo(true); + //crash + String userName = call.getEndpoints().get(0).getUserName(); + Contact contact = mDataManager.getProfile().getRoster().getContactByVoxUser(userName); + getViewState().setCall(contact); } - @Override public void detachView(IncomeCallView view) { - super.detachView(view); - if (mCall != null) mCall.removeCallListener(this); + @Override public void audioCall(ICall call) { + getViewState().hasVideo(false); + //crash + String userName = call.getEndpoints().get(0).getUserName(); + Contact contact = mDataManager.getProfile().getRoster().getContactByVoxUser(userName); + getViewState().setCall(contact); } } diff --git a/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/LoginPresenter.java b/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/LoginPresenter.java index d6596202721edb248df7abc0e248a84243517e5c..2c1f25ec1146b570ecc6bed3ade23af74eb64d09 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/LoginPresenter.java +++ b/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/LoginPresenter.java @@ -19,8 +19,6 @@ import io.reactivex.Observable; import io.reactivex.disposables.Disposable; import timber.log.Timber; -; - /** * Date: 25.06.17 * Time: 04:10 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 5408be1116e6c66ec6bee0bf1ac6d19671e25e5d..a1fc6096ad096ea36accbd36e5235033c52b62f9 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 @@ -2,33 +2,38 @@ package com.nynja.mobile.communicator.mvp.view; import com.arellomobile.mvp.MvpView; import com.nynja.mobile.communicator.data.models.mqtt.Contact; -import com.voximplant.sdk.call.ICall; import com.voximplant.sdk.call.IVideoStream; -public interface CallView extends MvpView { +public interface CallView extends MvpView, ErrorMvpView { void onCameraSwitch(); void onSpeaker(boolean on); void onMute(boolean audioWorking); - void switchUi(boolean on); - void onLocalVideoStreamAdded(IVideoStream iVideoStream, boolean added); + void onRemoteVideoStreamAdded(IVideoStream iVideoStream); + + void onRemoteVideoStreamRemoved(IVideoStream iVideoStream); + void onCallFailed(String description); void onCallRinging(); void onCallConnected(); - void onCallDisconnected(); - - void onCallSet(ICall call); - - void fatality(); + void onCallEnded(); void callTimeUpdated(String time); void setUser(Contact contact); + + void audioCall(); + + void videoCall(); + + void activeAudioCall(); + + void activeVideoCall(); } diff --git a/app/src/main/java/com/nynja/mobile/communicator/mvp/view/HomeView.java b/app/src/main/java/com/nynja/mobile/communicator/mvp/view/HomeView.java index 7b7d357a693a3085894023986ecfad4a0a37be13..e805b7689c3ce0d2ac93ab548e66ff33bf44626e 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/mvp/view/HomeView.java +++ b/app/src/main/java/com/nynja/mobile/communicator/mvp/view/HomeView.java @@ -1,5 +1,7 @@ package com.nynja.mobile.communicator.mvp.view; +import com.voximplant.sdk.call.IVideoStream; + /** * Created by dmitro.boiko on 21/07/2017. */ @@ -7,4 +9,19 @@ package com.nynja.mobile.communicator.mvp.view; public interface HomeView extends ErrorMvpView{ void setLetter(char letter); + + void onActiveAudioCall(); + + void onActiveVideoCall(); + + void onCallTimeChange(String time); + + void onCallEnded(); + + void onVideoStreamAdded(IVideoStream iVideoStream); + + void onVideoStreamRemoved(IVideoStream iVideoStream); + + void onAudioCallPhoto(String url); + } diff --git a/app/src/main/java/com/nynja/mobile/communicator/mvp/view/IncomeCallView.java b/app/src/main/java/com/nynja/mobile/communicator/mvp/view/IncomeCallView.java index 5091d6d6ebf897b1f5cfc64e6444b547d7e3bee0..a69790f87b4defb017c61b069ae2fec8a82da4e1 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/mvp/view/IncomeCallView.java +++ b/app/src/main/java/com/nynja/mobile/communicator/mvp/view/IncomeCallView.java @@ -2,9 +2,8 @@ package com.nynja.mobile.communicator.mvp.view; import com.arellomobile.mvp.MvpView; import com.nynja.mobile.communicator.data.models.mqtt.Contact; -import com.voximplant.sdk.call.ICall; -public interface IncomeCallView extends MvpView { +public interface IncomeCallView extends MvpView, ErrorMvpView { void onAnswerCall(boolean withVideoIfCan); @@ -12,5 +11,6 @@ public interface IncomeCallView extends MvpView { void hasVideo(boolean video); - void setCall(ICall call, Contact contact); + // void setCall(ICall call, Contact contact); + void setCall(Contact contact); } diff --git a/app/src/main/java/com/nynja/mobile/communicator/ui/activities/HomeActivity.java b/app/src/main/java/com/nynja/mobile/communicator/ui/activities/HomeActivity.java index 8b9b059f7d54bd4c50e0aa803949fdd35d932e78..5a705b16f2d5d89510411fc3ad6d5022c40a3577 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/ui/activities/HomeActivity.java +++ b/app/src/main/java/com/nynja/mobile/communicator/ui/activities/HomeActivity.java @@ -7,12 +7,17 @@ import android.content.Intent; import android.os.Bundle; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; import com.arellomobile.mvp.presenter.InjectPresenter; +import com.bumptech.glide.Glide; import com.nynja.mobile.communicator.NynjaApp; import com.nynja.mobile.communicator.R; import com.nynja.mobile.communicator.data.models.ChatModel; import com.nynja.mobile.communicator.data.models.mqtt.Contact; +import com.nynja.mobile.communicator.data.voximplant.VoxImplantModule; import com.nynja.mobile.communicator.mvp.presenters.HomePresenter; import com.nynja.mobile.communicator.mvp.view.HomeView; import com.nynja.mobile.communicator.ui.base.BaseActivity; @@ -32,10 +37,14 @@ import com.nynja.mobile.communicator.ui.views.wheel.WheelIconModel; import com.nynja.mobile.communicator.ui.views.wheel.WheelItemFactory; import com.nynja.mobile.communicator.ui.views.wheel.adapter.WheelArrayAdapter; import com.nynja.mobile.communicator.utils.Utils; +import com.voximplant.sdk.call.IVideoStream; + +import org.webrtc.SurfaceViewRenderer; import java.util.List; import butterknife.BindView; +import butterknife.OnClick; import ru.terrakok.cicerone.Navigator; import ru.terrakok.cicerone.commands.Command; import ru.terrakok.cicerone.commands.Forward; @@ -49,6 +58,11 @@ public class HomeActivity extends BaseActivity implements HomeView, MenuButton.O @BindView(R.id.cascadeWheel) CascadeWheel cascadeWheel; + @BindView(R.id.chat_active_video) SurfaceViewRenderer video; + @BindView(R.id.chat_audio_layout) View chatAudioLayout; + @BindView(R.id.chat_audio_duration) TextView duration; + @BindView(R.id.chat_audio_photo) ImageView audioAvatar; + @InjectPresenter HomePresenter mHomePresenter; private Navigator navigator = HomeActivity.this::handleCommand; @@ -261,4 +275,56 @@ public class HomeActivity extends BaseActivity implements HomeView, MenuButton.O super.onBackPressed(); } } + + + @OnClick(R.id.chat_active_video) void openVideoCall() { + mHomePresenter.openCall(true); + } + + @OnClick(R.id.chat_audio_layout) void openAudioCall() { + mHomePresenter.openCall(false); + } + + @Override public void onActiveAudioCall() { + chatAudioLayout.setVisibility(View.VISIBLE); + mHomePresenter.requestPhoto(); + } + + @Override public void onActiveVideoCall() { + video.setVisibility(View.VISIBLE); + mHomePresenter.reloadVideo(); + } + + @Override public void onCallTimeChange(String time) { + runOnUiThread(() -> { + if (chatAudioLayout != null && chatAudioLayout.getVisibility() == View.VISIBLE) { + duration.setText(time); + } + }); + } + + @Override public void onCallEnded() { + runOnUiThread(() -> { + if (video.getVisibility() == View.VISIBLE) { + video.setVisibility(View.GONE); + } + + if (chatAudioLayout.getVisibility() == View.VISIBLE) { + chatAudioLayout.setVisibility(View.GONE); + } + + }); + } + + @Override public void onVideoStreamAdded(IVideoStream iVideoStream) { + iVideoStream.addVideoRenderer(video, VoxImplantModule.RENDER_TYPE); + } + + @Override public void onVideoStreamRemoved(IVideoStream iVideoStream) { + iVideoStream.removeVideoRenderer(video); + } + + @Override public void onAudioCallPhoto(String url) { + Glide.with(this).load(url).placeholder(R.drawable.avatar_placeholder).into(audioAvatar); + } } diff --git a/app/src/main/java/com/nynja/mobile/communicator/ui/activities/calls/CallActivity.java b/app/src/main/java/com/nynja/mobile/communicator/ui/activities/calls/CallActivity.java index d8b9c4d85f5d3960c9e00ac60f666082edba0f91..e946e0bbd4c7f1593f41cf5b29a3c0939c229025 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/ui/activities/calls/CallActivity.java +++ b/app/src/main/java/com/nynja/mobile/communicator/ui/activities/calls/CallActivity.java @@ -13,18 +13,16 @@ import android.widget.ImageView; import android.widget.TextView; import com.arellomobile.mvp.presenter.InjectPresenter; +import com.bumptech.glide.Glide; import com.nynja.mobile.communicator.R; import com.nynja.mobile.communicator.data.models.mqtt.Contact; +import com.nynja.mobile.communicator.data.voximplant.VoxImplantModule; import com.nynja.mobile.communicator.mvp.presenters.CallPresenter; import com.nynja.mobile.communicator.mvp.view.CallView; import com.nynja.mobile.communicator.ui.base.BaseActivity; import com.nynja.mobile.communicator.utils.DialogFactory; import com.voximplant.sdk.Voximplant; -import com.voximplant.sdk.call.ICall; -import com.voximplant.sdk.call.IEndpoint; -import com.voximplant.sdk.call.IEndpointListener; import com.voximplant.sdk.call.IVideoStream; -import com.voximplant.sdk.call.RenderScaleType; import com.voximplant.sdk.hardware.ICameraEventsListener; import com.voximplant.sdk.hardware.ICameraManager; import com.voximplant.sdk.hardware.VideoQuality; @@ -35,11 +33,12 @@ import butterknife.BindView; import butterknife.OnClick; import timber.log.Timber; -public class CallActivity extends BaseActivity implements IEndpointListener, CallView, - ICameraEventsListener { +public class CallActivity extends BaseActivity implements CallView, ICameraEventsListener { private static final int FRONT_CAMERA = 1; private static final String USER_NAME_TAG = "username"; + private static final String INCOME = "income"; + private static final String WITH_VIDEO = "with_video"; private static final VideoQuality DEFAULT_VIDEO_QUALITY = VideoQuality.VIDEO_QUALITY_HIGH; //Base layouts for audio or video @BindView(R.id.audio_active_layout) ConstraintLayout audioIncomeLayout; @@ -60,12 +59,11 @@ public class CallActivity extends BaseActivity implements IEndpointListener, Cal @BindView(R.id.audio_active_hangup) ImageView audioHangUp; @BindView(R.id.audio_active_mute) ImageView audioMute; @BindView(R.id.audio_active_speaker) ImageView audioSpeaker; - @BindView(R.id.audio_active_text) ImageView audioText; - @BindView(R.id.audio_active_photo) ImageView userPhoto; @BindView(R.id.audio_active_duration) TextView audioDuration; @BindView(R.id.call_active_name) TextView name; @BindView(R.id.call_active_status) TextView status; + @BindView(R.id.call_active_user_photo) ImageView userPhoto; @BindView(R.id.audio_active_speaker_image) ImageView speakerImage; @BindView(R.id.audio_active_mute_image) ImageView muteImage; @@ -73,16 +71,25 @@ public class CallActivity extends BaseActivity implements IEndpointListener, Cal private int mCameraType = FRONT_CAMERA; private boolean mIsSpeakerPhoneEnabled; private ICameraManager mCameraManager; - private boolean mIsVideoEnabled; private boolean callInProgress; private boolean microActive = true; + private boolean withVideoIfCan = true; + private Contact mContact; - private IEndpoint mEndpoint; + public static Intent getLaunchIntent(Context context, String to, boolean withVideo) { + Intent intent = new Intent(context, CallActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + intent.putExtra(USER_NAME_TAG, to); + intent.putExtra(WITH_VIDEO, withVideo); + return intent; + } - public static Intent getLaunchIntent(Context context, String to) { + public static Intent getLaunchIntent(Context context, String to, boolean withVideo, boolean income) { Intent intent = new Intent(context, CallActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.putExtra(USER_NAME_TAG, to); + intent.putExtra(WITH_VIDEO, withVideo); + intent.putExtra(INCOME, income); return intent; } @@ -90,57 +97,59 @@ public class CallActivity extends BaseActivity implements IEndpointListener, Cal public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_call); - - mPresenter.getCall(); - if (getIntent() != null && getIntent().hasExtra(USER_NAME_TAG)) { - mPresenter.getUser(getIntent().getStringExtra(USER_NAME_TAG)); - } } - private void initUI() { - if (mIsVideoEnabled) { - mPresenter.sendVideo(true); - showVideo(); + @Override protected void onStart() { + super.onStart(); + if (getIntent() != null) { + mPresenter.loadUser(getIntent().getStringExtra(USER_NAME_TAG)); + startCall(getIntent().getBooleanExtra(INCOME, false)); + withVideoIfCan = getIntent().getBooleanExtra(WITH_VIDEO, true); + } + if (!withVideoIfCan) { + mPresenter.switchToAudio(); } else { - mPresenter.sendVideo(false); - showAudio(); + mPresenter.reloadVideo(); } } private void showVideo() { - videoViewLayout.setVisibility(View.VISIBLE); - - if (!mIsSpeakerPhoneEnabled) turnSpeaker(); //in case of starting call after callback + runOnUiThread(() -> { + if (!mIsSpeakerPhoneEnabled) turnSpeaker(); //in case of starting call after callback - videoLocal.setZOrderMediaOverlay(true); - mCameraManager = Voximplant.getCameraManager(this); + videoLocal.setZOrderMediaOverlay(true); + mCameraManager = Voximplant.getCameraManager(this); - if (callInProgress) { - videoIncomeLayout.setVisibility(View.VISIBLE); - videoOutgoingLayout.setVisibility(View.GONE); - name.setVisibility(View.GONE); - } else { - videoOutgoingLayout.setVisibility(View.VISIBLE); - } + if (callInProgress) { + videoIncomeLayout.setVisibility(View.VISIBLE); + videoOutgoingLayout.setVisibility(View.GONE); + name.setVisibility(View.GONE); + videoViewLayout.setVisibility(View.VISIBLE); + } else { + videoOutgoingLayout.setVisibility(View.VISIBLE); + videoViewLayout.setVisibility(View.GONE); + } + }); } private void showAudio() { - videoViewLayout.setVisibility(View.GONE); - videoIncomeLayout.setVisibility(View.GONE); - videoOutgoingLayout.setVisibility(View.GONE); + runOnUiThread(() -> { + videoViewLayout.setVisibility(View.GONE); + videoIncomeLayout.setVisibility(View.GONE); + videoOutgoingLayout.setVisibility(View.GONE); - if (callInProgress) { - audioIncomeLayout.setVisibility(View.VISIBLE); - name.setVisibility(View.VISIBLE ); - } else { - audioOutgoingLayout.setVisibility(View.VISIBLE); - } + if (callInProgress) { + audioIncomeLayout.setVisibility(View.VISIBLE); + name.setVisibility(View.VISIBLE); + } else { + audioOutgoingLayout.setVisibility(View.VISIBLE); + } + }); } - @OnClick({R.id.audio_active_hangup, R.id.video_active_hangup, R.id.audio_call_outgoing_hangup, R.id.video_outgoing_hangup}) void hangUp() { - mPresenter.hanUp(); + mPresenter.hangUp(); } @OnClick(R.id.video_active_switch_camera) @@ -159,6 +168,11 @@ public class CallActivity extends BaseActivity implements IEndpointListener, Cal mPresenter.speaker(mIsSpeakerPhoneEnabled); } + @OnClick({R.id.audio_active_text, R.id.video_active_chat}) + void openChat() { + mPresenter.openChat(mContact); + } + @Override public void onCameraSwitch() { mCameraType = (mCameraType == 0) ? 1 : 0; mCameraManager.setCamera(mCameraType, DEFAULT_VIDEO_QUALITY); @@ -183,104 +197,78 @@ public class CallActivity extends BaseActivity implements IEndpointListener, Cal microActive = audioWorking; } - @OnClick(R.id.video_active_switch_audio) + @OnClick({R.id.video_active_switch_audio, R.id.video_outcome_switch_audio}) void switchToAudio() { - if (videoViewLayout.getVisibility() == View.VISIBLE) { - mPresenter.sendVideo(true); - } else { - mPresenter.sendVideo(false); - } - } - @Override public void switchUi(boolean showVideo) { - runOnUiThread(() -> { - if (showVideo) { - mIsVideoEnabled = true; - showVideo(); - } else { - mIsVideoEnabled = false; - showAudio(); - turnSpeaker(); + if (callInProgress) { + mPresenter.switchToAudio(); + } else { + if (videoOutgoingLayout.getVisibility() == View.VISIBLE) { + videoOutgoingLayout.setVisibility(View.GONE); + audioOutgoingLayout.setVisibility(View.VISIBLE); } - }); - - } - - @Override public void fatality() { - finish(); - } - - @Override public void onCallSet(ICall call) { - if (!call.getEndpoints().isEmpty()) { - mIsVideoEnabled = call.isVideoEnabled(); - mEndpoint = call.getEndpoints().get(0); - mEndpoint.setEndpointListener(this); - startCall(); - initUI(); + mPresenter.switchToAudio(); } } - private void startCall() { - mPresenter.startCall(callInProgress); - audioDuration.setText("call connecting"); + private void startCall(boolean income) { + mPresenter.startCall(income); + status.setText("call connecting"); } - @Override public void onCallDisconnected() { - this.runOnUiThread(() -> audioDuration.setText("Call disconnected")); - + @Override public void onCallEnded() { + // status.setText("Call disconnected"); + runOnUiThread(this::finish); } @Override public void onCallConnected() { - this.runOnUiThread(() -> { - audioDuration.setText("call in progress"); - callInProgress = true; - initUI(); - }); + runOnUiThread(() -> callInProgress = true); } @Override public void onCallRinging() { - this.runOnUiThread(() -> audioDuration.setText("Call ringing")); + runOnUiThread(() -> status.setText("Ringing...")); } @Override public void onCallFailed(String description) { - this.runOnUiThread(() -> DialogFactory.showAlert(CallActivity.this, "Reason: " + description, "Call Failed", dialog -> CallActivity.this.finish())); + runOnUiThread(() -> DialogFactory.showAlert(CallActivity.this, "Reason: " + description, "Call Failed", dialog -> CallActivity.this.finish())); } @Override public void callTimeUpdated(String time) { runOnUiThread(() -> { - if (mIsVideoEnabled) { + if (videoViewLayout.getVisibility() == View.VISIBLE) { videoDuration.setText(time); } else { - audioDuration.setText(getString(R.string.call_voice_call, time)); + String text = withVideoIfCan ? getString(R.string.video_call) + : getString(R.string.call_voice_call, time); + status.setText(text); } }); } @Override public void setUser(Contact contact) { + mContact = contact; if (contact != null) { name.setText(contact.getFullName()); + Glide.with(this).load(contact.avatar).placeholder(R.drawable.avatar_placeholder).into(userPhoto); } } @Override public void onLocalVideoStreamAdded(IVideoStream videoStream, boolean added) { if (added) { - videoStream.addVideoRenderer(videoLocal, RenderScaleType.SCALE_FIT); + videoStream.addVideoRenderer(videoLocal, VoxImplantModule.RENDER_TYPE); } else { videoStream.removeVideoRenderer(videoLocal); } } - @Override - public void onRemoteVideoStreamAdded(IEndpoint endpoint, IVideoStream videoStream) { - videoStream.addVideoRenderer(videoRemote, RenderScaleType.SCALE_FIT); + @Override public void onRemoteVideoStreamAdded(IVideoStream iVideoStream) { + iVideoStream.addVideoRenderer(videoRemote, VoxImplantModule.RENDER_TYPE); } - @Override - public void onRemoteVideoStreamRemoved(IEndpoint endpoint, IVideoStream videoStream) { - videoStream.removeVideoRenderer(videoRemote); + @Override public void onRemoteVideoStreamRemoved(IVideoStream iVideoStream) { + iVideoStream.removeVideoRenderer(videoRemote); } - //Callback for camera events @Override public void onCameraError(String s) { Timber.e(s); @@ -297,4 +285,31 @@ public class CallActivity extends BaseActivity implements IEndpointListener, Cal @Override public void onCameraSwitchError(String s) { Timber.e("Camera switch error"); } + + @Override public void audioCall() { + showAudio(); + } + + @Override public void videoCall() { + showVideo(); + } + + @Override public void activeAudioCall() { + callInProgress = true; + showAudio(); + } + + @Override public void activeVideoCall() { + callInProgress = true; + showVideo(); + } + + @Override public void showInternetError() { + + } + + @Override protected void onDestroy() { + super.onDestroy(); + Timber.e("onDestroy"); + } } diff --git a/app/src/main/java/com/nynja/mobile/communicator/ui/activities/calls/IncomeCallActivity.java b/app/src/main/java/com/nynja/mobile/communicator/ui/activities/calls/IncomeCallActivity.java index 10dbac5b9d952e6fd607beb843ddfecdc018c107..7349f0c3516846898868874b5eb6bb72765eb0f3 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/ui/activities/calls/IncomeCallActivity.java +++ b/app/src/main/java/com/nynja/mobile/communicator/ui/activities/calls/IncomeCallActivity.java @@ -15,7 +15,6 @@ import com.nynja.mobile.communicator.data.models.mqtt.Contact; import com.nynja.mobile.communicator.mvp.presenters.IncomeCallPresenter; import com.nynja.mobile.communicator.mvp.view.IncomeCallView; import com.nynja.mobile.communicator.ui.base.BaseActivity; -import com.voximplant.sdk.call.ICall; import butterknife.BindView; import butterknife.OnClick; @@ -30,8 +29,8 @@ public class IncomeCallActivity extends BaseActivity implements IncomeCallView { @InjectPresenter IncomeCallPresenter mPresenter; - private ICall mCall; private String mUserName; + boolean hasVideo; public static Intent getLaunchIntent(Context context) { Intent intent = new Intent(context, IncomeCallActivity.class); @@ -39,7 +38,7 @@ public class IncomeCallActivity extends BaseActivity implements IncomeCallView { return intent; } - private void initUI(boolean hasVideo) { + private void initUI() { if (hasVideo) { callStatus.setText(R.string.call_incoming_video); videoLayout.setVisibility(View.VISIBLE); @@ -52,7 +51,6 @@ public class IncomeCallActivity extends BaseActivity implements IncomeCallView { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_voice_call); - initIncomeCall(); } @OnClick({R.id.voice_call_income_accept, R.id.video_income_accept}) @@ -71,52 +69,45 @@ public class IncomeCallActivity extends BaseActivity implements IncomeCallView { mPresenter.answerCall(false); } - private void initIncomeCall() { - mPresenter.geCall(); - } - @Override public void onCallDisconnected() { finish(); } @Override public void onAnswerCall(boolean withVideoIfCan) { - if (mCall != null) { - if (mCall.getEndpoints() != null && !mCall.getEndpoints().isEmpty()) { - mUserName = mCall.getEndpoints().get(0).getUserName(); - } - if (mCall.isVideoEnabled()) { - mRxPermissions.request(Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA) - .subscribe(granted -> { - if (granted) { - startActivity(CallActivity.getLaunchIntent(IncomeCallActivity.this, mUserName)); - } - finish(); - }); - } else { - mRxPermissions.request(Manifest.permission.RECORD_AUDIO) - .subscribe(granted -> { - if (granted) { - startActivity(CallActivity.getLaunchIntent(IncomeCallActivity.this, mUserName)); - } - finish(); - }); - } + if (hasVideo && withVideoIfCan) { + mRxPermissions.request(Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA) + .subscribe(granted -> { + if (granted) { + startActivity(CallActivity.getLaunchIntent(IncomeCallActivity.this, mUserName, withVideoIfCan, true)); + } + finish(); + }); } else { - finish(); + mRxPermissions.request(Manifest.permission.RECORD_AUDIO) + .subscribe(granted -> { + if (granted) { + startActivity(CallActivity.getLaunchIntent(IncomeCallActivity.this, mUserName, withVideoIfCan, true)); + } + finish(); + }); } + finish(); } @Override public void hasVideo(boolean video) { - initUI(video); + hasVideo = video; + initUI(); } - @Override public void setCall(ICall call, Contact contact) { - mCall = call; + @Override public void setCall(Contact contact) { if (contact != null) { callFrom.setText(contact.getFullName()); + mUserName = contact.person_id; Glide.with(this).load(contact.avatar).placeholder(R.drawable.contact_placeholder).into(userAvatar); - } else if (call != null && call.getEndpoints() != null) { - callFrom.setText(call.getEndpoints().get(0).getUserName()); } } + + @Override public void showInternetError() { + + } } diff --git a/app/src/main/java/com/nynja/mobile/communicator/ui/fragments/chats/ChatFragment.java b/app/src/main/java/com/nynja/mobile/communicator/ui/fragments/chats/ChatFragment.java index 9bcbe3098443df2900e66002754ed4fccaa7e206..04b03f21fe801bd46b11368d074817c2ff78a0e3 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/ui/fragments/chats/ChatFragment.java +++ b/app/src/main/java/com/nynja/mobile/communicator/ui/fragments/chats/ChatFragment.java @@ -259,6 +259,8 @@ public class ChatFragment extends BaseFragment implements ChatView, @Override public void newMessage(Message message) { mAdapter.addItem(message); mRecyclerView.scrollToPosition(mAdapter.getItemCount() - 1); + + } @Override public void navigateToGallery() { diff --git a/app/src/main/java/com/nynja/mobile/communicator/ui/views/CascadeWheel.java b/app/src/main/java/com/nynja/mobile/communicator/ui/views/CascadeWheel.java index 9618dd836be130aa31bd91603bd9fc8e7bd42fc8..598638444e5a2d6c03d56607cc1c1f9135e9314c 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/ui/views/CascadeWheel.java +++ b/app/src/main/java/com/nynja/mobile/communicator/ui/views/CascadeWheel.java @@ -75,7 +75,6 @@ public class CascadeWheel extends FrameLayout implements MenuButton.OnMenuClickL mAlphabetView.setOnLetterChangeListener(new AlphabetView.OnAlphabetCharChangeListener() { @Override public void onAlphabetCharChanged(char currentLetter, char previousLetter) { -// mSecondWheel.setSelected(currentLetter); if (mOnAlphabetCharChangeListener != null) { mOnAlphabetCharChangeListener.onAlphabetCharStarted(currentLetter); } @@ -86,7 +85,6 @@ public class CascadeWheel extends FrameLayout implements MenuButton.OnMenuClickL if (mOnAlphabetCharChangeListener != null) { mOnAlphabetCharChangeListener.onAlphabetCharStarted(selectedLetter); } -// mSecondWheel.setSelected(selectedLetter); } }); setLayerType(LAYER_TYPE_HARDWARE, null); diff --git a/app/src/main/java/com/nynja/mobile/communicator/utils/FileUtils.java b/app/src/main/java/com/nynja/mobile/communicator/utils/FileUtils.java index 81f1140f6d90b25366e16a7a2a411916cfba7a73..f8bb37898cc9c716a64c5e5574e3c338b0188c58 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/utils/FileUtils.java +++ b/app/src/main/java/com/nynja/mobile/communicator/utils/FileUtils.java @@ -96,7 +96,7 @@ public class FileUtils { * @return The value of the _data column, which is typically a file path. */ private static String getDataColumn(Context context, Uri uri, String selection, - String[] selectionArgs) { + String[] selectionArgs) { Cursor cursor = null; final String column = "_data"; diff --git a/app/src/main/java/com/nynja/mobile/communicator/utils/Utils.java b/app/src/main/java/com/nynja/mobile/communicator/utils/Utils.java index 2b3b45c20074f61eec4ed906350f8cd45fb72d2e..2eba7a5f75def6a4598d415cce774b06309ac5aa 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/utils/Utils.java +++ b/app/src/main/java/com/nynja/mobile/communicator/utils/Utils.java @@ -80,7 +80,7 @@ public class Utils { } } - public static String getRecordCurrentTime(int milliseconds) { + public static String getRecordCurrentTime(int milliseconds) { String minutesString; String secondsString; diff --git a/app/src/main/res/drawable-hdpi/incoming_light.png b/app/src/main/res/drawable-hdpi/incoming_light.png new file mode 100644 index 0000000000000000000000000000000000000000..c3397214b6ac1241d4c35a5d29a3b1d08d8279dd Binary files /dev/null and b/app/src/main/res/drawable-hdpi/incoming_light.png differ diff --git a/app/src/main/res/drawable-hdpi/maximize.png b/app/src/main/res/drawable-hdpi/maximize.png new file mode 100644 index 0000000000000000000000000000000000000000..e6696fd8375e11915b5608d8db8f6a5e2d9c2b39 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/maximize.png differ diff --git a/app/src/main/res/drawable-hdpi/minimize.png b/app/src/main/res/drawable-hdpi/minimize.png new file mode 100644 index 0000000000000000000000000000000000000000..382e26ed13497c21dc13d6a1b3b00a18b203fcfe Binary files /dev/null and b/app/src/main/res/drawable-hdpi/minimize.png differ diff --git a/app/src/main/res/drawable-mdpi/incoming_light.png b/app/src/main/res/drawable-mdpi/incoming_light.png new file mode 100644 index 0000000000000000000000000000000000000000..0495f81c40362a0d126abd94aa6f203c7b95780c Binary files /dev/null and b/app/src/main/res/drawable-mdpi/incoming_light.png differ diff --git a/app/src/main/res/drawable-mdpi/maximize.png b/app/src/main/res/drawable-mdpi/maximize.png new file mode 100644 index 0000000000000000000000000000000000000000..a7fb366fe348b2c4f8a96410423696421c294732 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/maximize.png differ diff --git a/app/src/main/res/drawable-mdpi/minimize.png b/app/src/main/res/drawable-mdpi/minimize.png new file mode 100644 index 0000000000000000000000000000000000000000..a42d9dc9e25755e99cb28743e8b2e8a369828c1e Binary files /dev/null and b/app/src/main/res/drawable-mdpi/minimize.png differ diff --git a/app/src/main/res/drawable-xhdpi/incoming_light.png b/app/src/main/res/drawable-xhdpi/incoming_light.png new file mode 100644 index 0000000000000000000000000000000000000000..46796cec2664945eed3d46acf2dae1f6d291fad8 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/incoming_light.png differ diff --git a/app/src/main/res/drawable-xhdpi/maximize.png b/app/src/main/res/drawable-xhdpi/maximize.png new file mode 100644 index 0000000000000000000000000000000000000000..b31b6ab84199a5c0102f957745a72eae836f9b3d Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/maximize.png differ diff --git a/app/src/main/res/drawable-xhdpi/minimize.png b/app/src/main/res/drawable-xhdpi/minimize.png new file mode 100644 index 0000000000000000000000000000000000000000..b778a9e396ee4ce60aa3b171fcfbb726445b1581 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/minimize.png differ diff --git a/app/src/main/res/drawable-xxhdpi/incoming_light.png b/app/src/main/res/drawable-xxhdpi/incoming_light.png new file mode 100644 index 0000000000000000000000000000000000000000..6d953d073869484cb51298c710719e6e30169a7b Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/incoming_light.png differ diff --git a/app/src/main/res/drawable-xxhdpi/maximize.png b/app/src/main/res/drawable-xxhdpi/maximize.png new file mode 100644 index 0000000000000000000000000000000000000000..2b46db930b7ab2e8996d534af8b149322c69612b Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/maximize.png differ diff --git a/app/src/main/res/drawable-xxhdpi/minimize.png b/app/src/main/res/drawable-xxhdpi/minimize.png new file mode 100644 index 0000000000000000000000000000000000000000..83829fd7ac56a88439e59fbaa4cfc204d8106e87 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/minimize.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/incoming_light.png b/app/src/main/res/drawable-xxxhdpi/incoming_light.png new file mode 100644 index 0000000000000000000000000000000000000000..895432462e5b4e5b3a794b053a404afb43a331d1 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/incoming_light.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/maximize.png b/app/src/main/res/drawable-xxxhdpi/maximize.png new file mode 100644 index 0000000000000000000000000000000000000000..0a19b6b64984e85556551fc10e0e07a70327edc6 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/maximize.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/minimize.png b/app/src/main/res/drawable-xxxhdpi/minimize.png new file mode 100644 index 0000000000000000000000000000000000000000..8d20019ec3d129a824ff973acdcbff7e320ff0a4 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/minimize.png differ diff --git a/app/src/main/res/drawable/ic_featured_video.xml b/app/src/main/res/drawable/ic_featured_video.xml new file mode 100644 index 0000000000000000000000000000000000000000..a7da6f33c4a3d9caa6c2b0c2690d7e1714965aff --- /dev/null +++ b/app/src/main/res/drawable/ic_featured_video.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/shape_rectangle_grey.xml b/app/src/main/res/drawable/shape_rectangle_grey.xml index 107e69516ec438c6e669891b082cf71fdaccb3de..373ed8a5b4529f1e1c4e89bb1393fbdf39994491 100644 --- a/app/src/main/res/drawable/shape_rectangle_grey.xml +++ b/app/src/main/res/drawable/shape_rectangle_grey.xml @@ -1,12 +1,13 @@ - + + android:topRightRadius="0dp" /> - + \ No newline at end of file diff --git a/app/src/main/res/drawable/v_play_red.xml b/app/src/main/res/drawable/v_play_red.xml index 333be5c8091da26587d71c401de0700b34f30e1d..62d12c854b204b0d37e411bf4d45c36a16f08c90 100644 --- a/app/src/main/res/drawable/v_play_red.xml +++ b/app/src/main/res/drawable/v_play_red.xml @@ -1,9 +1,9 @@ + android:width="38dp" + android:height="38dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + android:pathData="M8,5v14l11,-7z" /> diff --git a/app/src/main/res/drawable/v_stop_red.xml b/app/src/main/res/drawable/v_stop_red.xml index 65ca6314b26481dc9c62519904e9028794249644..f63a0a871654fb9cb6508bae3a766070dffd616e 100644 --- a/app/src/main/res/drawable/v_stop_red.xml +++ b/app/src/main/res/drawable/v_stop_red.xml @@ -1,9 +1,9 @@ + android:width="38dp" + android:height="38dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + android:pathData="M6,6h12v12H6z" /> diff --git a/app/src/main/res/layout/activity_call.xml b/app/src/main/res/layout/activity_call.xml index 158a83d13bdbcf3faabbc5201c902b63fef6f923..7fb8a6041799cd068905af8e53dc358af7533701 100644 --- a/app/src/main/res/layout/activity_call.xml +++ b/app/src/main/res/layout/activity_call.xml @@ -6,11 +6,21 @@ android:layout_height="match_parent" android:orientation="vertical"> + + - + app:layout_constraintTop_toTopOf="parent" /> - - - - - - - - - - + app:layout_constraintTop_toTopOf="parent" /> - - - - + app:layout_constraintTop_toTopOf="parent" /> - - - - - - - + app:layout_constraintTop_toTopOf="parent" /> diff --git a/app/src/main/res/layout/activity_home.xml b/app/src/main/res/layout/activity_home.xml index d0c06df4518ddc194dcea73022bc1e8cc0bc9680..ce610aaa94de638351406d0007f3076715965a7a 100644 --- a/app/src/main/res/layout/activity_home.xml +++ b/app/src/main/res/layout/activity_home.xml @@ -9,8 +9,23 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/li_chat_my_audio_message.xml b/app/src/main/res/layout/li_chat_my_audio_message.xml index 18ce294e4355642cde528b63881312f28be4f82d..0d27638460a9fb8a62431d3f7bef2b3fc2e8cc8b 100644 --- a/app/src/main/res/layout/li_chat_my_audio_message.xml +++ b/app/src/main/res/layout/li_chat_my_audio_message.xml @@ -3,9 +3,9 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginEnd="24dp" - android:layout_marginStart="51dp"> + android:layout_height="wrap_content" + android:layout_marginEnd="24dp" + android:layout_marginStart="51dp"> + tools:ignore="ContentDescription" /> + android:visibility="gone" /> @@ -51,7 +51,7 @@ android:id="@+id/li_chat_my_wave" android:layout_width="140dp" android:layout_height="35dp" - app:wf_waveProgressColor="@color/colorAccent"/> + app:wf_waveProgressColor="@color/colorAccent" /> + tools:text="11:20 am" /> @@ -75,7 +75,7 @@ android:text="@string/chat.text.audio.default_time" android:textColor="@android:color/black" android:textSize="10sp" - tools:ignore="SmallSp"/> + tools:ignore="SmallSp" /> diff --git a/app/src/main/res/layout/li_chat_other_audio_message.xml b/app/src/main/res/layout/li_chat_other_audio_message.xml index b62cfebd201fe5ee5ecf10ddb4bb9d6b894a43f3..33cb65b5fd21616f5b4f2f78f5e1ea828c6ccbc3 100644 --- a/app/src/main/res/layout/li_chat_other_audio_message.xml +++ b/app/src/main/res/layout/li_chat_other_audio_message.xml @@ -2,10 +2,10 @@ + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginEnd="51dp" + android:layout_marginStart="24dp"> + android:layout_gravity="center" /> + tools:ignore="ContentDescription" /> @@ -45,17 +45,17 @@ android:paddingTop="6dp"> + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical" + android:padding="4dp"> + app:wf_waveProgressColor="@color/colorAccent" /> + tools:text="11:20 am" /> @@ -80,7 +80,7 @@ android:textColor="@android:color/black" android:textSize="10sp" tools:ignore="SmallSp" - tools:text="00:12"/> + tools:text="00:12" /> diff --git a/app/src/main/res/layout/partial_audio_active.xml b/app/src/main/res/layout/partial_audio_active.xml index 5c2207143dfe46ebe926bb7f21b2b939d3b27186..4a3099681dd1fba2cdf282a024bcfb4c5cff78e2 100644 --- a/app/src/main/res/layout/partial_audio_active.xml +++ b/app/src/main/res/layout/partial_audio_active.xml @@ -17,16 +17,6 @@ app:layout_constraintTop_toTopOf="parent" tools:text="Name" /> - - + app:layout_constraintRight_toRightOf="parent" + android:padding="18dp" /> + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/partial_chat_footer_audiogram.xml b/app/src/main/res/layout/partial_chat_footer_audiogram.xml index 359055243bdcfd91f07e67559b916d05e9093bd4..c24d25dea16537e94ba72ae51f0f9c197ca903eb 100644 --- a/app/src/main/res/layout/partial_chat_footer_audiogram.xml +++ b/app/src/main/res/layout/partial_chat_footer_audiogram.xml @@ -44,7 +44,7 @@ android:gravity="center_vertical" android:layout_toEndOf="@+id/f_chat_img_play" android:layout_toStartOf="@+id/f_chat_send_audio" - app:wf_waveProgressColor="@color/colorAccent"/> + app:wf_waveProgressColor="@color/colorAccent" /> + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e9da7d6032e963264a3d82557129c4900b6a44c6..37344e00b7caf4f0c1dcfd8f6249927fa8085144 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -107,6 +107,7 @@ 00:00:00 00:00 Unread + Return to call