├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values-v21
│ │ │ │ └── styles.xml
│ │ │ ├── raw
│ │ │ │ └── skype_call.mp3
│ │ │ ├── drawable
│ │ │ │ ├── browser.png
│ │ │ │ ├── useradd.png
│ │ │ │ ├── camera_off.png
│ │ │ │ ├── ic_pubrtc.png
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_action_call.png
│ │ │ │ ├── ic_action_end_call.png
│ │ │ │ ├── ic_action_send_now.png
│ │ │ │ ├── light_fade_down.xml
│ │ │ │ ├── light_fade_up.xml
│ │ │ │ ├── round_button.xml
│ │ │ │ └── round_button_send.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── values
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── colors.xml
│ │ │ │ ├── styles.xml
│ │ │ │ └── strings.xml
│ │ │ ├── menu
│ │ │ │ └── menu_rtc.xml
│ │ │ ├── values-w820dp
│ │ │ │ └── dimens.xml
│ │ │ └── layout
│ │ │ │ ├── chat_message_row_layout.xml
│ │ │ │ ├── user_row_layout.xml
│ │ │ │ ├── activity_calling.xml
│ │ │ │ ├── notification_video_calling.xml
│ │ │ │ ├── notification_incoming_call.xml
│ │ │ │ ├── activity_incoming_call.xml
│ │ │ │ ├── activity_main.xml
│ │ │ │ ├── history_row_layout.xml
│ │ │ │ ├── main.xml
│ │ │ │ ├── activity_login.xml
│ │ │ │ └── content_register.xml
│ │ ├── java
│ │ │ └── fr
│ │ │ │ └── pchab
│ │ │ │ └── androidrtc
│ │ │ │ ├── Model
│ │ │ │ ├── ChatMessage.java
│ │ │ │ ├── User.java
│ │ │ │ └── HistoryItem.java
│ │ │ │ ├── Adapter
│ │ │ │ ├── HistoryAdapter.java
│ │ │ │ ├── UserAdapter.java
│ │ │ │ └── ChatAdapter.java
│ │ │ │ ├── IncomingCallActivity.java
│ │ │ │ ├── CallingActivity.java
│ │ │ │ ├── RegisterActivity.java
│ │ │ │ ├── LoginActivity.java
│ │ │ │ ├── RtcActivity.java
│ │ │ │ └── MainActivity.java
│ │ └── AndroidManifest.xml
│ └── androidTest
│ │ └── java
│ │ └── fr
│ │ └── pchab
│ │ └── androidrtc
│ │ └── ApplicationTest.java
├── build.gradle
├── proguard-rules.pro
└── app.iml
├── .idea
├── .name
├── copyright
│ └── profiles_settings.xml
├── vcs.xml
├── modules.xml
├── runConfigurations.xml
├── gradle.xml
├── compiler.xml
└── misc.xml
├── webrtc-client
├── .gitignore
├── src
│ ├── androidTest
│ │ └── java
│ │ │ └── fr
│ │ │ └── pchab
│ │ │ └── webrtcclient
│ │ │ └── ApplicationTest.java
│ └── main
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── fr
│ │ └── pchab
│ │ └── webrtcclient
│ │ ├── PeerConnectionParameters.java
│ │ └── WebRtcClient.java
├── build.gradle
├── proguard-rules.pro
├── webrtc-client.iml
└── app.iml
├── settings.gradle
├── markdown_img
├── img1.png
├── img2.png
├── img3.png
├── img4.png
├── img5.png
├── img6.png
├── img7.png
└── img8.png
├── .gitignore
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── DANG KY XET GIAI THUONG HCM VE KHCN.docx
├── LICENSE.txt
├── AndroidRTC.iml
├── gradle.properties
├── AndroidRTC-android-studio 2.iml
├── README.md
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | AndroidRTC-android-studio 2
--------------------------------------------------------------------------------
/webrtc-client/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':webrtc-client'
2 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 | >
2 |
3 |
--------------------------------------------------------------------------------
/markdown_img/img1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minhdl93/webrtc_client/HEAD/markdown_img/img1.png
--------------------------------------------------------------------------------
/markdown_img/img2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minhdl93/webrtc_client/HEAD/markdown_img/img2.png
--------------------------------------------------------------------------------
/markdown_img/img3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minhdl93/webrtc_client/HEAD/markdown_img/img3.png
--------------------------------------------------------------------------------
/markdown_img/img4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minhdl93/webrtc_client/HEAD/markdown_img/img4.png
--------------------------------------------------------------------------------
/markdown_img/img5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minhdl93/webrtc_client/HEAD/markdown_img/img5.png
--------------------------------------------------------------------------------
/markdown_img/img6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minhdl93/webrtc_client/HEAD/markdown_img/img6.png
--------------------------------------------------------------------------------
/markdown_img/img7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minhdl93/webrtc_client/HEAD/markdown_img/img7.png
--------------------------------------------------------------------------------
/markdown_img/img8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minhdl93/webrtc_client/HEAD/markdown_img/img8.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | /.idea/libraries
5 | .DS_Store
6 | /build
7 | *~
8 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/raw/skype_call.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minhdl93/webrtc_client/HEAD/app/src/main/res/raw/skype_call.mp3
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minhdl93/webrtc_client/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/drawable/browser.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minhdl93/webrtc_client/HEAD/app/src/main/res/drawable/browser.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/useradd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minhdl93/webrtc_client/HEAD/app/src/main/res/drawable/useradd.png
--------------------------------------------------------------------------------
/DANG KY XET GIAI THUONG HCM VE KHCN.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minhdl93/webrtc_client/HEAD/DANG KY XET GIAI THUONG HCM VE KHCN.docx
--------------------------------------------------------------------------------
/app/src/main/res/drawable/camera_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minhdl93/webrtc_client/HEAD/app/src/main/res/drawable/camera_off.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_pubrtc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minhdl93/webrtc_client/HEAD/app/src/main/res/drawable/ic_pubrtc.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minhdl93/webrtc_client/HEAD/app/src/main/res/drawable/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_call.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minhdl93/webrtc_client/HEAD/app/src/main/res/drawable/ic_action_call.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minhdl93/webrtc_client/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minhdl93/webrtc_client/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minhdl93/webrtc_client/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minhdl93/webrtc_client/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minhdl93/webrtc_client/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_end_call.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minhdl93/webrtc_client/HEAD/app/src/main/res/drawable/ic_action_end_call.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_send_now.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minhdl93/webrtc_client/HEAD/app/src/main/res/drawable/ic_action_send_now.png
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 16dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #d02129
4 | #ff19a2c6
5 | #ff187998
6 | #FFF
7 | #ff1ce322
8 | #eee
9 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_rtc.xml:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/light_fade_down.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/light_fade_up.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/fr/pchab/androidrtc/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package fr.pchab.androidrtc;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/webrtc-client/src/androidTest/java/fr/pchab/webrtcclient/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package fr.pchab.webrtcclient;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/round_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
10 |
11 |
15 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright 2014 Pierre Chabardes
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/webrtc-client/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 |
4 | android {
5 | compileSdkVersion 22
6 | buildToolsVersion "22.0.0"
7 |
8 | defaultConfig {
9 | minSdkVersion 15
10 | targetSdkVersion 22
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile 'com.github.nkzawa:socket.io-client:0.4.2'
24 | compile 'io.pristine:libjingle:11139@aar'
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/round_button_send.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
14 |
15 |
19 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 22
5 | buildToolsVersion "22.0.0"
6 |
7 | defaultConfig {
8 | applicationId "fr.pchab.androidrtc"
9 | minSdkVersion 15
10 | targetSdkVersion 22
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile project(':webrtc-client')
24 | compile 'com.android.support:appcompat-v7:22.2.1'
25 | compile 'com.android.support:design:22.2.1'
26 | }
27 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /home/pierre/Workspace/src/chromium/src/third_party/android_tools/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/webrtc-client/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /home/pierre/Workspace/src/chromium/src/third_party/android_tools/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/webrtc-client/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/java/fr/pchab/androidrtc/Model/ChatMessage.java:
--------------------------------------------------------------------------------
1 | package fr.pchab.androidrtc.Model;
2 |
3 | /**
4 | * Created by gumiMinh on 4/6/16.
5 | */
6 | public class ChatMessage {
7 | private String sender;
8 | private String message;
9 | private long timeStamp;
10 |
11 | public ChatMessage(String sender, String message, long timeStamp){
12 | this.sender = sender;
13 | this.message = message;
14 | this.timeStamp=timeStamp;
15 | }
16 |
17 | public String getSender() {
18 | return sender;
19 | }
20 |
21 | public String getMessage() {
22 | return message;
23 | }
24 |
25 | public long getTimeStamp() {
26 | return timeStamp;
27 | }
28 |
29 | @Override
30 | public int hashCode() {
31 | return (this.sender + this.message + this.timeStamp).hashCode();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/AndroidRTC.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/app/src/main/java/fr/pchab/androidrtc/Model/User.java:
--------------------------------------------------------------------------------
1 | package fr.pchab.androidrtc.Model;
2 |
3 | /**
4 | * Created by gumiMinh on 4/11/16.
5 | */
6 | public class User {
7 | private String userId;
8 | private String userName;
9 |
10 | public User(String userId,String userName) {
11 | this.userId = userId;
12 | this.userName = userName;
13 | }
14 |
15 |
16 | public String getUserId() {
17 | return userId;
18 | }
19 | public String getUserName() {
20 | return userName;
21 | }
22 |
23 |
24 | @Override
25 | public boolean equals(Object o) {
26 | if (this==o) return true;
27 | if (!(o instanceof HistoryItem)) return false;
28 | HistoryItem cu = (HistoryItem)o;
29 | return this.userId.equals(((HistoryItem) o).getUserId());
30 | }
31 |
32 | @Override
33 | public int hashCode() {
34 | return this.getUserId().hashCode();
35 | }
36 | }
--------------------------------------------------------------------------------
/AndroidRTC-android-studio 2.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/java/fr/pchab/androidrtc/Model/HistoryItem.java:
--------------------------------------------------------------------------------
1 | package fr.pchab.androidrtc.Model;
2 |
3 | /**
4 | * Created by gumiMinh on 4/11/16.
5 | */
6 | public class HistoryItem {
7 | private String userId;
8 | private String status;
9 | private String userName;
10 |
11 | public HistoryItem(String userId,String userName) {
12 | this.userId = userId;
13 | this.userName = userName;
14 | this.status = "Offline";
15 | }
16 |
17 | public HistoryItem(String userId,String userName, String status) {
18 | this.userId = userId;
19 | this.userName = userName;
20 | this.status = status;
21 | }
22 |
23 | public String getUserId() {
24 | return userId;
25 | }
26 | public String getUserName() {
27 | return userName;
28 | }
29 |
30 | public String getStatus() {
31 | return status;
32 | }
33 |
34 | public void setStatus(String status) {
35 | this.status = status;
36 | }
37 |
38 | @Override
39 | public boolean equals(Object o) {
40 | if (this==o) return true;
41 | if (!(o instanceof HistoryItem)) return false;
42 | HistoryItem cu = (HistoryItem)o;
43 | return this.userId.equals(((HistoryItem) o).getUserId());
44 | }
45 |
46 | @Override
47 | public int hashCode() {
48 | return this.getUserId().hashCode();
49 | }
50 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/chat_message_row_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
13 |
20 |
21 |
28 |
29 |
30 |
31 |
32 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/webrtc-client/src/main/java/fr/pchab/webrtcclient/PeerConnectionParameters.java:
--------------------------------------------------------------------------------
1 | package fr.pchab.webrtcclient;
2 |
3 | public class PeerConnectionParameters {
4 | public final boolean videoCallEnabled;
5 | public final boolean loopback;
6 | public final int videoWidth;
7 | public final int videoHeight;
8 | public final int videoFps;
9 | public final int videoStartBitrate;
10 | public final String videoCodec;
11 | public final boolean videoCodecHwAcceleration;
12 | public final int audioStartBitrate;
13 | public final String audioCodec;
14 | public final boolean cpuOveruseDetection;
15 | public PeerConnectionParameters(
16 | boolean videoCallEnabled, boolean loopback,
17 | int videoWidth, int videoHeight, int videoFps, int videoStartBitrate,
18 | String videoCodec, boolean videoCodecHwAcceleration,
19 | int audioStartBitrate, String audioCodec,
20 | boolean cpuOveruseDetection) {
21 | this.videoCallEnabled = videoCallEnabled;
22 | this.loopback = loopback;
23 | this.videoWidth = videoWidth;
24 | this.videoHeight = videoHeight;
25 | this.videoFps = videoFps;
26 | this.videoStartBitrate = videoStartBitrate;
27 | this.videoCodec = videoCodec;
28 | this.videoCodecHwAcceleration = videoCodecHwAcceleration;
29 | this.audioStartBitrate = audioStartBitrate;
30 | this.audioCodec = audioCodec;
31 | this.cpuOveruseDetection = cpuOveruseDetection;
32 | }
33 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Demo chat and call
4 |
5 |
6 | dev.gumiviet.com
7 | 300
8 | Options
9 | Demo chat and call
10 | No friends
11 |
12 | Username
13 | Password
14 | Sign in
15 | Register
16 | Name
17 | Phone
18 | Back to login
19 | Incoming Call…
20 | Kevin Gleason
21 | Chat Video
22 | This email address is invalid
23 | This password is too short
24 | This password is incorrect
25 | This field is required
26 | "Contacts permissions are needed for providing email
27 | completions."
28 |
29 | RegisterActivity
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/user_row_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
17 |
18 |
24 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_calling.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
16 |
17 |
22 |
23 |
33 |
34 |
38 |
39 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/notification_video_calling.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
13 |
19 |
27 |
33 |
41 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/notification_incoming_call.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
13 |
19 |
20 |
21 |
28 |
34 |
35 |
42 |
48 |
49 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # WebRTC android client -
2 | Core forked from https://github.com/pchab/AndroidRTC
3 | GUI forked from https://github.com/GleasonK/AndroidRTC
4 |
5 | An Android client for [webrtc_server](https://github.com/DangLienMinh/webrtc_server).
6 |
7 | It is designed to demonstrate WebRTC video calls between androids clients.
8 |
9 | ## How To
10 |
11 | You need [webrtc_server](https://github.com/DangLienMinh/webrtc_server) up and running on port 3000, and it must be somewhere that your android can access. Modify the host string (in res/values/strings.xml) to the server IP.
12 |
13 | #Result screen
14 |
15 | #Login
16 |
17 | 
18 |
19 | #Register
20 |
21 | 
22 |
23 | #Main screen
24 |
25 | 
26 |
27 | #Add friend screen (search name and click the plus icon)
28 |
29 | 
30 |
31 | #When the people is online the status will change from offline to online
32 |
33 | 
34 |
35 | #Incoming call when someone calls you
36 |
37 | 
38 |
39 | #Two clients start to chat with other
40 |
41 | 
42 |
43 | #The chat between two users
44 |
45 | 
46 |
47 |
48 | ## Libraries
49 |
50 | ### [libjingle peerconnection](https://code.google.com/p/webrtc/)
51 | ### [socket.io-client](https://github.com/nkzawa/socket.io-client.java)
52 |
53 | ## Author
54 |
55 | - [Minh Dang](mailto:danglienminh93@gmail.com)
56 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_incoming_call.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
16 |
17 |
22 |
23 |
33 |
34 |
38 |
39 |
46 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
12 |
13 |
22 |
23 |
28 |
29 |
30 |
31 |
40 |
41 |
48 |
49 |
50 |
51 |
55 |
56 |
60 |
61 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/history_row_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
17 |
18 |
25 |
26 |
27 |
31 |
32 |
41 |
42 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
66 |
67 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
17 |
21 |
22 |
23 |
24 |
33 |
34 |
43 |
44 |
48 |
49 |
57 |
58 |
59 |
60 |
61 |
62 |
74 |
75 |
84 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
37 |
38 |
39 |
45 |
46 |
47 |
48 |
49 |
50 |
53 |
54 |
55 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_login.xml:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
21 |
22 |
26 |
27 |
32 |
33 |
36 |
37 |
45 |
46 |
47 |
48 |
51 |
52 |
63 |
64 |
65 |
66 |
67 |
75 |
76 |
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/app/src/main/java/fr/pchab/androidrtc/Adapter/HistoryAdapter.java:
--------------------------------------------------------------------------------
1 | package fr.pchab.androidrtc.Adapter;
2 |
3 | import android.content.Context;
4 | import android.graphics.Color;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.ArrayAdapter;
9 | import android.widget.ImageButton;
10 | import android.widget.TextView;
11 |
12 | import java.util.ArrayList;
13 | import java.util.HashMap;
14 | import java.util.List;
15 | import java.util.Map;
16 |
17 | import fr.pchab.androidrtc.Model.HistoryItem;
18 | import fr.pchab.androidrtc.MainActivity;
19 | import fr.pchab.androidrtc.R;
20 |
21 | /**
22 | * Created by gumiMinh on 4/11/16.
23 | */
24 | public class HistoryAdapter extends ArrayAdapter {
25 | private final Context context;
26 | private LayoutInflater inflater;
27 | private List values;
28 | private Map users;
29 | private ArrayList items;
30 | private ArrayList itemsAll;
31 | private ArrayList suggestions;
32 |
33 | public HistoryAdapter(Context context, ArrayList values) {
34 | super(context, R.layout.history_row_layout, android.R.id.text1, values);
35 | this.context = context;
36 | this.inflater = LayoutInflater.from(context);
37 | this.values = values;
38 | this.users = new HashMap();
39 | this.items = values;
40 | this.itemsAll = (ArrayList) items.clone();
41 | this.suggestions = new ArrayList();
42 | }
43 |
44 | class ViewHolder {
45 | TextView user;
46 | TextView status;
47 | TextView id;
48 | ImageButton callBtn;
49 | ImageButton browserBtn;
50 | HistoryItem histItem;
51 | }
52 |
53 | @Override
54 | public View getView(final int position, View convertView, ViewGroup parent) {
55 | final HistoryItem hItem = this.values.get(position);
56 | final ViewHolder holder;
57 | if (convertView == null) {
58 | holder = new ViewHolder();
59 | convertView = inflater.inflate(R.layout.history_row_layout, parent, false);
60 | holder.user = (TextView) convertView.findViewById(R.id.history_name);
61 | holder.status = (TextView) convertView.findViewById(R.id.history_status);
62 | holder.id = (TextView) convertView.findViewById(R.id.history_time);
63 | holder.callBtn = (ImageButton) convertView.findViewById(R.id.history_call);
64 | holder.browserBtn = (ImageButton) convertView.findViewById(R.id.history_call_browser);
65 | convertView.setTag(holder);
66 | } else {
67 | holder = (ViewHolder) convertView.getTag();
68 | }
69 | holder.user.setText(hItem.getUserName());
70 | holder.id.setText(hItem.getUserId());
71 | if(hItem.getStatus().equals("Online")){
72 | holder.status.setTextColor(Color.GREEN);
73 | }else{
74 | holder.status.setTextColor(Color.RED);
75 | }
76 | holder.status.setText(hItem.getStatus());
77 | holder.callBtn.setOnClickListener(new View.OnClickListener() {
78 | @Override
79 | public void onClick(View v) {
80 | holder.callBtn.setEnabled(false);
81 | ((MainActivity) v.getContext()).makeCall(holder.id.getText().toString(), holder.status.getText().toString());
82 | }
83 | });
84 | // holder.browserBtn.setOnClickListener(new View.OnClickListener() {
85 | // @Override
86 | // public void onClick(View v) {
87 | // ((MainActivity) v.getContext()).makeBrowserCall(holder.id.getText().toString(), holder.status.getText().toString());
88 | // }
89 | // });
90 | holder.histItem = hItem;
91 | return convertView;
92 | }
93 |
94 | @Override
95 | public int getCount() {
96 | return this.values.size();
97 | }
98 |
99 | public void removeButton(int loc) {
100 | this.values.remove(loc);
101 | notifyDataSetChanged();
102 | }
103 | }
104 |
105 |
--------------------------------------------------------------------------------
/app/src/main/java/fr/pchab/androidrtc/Adapter/UserAdapter.java:
--------------------------------------------------------------------------------
1 | package fr.pchab.androidrtc.Adapter;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.ArrayAdapter;
8 | import android.widget.Filter;
9 | import android.widget.ImageButton;
10 | import android.widget.TextView;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 | import fr.pchab.androidrtc.MainActivity;
16 | import fr.pchab.androidrtc.Model.User;
17 | import fr.pchab.androidrtc.R;
18 |
19 | /**
20 | * Created by gumiMinh on 4/12/16.
21 | */
22 | public class UserAdapter extends ArrayAdapter {
23 | private LayoutInflater inflater;
24 | private List values;
25 | private ArrayList items;
26 | private ArrayList itemsAll;
27 | private ArrayList suggestions;
28 |
29 | public UserAdapter(Context context, ArrayList values) {
30 | super(context, R.layout.user_row_layout, android.R.id.text1, values);
31 | this.inflater = LayoutInflater.from(context);
32 | this.values = values;
33 | this.items = values;
34 | this.itemsAll = (ArrayList) items.clone();
35 | this.suggestions = new ArrayList();
36 | }
37 |
38 | class ViewHolder {
39 | TextView user;
40 | TextView id;
41 | ImageButton addBtn;
42 | User histItem;
43 | }
44 |
45 | @Override
46 | public View getView(final int position, View convertView, ViewGroup parent) {
47 | final User hItem = this.values.get(position);
48 | final ViewHolder holder;
49 | if (convertView == null) {
50 | holder = new ViewHolder();
51 | convertView = inflater.inflate(R.layout.user_row_layout, parent, false);
52 | holder.user = (TextView) convertView.findViewById(R.id.user_name);
53 | holder.id = (TextView) convertView.findViewById(R.id.user_id);
54 | holder.addBtn = (ImageButton) convertView.findViewById(R.id.user_add);
55 | convertView.setTag(holder);
56 | } else {
57 | holder = (ViewHolder) convertView.getTag();
58 | }
59 | holder.user.setText(hItem.getUserName());
60 | holder.id.setText(hItem.getUserId());
61 | holder.addBtn.setOnClickListener(new View.OnClickListener() {
62 | @Override
63 | public void onClick(View v) {
64 | ((MainActivity) v.getContext()).addfriend(holder.id.getText().toString(), holder.user.getText().toString());
65 | }
66 | });
67 | holder.histItem = hItem;
68 | return convertView;
69 | }
70 |
71 | @Override
72 | public int getCount() {
73 | return this.values.size();
74 | }
75 |
76 | @Override
77 | public Filter getFilter() {
78 | return nameFilter;
79 | }
80 |
81 | Filter nameFilter = new Filter() {
82 | @Override
83 | public String convertResultToString(Object resultValue) {
84 | String str = ((User) (resultValue)).getUserName();
85 | return str;
86 | }
87 |
88 | @Override
89 | protected FilterResults performFiltering(CharSequence constraint) {
90 | if (constraint != null) {
91 | suggestions.clear();
92 | for (User customer : itemsAll) {
93 | if (customer.getUserName().toLowerCase().startsWith(constraint.toString().toLowerCase())) {
94 | suggestions.add(customer);
95 | }
96 | }
97 | FilterResults filterResults = new FilterResults();
98 | filterResults.values = suggestions;
99 | filterResults.count = suggestions.size();
100 | return filterResults;
101 | } else {
102 | return new FilterResults();
103 | }
104 | }
105 |
106 | @Override
107 | protected void publishResults(CharSequence constraint, FilterResults results) {
108 | ArrayList filteredList = (ArrayList) results.values;
109 | if (results != null && results.count > 0) {
110 | clear();
111 | for (User c : filteredList) {
112 | add(c);
113 | }
114 | notifyDataSetChanged();
115 | }
116 | }
117 | };
118 | }
119 |
--------------------------------------------------------------------------------
/app/src/main/java/fr/pchab/androidrtc/IncomingCallActivity.java:
--------------------------------------------------------------------------------
1 | package fr.pchab.androidrtc;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.media.AudioManager;
6 | import android.media.MediaPlayer;
7 | import android.os.Bundle;
8 | import android.os.Vibrator;
9 | import android.support.v7.app.AppCompatActivity;
10 | import android.view.MenuItem;
11 | import android.view.View;
12 | import android.widget.TextView;
13 |
14 | import com.github.nkzawa.socketio.client.IO;
15 | import com.github.nkzawa.socketio.client.Socket;
16 |
17 | import org.json.JSONException;
18 | import org.json.JSONObject;
19 |
20 | import java.net.URISyntaxException;
21 |
22 | public class IncomingCallActivity extends AppCompatActivity {
23 | private String callerName;
24 | private TextView mCallerID;
25 | private String userName;
26 | private String userId;
27 | private Socket client;
28 | private String callerId;
29 | private Vibrator vib;
30 | private MediaPlayer mMediaPlayer;
31 |
32 | @Override
33 | protected void onCreate(Bundle savedInstanceState) {
34 | super.onCreate(savedInstanceState);
35 | setContentView(R.layout.activity_incoming_call);
36 |
37 | Bundle extras = getIntent().getExtras();
38 | callerId = extras.getString("CALLER_ID");
39 | userId = extras.getString("USER_ID");
40 | callerName = extras.getString("CALLER_NAME");
41 | userName= extras.getString("USER_NAME");
42 |
43 |
44 | this.mCallerID = (TextView) findViewById(R.id.caller_id);
45 | this.mCallerID.setText(this.callerName);
46 | mMediaPlayer = new MediaPlayer();
47 | mMediaPlayer = MediaPlayer.create(this, R.raw.skype_call);
48 | mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
49 | mMediaPlayer.setLooping(true);
50 | mMediaPlayer.start();
51 |
52 | vib= (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
53 | long[] pattern = {0, 100, 1000};
54 | vib.vibrate(pattern,0);
55 | }
56 |
57 |
58 | @Override
59 | public boolean onOptionsItemSelected(MenuItem item) {
60 | int id = item.getItemId();
61 |
62 | //noinspection SimplifiableIfStatement
63 | if (id == R.id.action_settings) {
64 | return true;
65 | }
66 |
67 | return super.onOptionsItemSelected(item);
68 | }
69 |
70 | public void acceptCall(View view) {
71 | vib.cancel();
72 | mMediaPlayer.stop();
73 | finish();
74 | Intent intent = new Intent(IncomingCallActivity.this, RtcActivity.class);
75 | intent.putExtra("id", this.userId);
76 | intent.putExtra("name",this.userName);
77 | intent.putExtra("callerIdChat", callerId);
78 | //incointent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
79 | startActivity(intent);
80 | String host = "http://" + getResources().getString(R.string.host);
81 | host += (":" + getResources().getString(R.string.port) + "/");
82 | try {
83 | client = IO.socket(host);
84 | } catch (URISyntaxException e) {
85 | e.printStackTrace();
86 | }
87 | client.connect();
88 | try {
89 | JSONObject message = new JSONObject();
90 | message.put("myId", userId);
91 | message.put("callerId", callerId);
92 | client.emit("acceptcall", message);
93 | } catch (JSONException e) {
94 | e.printStackTrace();
95 | }
96 | }
97 |
98 | /**
99 | * Publish a hangup command if rejecting call.
100 | *
101 | * @param view
102 | */
103 | public void rejectCall(View view) {
104 | vib.cancel();
105 | mMediaPlayer.stop();
106 |
107 | String host = "http://" + getResources().getString(R.string.host);
108 | host += (":" + getResources().getString(R.string.port) + "/");
109 | try {
110 | client = IO.socket(host);
111 | } catch (URISyntaxException e) {
112 | e.printStackTrace();
113 | }
114 | client.connect();
115 | try {
116 | JSONObject message = new JSONObject();
117 | message.put("myId", userId);
118 | message.put("callerId", callerId);
119 | client.emit("ejectcall", message);
120 | } catch (JSONException e) {
121 | e.printStackTrace();
122 | }
123 |
124 | finish();
125 | Intent intent = new Intent(IncomingCallActivity.this, MainActivity.class);
126 | intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
127 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
128 | startActivity(intent);
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_register.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
17 |
18 |
25 |
29 |
30 |
35 |
36 |
37 |
40 |
41 |
48 |
49 |
50 |
51 |
54 |
55 |
66 |
67 |
68 |
71 |
72 |
79 |
80 |
81 |
84 |
85 |
92 |
93 |
94 |
97 |
98 |
105 |
106 |
107 |
115 |
116 |
123 |
124 |
125 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/app/src/main/java/fr/pchab/androidrtc/CallingActivity.java:
--------------------------------------------------------------------------------
1 | //package fr.pchab.androidrtc;
2 | //
3 | //import android.media.AudioManager;
4 | //import android.media.MediaPlayer;
5 | //import android.os.Bundle;
6 | //import android.support.v7.app.AppCompatActivity;
7 | //import android.view.MenuItem;
8 | //import android.view.View;
9 | //import android.widget.TextView;
10 | //
11 | //import com.github.nkzawa.socketio.client.IO;
12 | //import com.github.nkzawa.socketio.client.Socket;
13 | //
14 | //import org.json.JSONException;
15 | //import org.json.JSONObject;
16 | //import org.webrtc.MediaStream;
17 | //
18 | //import java.net.URISyntaxException;
19 | //
20 | //import fr.pchab.webrtcclient.WebRtcClient;
21 | //
22 | //public class CallingActivity extends AppCompatActivity implements WebRtcClient.RtcListener{
23 | // private String callerName;
24 | // private TextView mCallerID;
25 | // private String userName;
26 | // private String userId;
27 | // private Socket client;
28 | // private String callerId;
29 | //
30 | // @Override
31 | // protected void onCreate(Bundle savedInstanceState) {
32 | // super.onCreate(savedInstanceState);
33 | // setContentView(R.layout.activity_incoming_call);
34 | //
35 | // Bundle extras = getIntent().getExtras();
36 | // callerId = extras.getString("CALLER_ID");
37 | // userId = extras.getString("USER_ID");
38 | // callerName = extras.getString("CALLER_NAME");
39 | // userName= extras.getString("USER_NAME");
40 | //
41 | //
42 | // this.mCallerID = (TextView) findViewById(R.id.caller_id);
43 | // this.mCallerID.setText(this.callerName);
44 | // MediaPlayer mMediaPlayer = new MediaPlayer();
45 | // mMediaPlayer = MediaPlayer.create(this, R.raw.skype_call);
46 | // mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
47 | // mMediaPlayer.setLooping(true);
48 | // mMediaPlayer.start();
49 | // String host = "http://" + getResources().getString(R.string.host);
50 | // host += (":" + getResources().getString(R.string.port) + "/");
51 | // try {
52 | // client = IO.socket(host);
53 | // } catch (URISyntaxException e) {
54 | // e.printStackTrace();
55 | // }
56 | // client.connect();
57 | // JSONObject message = new JSONObject();
58 | //
59 | // try {
60 | // message.put("to", callerId);
61 | // message.put("type", "init");
62 | // message.put("payload", null);
63 | // client.emit("startclient", message);
64 | // } catch (JSONException e) {
65 | // e.printStackTrace();
66 | // }
67 | //
68 | // }
69 | //
70 | //
71 | // @Override
72 | // public boolean onOptionsItemSelected(MenuItem item) {
73 | // int id = item.getItemId();
74 | //
75 | // //noinspection SimplifiableIfStatement
76 | // if (id == R.id.action_settings) {
77 | // return true;
78 | // }
79 | //
80 | // return super.onOptionsItemSelected(item);
81 | // }
82 | //
83 | // /**
84 | // * Publish a hangup command if rejecting call.
85 | // *
86 | // * @param view
87 | // */
88 | // public void rejectCall(View view) {
89 | // finish();
90 | // String host = "http://" + getResources().getString(R.string.host);
91 | // host += (":" + getResources().getString(R.string.port) + "/");
92 | // try {
93 | // client = IO.socket(host);
94 | // } catch (URISyntaxException e) {
95 | // e.printStackTrace();
96 | // }
97 | // client.connect();
98 | // try {
99 | // JSONObject message = new JSONObject();
100 | // message.put("myId", userId);
101 | // message.put("callerId", callerId);
102 | // client.emit("ejectcall", message);
103 | // } catch (JSONException e) {
104 | // e.printStackTrace();
105 | // }
106 | // }
107 | //
108 | // @Override
109 | // public void onCallReady(String callId) {
110 | //
111 | // }
112 | //
113 | // @Override
114 | // public void onAcceptCall(String callId) {
115 | // try {
116 | // try{ Thread.sleep(1500); }catch(InterruptedException e){ }
117 | // answer(callId);
118 | // } catch (JSONException e) {
119 | // e.printStackTrace();
120 | // }
121 | // }
122 | //
123 | // /**
124 | // * This function is being call to answer call from other user
125 | // *
126 | // * send init message to the caller and connect
127 | // * start the camera
128 | // *
129 | // * @param callerId the id of the caler
130 | // */
131 | // public void answer(String callerId) throws JSONException {
132 | // JSONObject message = new JSONObject();
133 | // try {
134 | // message.put("to",callerId );
135 | // message.put("type", "init");
136 | // message.put("payload", null);
137 | // client.emit("message", message);
138 | // //client.start("android_test");
139 | // } catch (JSONException e) {
140 | // e.printStackTrace();
141 | // }
142 | // }
143 | //
144 | // @Override
145 | // public void onStatusChanged(String newStatus) {
146 | //
147 | // }
148 | //
149 | // @Override
150 | // public void receiveMessage(String id, String msg) {
151 | //
152 | // }
153 | //
154 | // @Override
155 | // public void onLocalStream(MediaStream localStream) {
156 | //
157 | // }
158 | //
159 | // @Override
160 | // public void onAddRemoteStream(MediaStream remoteStream, int endPoint) {
161 | //
162 | // }
163 | //
164 | // @Override
165 | // public void onRemoveRemoteStream(int endPoint) {
166 | //
167 | // }
168 | //
169 | // @Override
170 | // public void onReceiveCall(String id) {
171 | //
172 | // }
173 | //}
174 |
--------------------------------------------------------------------------------
/webrtc-client/webrtc-client.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | generateDebugAndroidTestSources
19 | generateDebugSources
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | generateDebugAndroidTestSources
19 | generateDebugSources
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/app/src/main/java/fr/pchab/androidrtc/Adapter/ChatAdapter.java:
--------------------------------------------------------------------------------
1 | package fr.pchab.androidrtc.Adapter;
2 |
3 | /**
4 | * Created by gumiMinh on 4/6/16.
5 | */
6 |
7 | import android.content.Context;
8 | import android.util.Log;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.view.animation.AccelerateInterpolator;
13 | import android.view.animation.AlphaAnimation;
14 | import android.view.animation.Animation;
15 | import android.view.animation.AnimationSet;
16 | import android.widget.ArrayAdapter;
17 | import android.widget.TextView;
18 |
19 | import java.text.SimpleDateFormat;
20 | import java.util.Calendar;
21 | import java.util.List;
22 |
23 | import fr.pchab.androidrtc.Model.ChatMessage;
24 | import fr.pchab.androidrtc.R;
25 |
26 | /**
27 | * Created by GleasonK on 6/25/15.
28 | */
29 | public class ChatAdapter extends ArrayAdapter {
30 | private static final long FADE_TIMEOUT = 3000;
31 |
32 | private final Context context;
33 | private LayoutInflater inflater;
34 | private List values;
35 |
36 | public ChatAdapter(Context context, List values) {
37 | super(context, R.layout.chat_message_row_layout, android.R.id.text1, values);
38 | this.context = context;
39 | this.inflater = LayoutInflater.from(context);
40 | this.values = values;
41 | }
42 |
43 | class ViewHolder {
44 | TextView sender;
45 | TextView message;
46 | TextView timeStamp;
47 | ChatMessage chatMsg;
48 | }
49 |
50 | @Override
51 | public View getView(final int position, View convertView, ViewGroup parent) {
52 | ChatMessage chatMsg;
53 | if (position >= values.size()) {
54 | chatMsg = new ChatMessage("", "", 0);
55 | } // Catch Edge Case
56 | else {
57 | chatMsg = this.values.get(position);
58 | }
59 | ViewHolder holder;
60 | if (convertView == null) {
61 | holder = new ViewHolder();
62 | convertView = inflater.inflate(R.layout.chat_message_row_layout, parent, false);
63 | holder.sender = (TextView) convertView.findViewById(R.id.chat_user);
64 | holder.message = (TextView) convertView.findViewById(R.id.chat_message);
65 | holder.timeStamp = (TextView) convertView.findViewById(R.id.chat_timestamp);
66 | convertView.setTag(holder);
67 | Log.d("Adapter", "Recreating fadeout.");
68 | } else {
69 | holder = (ViewHolder) convertView.getTag();
70 | }
71 | holder.sender.setText(chatMsg.getSender() + ": ");
72 | holder.message.setText(chatMsg.getMessage());
73 | holder.timeStamp.setText(formatTimeStamp(chatMsg.getTimeStamp()));
74 | holder.chatMsg = chatMsg;
75 | setFadeOut3(convertView, chatMsg);
76 | return convertView;
77 | }
78 |
79 | @Override
80 | public int getCount() {
81 | return this.values.size();
82 | }
83 |
84 | @Override
85 | public boolean hasStableIds() {
86 | return true;
87 | }
88 |
89 | @Override
90 | public long getItemId(int position) {
91 | if (position >= values.size()) {
92 | return -1;
93 | }
94 | return values.get(position).hashCode();
95 | }
96 |
97 | public void removeMsg(int loc) {
98 | this.values.remove(loc);
99 | notifyDataSetChanged();
100 | }
101 |
102 | public void addMessage(ChatMessage chatMsg) {
103 | this.values.add(chatMsg);
104 | notifyDataSetChanged();
105 | }
106 |
107 | private void setFadeOut2(final View view, final ChatMessage message) {
108 | Log.i("AdapterFade", "Caling Fade2");
109 | view.animate().setDuration(1000).setStartDelay(2000).alpha(0)
110 | .withEndAction(new Runnable() {
111 | @Override
112 | public void run() {
113 | if (values.contains(message))
114 | values.remove(message);
115 | notifyDataSetChanged();
116 | view.setAlpha(1);
117 | }
118 | });
119 | }
120 |
121 | private void setFadeOut3(final View view, final ChatMessage message) {
122 | Log.i("AdapterFade", "Caling Fade3");
123 | long elapsed = System.currentTimeMillis() - message.getTimeStamp();
124 | if (elapsed >= FADE_TIMEOUT) {
125 | if (values.contains(message))
126 | values.remove(message);
127 | notifyDataSetChanged();
128 | return;
129 | }
130 | view.animate().setStartDelay(FADE_TIMEOUT - elapsed).setDuration(1500).alpha(0)
131 | .withEndAction(new Runnable() {
132 | @Override
133 | public void run() {
134 | if (values.contains(message)) {
135 | values.remove(message);
136 | }
137 | notifyDataSetChanged();
138 | view.setAlpha(1);
139 | }
140 | });
141 | }
142 |
143 |
144 | private void setFadeOut(final View view, final ChatMessage message) {
145 | long elapsed = System.currentTimeMillis() - message.getTimeStamp();
146 | if (elapsed >= FADE_TIMEOUT) {
147 | if (values.contains(message))
148 | values.remove(message);
149 | notifyDataSetChanged();
150 | return;
151 | }
152 |
153 | view.setHasTransientState(true);
154 | Animation fadeOut = new AlphaAnimation(1, 0);
155 | fadeOut.setInterpolator(new AccelerateInterpolator()); //and this
156 | fadeOut.setStartOffset(FADE_TIMEOUT - elapsed);
157 | fadeOut.setDuration(1000);
158 |
159 | AnimationSet animation = new AnimationSet(false);
160 | animation.addAnimation(fadeOut);
161 | animation.setRepeatCount(1);
162 |
163 | view.setAnimation(animation);
164 | animation.setAnimationListener(new Animation.AnimationListener() {
165 | @Override
166 | public void onAnimationStart(Animation animation) {
167 | }
168 |
169 | @Override
170 | public void onAnimationEnd(Animation animation) {
171 | if (values.contains(message)) {
172 | values.remove(message);
173 | }
174 | notifyDataSetChanged();
175 | view.setAlpha(1);
176 | view.setHasTransientState(false);
177 | }
178 |
179 | @Override
180 | public void onAnimationRepeat(Animation animation) {
181 | }
182 | });
183 | }
184 |
185 | /**
186 | * Format the long System.currentTimeMillis() to a better looking timestamp. Uses a calendar
187 | * object to format with the user's current time zone.
188 | *
189 | * @param timeStamp
190 | * @return
191 | */
192 | public static String formatTimeStamp(long timeStamp) {
193 | // Create a DateFormatter object for displaying date in specified format.
194 | SimpleDateFormat formatter = new SimpleDateFormat("h:mm.ss a");
195 |
196 | // Create a calendar object that will convert the date and time value in milliseconds to date.
197 | Calendar calendar = Calendar.getInstance();
198 | calendar.setTimeInMillis(timeStamp);
199 | return formatter.format(calendar.getTime());
200 | }
201 |
202 | }
--------------------------------------------------------------------------------
/webrtc-client/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/app/src/main/java/fr/pchab/androidrtc/RegisterActivity.java:
--------------------------------------------------------------------------------
1 | package fr.pchab.androidrtc;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorListenerAdapter;
5 | import android.annotation.TargetApi;
6 | import android.app.AlertDialog;
7 | import android.content.DialogInterface;
8 | import android.content.Intent;
9 | import android.content.SharedPreferences;
10 | import android.os.AsyncTask;
11 | import android.os.Build;
12 | import android.os.Bundle;
13 | import android.support.v7.app.AppCompatActivity;
14 | import android.text.TextUtils;
15 | import android.util.Log;
16 | import android.view.View;
17 | import android.widget.Button;
18 | import android.widget.EditText;
19 | import android.widget.TextView;
20 |
21 | import org.apache.http.HttpResponse;
22 | import org.apache.http.NameValuePair;
23 | import org.apache.http.client.ClientProtocolException;
24 | import org.apache.http.client.HttpClient;
25 | import org.apache.http.client.entity.UrlEncodedFormEntity;
26 | import org.apache.http.client.methods.HttpPost;
27 | import org.apache.http.impl.client.DefaultHttpClient;
28 | import org.apache.http.message.BasicNameValuePair;
29 | import org.apache.http.util.EntityUtils;
30 | import org.json.JSONObject;
31 |
32 | import java.io.IOException;
33 | import java.io.UnsupportedEncodingException;
34 | import java.util.ArrayList;
35 | import java.util.List;
36 |
37 | public class RegisterActivity extends AppCompatActivity {
38 | private UserRegisterTask mAuthTask = null;
39 |
40 | private EditText mUsernameView;
41 | private EditText mPasswordView;
42 | private EditText mNameView;
43 | private EditText mPhoneView;
44 | private EditText mEmailView;
45 | private View mRegisterFormView;
46 | private View mProgressView;
47 |
48 | @Override
49 | protected void onCreate(Bundle savedInstanceState) {
50 | super.onCreate(savedInstanceState);
51 | setContentView(R.layout.content_register);
52 | mUsernameView = (EditText) findViewById(R.id.username);
53 | mPasswordView = (EditText) findViewById(R.id.password);
54 | mNameView = (EditText) findViewById(R.id.name);
55 | mPhoneView = (EditText) findViewById(R.id.phone);
56 | mEmailView = (EditText) findViewById(R.id.email);
57 | mRegisterFormView = findViewById(R.id.register_form);
58 | mProgressView = findViewById(R.id.register_progress);
59 | TextView mSignInButton = (TextView) findViewById(R.id.login_button);
60 | mSignInButton.setOnClickListener(new View.OnClickListener() {
61 | @Override
62 | public void onClick(View view) {
63 | Intent intent = new Intent(view.getContext(), LoginActivity.class);
64 | startActivity(intent);
65 | }
66 | });
67 |
68 | Button mRegisterButton = (Button) findViewById(R.id.register_button);
69 | mRegisterButton.setOnClickListener(new View.OnClickListener() {
70 | @Override
71 | public void onClick(View view) {
72 | register();
73 | }
74 | });
75 | }
76 |
77 | private void register() {
78 | if (mAuthTask != null) {
79 | return;
80 | }
81 |
82 | // Reset errors.
83 | mEmailView.setError(null);
84 | mPasswordView.setError(null);
85 | mNameView.setError(null);
86 | mPhoneView.setError(null);
87 | mUsernameView.setError(null);
88 |
89 | // Store values at the time of the login attempt.
90 | String email = mEmailView.getText().toString();
91 | String password = mPasswordView.getText().toString();
92 | String username = mUsernameView.getText().toString();
93 | String name = mNameView.getText().toString();
94 | String phone = mPhoneView.getText().toString();
95 |
96 | boolean cancel = false;
97 | View focusView = null;
98 |
99 | // Check for a valid password, if the user entered one.
100 | if (TextUtils.isEmpty(password)) {
101 | mPasswordView.setError(getString(R.string.error_invalid_password));
102 | focusView = mPasswordView;
103 | cancel = true;
104 | }
105 |
106 | // Check for a valid email address.
107 | // if (TextUtils.isEmpty(email) && !isValidEmail(email)) {
108 | // mEmailView.setError(getString(R.string.error_field_required));
109 | // focusView = mEmailView;
110 | // cancel = true;
111 | // }
112 |
113 | // Check for a valid email address.
114 | if (TextUtils.isEmpty(name)) {
115 | mNameView.setError(getString(R.string.error_field_required));
116 | focusView = mNameView;
117 | cancel = true;
118 | }
119 |
120 | // Check for a valid email address.
121 | // if (TextUtils.isEmpty(phone)) {
122 | // mPhoneView.setError(getString(R.string.error_field_required));
123 | // focusView = mPhoneView;
124 | // cancel = true;
125 | // }
126 |
127 | // Check for a valid email address.
128 | if (TextUtils.isEmpty(username)) {
129 | mUsernameView.setError(getString(R.string.error_field_required));
130 | focusView = mUsernameView;
131 | cancel = true;
132 | }
133 |
134 |
135 | if (cancel) {
136 | // There was an error; don't attempt login and focus the first
137 | // form field with an error.
138 | focusView.requestFocus();
139 | } else {
140 | // Show a progress spinner, and kick off a background task to
141 | // perform the user login attempt.
142 | showProgress(true);
143 | mAuthTask = new UserRegisterTask(email, password, username, name, phone);
144 | mAuthTask.execute((Void) null);
145 |
146 | }
147 | }
148 |
149 | /**
150 | * Shows the progress UI and hides the login form.
151 | */
152 | @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
153 | private void showProgress(final boolean show) {
154 | // On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
155 | // for very easy animations. If available, use these APIs to fade-in
156 | // the progress spinner.
157 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
158 | int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);
159 |
160 | mRegisterFormView.setVisibility(show ? View.GONE : View.VISIBLE);
161 | mRegisterFormView.animate().setDuration(shortAnimTime).alpha(
162 | show ? 0 : 1).setListener(new AnimatorListenerAdapter() {
163 | @Override
164 | public void onAnimationEnd(Animator animation) {
165 | mRegisterFormView.setVisibility(show ? View.GONE : View.VISIBLE);
166 | }
167 | });
168 |
169 | mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
170 | mProgressView.animate().setDuration(shortAnimTime).alpha(
171 | show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
172 | @Override
173 | public void onAnimationEnd(Animator animation) {
174 | mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
175 | }
176 | });
177 | } else {
178 | // The ViewPropertyAnimator APIs are not available, so simply show
179 | // and hide the relevant UI components.
180 | mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
181 | mRegisterFormView.setVisibility(show ? View.GONE : View.VISIBLE);
182 | }
183 | }
184 |
185 | public class UserRegisterTask extends AsyncTask {
186 |
187 | private final String mEmail;
188 | private final String mPassword;
189 | private final String mName;
190 | private final String mPhone;
191 | private final String mUsername;
192 |
193 | UserRegisterTask(String email, String password, String username, String name, String phone) {
194 | mEmail = email;
195 | mPassword = password;
196 | mName = name;
197 | mPhone = phone;
198 | mUsername = username;
199 | }
200 |
201 | @Override
202 | protected Boolean doInBackground(Void... params) {
203 | try {
204 | HttpClient httpClient = new DefaultHttpClient();
205 | // replace with your url
206 | String host = "http://" + getResources().getString(R.string.host);
207 | host += (":" + getResources().getString(R.string.port) + "/");
208 | HttpPost httpPost = new HttpPost(host+"register");
209 |
210 | //Post Data
211 | List nameValuePair = new ArrayList(5);
212 | nameValuePair.add(new BasicNameValuePair("username", mUsername));
213 | nameValuePair.add(new BasicNameValuePair("password", mPassword));
214 | nameValuePair.add(new BasicNameValuePair("name", mName));
215 | nameValuePair.add(new BasicNameValuePair("phone", mPhone));
216 | nameValuePair.add(new BasicNameValuePair("email", mEmail));
217 |
218 |
219 | //Encoding POST data
220 | try {
221 | httpPost.setEntity(new UrlEncodedFormEntity(nameValuePair));
222 | } catch (UnsupportedEncodingException e) {
223 | // log exception
224 | e.printStackTrace();
225 | }
226 | //making POST request.
227 | try {
228 | HttpResponse response = httpClient.execute(httpPost);
229 | String json_string = EntityUtils.toString(response.getEntity());
230 | JSONObject json_data = new JSONObject(json_string);
231 | int status = json_data.getInt("status");
232 | if (status == 1){
233 | String id = json_data.getString("id");
234 | String name = mUsername;
235 | SharedPreferences sp = getSharedPreferences("SHARED_PREFS", MODE_PRIVATE);
236 | SharedPreferences.Editor edit = sp.edit();
237 | edit.putString("USER_ID", id);
238 | edit.putString("USER_NAME", name);
239 | edit.apply();
240 | Intent intent = new Intent(RegisterActivity.this, MainActivity.class);
241 | startActivity(intent);
242 | }else{
243 | return false;
244 | }
245 |
246 |
247 | } catch (ClientProtocolException e) {
248 | // Log exception
249 |
250 | Log.d("minh_res", "error");
251 | } catch (IOException e) {
252 | // Log exception
253 | e.printStackTrace();
254 | Log.d("minh_res", e.getMessage());
255 |
256 | }
257 | } catch (Exception e) {
258 | }
259 |
260 | // TODO: register the new account here.
261 | return true;
262 | }
263 |
264 | @Override
265 | protected void onPostExecute(final Boolean success) {
266 | mAuthTask = null;
267 | showProgress(false);
268 |
269 | if (success) {
270 | finish();
271 | } else {
272 | new AlertDialog.Builder(RegisterActivity.this)
273 | .setTitle("Error")
274 | .setMessage("Cannot register, please try again!")
275 | .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
276 | public void onClick(DialogInterface dialog, int which) {
277 | // mEmailView.setText("");
278 | // mPasswordView.setText("");
279 | // mUsernameView.setText("");
280 | // mNameView.setText("");
281 | // mPhoneView.setText("");
282 | }
283 | })
284 | .setIcon(android.R.drawable.ic_dialog_alert)
285 | .show();
286 |
287 | }
288 | }
289 |
290 | @Override
291 | protected void onCancelled() {
292 | mAuthTask = null;
293 | showProgress(false);
294 | }
295 | }
296 |
297 | public final static boolean isValidEmail(CharSequence target) {
298 | if (target == null) {
299 | return false;
300 | } else {
301 | return android.util.Patterns.EMAIL_ADDRESS.matcher(target).matches();
302 | }
303 | }
304 | }
305 |
--------------------------------------------------------------------------------
/app/src/main/java/fr/pchab/androidrtc/LoginActivity.java:
--------------------------------------------------------------------------------
1 | package fr.pchab.androidrtc;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorListenerAdapter;
5 | import android.annotation.TargetApi;
6 | import android.app.AlertDialog;
7 | import android.app.LoaderManager.LoaderCallbacks;
8 | import android.content.CursorLoader;
9 | import android.content.DialogInterface;
10 | import android.content.Intent;
11 | import android.content.Loader;
12 | import android.content.SharedPreferences;
13 | import android.database.Cursor;
14 | import android.net.Uri;
15 | import android.os.AsyncTask;
16 | import android.os.Build;
17 | import android.os.Bundle;
18 | import android.provider.ContactsContract;
19 | import android.support.v7.app.AppCompatActivity;
20 | import android.text.TextUtils;
21 | import android.util.Log;
22 | import android.view.KeyEvent;
23 | import android.view.View;
24 | import android.view.View.OnClickListener;
25 | import android.view.inputmethod.EditorInfo;
26 | import android.widget.ArrayAdapter;
27 | import android.widget.AutoCompleteTextView;
28 | import android.widget.Button;
29 | import android.widget.EditText;
30 | import android.widget.TextView;
31 |
32 | import org.apache.http.HttpResponse;
33 | import org.apache.http.NameValuePair;
34 | import org.apache.http.client.ClientProtocolException;
35 | import org.apache.http.client.HttpClient;
36 | import org.apache.http.client.entity.UrlEncodedFormEntity;
37 | import org.apache.http.client.methods.HttpPost;
38 | import org.apache.http.impl.client.DefaultHttpClient;
39 | import org.apache.http.message.BasicNameValuePair;
40 | import org.apache.http.util.EntityUtils;
41 | import org.json.JSONObject;
42 |
43 | import java.io.IOException;
44 | import java.io.UnsupportedEncodingException;
45 | import java.util.ArrayList;
46 | import java.util.List;
47 |
48 |
49 | /**
50 | * A login screen that offers login via email/password.
51 | */
52 | public class LoginActivity extends AppCompatActivity implements LoaderCallbacks {
53 |
54 | /**
55 | * A dummy authentication store containing known user names and passwords.
56 | * TODO: remove after connecting to a real authentication system.
57 | */
58 | /**
59 | * Keep track of the login task to ensure we can cancel it if requested.
60 | */
61 | private UserLoginTask mAuthTask = null;
62 |
63 | // UI references.
64 | private AutoCompleteTextView mEmailView;
65 | private EditText mPasswordView;
66 | private View mProgressView;
67 | private View mLoginFormView;
68 |
69 | @Override
70 | protected void onCreate(Bundle savedInstanceState) {
71 | super.onCreate(savedInstanceState);
72 | setContentView(R.layout.activity_login);
73 | // Set up the login form.
74 | mEmailView = (AutoCompleteTextView) findViewById(R.id.email);
75 | populateAutoComplete();
76 |
77 | mPasswordView = (EditText) findViewById(R.id.password);
78 | mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
79 | @Override
80 | public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
81 | if (id == R.id.login || id == EditorInfo.IME_NULL) {
82 | attemptLogin();
83 | return true;
84 | }
85 | return false;
86 | }
87 | });
88 |
89 | Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button);
90 | mEmailSignInButton.setOnClickListener(new OnClickListener() {
91 | @Override
92 | public void onClick(View view) {
93 |
94 | attemptLogin();
95 | }
96 | });
97 |
98 | TextView mRegisterButton = (TextView) findViewById(R.id.email_register_button);
99 | mRegisterButton.setOnClickListener(new OnClickListener() {
100 | @Override
101 | public void onClick(View view) {
102 | Intent intent = new Intent(view.getContext(), RegisterActivity.class);
103 | startActivity(intent);
104 | }
105 | });
106 |
107 | mLoginFormView = findViewById(R.id.login_form);
108 | mProgressView = findViewById(R.id.login_progress);
109 | }
110 |
111 | private void populateAutoComplete() {
112 | getLoaderManager().initLoader(0, null, this);
113 | }
114 |
115 |
116 | /**
117 | * Attempts to sign in or register the account specified by the login form.
118 | * If there are form errors (invalid email, missing fields, etc.), the
119 | * errors are presented and no actual login attempt is made.
120 | */
121 | private void attemptLogin() {
122 | if (mAuthTask != null) {
123 | return;
124 | }
125 |
126 | // Reset errors.
127 | mEmailView.setError(null);
128 | mPasswordView.setError(null);
129 |
130 | // Store values at the time of the login attempt.
131 | String email = mEmailView.getText().toString();
132 | String password = mPasswordView.getText().toString();
133 |
134 | boolean cancel = false;
135 | View focusView = null;
136 |
137 | // Check for a valid password, if the user entered one.
138 | if (!TextUtils.isEmpty(password) && !isPasswordValid(password)) {
139 | mPasswordView.setError(getString(R.string.error_invalid_password));
140 | focusView = mPasswordView;
141 | cancel = true;
142 | }
143 |
144 | // Check for a valid email address.
145 | if (TextUtils.isEmpty(email)) {
146 | mEmailView.setError(getString(R.string.error_field_required));
147 | focusView = mEmailView;
148 | cancel = true;
149 | }
150 |
151 | if (cancel) {
152 | // There was an error; don't attempt login and focus the first
153 | // form field with an error.
154 | focusView.requestFocus();
155 | } else {
156 | // Show a progress spinner, and kick off a background task to
157 | // perform the user login attempt.
158 | showProgress(true);
159 | mAuthTask = new UserLoginTask(email, password);
160 | mAuthTask.execute((Void) null);
161 | }
162 | }
163 |
164 | private boolean isPasswordValid(String password) {
165 | //TODO: Replace this with your own logic
166 | return password.length() > 4;
167 | }
168 |
169 | /**
170 | * Shows the progress UI and hides the login form.
171 | */
172 | @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
173 | private void showProgress(final boolean show) {
174 | // On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
175 | // for very easy animations. If available, use these APIs to fade-in
176 | // the progress spinner.
177 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
178 | int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);
179 |
180 | mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
181 | mLoginFormView.animate().setDuration(shortAnimTime).alpha(
182 | show ? 0 : 1).setListener(new AnimatorListenerAdapter() {
183 | @Override
184 | public void onAnimationEnd(Animator animation) {
185 | mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
186 | }
187 | });
188 |
189 | mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
190 | mProgressView.animate().setDuration(shortAnimTime).alpha(
191 | show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
192 | @Override
193 | public void onAnimationEnd(Animator animation) {
194 | mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
195 | }
196 | });
197 | } else {
198 | // The ViewPropertyAnimator APIs are not available, so simply show
199 | // and hide the relevant UI components.
200 | mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
201 | mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
202 | }
203 | }
204 |
205 | @Override
206 | public Loader onCreateLoader(int i, Bundle bundle) {
207 | return new CursorLoader(this,
208 | // Retrieve data rows for the device user's 'profile' contact.
209 | Uri.withAppendedPath(ContactsContract.Profile.CONTENT_URI,
210 | ContactsContract.Contacts.Data.CONTENT_DIRECTORY), ProfileQuery.PROJECTION,
211 |
212 | // Select only email addresses.
213 | ContactsContract.Contacts.Data.MIMETYPE +
214 | " = ?", new String[]{ContactsContract.CommonDataKinds.Email
215 | .CONTENT_ITEM_TYPE},
216 |
217 | // Show primary email addresses first. Note that there won't be
218 | // a primary email address if the user hasn't specified one.
219 | ContactsContract.Contacts.Data.IS_PRIMARY + " DESC");
220 | }
221 |
222 | @Override
223 | public void onLoadFinished(Loader cursorLoader, Cursor cursor) {
224 | List emails = new ArrayList<>();
225 | cursor.moveToFirst();
226 | while (!cursor.isAfterLast()) {
227 | emails.add(cursor.getString(ProfileQuery.ADDRESS));
228 | cursor.moveToNext();
229 | }
230 |
231 | addEmailsToAutoComplete(emails);
232 | }
233 |
234 | @Override
235 | public void onLoaderReset(Loader cursorLoader) {
236 |
237 | }
238 |
239 | private void addEmailsToAutoComplete(List emailAddressCollection) {
240 | //Create adapter to tell the AutoCompleteTextView what to show in its dropdown list.
241 | ArrayAdapter adapter =
242 | new ArrayAdapter<>(LoginActivity.this,
243 | android.R.layout.simple_dropdown_item_1line, emailAddressCollection);
244 |
245 | mEmailView.setAdapter(adapter);
246 | }
247 |
248 |
249 | private interface ProfileQuery {
250 | String[] PROJECTION = {
251 | ContactsContract.CommonDataKinds.Email.ADDRESS,
252 | ContactsContract.CommonDataKinds.Email.IS_PRIMARY,
253 | };
254 |
255 | int ADDRESS = 0;
256 | int IS_PRIMARY = 1;
257 | }
258 |
259 | /**
260 | * Represents an asynchronous login/registration task used to authenticate
261 | * the user.
262 | */
263 | public class UserLoginTask extends AsyncTask {
264 |
265 | private final String mEmail;
266 | private final String mPassword;
267 |
268 | UserLoginTask(String email, String password) {
269 | mEmail = email;
270 | mPassword = password;
271 | }
272 |
273 | @Override
274 | protected Boolean doInBackground(Void... params) {
275 | try {
276 | HttpClient httpClient = new DefaultHttpClient();
277 | // replace with your url
278 | String host = "http://" + getResources().getString(R.string.host);
279 | host += (":" + getResources().getString(R.string.port) + "/");
280 | HttpPost httpPost = new HttpPost(host + "login");
281 |
282 |
283 | //Post Data
284 | List nameValuePair = new ArrayList(2);
285 | nameValuePair.add(new BasicNameValuePair("username", mEmail));
286 | nameValuePair.add(new BasicNameValuePair("password", mPassword));
287 |
288 |
289 | //Encoding POST data
290 | try {
291 | httpPost.setEntity(new UrlEncodedFormEntity(nameValuePair));
292 | } catch (UnsupportedEncodingException e) {
293 | // log exception
294 | e.printStackTrace();
295 | }
296 | //making POST request.
297 | try {
298 | HttpResponse response = httpClient.execute(httpPost);
299 | String json_string = EntityUtils.toString(response.getEntity());
300 | JSONObject json_data = new JSONObject(json_string);
301 | int status = json_data.getInt("status");
302 | Log.d("debugminh", Integer.toString(status));
303 | if (status == 1) {
304 | String id = json_data.getString("id");
305 | String name = json_data.getString("name");
306 | SharedPreferences sp = getSharedPreferences("SHARED_PREFS", MODE_PRIVATE);
307 | SharedPreferences.Editor edit = sp.edit();
308 | edit.putString("USER_ID", id);
309 | edit.putString("USER_NAME", name);
310 | edit.apply();
311 | Intent intent = new Intent(LoginActivity.this, MainActivity.class);
312 | startActivity(intent);
313 | } else {
314 | return false;
315 | }
316 |
317 | //Log.d("log_tag", "id" + json_data.getInt("status") + ", status" + json_data.getString("id"));
318 |
319 | } catch (ClientProtocolException e) {
320 | // Log exception
321 |
322 |
323 | Log.d("minh_res", "error");
324 | } catch (IOException e) {
325 | // Log exception
326 | e.printStackTrace();
327 | Log.d("minh_res", e.getMessage());
328 |
329 | }
330 | } catch (Exception e) {
331 | }
332 |
333 |
334 | // TODO: register the new account here.
335 | return true;
336 | }
337 |
338 | @Override
339 | protected void onPostExecute(final Boolean success) {
340 | mAuthTask = null;
341 | showProgress(false);
342 |
343 | if (success) {
344 | finish();
345 | } else {
346 | new AlertDialog.Builder(LoginActivity.this)
347 | .setTitle("Error")
348 | .setMessage("User name or/and password is not correct!")
349 | .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
350 | public void onClick(DialogInterface dialog, int which) {
351 | // mEmailView.setText("");
352 | // mPasswordView.setText("");
353 | }
354 | })
355 | .setIcon(android.R.drawable.ic_dialog_alert)
356 | .show();
357 | }
358 | }
359 |
360 | @Override
361 | protected void onCancelled() {
362 | mAuthTask = null;
363 | showProgress(false);
364 | }
365 | }
366 | }
367 |
368 |
--------------------------------------------------------------------------------
/webrtc-client/src/main/java/fr/pchab/webrtcclient/WebRtcClient.java:
--------------------------------------------------------------------------------
1 | package fr.pchab.webrtcclient;
2 |
3 | import android.hardware.Camera;
4 | import android.util.Log;
5 |
6 | import com.github.nkzawa.emitter.Emitter;
7 | import com.github.nkzawa.socketio.client.IO;
8 | import com.github.nkzawa.socketio.client.Socket;
9 |
10 | import org.json.JSONException;
11 | import org.json.JSONObject;
12 | import org.webrtc.AudioSource;
13 | import org.webrtc.DataChannel;
14 | import org.webrtc.IceCandidate;
15 | import org.webrtc.MediaConstraints;
16 | import org.webrtc.MediaStream;
17 | import org.webrtc.PeerConnection;
18 | import org.webrtc.PeerConnectionFactory;
19 | import org.webrtc.SdpObserver;
20 | import org.webrtc.SessionDescription;
21 | import org.webrtc.VideoCapturer;
22 | import org.webrtc.VideoCapturerAndroid;
23 | import org.webrtc.VideoSource;
24 |
25 | import java.net.URISyntaxException;
26 | import java.util.HashMap;
27 | import java.util.LinkedList;
28 |
29 | public class WebRtcClient {
30 | private final static String TAG = WebRtcClient.class.getCanonicalName();
31 | private final static int MAX_PEER = 2;
32 | private boolean[] endPoints = new boolean[MAX_PEER];
33 | private PeerConnectionFactory factory;
34 | private HashMap peers = new HashMap<>();
35 | private LinkedList iceServers = new LinkedList<>();
36 | private PeerConnectionParameters pcParams;
37 | private MediaConstraints pcConstraints = new MediaConstraints();
38 | private MediaStream localMS;
39 | private VideoSource videoSource;
40 | private RtcListener mListener;
41 | private Socket client;
42 | private String myId;
43 |
44 | /**
45 | * Implement this interface to be notified of events.
46 | */
47 | public interface RtcListener {
48 | void onCallReady(String callId);
49 |
50 | void onAcceptCall(String callId);
51 |
52 | void onStatusChanged(String newStatus);
53 |
54 | void receiveMessage(String id, String msg);
55 |
56 | void onLocalStream(MediaStream localStream);
57 |
58 | void onAddRemoteStream(MediaStream remoteStream, int endPoint);
59 |
60 | void onRemoveRemoteStream(int endPoint);
61 |
62 | void onReject();
63 | }
64 |
65 | private interface Command {
66 | void execute(String peerId, JSONObject payload) throws JSONException;
67 | }
68 |
69 | /**
70 | * create an offer and send it to the server
71 | *
72 | * If you are the one initiating the call,
73 | * you would use navigator.getUserMedia() to get a video stream, then add the stream to the RTCPeerConnection
74 | * create and send offer to the server
75 | */
76 | private class CreateOfferCommand implements Command {
77 | public void execute(String peerId, JSONObject payload) throws JSONException {
78 | Log.d(TAG, "CreateOfferCommand");
79 | Peer peer = peers.get(peerId);
80 | peer.pc.createOffer(peer, pcConstraints);
81 | }
82 | }
83 |
84 | /**
85 | * create an answer and send it to the server
86 | *
87 | * On the opposite end, the friend will receive the offer from the server
88 | * Once the offer arrives, navigator.getUserMedia() is once again used to create the stream
89 | * An RTCSessionDescription object is created and set up as the remote description by calling
90 | * Then an answer is created using RTCPeerConnection.createAnswer() and sent back to the server, which forwards it to the caller.
91 | */
92 | private class CreateAnswerCommand implements Command {
93 | public void execute(String peerId, JSONObject payload) throws JSONException {
94 | Log.d(TAG, "CreateAnswerCommand");
95 | Peer peer = peers.get(peerId);
96 | SessionDescription sdp = new SessionDescription(
97 | SessionDescription.Type.fromCanonicalForm(payload.getString("type")),
98 | payload.getString("sdp")
99 | );
100 | peer.pc.setRemoteDescription(peer, sdp);
101 | peer.pc.createAnswer(peer, pcConstraints);
102 | }
103 | }
104 |
105 | private class SetRemoteSDPCommand implements Command {
106 | public void execute(String peerId, JSONObject payload) throws JSONException {
107 | Log.d(TAG, "SetRemoteSDPCommand");
108 | Peer peer = peers.get(peerId);
109 | SessionDescription sdp = new SessionDescription(
110 | SessionDescription.Type.fromCanonicalForm(payload.getString("type")),
111 | payload.getString("sdp")
112 | );
113 | peer.pc.setRemoteDescription(peer, sdp);
114 | }
115 | }
116 |
117 | private class AddIceCandidateCommand implements Command {
118 | public void execute(String peerId, JSONObject payload) throws JSONException {
119 | Log.d(TAG, "AddIceCandidateCommand");
120 | PeerConnection pc = peers.get(peerId).pc;
121 | if (pc.getRemoteDescription() != null) {
122 | IceCandidate candidate = new IceCandidate(
123 | payload.getString("id"),
124 | payload.getInt("label"),
125 | payload.getString("candidate")
126 | );
127 | pc.addIceCandidate(candidate);
128 | }
129 | }
130 | }
131 |
132 | /**
133 | * Send a message through the signaling server
134 | *
135 | * @param to id of recipient
136 | * @param type type of message
137 | * @param payload payload of message
138 | * @throws JSONException
139 | */
140 | public void sendMessage(String to, String type, JSONObject payload) throws JSONException {
141 | JSONObject message = new JSONObject();
142 | message.put("to", to);
143 | message.put("type", type);
144 | message.put("payload", payload);
145 | client.emit("message", message);
146 |
147 | }
148 |
149 | private class MessageHandler {
150 | private HashMap commandMap;
151 |
152 | private MessageHandler() {
153 | this.commandMap = new HashMap<>();
154 | commandMap.put("init", new CreateOfferCommand());
155 | commandMap.put("offer", new CreateAnswerCommand());
156 | commandMap.put("answer", new SetRemoteSDPCommand());
157 | commandMap.put("candidate", new AddIceCandidateCommand());
158 | }
159 |
160 | private Emitter.Listener onMessage = new Emitter.Listener() {
161 | @Override
162 | public void call(Object... args) {
163 | JSONObject data = (JSONObject) args[0];
164 | try {
165 | String from = data.getString("from");
166 | String type = data.getString("type");
167 | JSONObject payload = null;
168 | Log.d("minhhere ", from + " " + type);
169 | if (!type.equals("init")) {
170 | payload = data.getJSONObject("payload");
171 | }
172 | // if peer is unknown, try to add him
173 | if (!peers.containsKey(from)) {
174 | // if MAX_PEER is reach, ignore the call
175 | int endPoint = findEndPoint();
176 | if (endPoint != MAX_PEER) {
177 | Peer peer = addPeer(from, endPoint);
178 | peer.pc.addStream(localMS);
179 | commandMap.get(type).execute(from, payload);
180 | }
181 | } else {
182 | commandMap.get(type).execute(from, payload);
183 | }
184 | } catch (JSONException e) {
185 | e.printStackTrace();
186 | }
187 | }
188 | };
189 |
190 | private Emitter.Listener onEject = new Emitter.Listener() {
191 | @Override
192 | public void call(Object... args) {
193 | android.os.Process.killProcess(android.os.Process.myPid());
194 | //mListener.onReject();
195 | }
196 | };
197 |
198 | private Emitter.Listener onRemoveCall = new Emitter.Listener() {
199 | @Override
200 | public void call(Object... args) {
201 | android.os.Process.killProcess(android.os.Process.myPid());
202 | }
203 | };
204 |
205 | private Emitter.Listener onAccept = new Emitter.Listener() {
206 | @Override
207 | public void call(Object... args) {
208 | JSONObject data = (JSONObject) args[0];
209 | try {
210 | String from = data.getString("myId");
211 | mListener.onAcceptCall(from);
212 | } catch (JSONException e) {
213 | e.printStackTrace();
214 | }
215 |
216 | }
217 | };
218 |
219 | //listen to the id event from the server to get the user id
220 | private Emitter.Listener onId = new Emitter.Listener() {
221 | @Override
222 | public void call(Object... args) {
223 | String id = (String) args[0];
224 | mListener.onCallReady(id);
225 | }
226 | };
227 |
228 | //listen to the chat event from the server and then chat adapter add message to view
229 | private Emitter.Listener onChat = new Emitter.Listener() {
230 | @Override
231 | public void call(Object... args) {
232 | try {
233 | JSONObject obj = (JSONObject) args[0];
234 | String id = obj.getString("user_id");
235 | String msg = obj.getString("msg");
236 | mListener.receiveMessage(id, msg);
237 | } catch (JSONException e) {
238 | }
239 | }
240 | };
241 | }
242 |
243 | private class Peer implements SdpObserver, PeerConnection.Observer {
244 | private PeerConnection pc;
245 | private String id;
246 | private int endPoint;
247 |
248 | @Override
249 | public void onCreateSuccess(final SessionDescription sdp) {
250 | // TODO: modify sdp to use pcParams prefered codecs
251 | try {
252 | JSONObject payload = new JSONObject();
253 | payload.put("type", sdp.type.canonicalForm());
254 | payload.put("sdp", sdp.description);
255 | sendMessage(id, sdp.type.canonicalForm(), payload);
256 | pc.setLocalDescription(Peer.this, sdp);
257 | } catch (JSONException e) {
258 | e.printStackTrace();
259 | }
260 | }
261 |
262 | @Override
263 | public void onSetSuccess() {
264 | }
265 |
266 | @Override
267 | public void onCreateFailure(String s) {
268 | }
269 |
270 | @Override
271 | public void onSetFailure(String s) {
272 | }
273 |
274 | @Override
275 | public void onSignalingChange(PeerConnection.SignalingState signalingState) {
276 | }
277 |
278 | @Override
279 | public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) {
280 | Log.d("minhfinal","ice conenction change "+iceConnectionState);
281 | // if (iceConnectionState == PeerConnection.IceConnectionState.DISCONNECTED) {
282 | // removePeer(id);
283 | // mListener.onStatusChanged("DISCONNECTED");
284 | // }
285 | }
286 |
287 | @Override
288 | public void onIceConnectionReceivingChange(boolean b) {
289 |
290 | }
291 |
292 | @Override
293 | public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {
294 | }
295 |
296 | @Override
297 | public void onIceCandidate(final IceCandidate candidate) {
298 | try {
299 | JSONObject payload = new JSONObject();
300 | payload.put("label", candidate.sdpMLineIndex);
301 | payload.put("id", candidate.sdpMid);
302 | payload.put("candidate", candidate.sdp);
303 | sendMessage(id, "candidate", payload);
304 | } catch (JSONException e) {
305 | e.printStackTrace();
306 | }
307 | }
308 |
309 | @Override
310 | public void onAddStream(MediaStream mediaStream) {
311 | Log.d(TAG, "onAddStream " + mediaStream.label());
312 | // remote streams are displayed from 1 to MAX_PEER (0 is localStream)
313 | mListener.onAddRemoteStream(mediaStream, endPoint + 1);
314 | }
315 |
316 | @Override
317 | public void onRemoveStream(MediaStream mediaStream) {
318 | Log.d(TAG, "onRemoveStream " + mediaStream.label());
319 | removePeer(id);
320 | }
321 |
322 | @Override
323 | public void onDataChannel(DataChannel dataChannel) {
324 | }
325 |
326 | @Override
327 | public void onRenegotiationNeeded() {
328 |
329 | }
330 |
331 | public Peer(String id, int endPoint) {
332 | Log.d("anhminh", "new Peer: " + id + " " + endPoint);
333 | this.pc = factory.createPeerConnection(iceServers, pcConstraints, this);
334 | this.id = id;
335 | this.endPoint = endPoint;
336 |
337 | pc.addStream(localMS); //, new MediaConstraints()
338 |
339 | mListener.onStatusChanged("CONNECTING");
340 | }
341 | }
342 |
343 | private Peer addPeer(String id, int endPoint) {
344 | Peer peer = new Peer(id, endPoint);
345 | peers.put(id, peer);
346 |
347 | endPoints[endPoint] = true;
348 | return peer;
349 | }
350 |
351 | public void removePeer(String id) {
352 | Peer peer = peers.get(id);
353 | mListener.onRemoveRemoteStream(peer.endPoint);
354 | peer.pc.close();
355 | peers.remove(peer.id);
356 | endPoints[peer.endPoint] = false;
357 | }
358 |
359 | public WebRtcClient(RtcListener listener, String host, PeerConnectionParameters params, String myId) {
360 | mListener = listener;
361 | pcParams = params;
362 | this.myId = myId;
363 | PeerConnectionFactory.initializeAndroidGlobals(listener, true, true,
364 | params.videoCodecHwAcceleration);
365 | factory = new PeerConnectionFactory();
366 | MessageHandler messageHandler = new MessageHandler();
367 |
368 | try {
369 | client = IO.socket(host);
370 | } catch (URISyntaxException e) {
371 | e.printStackTrace();
372 | }
373 | client.on("id", messageHandler.onId);
374 | client.on("message", messageHandler.onMessage);
375 | client.on("chat", messageHandler.onChat);
376 | client.on("ejectcall", messageHandler.onEject);
377 | client.on("acceptcall", messageHandler.onAccept);
378 | client.on("removecall", messageHandler.onRemoveCall);
379 | client.connect();
380 | try {
381 | JSONObject message = new JSONObject();
382 | message.put("myId", this.myId);
383 | client.emit("resetId", message);
384 | } catch (JSONException e) {
385 | e.printStackTrace();
386 | }
387 | //iceServers.add(new PeerConnection.IceServer("stun:23.21.150.121:3478"));
388 | //iceServers.add(new PeerConnection.IceServer("stun:stun.l.google.com:19302"));
389 | //iceServers.add(new PeerConnection.IceServer("stun:stun1.l.google.com:19302"));
390 | pcConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"));
391 | pcConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", "true"));
392 | pcConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));
393 | }
394 |
395 | /**
396 | * Call this method in Activity.onPause()
397 | */
398 | public void onPause() {
399 | if (videoSource != null) videoSource.stop();
400 | }
401 |
402 | /**
403 | * Call this method in Activity.onResume()
404 | */
405 | public void onResume() {
406 | if (videoSource != null) videoSource.restart();
407 | }
408 |
409 | /**
410 | * Call this method in Activity.onDestroy()
411 | */
412 | public void onDestroy() {
413 | for (Peer peer : peers.values()) {
414 | peer.pc.dispose();
415 | }
416 | videoSource.dispose();
417 | factory.dispose();
418 | client.disconnect();
419 | client.close();
420 | }
421 |
422 | public void stopVideo() {
423 | videoSource.stop();
424 | }
425 |
426 | private int findEndPoint() {
427 | for (int i = 0; i < MAX_PEER; i++) if (!endPoints[i]) return i;
428 | return MAX_PEER;
429 | }
430 |
431 | /**
432 | * Start the client.
433 | *
434 | * Set up the local stream and notify the signaling server.
435 | * Call this method after onCallReady.
436 | *
437 | * @param name client name
438 | */
439 | public void start(String name) {
440 | setCamera();
441 | try {
442 | JSONObject message = new JSONObject();
443 | message.put("name", name);
444 | client.emit("readyToStream", message);
445 | } catch (JSONException e) {
446 | e.printStackTrace();
447 | }
448 | }
449 |
450 | public void transmitChat(JSONObject message) {
451 | client.emit("chat", message);
452 | }
453 |
454 | public void removeCall(JSONObject message){
455 | client.emit("removecall", message);
456 |
457 | }
458 |
459 | // public String client_id() {
460 | // return client.id();
461 | // }
462 |
463 | public void startClient(String to, String type, JSONObject payload) throws JSONException {
464 | Log.d("minhminh", "vao ham moi tao");
465 | JSONObject message = new JSONObject();
466 | message.put("to", to);
467 | message.put("type", type);
468 | message.put("payload", payload);
469 | client.emit("startclient", message);
470 | }
471 |
472 | private void setCamera() {
473 | localMS = factory.createLocalMediaStream("ARDAMS");
474 | if (pcParams.videoCallEnabled) {
475 | MediaConstraints videoConstraints = new MediaConstraints();
476 | videoConstraints.mandatory.add(new MediaConstraints.KeyValuePair("maxHeight", Integer.toString(pcParams.videoHeight)));
477 | videoConstraints.mandatory.add(new MediaConstraints.KeyValuePair("maxWidth", Integer.toString(pcParams.videoWidth)));
478 | videoConstraints.mandatory.add(new MediaConstraints.KeyValuePair("maxFrameRate", Integer.toString(pcParams.videoFps)));
479 | videoConstraints.mandatory.add(new MediaConstraints.KeyValuePair("minFrameRate", Integer.toString(pcParams.videoFps)));
480 |
481 | videoSource = factory.createVideoSource(getVideoCapturer(), videoConstraints);
482 | localMS.addTrack(factory.createVideoTrack("ARDAMSv0", videoSource));
483 | }
484 |
485 | AudioSource audioSource = factory.createAudioSource(new MediaConstraints());
486 | localMS.addTrack(factory.createAudioTrack("ARDAMSa0", audioSource));
487 |
488 | mListener.onLocalStream(localMS);
489 | }
490 |
491 | private VideoCapturer getVideoCapturer() {
492 | String frontCameraDeviceName = getNameOfFrontFacingDevice();
493 | return VideoCapturerAndroid.create(frontCameraDeviceName);
494 | }
495 |
496 | public static String getNameOfFrontFacingDevice() {
497 | for (int i = 0; i < Camera.getNumberOfCameras(); ++i) {
498 | Camera.CameraInfo info = new Camera.CameraInfo();
499 | Camera.getCameraInfo(i, info);
500 | if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)
501 | return getDeviceName(i);
502 | }
503 | throw new RuntimeException("Front facing camera does not exist.");
504 | }
505 |
506 | public static String getDeviceName(int index) {
507 | Camera.CameraInfo info = new Camera.CameraInfo();
508 | Camera.getCameraInfo(index, info);
509 | String facing =
510 | (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) ? "front" : "back";
511 | return "Camera " + index + ", Facing " + facing
512 | + ", Orientation " + info.orientation;
513 | }
514 | }
--------------------------------------------------------------------------------
/app/src/main/java/fr/pchab/androidrtc/RtcActivity.java:
--------------------------------------------------------------------------------
1 | package fr.pchab.androidrtc;
2 |
3 | import android.app.ActivityManager;
4 | import android.app.ListActivity;
5 | import android.app.Notification;
6 | import android.app.NotificationManager;
7 | import android.app.PendingIntent;
8 | import android.content.BroadcastReceiver;
9 | import android.content.ComponentName;
10 | import android.content.Context;
11 | import android.content.Intent;
12 | import android.graphics.Point;
13 | import android.media.RingtoneManager;
14 | import android.opengl.GLSurfaceView;
15 | import android.os.Build;
16 | import android.os.Bundle;
17 | import android.util.Log;
18 | import android.view.View;
19 | import android.view.Window;
20 | import android.view.WindowManager.LayoutParams;
21 | import android.view.inputmethod.InputMethodManager;
22 | import android.widget.EditText;
23 | import android.widget.ListView;
24 | import android.widget.RemoteViews;
25 | import android.widget.Toast;
26 |
27 | import org.json.JSONException;
28 | import org.json.JSONObject;
29 | import org.webrtc.MediaStream;
30 | import org.webrtc.RendererCommon;
31 | import org.webrtc.VideoRenderer;
32 | import org.webrtc.VideoRendererGui;
33 |
34 | import java.util.LinkedList;
35 | import java.util.List;
36 |
37 | import fr.pchab.androidrtc.Adapter.ChatAdapter;
38 | import fr.pchab.androidrtc.Model.ChatMessage;
39 | import fr.pchab.webrtcclient.PeerConnectionParameters;
40 | import fr.pchab.webrtcclient.WebRtcClient;
41 |
42 | public class RtcActivity extends ListActivity implements WebRtcClient.RtcListener {
43 | private static final String VIDEO_CODEC_VP9 = "VP8";
44 | private static final String AUDIO_CODEC_OPUS = "opus";
45 | // Local preview screen position before call is connected.
46 | private static final int LOCAL_X_CONNECTING = 0;
47 | private static final int LOCAL_Y_CONNECTING = 0;
48 | private static final int LOCAL_WIDTH_CONNECTING = 100;
49 | private static final int LOCAL_HEIGHT_CONNECTING = 100;
50 | // Local preview screen position after call is connected.
51 | private static final int LOCAL_X_CONNECTED = 72;
52 | private static final int LOCAL_Y_CONNECTED = 72;
53 | private static final int LOCAL_WIDTH_CONNECTED = 25;
54 | private static final int LOCAL_HEIGHT_CONNECTED = 25;
55 | // Remote video screen position
56 | private static final int REMOTE_X = 0;
57 | private static final int REMOTE_Y = 0;
58 | private static final int REMOTE_WIDTH = 100;
59 | private static final int REMOTE_HEIGHT = 100;
60 | private RendererCommon.ScalingType scalingType = RendererCommon.ScalingType.SCALE_ASPECT_FILL;
61 | private GLSurfaceView vsv;
62 | private VideoRenderer.Callbacks localRender;
63 | private VideoRenderer.Callbacks remoteRender;
64 | private static WebRtcClient client;
65 | private String mSocketAddress;
66 | private EditText mChatEditText;
67 | private String username;
68 | private ListView mChatList;
69 | private ChatAdapter mChatAdapter;
70 | private String myId;
71 | private String number="";
72 | private String callerIdChat="";
73 |
74 | @Override
75 | public void onCreate(Bundle savedInstanceState) {
76 | super.onCreate(savedInstanceState);
77 | requestWindowFeature(Window.FEATURE_NO_TITLE);
78 | getWindow().addFlags(
79 | LayoutParams.FLAG_FULLSCREEN
80 | | LayoutParams.FLAG_KEEP_SCREEN_ON
81 | | LayoutParams.FLAG_DISMISS_KEYGUARD
82 | | LayoutParams.FLAG_SHOW_WHEN_LOCKED
83 | | LayoutParams.FLAG_TURN_SCREEN_ON);
84 | setContentView(R.layout.main);
85 | this.mChatEditText = (EditText) findViewById(R.id.chat_input);
86 | this.mChatList = getListView();
87 | this.mChatEditText = (EditText) findViewById(R.id.chat_input);
88 |
89 | //Set list chat adapter for the list activity
90 | List ll = new LinkedList();
91 | mChatAdapter = new ChatAdapter(this, ll);
92 | mChatList.setAdapter(mChatAdapter);
93 |
94 | mSocketAddress = "http://" + getResources().getString(R.string.host);
95 | mSocketAddress += (":" + getResources().getString(R.string.port) + "/");
96 |
97 | //Set sources for video renderer in view
98 | vsv = (GLSurfaceView) findViewById(R.id.glview_call);
99 | vsv.setPreserveEGLContextOnPause(true);
100 | vsv.setKeepScreenOn(true);
101 |
102 | Bundle extras = getIntent().getExtras();
103 | if (extras != null) {
104 | myId = extras.getString("id");
105 | number = extras.getString("number");
106 | callerIdChat = extras.getString("callerIdChat");
107 | username = extras.getString("name");
108 | }
109 | VideoRendererGui.setView(vsv, new Runnable() {
110 | @Override
111 | public void run() {
112 | init();
113 | }
114 | });
115 |
116 | // local and remote render
117 | remoteRender = VideoRendererGui.create(
118 | REMOTE_X, REMOTE_Y,
119 | REMOTE_WIDTH, REMOTE_HEIGHT, scalingType, false);
120 | localRender = VideoRendererGui.create(
121 | LOCAL_X_CONNECTING, LOCAL_Y_CONNECTING,
122 | LOCAL_WIDTH_CONNECTING, LOCAL_HEIGHT_CONNECTING, scalingType, true);
123 | }
124 |
125 | /**
126 | * Initialize webrtc client
127 | *
128 | * Set up the peer connection parameters get some video information and then pass these information to Webrtcclient class.
129 | */
130 | private void init() {
131 | Point displaySize = new Point();
132 | getWindowManager().getDefaultDisplay().getSize(displaySize);
133 | PeerConnectionParameters params = new PeerConnectionParameters(
134 | true, false, displaySize.x, displaySize.y, 30, 1, VIDEO_CODEC_VP9, true, 1, AUDIO_CODEC_OPUS, true);
135 | client = new WebRtcClient(this, mSocketAddress, params, this.myId);
136 | }
137 |
138 | /**
139 | * Handle chat messages when people click the send button
140 | *
141 | * Get the message from input then add it to chat adapter
142 | * Transmit the message to other users except the one who call this function
143 | *
144 | * @param view the view that contain the button
145 | */
146 | public void sendMessage(View view) {
147 | String message = mChatEditText.getText().toString();
148 | if (message.equals("")) return; // Return if empty
149 | ChatMessage chatMsg = new ChatMessage(username, message, System.currentTimeMillis());
150 | mChatAdapter.addMessage(chatMsg);
151 |
152 | //Data is being sent under JSON object
153 | JSONObject messageJSON = new JSONObject();
154 | try {
155 |
156 | if (number != "" && number != null){
157 | //Log.d("minthestfinal","come first "+number);
158 | messageJSON.put("to", number);
159 | }else{
160 | //Log.d("minthestfinal","come second "+callerIdChat);
161 | messageJSON.put("to", callerIdChat);
162 | }
163 | //Log.d("minthestfinal","chet ngay day "+ );
164 | messageJSON.put("user_id", chatMsg.getSender());
165 | messageJSON.put("msg", chatMsg.getMessage());
166 | messageJSON.put("time", chatMsg.getTimeStamp());
167 | client.transmitChat(messageJSON);
168 | } catch (JSONException e) {
169 | e.printStackTrace();
170 | }
171 |
172 | // Hide keyboard when you send a message.
173 | View focusView = this.getCurrentFocus();
174 | if (focusView != null) {
175 | InputMethodManager inputManager = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE);
176 | inputManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
177 | }
178 | mChatEditText.setText("");
179 | }
180 |
181 | /**
182 | * Handle when people click hangup button
183 | *
184 | * Destroy all video resources and connection
185 | *
186 | * @param view the view that contain the button
187 | */
188 | public void hangup(View view) {
189 | if (client != null) {
190 | String mNumber = "";
191 | try {
192 | if (number != "" && number != null){
193 | mNumber = number;
194 | }else{
195 | mNumber= callerIdChat;
196 | }
197 | JSONObject messageJSON = new JSONObject();
198 | messageJSON.put("callerId", mNumber);
199 | client.removeCall(messageJSON);
200 | } catch (JSONException e) {
201 | e.printStackTrace();
202 | }
203 | try{ Thread.sleep(1000); }catch(InterruptedException e){ }
204 | onDestroy();
205 | }
206 | }
207 |
208 | /**
209 | * Handle when people click stopvideo button
210 | *
211 | * Stop all video resources and connection
212 | *
213 | * @param view the view that contain the button
214 | */
215 | public void stopvideo(View view) {
216 | if (client != null) {
217 | client.stopVideo();
218 |
219 | }
220 | }
221 |
222 | /**
223 | * Handle onPause event which is implement by RtcListener class
224 | *
225 | * Pause the video source
226 | */
227 | @Override
228 | public void onPause() {
229 | super.onPause();
230 | // vsv.onPause();
231 | // if (client != null) {
232 | // client.onPause();
233 | // }
234 | if(isAppIsInBackground(getBaseContext())){
235 | NotificationManager mManager;
236 | mManager = (NotificationManager) getApplicationContext()
237 | .getSystemService(
238 | getApplicationContext().NOTIFICATION_SERVICE);
239 | Intent in = new Intent(getApplicationContext(),
240 | RtcActivity.class);
241 | Notification notification = new Notification(R.drawable.notification_template_icon_bg,
242 | "Demo video ", System.currentTimeMillis());
243 | RemoteViews notificationView = new RemoteViews(getPackageName(),
244 | R.layout.notification_video_calling);
245 | in.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP
246 | | Intent.FLAG_ACTIVITY_CLEAR_TOP);
247 |
248 | Intent hangIntent = new Intent(this, hangButtonListener.class);
249 | PendingIntent pendingHangIntent = PendingIntent.getBroadcast(this, 0,
250 | hangIntent, 0);
251 | notificationView.setOnClickPendingIntent(R.id.hang_up_noti,
252 | pendingHangIntent);
253 | Intent stopIntent = new Intent(this, stopButtonListener.class);
254 | if (number != "" && number != null){
255 | stopIntent.putExtra("otheruser",number);
256 | }else{
257 | stopIntent.putExtra("otheruser",callerIdChat);
258 | }
259 |
260 | PendingIntent pendingStopIntent = PendingIntent.getBroadcast(this, 0,
261 | stopIntent, 0);
262 | notificationView.setOnClickPendingIntent(R.id.end_call_noti,pendingStopIntent
263 | );
264 | PendingIntent pendingNotificationIntent = PendingIntent.getActivity(
265 | getApplicationContext(), 0, in,
266 | PendingIntent.FLAG_UPDATE_CURRENT);
267 | notification.flags |= Notification.FLAG_AUTO_CANCEL;
268 | notification.contentView = notificationView;
269 | notification.contentIntent = pendingNotificationIntent;
270 | mManager.notify(0, notification);
271 | }
272 | }
273 |
274 | public static class hangButtonListener extends BroadcastReceiver {
275 | @Override
276 | public void onReceive(Context context, Intent intent) {
277 | client.stopVideo();
278 | }
279 | }
280 |
281 | public static class stopButtonListener extends BroadcastReceiver {
282 | @Override
283 | public void onReceive(Context context, Intent intent) {
284 | Bundle extras = intent.getExtras();
285 | //client.onDestroy();
286 | //android.os.Process.killProcess(android.os.Process.myPid());
287 | Intent mainview = new Intent(context,MainActivity.class);
288 | mainview.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
289 | context.startActivity(mainview);
290 |
291 | if (extras.containsKey("otheruser")){
292 | try {
293 | JSONObject messageJSON = new JSONObject();
294 | messageJSON.put("callerId", extras.getString("otheruser"));
295 | client.removeCall(messageJSON);
296 | } catch (JSONException e) {
297 | e.printStackTrace();
298 | }
299 | }else{
300 | Log.d("minhhhh","Loi khong co key");
301 | }
302 |
303 | }
304 | }
305 |
306 |
307 | /**
308 | * Handle onResume event which is implement by RtcListener class
309 | *
310 | * Resume the video source
311 | */
312 | @Override
313 | public void onResume() {
314 | super.onResume();
315 | // vsv.onResume();
316 | // if (client != null) {
317 | // client.onResume();
318 | // }
319 | }
320 |
321 | /**
322 | * Handle onDestroy event which is implement by RtcListener class
323 | *
324 | * Destroy the video source
325 | */
326 | @Override
327 | public void onDestroy() {
328 | // if(client != null) {
329 | // client.onDestroy();
330 | // }
331 | super.onDestroy();
332 | android.os.Process.killProcess(android.os.Process.myPid());
333 | }
334 |
335 | /**
336 | * This function is being call when user have got an id from nodejs server
337 | *
338 | * check if caller id is not null then answer the call
339 | * if not then start the camera and send id to other user
340 | *
341 | * @param callId the id of the user
342 | */
343 | @Override
344 | public void onCallReady(String callId) {
345 | // this.username = client.client_id();
346 | if (number != null) {
347 | try {
348 | client.startClient(number, "init", null);
349 | } catch (JSONException e) {
350 | e.printStackTrace();
351 | }
352 | } else {
353 | call(callId);
354 | }
355 | }
356 |
357 | /**
358 | * This function is being call when user reject phone call
359 | */
360 | @Override
361 | public void onReject() {
362 | // Intent intent = new Intent(getApplicationContext(), MainActivity.class);
363 | // intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
364 | // intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
365 | // startActivity(intent);
366 | // onDestroy();
367 | //android.os.Process.killProcess(android.os.Process.myPid());
368 | // Intent mainview = new Intent(getApplicationContext(),MainActivity.class);
369 | // mainview.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
370 | // startActivity(mainview);\
371 | }
372 |
373 | @Override
374 | public void onAcceptCall(String callId) {
375 | try {
376 | try{ Thread.sleep(1500); }catch(InterruptedException e){ }
377 | answer(callId);
378 | } catch (JSONException e) {
379 | e.printStackTrace();
380 | }
381 | }
382 |
383 | /**
384 | * This function is being when the chat event is being triggered
385 | *
386 | * Add the chat message to the chat adapter
387 | *
388 | * @param id the id of the user sent the chat
389 | * @param msg the message
390 | */
391 | @Override
392 | public void receiveMessage(final String id, final String msg) {
393 |
394 | runOnUiThread(new Runnable() {
395 | @Override
396 | public void run() {
397 | ChatMessage chatMsg = new ChatMessage(id, msg, System.currentTimeMillis());
398 | mChatAdapter.addMessage(chatMsg);
399 | if(isAppIsInBackground(getBaseContext())){
400 | NotificationManager mManager;
401 | mManager = (NotificationManager) getApplicationContext()
402 | .getSystemService(
403 | getApplicationContext().NOTIFICATION_SERVICE);
404 | Intent in = new Intent(getApplicationContext(),
405 | RtcActivity.class);
406 | Notification notification = new Notification(R.drawable.notification_template_icon_bg,
407 | "New message from "+id, System.currentTimeMillis());
408 | notification.sound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
409 | in.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP
410 | | Intent.FLAG_ACTIVITY_CLEAR_TOP);
411 |
412 | PendingIntent pendingNotificationIntent = PendingIntent.getActivity(
413 | getApplicationContext(), 0, in,
414 | PendingIntent.FLAG_UPDATE_CURRENT);
415 | notification.flags |= Notification.FLAG_AUTO_CANCEL;
416 | notification.setLatestEventInfo(getApplicationContext(),
417 | "New message", msg,
418 | pendingNotificationIntent);
419 | mManager.notify(0, notification);
420 | }
421 | }
422 | });
423 | }
424 |
425 | /**
426 | * Check application is in the backgroud or in foreground
427 | *
428 | * @param context the id of the user sent the chat
429 | */
430 | private boolean isAppIsInBackground(Context context) {
431 | boolean isInBackground = true;
432 | ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
433 | if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH) {
434 | List runningProcesses = am.getRunningAppProcesses();
435 | for (ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) {
436 | if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
437 | for (String activeProcess : processInfo.pkgList) {
438 | if (activeProcess.equals(context.getPackageName())) {
439 | isInBackground = false;
440 | }
441 | }
442 | }
443 | }
444 | } else {
445 | List taskInfo = am.getRunningTasks(1);
446 | ComponentName componentInfo = taskInfo.get(0).topActivity;
447 | if (componentInfo.getPackageName().equals(context.getPackageName())) {
448 | isInBackground = false;
449 | }
450 | }
451 |
452 | return isInBackground;
453 | }
454 |
455 | /**
456 | * This function is being call to answer call from other user
457 | *
458 | * send init message to the caller and connect
459 | * start the camera
460 | *
461 | * @param callerId the id of the caler
462 | */
463 | public void answer(String callerId) throws JSONException {
464 | client.sendMessage(callerId, "init", null);
465 | startCam();
466 | }
467 |
468 | /**
469 | * This function is to send message contain id to the other user in order to start a call
470 | *
471 | * Start intent then start the message intent contain url and user id
472 | *
473 | * @param callId the id of the user
474 | */
475 | public void call(String callId) {
476 | startCam();
477 | }
478 |
479 |
480 | /**
481 | * Start camera function
482 | *
483 | * call the webrtc start camera function
484 | */
485 | public void startCam() {
486 | // Camera settings
487 | client.start("android_test");
488 | }
489 |
490 | /**
491 | * Being called when call status change
492 | *
493 | * Log message when webrtc status change
494 | */
495 | @Override
496 | public void onStatusChanged(final String newStatus) {
497 | runOnUiThread(new Runnable() {
498 | @Override
499 | public void run() {
500 | Toast.makeText(getApplicationContext(), newStatus, Toast.LENGTH_SHORT).show();
501 | }
502 | });
503 | }
504 |
505 | /**
506 | * Being called when local stream is added
507 | *
508 | * Update render view for the local stream in the small window
509 | */
510 | @Override
511 | public void onLocalStream(MediaStream localStream) {
512 | localStream.videoTracks.get(0).addRenderer(new VideoRenderer(localRender));
513 | VideoRendererGui.update(localRender,
514 | LOCAL_X_CONNECTING, LOCAL_Y_CONNECTING,
515 | LOCAL_WIDTH_CONNECTING, LOCAL_HEIGHT_CONNECTING,
516 | scalingType,false);
517 | }
518 |
519 | /**
520 | * Being called when remote stream is added
521 | *
522 | * Update render view for the remote stream in the big window
523 | */
524 | @Override
525 | public void onAddRemoteStream(MediaStream remoteStream, int endPoint) {
526 | remoteStream.videoTracks.get(0).addRenderer(new VideoRenderer(remoteRender));
527 | VideoRendererGui.update(remoteRender,
528 | REMOTE_X, REMOTE_Y,
529 | REMOTE_WIDTH, REMOTE_HEIGHT, RendererCommon.ScalingType.SCALE_ASPECT_FILL,false);
530 | VideoRendererGui.update(localRender,
531 | LOCAL_X_CONNECTED, LOCAL_Y_CONNECTED,
532 | LOCAL_WIDTH_CONNECTED, LOCAL_HEIGHT_CONNECTED,
533 | scalingType,false);
534 | }
535 |
536 |
537 | /**
538 | * Being called when remote stream is removed
539 | *
540 | * make local renderer become the big one again
541 | */
542 | @Override
543 | public void onRemoveRemoteStream(int endPoint) {
544 | VideoRendererGui.update(localRender,
545 | LOCAL_X_CONNECTING, LOCAL_Y_CONNECTING,
546 | LOCAL_WIDTH_CONNECTING, LOCAL_HEIGHT_CONNECTING,
547 | scalingType,false);
548 | }
549 | }
--------------------------------------------------------------------------------
/app/src/main/java/fr/pchab/androidrtc/MainActivity.java:
--------------------------------------------------------------------------------
1 | package fr.pchab.androidrtc;
2 |
3 | import android.app.ActivityManager;
4 | import android.app.ListActivity;
5 | import android.app.Notification;
6 | import android.app.NotificationManager;
7 | import android.app.PendingIntent;
8 | import android.content.ComponentName;
9 | import android.content.Context;
10 | import android.content.Intent;
11 | import android.content.SharedPreferences;
12 | import android.os.AsyncTask;
13 | import android.os.Build;
14 | import android.os.Bundle;
15 | import android.os.Handler;
16 | import android.util.Log;
17 | import android.view.View;
18 | import android.widget.AutoCompleteTextView;
19 | import android.widget.ListView;
20 | import android.widget.TextView;
21 | import android.widget.Toast;
22 |
23 | import com.github.nkzawa.emitter.Emitter;
24 | import com.github.nkzawa.socketio.client.IO;
25 | import com.github.nkzawa.socketio.client.Socket;
26 |
27 | import org.apache.http.HttpResponse;
28 | import org.apache.http.NameValuePair;
29 | import org.apache.http.client.ClientProtocolException;
30 | import org.apache.http.client.HttpClient;
31 | import org.apache.http.client.entity.UrlEncodedFormEntity;
32 | import org.apache.http.client.methods.HttpGet;
33 | import org.apache.http.client.methods.HttpPost;
34 | import org.apache.http.impl.client.DefaultHttpClient;
35 | import org.apache.http.message.BasicNameValuePair;
36 | import org.apache.http.util.EntityUtils;
37 | import org.json.JSONArray;
38 | import org.json.JSONException;
39 | import org.json.JSONObject;
40 |
41 | import java.io.IOException;
42 | import java.io.UnsupportedEncodingException;
43 | import java.net.URISyntaxException;
44 | import java.util.ArrayList;
45 | import java.util.List;
46 | import java.util.concurrent.ExecutionException;
47 |
48 | import fr.pchab.androidrtc.Adapter.HistoryAdapter;
49 | import fr.pchab.androidrtc.Adapter.UserAdapter;
50 | import fr.pchab.androidrtc.Model.HistoryItem;
51 | import fr.pchab.androidrtc.Model.User;
52 |
53 | public class MainActivity extends ListActivity {
54 | private SharedPreferences mSharedPreferences;
55 | private String userName;
56 | private String userId;
57 | private ListView mHistoryList;
58 | private HistoryAdapter mHistoryAdapter;
59 | private static UserAdapter mUserAdapter;
60 | private AutoCompleteTextView mCallNumET;
61 | private TextView mUsernameTV;
62 | public ArrayList arrayOfUsers;
63 | private Handler handler = new Handler();
64 | private Socket client;
65 |
66 | @Override
67 | protected void onCreate(Bundle savedInstanceState) {
68 | super.onCreate(savedInstanceState);
69 | setContentView(R.layout.activity_main);
70 |
71 | //Get userid and username from login or registre acitivity
72 | this.mSharedPreferences = getSharedPreferences("SHARED_PREFS", MODE_PRIVATE);
73 | if (!this.mSharedPreferences.contains("USER_ID")) {
74 | Intent intent = new Intent(this, LoginActivity.class);
75 | startActivity(intent);
76 | finish();
77 | return;
78 | }
79 | this.userId = this.mSharedPreferences.getString("USER_ID", "");
80 | this.userName = this.mSharedPreferences.getString("USER_NAME", "");
81 | this.mHistoryList = getListView();
82 | this.mCallNumET = (AutoCompleteTextView) findViewById(R.id.call_num);
83 | this.mUsernameTV = (TextView) findViewById(R.id.main_username);
84 | this.mUsernameTV.setText(this.userName);
85 |
86 | mCallNumET.setOnFocusChangeListener(new AutoCompleteTextView.OnFocusChangeListener() {
87 | @Override
88 | public void onFocusChange(View v, boolean hasFocus) {
89 | if (hasFocus) {
90 | //Add all user for searching and add friends
91 | ArrayList adapter = new ArrayList();
92 | String json_users = "";
93 | try {
94 | try {
95 | json_users = new RetrieveUserTask().execute().get();
96 | } catch (ExecutionException e) {
97 | e.printStackTrace();
98 | }
99 | } catch (InterruptedException e) {
100 | throw new RuntimeException(e);
101 | }
102 |
103 |
104 | try {
105 | JSONArray jsonarr = new JSONArray(json_users);
106 | for (int i = 0; i < jsonarr.length(); i++) {
107 | JSONObject jsonobj = jsonarr.getJSONObject(i);
108 |
109 | String id = jsonobj.getString("id");
110 | String name = jsonobj.getString("name");
111 | if (!id.equals(userId)) {
112 | User x = new User(id, name);
113 | adapter.add(x);
114 | }
115 | }
116 | } catch (Exception e) {
117 | }
118 |
119 |
120 | mUserAdapter = new UserAdapter(v.getContext(), adapter);
121 | mCallNumET.setThreshold(1);//will start working from first character
122 | mCallNumET.setAdapter(mUserAdapter);//setting the adapter data into the AutoCompleteTextView
123 |
124 | } else {
125 | Toast.makeText(getApplicationContext(), "lost the focus", Toast.LENGTH_LONG).show();
126 | }
127 | }
128 | });
129 |
130 |
131 |
132 | //add friends to friend list
133 | arrayOfUsers = new ArrayList();
134 | String json_friend = "";
135 | try {
136 | try {
137 | json_friend = new ListFriendsTask().execute(userId).get();
138 | } catch (ExecutionException e) {
139 | e.printStackTrace();
140 | }
141 | } catch (InterruptedException e) {
142 | throw new RuntimeException(e);
143 | }
144 | try {
145 | JSONArray jsonarr = new JSONArray(json_friend);
146 | for (int i = 0; i < jsonarr.length(); i++) {
147 | JSONObject jsonobj = jsonarr.getJSONObject(i);
148 | String id = jsonobj.getString("friend_id");
149 | String name = "";
150 | String status = "";
151 | try {
152 | try {
153 | status = new RetrieveStatusTask().execute(id).get();
154 | name = new RetrieveName().execute(id).get();
155 |
156 | } catch (ExecutionException e) {
157 | e.printStackTrace();
158 | }
159 | } catch (InterruptedException e) {
160 | throw new RuntimeException(e);
161 | }
162 | HistoryItem x = new HistoryItem(id, name, status);
163 | arrayOfUsers.add(x);
164 | }
165 | } catch (Exception e) {
166 | }
167 |
168 | this.mHistoryAdapter = new HistoryAdapter(this, arrayOfUsers);
169 | this.mHistoryList.setAdapter(this.mHistoryAdapter);
170 |
171 | //start other thread for checking friend online status
172 | startHandler();
173 |
174 | //Receive call callback from when other people call you
175 | String host = "http://" + getResources().getString(R.string.host);
176 | host += (":" + getResources().getString(R.string.port) + "/");
177 | try {
178 | client = IO.socket(host);
179 | } catch (URISyntaxException e) {
180 | e.printStackTrace();
181 | }
182 | client.on("receiveCall", onReceiveCall);
183 |
184 | client.connect();
185 | try {
186 | JSONObject message = new JSONObject();
187 | message.put("myId", userId);
188 | client.emit("resetId", message);
189 | } catch (JSONException e) {
190 | e.printStackTrace();
191 | }
192 | }
193 |
194 | /**
195 | * Receive call emitter callback when others call you.
196 | *
197 | * @param args json value contain callerid, userid and caller name
198 | */
199 | private Emitter.Listener onReceiveCall = new Emitter.Listener() {
200 | @Override
201 | public void call(Object... args) {
202 | String from = "";
203 | String name = "";
204 | JSONObject data = (JSONObject) args[0];
205 | try {
206 | from = data.getString("from");
207 | name = data.getString("name");
208 | client.close();
209 | } catch (JSONException e) {
210 | e.printStackTrace();
211 | }
212 | if(isAppIsInBackground(getApplicationContext())){
213 | // NotificationManager mManager;
214 | // mManager = (NotificationManager) getApplicationContext()
215 | // .getSystemService(
216 | // getApplicationContext().NOTIFICATION_SERVICE);
217 | // Intent in = new Intent(getApplicationContext(),
218 | // IncomingCallActivity.class);
219 | // in.putExtra("CALLER_ID", from);
220 | // in.putExtra("USER_ID", userId);
221 | // in.putExtra("CALLER_NAME", "Lien Minh");
222 | // in.putExtra("USER_NAME",userName);
223 | // Notification notification = new Notification(R.drawable.notification_template_icon_bg,
224 | // "Demo video ", System.currentTimeMillis());
225 | // //RemoteViews notificationView = new RemoteViews(getPackageName(),
226 | // // R.layout.notification_incoming_call);
227 | // in.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP
228 | // | Intent.FLAG_ACTIVITY_CLEAR_TOP);
229 | //
230 | //// Intent receiveIntent = new Intent(getApplicationContext(), receiveButtonListener.class);
231 | //// PendingIntent pendingReceiveIntent = PendingIntent.getBroadcast(getApplicationContext(), 0,
232 | //// receiveIntent, 0);
233 | //// notificationView.setOnClickPendingIntent(R.id.noti_receive,
234 | //// pendingReceiveIntent);
235 | ////// Intent rejectIntent = new Intent(getApplicationContext(), rejectButtonListener.class);
236 | ////// PendingIntent pendingRejectIntent = PendingIntent.getBroadcast(getApplicationContext(), 0,
237 | ////// rejectIntent, 0);
238 | ////// notificationView.setOnClickPendingIntent(R.id.noti_reject,
239 | ////// pendingRejectIntent);
240 | //
241 | // PendingIntent pendingNotificationIntent = PendingIntent.getActivity(
242 | // getApplicationContext(), 0, in,
243 | // PendingIntent.FLAG_UPDATE_CURRENT);
244 | // notification.flags |= Notification.FLAG_AUTO_CANCEL;
245 | // notification.setLatestEventInfo(getApplicationContext(),
246 | // "Incoming phone", "You have a new phone ",
247 | // pendingNotificationIntent);
248 | // //notification.contentView = notificationView;
249 | // notification.contentIntent = pendingNotificationIntent;
250 | // mManager.notify(0, notification);
251 | Intent intent = new Intent(getApplicationContext(), IncomingCallActivity.class);
252 | //intent.setComponent(new ComponentName(getPackageName(), IncomingCallActivity.class.getName()));
253 | intent.setAction(Intent.ACTION_MAIN);
254 | intent.addCategory(Intent.CATEGORY_LAUNCHER);
255 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
256 | intent.putExtra("CALLER_ID", from);
257 | intent.putExtra("USER_ID", userId);
258 | intent.putExtra("CALLER_NAME", name);
259 | intent.putExtra("USER_NAME", userName);
260 | getApplicationContext().startActivity(intent);
261 |
262 |
263 | //context.getApplicationContext().startActivity(it);
264 | }else{
265 | Intent intent = new Intent(getApplicationContext(), IncomingCallActivity.class);
266 | intent.setAction(Intent.ACTION_MAIN);
267 | intent.addCategory(Intent.CATEGORY_LAUNCHER);
268 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
269 | intent.putExtra("CALLER_ID", from);
270 | intent.putExtra("USER_ID", userId);
271 | intent.putExtra("CALLER_NAME", name);
272 | intent.putExtra("USER_NAME",userName);
273 | startActivity(intent);
274 | }
275 | }
276 | };
277 |
278 | // public static class receiveButtonListener extends BroadcastReceiver {
279 | // @Override
280 | // public void onReceive(Context context, Intent intent) {
281 | // Log.d("minhtest","Receive call");
282 | // }
283 | // }
284 | //
285 | // public static class rejectButtonListener extends BroadcastReceiver {
286 | // @Override
287 | // public void onReceive(Context context, Intent intent) {
288 | // Log.d("minhtest","Reject call");
289 | // }
290 | // }
291 |
292 | /**
293 | * Check application is in the backgroud or in foreground
294 | *
295 | * @param context the id of the user sent the chat
296 | */
297 | private boolean isAppIsInBackground(Context context) {
298 | boolean isInBackground = true;
299 | ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
300 | if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH) {
301 | List runningProcesses = am.getRunningAppProcesses();
302 | for (ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) {
303 | if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
304 | for (String activeProcess : processInfo.pkgList) {
305 | if (activeProcess.equals(context.getPackageName())) {
306 | isInBackground = false;
307 | }
308 | }
309 | }
310 | }
311 | } else {
312 | List taskInfo = am.getRunningTasks(1);
313 | ComponentName componentInfo = taskInfo.get(0).topActivity;
314 | if (componentInfo.getPackageName().equals(context.getPackageName())) {
315 | isInBackground = false;
316 | }
317 | }
318 |
319 | return isInBackground;
320 | }
321 |
322 | /**
323 | * Task to get list of users.
324 | *
325 | * @param Void
326 | */
327 | class RetrieveUserTask extends AsyncTask {
328 |
329 | private Exception exception;
330 |
331 | @Override
332 | protected String doInBackground(Void... urls) {
333 | String name = "";
334 | try {
335 | HttpClient httpclient = new DefaultHttpClient();
336 | String host = "http://" + getResources().getString(R.string.host);
337 | host += (":" + getResources().getString(R.string.port) + "/");
338 | HttpGet request = new HttpGet(host + "users/" + userId);
339 | HttpResponse response = httpclient.execute(request);
340 | name = EntityUtils.toString(response.getEntity());
341 | } catch (Exception e) {
342 | //Log.e("log_tag", "Error in http connection " + e.toString());
343 | }
344 | return name;
345 | }
346 |
347 | protected void onPostExecute(String feed) {
348 | }
349 | }
350 |
351 | /**
352 | * Task to get status of a user.
353 | *
354 | * @param String id of user you want to get status
355 | */
356 | class RetrieveStatusTask extends AsyncTask {
357 |
358 | private Exception exception;
359 |
360 | @Override
361 | protected String doInBackground(String... urls) {
362 | String name = "";
363 | String id = urls[0];
364 | try {
365 | HttpClient httpclient = new DefaultHttpClient();
366 | String host = "http://" + getResources().getString(R.string.host);
367 | host += (":" + getResources().getString(R.string.port) + "/");
368 | HttpGet request = new HttpGet(host + "status/" + id);
369 | HttpResponse response = httpclient.execute(request);
370 | String json_string = EntityUtils.toString(response.getEntity());
371 | JSONObject x = new JSONObject(json_string);
372 | int status = x.getInt("status");
373 | if (status == 1) {
374 | name = "Online";
375 | } else {
376 | name = "Offline";
377 | }
378 |
379 | } catch (Exception e) {
380 | //Log.e("log_tag", "Error in http connection " + e.toString());
381 | }
382 | return name;
383 | }
384 |
385 | protected void onPostExecute(String feed) {
386 | }
387 | }
388 |
389 | /**
390 | * Task to add friend to your account.
391 | *
392 | * @param YOUR ID AND USER ID THAT YOU WANT TO ADD AS FRIEND
393 | */
394 | class AddFriendTask extends AsyncTask {
395 |
396 | private Exception exception;
397 |
398 | @Override
399 | protected Integer doInBackground(String... urls) {
400 | String id = urls[0];
401 | try {
402 | HttpClient httpClient = new DefaultHttpClient();
403 | // replace with your url
404 | String host = "http://" + getResources().getString(R.string.host);
405 | host += (":" + getResources().getString(R.string.port) + "/");
406 | HttpPost httpPost = new HttpPost(host + "addFriend");
407 |
408 | //Post Data
409 | List nameValuePair = new ArrayList(2);
410 | nameValuePair.add(new BasicNameValuePair("username", userId));
411 | nameValuePair.add(new BasicNameValuePair("friend_id", id));
412 |
413 |
414 | //Encoding POST data
415 | try {
416 | httpPost.setEntity(new UrlEncodedFormEntity(nameValuePair));
417 | } catch (UnsupportedEncodingException e) {
418 | // log exception
419 | //Log.d("minh_res", e.getMessage());
420 | e.printStackTrace();
421 | }
422 | //making POST request.
423 | try {
424 | HttpResponse response = httpClient.execute(httpPost);
425 | String json_string = EntityUtils.toString(response.getEntity());
426 | JSONObject json_data = new JSONObject(json_string);
427 | int status = json_data.getInt("status");
428 | //Log.d("minhstatus", Integer.toString(status));
429 | if (status == 1) {
430 | return 1;
431 | }
432 |
433 | } catch (ClientProtocolException e) {
434 | //Log.d("minh_res", "error");
435 | } catch (IOException e) {
436 | // Log exception
437 | e.printStackTrace();
438 | //Log.d("minh_res", e.getMessage());
439 |
440 | }
441 | } catch (Exception e) {
442 | e.printStackTrace();
443 | }
444 | return 0;
445 | }
446 |
447 | protected void onPostExecute(String feed) {
448 | }
449 | }
450 |
451 | /**
452 | * Task to list all of your friends.
453 | *
454 | * @param String id to get list of friends
455 | */
456 | class ListFriendsTask extends AsyncTask {
457 |
458 | private Exception exception;
459 |
460 | @Override
461 | protected String doInBackground(String... urls) {
462 | String json_string = "";
463 | String user = urls[0];
464 | try {
465 | HttpClient httpClient = new DefaultHttpClient();
466 | // replace with your url
467 | String host = "http://" + getResources().getString(R.string.host);
468 | host += (":" + getResources().getString(R.string.port) + "/");
469 | HttpPost httpPost = new HttpPost(host + "friends");
470 |
471 |
472 | //Post Data
473 | List nameValuePair = new ArrayList(1);
474 | nameValuePair.add(new BasicNameValuePair("username", user));
475 |
476 |
477 | //Encoding POST data
478 | try {
479 | httpPost.setEntity(new UrlEncodedFormEntity(nameValuePair));
480 | } catch (UnsupportedEncodingException e) {
481 | // log exception
482 | e.printStackTrace();
483 | }
484 | //making POST request.
485 | try {
486 | HttpResponse response = httpClient.execute(httpPost);
487 | json_string = EntityUtils.toString(response.getEntity());
488 |
489 |
490 | } catch (ClientProtocolException e) {
491 | // Log exception
492 |
493 | //Log.d("minh_res", "error");
494 | } catch (IOException e) {
495 | // Log exception
496 | e.printStackTrace();
497 | //Log.d("minh_res", e.getMessage());
498 |
499 | }
500 | } catch (Exception e) {
501 | }
502 | return json_string;
503 | }
504 |
505 | protected void onPostExecute(String feed) {
506 | }
507 | }
508 |
509 | /**
510 | * Task to get name of a users.
511 | *
512 | * @param String id of the user you want to get name
513 | */
514 | class RetrieveName extends AsyncTask {
515 |
516 | private Exception exception;
517 |
518 | @Override
519 | protected String doInBackground(String... urls) {
520 | String json_string = "";
521 | String user = urls[0];
522 |
523 | try {
524 | HttpClient httpClient = new DefaultHttpClient();
525 | // replace with your url
526 | String host = "http://" + getResources().getString(R.string.host);
527 | host += (":" + getResources().getString(R.string.port) + "/");
528 | HttpPost httpPost = new HttpPost(host + "friend_name");
529 |
530 |
531 | //Post Data
532 | List nameValuePair = new ArrayList(1);
533 | nameValuePair.add(new BasicNameValuePair("username", user));
534 |
535 |
536 | //Encoding POST data
537 | try {
538 | httpPost.setEntity(new UrlEncodedFormEntity(nameValuePair));
539 | } catch (UnsupportedEncodingException e) {
540 | // log exception
541 | e.printStackTrace();
542 | }
543 | //making POST request.
544 | try {
545 | HttpResponse response = httpClient.execute(httpPost);
546 | json_string = EntityUtils.toString(response.getEntity());
547 | JSONObject x = new JSONObject(json_string);
548 | json_string = x.getString("name");
549 | //Log.d("minhminhminh", json_string);
550 |
551 | } catch (ClientProtocolException e) {
552 | // Log exception
553 |
554 | //Log.d("minh_res", "error");
555 | } catch (IOException e) {
556 | // Log exception
557 | e.printStackTrace();
558 | //Log.d("minh_res", e.getMessage());
559 |
560 | }
561 | } catch (Exception e) {
562 | }
563 | return json_string;
564 | }
565 |
566 | protected void onPostExecute(String feed) {
567 | }
568 | }
569 |
570 | /**
571 | * Take the user to a video screen. USER_NAME is a required field.
572 | *
573 | * @param id button that is clicked to trigger toVideo
574 | */
575 | public void makeCall(String id, String status) {
576 | String callNum = id;
577 | if (callNum.isEmpty() || callNum.equals(this.userId)) {
578 | showToast("Enter a valid user ID to call.");
579 | return;
580 | }
581 | if (status.equals("Offline")){
582 | showToast("Your friend is offline. Please call again later!");
583 | }else{
584 | //remove callback check status every 10
585 | handler.removeCallbacksAndMessages(null);
586 | dispatchCall(callNum);
587 | }
588 | }
589 |
590 |
591 | /**
592 | * TODO: Debate who calls who. Should one be on standby? Or use State API for busy/available
593 | * Check that user is online. If they are, dispatch the call by publishing to their standby
594 | * channel. If the publish was successful, then change activities over to the video chat.
595 | * The called user will then have the option to accept of decline the call. If they accept,
596 | * they will be brought to the video chat activity as well, to connect video/audio. If
597 | * they decline, a hangup will be issued, and the VideoChat adapter's onHangup callback will
598 | * be invoked.
599 | *
600 | * @param callNum Number to publish a call to.
601 | */
602 | public void dispatchCall(final String callNum) {
603 | Log.d("minhfinal",callNum);
604 | Intent intent = new Intent(MainActivity.this, RtcActivity.class);
605 | //boolean activityExists = intent.resolveActivityInfo(getPackageManager(), 0) != null;
606 | //Log.d("minhfinal",Boolean.toString(activityExists) );
607 | // if (activityExists){
608 | // intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
609 | // intent.putExtra("id", this.userId);
610 | // intent.putExtra("name", this.userName);
611 | // intent.putExtra("number", callNum);
612 | // }else{
613 | // Log.d("minhfinal", "come here re");
614 | // intent.putExtra("id", this.userId);
615 | // intent.putExtra("name", this.userName);
616 | // intent.putExtra("number", callNum);
617 | //
618 | // }
619 | //intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
620 | Log.d("minhfinal", "come here re");
621 | intent.putExtra("id", this.userId);
622 | intent.putExtra("name", this.userName);
623 | intent.putExtra("number", callNum);
624 | startActivity(intent);
625 |
626 |
627 | // Intent intent = new Intent(MainActivity.this, CallingActivity.class);
628 | // intent.putExtra("CALLER_ID", callNum);
629 | // intent.putExtra("USER_ID", userId);
630 | // intent.putExtra("CALLER_NAME", "Lien Minh");
631 | // intent.putExtra("USER_NAME", userName);
632 | // startActivity(intent);
633 |
634 | }
635 |
636 |
637 | /**
638 | * Ensures that toast is run on the UI thread.
639 | *
640 | * @param message
641 | */
642 | private void showToast(final String message) {
643 | runOnUiThread(new Runnable() {
644 | @Override
645 | public void run() {
646 | Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();
647 | }
648 | });
649 | }
650 |
651 | /**
652 | * Add friend to your directory when you click add friend.
653 | *
654 | * @param id,name id and name of your friend
655 | */
656 | public void addfriend(String id, String name) {
657 | this.mCallNumET.dismissDropDown();
658 | int result = 0;
659 | try {
660 | result = new AddFriendTask().execute(id).get();
661 | } catch (InterruptedException e) {
662 | e.printStackTrace();
663 | } catch (ExecutionException e) {
664 | e.printStackTrace();
665 | }
666 | if (result != 0) {
667 | HistoryItem x = new HistoryItem(id, name, "online");
668 | arrayOfUsers.add(x);
669 | mHistoryAdapter.notifyDataSetChanged();
670 | } else {
671 | showToast("error occured");
672 | }
673 | }
674 |
675 | /**
676 | * Check status of your friend whether online or offline.
677 | *
678 | * @param none
679 | */
680 | private void checkFriendStatus() {
681 | int checkChange = 0;
682 | for (HistoryItem user : arrayOfUsers) {
683 | String status;
684 | try {
685 | try {
686 | status = new RetrieveStatusTask().execute(user.getUserId()).get();
687 | Log.d("minhlog","come here handler status old: " + user.getStatus()+ "stayts new "+status);
688 | if (status != null && !status.isEmpty() && !status.equals(user.getStatus())) {
689 | user.setStatus(status);
690 | checkChange = 1;
691 | }
692 | } catch (ExecutionException e) {
693 | e.printStackTrace();
694 | }
695 | } catch (InterruptedException e) {
696 | throw new RuntimeException(e);
697 | }
698 |
699 | }
700 | if (checkChange != 0) {
701 | mHistoryAdapter.notifyDataSetChanged();
702 | }
703 | }
704 |
705 |
706 |
707 | public void startHandler() {
708 | handler.postDelayed(new Runnable() {
709 |
710 | @Override
711 | public void run() {
712 | checkFriendStatus();
713 | handler.postDelayed(this, 3000);
714 | }
715 | }, 3000);
716 | }
717 | }
--------------------------------------------------------------------------------