diff --git a/app/src/main/java/org/linphone/LinphoneActivity.java b/app/src/main/java/org/linphone/LinphoneActivity.java
index 404964729..4de17425a 100644
--- a/app/src/main/java/org/linphone/LinphoneActivity.java
+++ b/app/src/main/java/org/linphone/LinphoneActivity.java
@@ -637,6 +637,10 @@ public class LinphoneActivity extends LinphoneGenericActivity implements OnClick
changeCurrentFragment(FragmentsAvailable.ABOUT, null);
}
+ public void displayRecordings() {
+
+ }
+
public void displayContactsForEdition(String sipAddress, String displayName) {
Bundle extras = new Bundle();
extras.putBoolean("EditOnClick", true);
@@ -1606,6 +1610,7 @@ public class LinphoneActivity extends LinphoneGenericActivity implements OnClick
if (getResources().getBoolean(R.bool.enable_in_app_purchase)) {
sideMenuItems.add(new MenuItem(getResources().getString(R.string.inapp), R.drawable.menu_options));
}
+ sideMenuItems.add(new MenuItem(getResources().getString(R.string.menu_recordings), R.drawable.menu_recordings));
sideMenuItems.add(new MenuItem(getResources().getString(R.string.menu_about), R.drawable.menu_about));
sideMenuContent = findViewById(R.id.side_menu_content);
sideMenuItemList = findViewById(R.id.item_list);
@@ -1629,6 +1634,9 @@ public class LinphoneActivity extends LinphoneGenericActivity implements OnClick
LinphoneActivity.instance().displayInapp();
}
}
+ if (sideMenuItemList.getAdapter().getItem(i).toString().equals(R.string.menu_recordings)) {
+ LinphoneActivity.instance().displayRecordings();
+ }
openOrCloseSideMenu(false);
}
});
diff --git a/app/src/main/java/org/linphone/call/CallActivity.java b/app/src/main/java/org/linphone/call/CallActivity.java
index dd24a68dd..55649595a 100644
--- a/app/src/main/java/org/linphone/call/CallActivity.java
+++ b/app/src/main/java/org/linphone/call/CallActivity.java
@@ -101,6 +101,7 @@ public class CallActivity extends LinphoneGenericActivity implements OnClickList
private static final int PERMISSIONS_REQUEST_CAMERA = 202;
private static final int PERMISSIONS_ENABLED_CAMERA = 203;
private static final int PERMISSIONS_ENABLED_MIC = 204;
+ private static final int PERMISSIONS_EXTERNAL_STORAGE = 205;
private static CallActivity instance;
@@ -109,14 +110,14 @@ public class CallActivity extends LinphoneGenericActivity implements OnClickList
private ImageView switchCamera;
private TextView missedChats;
private RelativeLayout mActiveCallHeader, sideMenuContent, avatar_layout;
- private ImageView pause, hangUp, dialer, video, micro, speaker, options, addCall, transfer, conference, conferenceStatus, contactPicture;
+ private ImageView pause, hangUp, dialer, video, micro, speaker, options, addCall, transfer, conference, conferenceStatus, contactPicture, recordCall, recording;
private ImageView audioRoute, routeSpeaker, routeEarpiece, routeBluetooth, menu, chat;
private LinearLayout mNoCurrentCall, callInfo, mCallPaused;
private ProgressBar videoProgress;
private StatusFragment status;
private CallAudioFragment audioCallFragment;
private CallVideoFragment videoCallFragment;
- private boolean isSpeakerEnabled = false, isMicMuted = false, isTransferAllowed, isVideoAsk;
+ private boolean isSpeakerEnabled = false, isMicMuted = false, isTransferAllowed, isVideoAsk, isRecording = false;
private LinearLayout mControlsLayout;
private Numpad numpad;
private int cameraNumber;
@@ -194,7 +195,7 @@ public class CallActivity extends LinphoneGenericActivity implements OnClickList
return;
} else if (state == State.Paused || state == State.PausedByRemote || state == State.Pausing) {
if (LinphoneManager.getLc().getCurrentCall() != null) {
- enabledVideoButton(false);
+ video.setEnabled(false);
}
if (isVideoEnabled(call)) {
showAudioView();
@@ -207,7 +208,7 @@ public class CallActivity extends LinphoneGenericActivity implements OnClickList
}
}
if (LinphoneManager.getLc().getCurrentCall() != null) {
- enabledVideoButton(true);
+ video.setEnabled(true);
}
} else if (state == State.StreamsRunning) {
switchVideo(isVideoEnabled(call));
@@ -344,7 +345,7 @@ public class CallActivity extends LinphoneGenericActivity implements OnClickList
//TopBar
video = findViewById(R.id.video);
video.setOnClickListener(this);
- enabledVideoButton(false);
+ video.setEnabled(false);
videoProgress = findViewById(R.id.video_in_progress);
videoProgress.setVisibility(View.GONE);
@@ -380,7 +381,7 @@ public class CallActivity extends LinphoneGenericActivity implements OnClickList
pause = findViewById(R.id.pause);
pause.setOnClickListener(this);
- enabledPauseButton(false);
+ pause.setEnabled(false);
mActiveCallHeader = findViewById(R.id.active_call);
mNoCurrentCall = findViewById(R.id.no_current_call);
@@ -402,6 +403,15 @@ public class CallActivity extends LinphoneGenericActivity implements OnClickList
conference.setEnabled(false);
conference.setOnClickListener(this);
+ recordCall = findViewById(R.id.record_call);
+ recordCall.setOnClickListener(this);
+ recordCall.setEnabled(false);
+
+ recording = findViewById(R.id.recording);
+ recording.setOnClickListener(this);
+ recording.setEnabled(false);
+ recording.setVisibility(View.GONE);
+
try {
audioRoute = findViewById(R.id.audio_route);
audioRoute.setOnClickListener(this);
@@ -489,6 +499,15 @@ public class CallActivity extends LinphoneGenericActivity implements OnClickList
}
});
break;
+ case PERMISSIONS_EXTERNAL_STORAGE:
+ LinphoneUtils.dispatchOnUIThread(new Runnable() {
+ @Override
+ public void run() {
+ if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ toggleCallRecording(!isRecording);
+ }
+ }
+ });
}
}
@@ -528,7 +547,7 @@ public class CallActivity extends LinphoneGenericActivity implements OnClickList
public void refreshInCallActions() {
if (!LinphonePreferences.instance().isVideoEnabled() || isConferenceRunning) {
- enabledVideoButton(false);
+ video.setEnabled(false);
} else {
if (video.isEnabled()) {
if (isVideoEnabled(LinphoneManager.getLc().getCurrentCall())) {
@@ -582,33 +601,27 @@ public class CallActivity extends LinphoneGenericActivity implements OnClickList
}
//Enabled transfer button
- if (isTransferAllowed && !LinphoneManager.getLc().soundResourcesLocked())
- enabledTransferButton(true);
+ transfer.setEnabled(isTransferAllowed && !LinphoneManager.getLc().soundResourcesLocked());
//Enable conference button
- if (LinphoneManager.getLc().getCallsNb() > 1 && LinphoneManager.getLc().getCallsNb() > confsize && !LinphoneManager.getLc().soundResourcesLocked()) {
- enabledConferenceButton(true);
- } else {
- enabledConferenceButton(false);
- }
+ conference.setEnabled(LinphoneManager.getLc().getCallsNb() > 1 && LinphoneManager.getLc().getCallsNb() > confsize && !LinphoneManager.getLc().soundResourcesLocked());
addCall.setEnabled(LinphoneManager.getLc().getCallsNb() < LinphoneManager.getLc().getMaxCalls() && !LinphoneManager.getLc().soundResourcesLocked());
options.setEnabled(!getResources().getBoolean(R.bool.disable_options_in_call) && (addCall.isEnabled() || transfer.isEnabled()));
- if (LinphoneManager.getLc().getCurrentCall() != null && LinphonePreferences.instance().isVideoEnabled() && !LinphoneManager.getLc().getCurrentCall().mediaInProgress()) {
- enabledVideoButton(true);
- } else {
- enabledVideoButton(false);
- }
- if (LinphoneManager.getLc().getCurrentCall() != null && !LinphoneManager.getLc().getCurrentCall().mediaInProgress()) {
- enabledPauseButton(true);
- } else {
- enabledPauseButton(false);
- }
+ recordCall.setEnabled(!LinphoneManager.getLc().soundResourcesLocked());
+ recordCall.setImageResource(isRecording ? R.drawable.options_rec_selected : R.drawable.options_rec_default);
+
+ recording.setEnabled(isRecording);
+ recording.setVisibility(isRecording ? View.VISIBLE : View.GONE);
+
+
+ video.setEnabled(LinphoneManager.getLc().getCurrentCall() != null && LinphonePreferences.instance().isVideoEnabled() && !LinphoneManager.getLc().getCurrentCall().mediaInProgress());
+
+ pause.setEnabled(LinphoneManager.getLc().getCurrentCall() != null && !LinphoneManager.getLc().getCurrentCall().mediaInProgress());
+
micro.setEnabled(true);
- if (!isTablet()) {
- speaker.setEnabled(true);
- }
+ speaker.setEnabled(!isTablet());
transfer.setEnabled(true);
pause.setEnabled(true);
dialer.setEnabled(true);
@@ -649,6 +662,17 @@ public class CallActivity extends LinphoneGenericActivity implements OnClickList
toggleSpeaker();
} else if (id == R.id.add_call) {
goBackToDialer();
+ } else if (id == R.id.record_call) {
+ int externalStorage = getPackageManager().checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, getPackageName());
+ Log.i("[Permission] External storage permission is " + (externalStorage == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
+
+ if (externalStorage == PackageManager.PERMISSION_GRANTED) {
+ toggleCallRecording(!isRecording);
+ } else {
+ checkAndRequestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, PERMISSIONS_EXTERNAL_STORAGE);
+ }
+ } else if (id == R.id.recording) {
+ toggleCallRecording(false);
} else if (id == R.id.pause) {
pauseOrResumeCall(LinphoneManager.getLc().getCurrentCall());
} else if (id == R.id.hang_up) {
@@ -700,35 +724,31 @@ public class CallActivity extends LinphoneGenericActivity implements OnClickList
}
}
- private void enabledVideoButton(boolean enabled) {
- if (enabled) {
- video.setEnabled(true);
- } else {
- video.setEnabled(false);
- }
- }
+ private void toggleCallRecording(boolean enable) {
+ Call call = LinphoneManager.getLc().getCurrentCall();
- private void enabledPauseButton(boolean enabled) {
- if (enabled) {
- pause.setEnabled(true);
- } else {
- pause.setEnabled(false);
- }
- }
+ if (call == null) return;
- private void enabledTransferButton(boolean enabled) {
- if (enabled) {
- transfer.setEnabled(true);
- } else {
- transfer.setEnabled(false);
- }
- }
+ if (enable && !isRecording) {
+ call.startRecording();
+ Log.d("start call recording");
- private void enabledConferenceButton(boolean enabled) {
- if (enabled) {
- conference.setEnabled(true);
- } else {
- conference.setEnabled(false);
+ recordCall.setImageResource(R.drawable.options_rec_selected);
+
+ recording.setVisibility(View.VISIBLE);
+ recording.setEnabled(true);
+
+ isRecording = true;
+ } else if (!enable && isRecording) {
+ call.stopRecording();
+ Log.d("stop call recording");
+
+ recordCall.setImageResource(R.drawable.options_rec_default);
+
+ recording.setVisibility(View.GONE);
+ recording.setEnabled(false);
+
+ isRecording = false;
}
}
@@ -910,6 +930,10 @@ public class CallActivity extends LinphoneGenericActivity implements OnClickList
Core lc = LinphoneManager.getLc();
Call currentCall = lc.getCurrentCall();
+ if (isRecording) {
+ toggleCallRecording(false);
+ }
+
if (currentCall != null) {
lc.terminateCall(currentCall);
} else if (lc.isInConference()) {
@@ -963,6 +987,7 @@ public class CallActivity extends LinphoneGenericActivity implements OnClickList
transfer.setVisibility(View.INVISIBLE);
addCall.setVisibility(View.INVISIBLE);
conference.setVisibility(View.INVISIBLE);
+ recordCall.setVisibility(View.INVISIBLE);
displayVideoCall(false);
numpad.setVisibility(View.GONE);
options.setSelected(false);
@@ -1023,12 +1048,14 @@ public class CallActivity extends LinphoneGenericActivity implements OnClickList
}
addCall.setVisibility(View.INVISIBLE);
conference.setVisibility(View.INVISIBLE);
+ recordCall.setVisibility(View.INVISIBLE);
} else { //Display options
if (isTransferAllowed) {
transfer.setVisibility(View.VISIBLE);
}
addCall.setVisibility(View.VISIBLE);
conference.setVisibility(View.VISIBLE);
+ recordCall.setVisibility(View.VISIBLE);
options.setSelected(true);
transfer.setEnabled(LinphoneManager.getLc().getCurrentCall() != null);
}
diff --git a/app/src/main/java/org/linphone/utils/FileUtils.java b/app/src/main/java/org/linphone/utils/FileUtils.java
index 7249b2cab..6eebd6548 100644
--- a/app/src/main/java/org/linphone/utils/FileUtils.java
+++ b/app/src/main/java/org/linphone/utils/FileUtils.java
@@ -19,6 +19,7 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import android.annotation.SuppressLint;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
@@ -28,6 +29,7 @@ import android.provider.OpenableColumns;
import android.text.TextUtils;
import org.linphone.LinphoneManager;
+import org.linphone.core.Address;
import org.linphone.core.ChatMessage;
import org.linphone.core.Content;
import org.linphone.core.Friend;
@@ -40,6 +42,7 @@ import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
@@ -197,6 +200,30 @@ public class FileUtils {
return storageDir;
}
+ public static String getRecordingsDirectory(Context mContext) {
+ String recordingsDir = Environment.getExternalStorageDirectory() + "/" + mContext.getString(mContext.getResources().getIdentifier("app_name", "string", mContext.getPackageName())) + "/recordings";
+ File file = new File(recordingsDir);
+ if (!file.isDirectory() || !file.exists()) {
+ Log.w("Directory " + file + " doesn't seem to exists yet, let's create it");
+ file.mkdirs();
+ LinphoneManager.getInstance().getMediaScanner().scanFile(file);
+ }
+ return recordingsDir;
+ }
+
+ @SuppressLint("SimpleDateFormat")
+ public static String getCallRecordingFilename(Context context, Address address) {
+ String fileName = getRecordingsDirectory(context) + "/";
+
+ String name = address.getDisplayName() == null ? address.getUsername() : address.getDisplayName();
+ fileName += name + "_";
+
+ DateFormat format = new SimpleDateFormat("dd-MM-yyyy-HH-mm-ss");
+ fileName += format.format(new Date()) + ".mkv";
+
+ return fileName;
+ }
+
public static void scanFile(ChatMessage message) {
String appData = message.getAppdata();
if (appData == null) {
diff --git a/app/src/main/res/drawable/menu_recordings.png b/app/src/main/res/drawable/menu_recordings.png
new file mode 100644
index 000000000..3bef81d13
Binary files /dev/null and b/app/src/main/res/drawable/menu_recordings.png differ
diff --git a/app/src/main/res/drawable/options_rec_default.png b/app/src/main/res/drawable/options_rec_default.png
new file mode 100644
index 000000000..075c09314
Binary files /dev/null and b/app/src/main/res/drawable/options_rec_default.png differ
diff --git a/app/src/main/res/drawable/options_rec_selected.png b/app/src/main/res/drawable/options_rec_selected.png
new file mode 100644
index 000000000..0ef1ca322
Binary files /dev/null and b/app/src/main/res/drawable/options_rec_selected.png differ
diff --git a/app/src/main/res/drawable/recording.png b/app/src/main/res/drawable/recording.png
new file mode 100644
index 000000000..fb4e82669
Binary files /dev/null and b/app/src/main/res/drawable/recording.png differ
diff --git a/app/src/main/res/layout-land/call.xml b/app/src/main/res/layout-land/call.xml
index 9208c06a0..5e4fa5fc9 100644
--- a/app/src/main/res/layout-land/call.xml
+++ b/app/src/main/res/layout-land/call.xml
@@ -181,6 +181,19 @@
android:layout_gravity="center"/>
+
+
+
+
+
+
+
+
Assistant
Settings
+ My recordings
About
Quit
@@ -286,6 +287,9 @@
Display filter:
Call
+
+ No recordings.
+
Send log
Reset log
@@ -546,4 +550,5 @@
Linphone instant messages notifications
Group chat room subject
Group chat room info
+ Record call