Add call recording functionality in call view
This commit is contained in:
parent
a895fde7eb
commit
bcb5e2da66
10 changed files with 170 additions and 55 deletions
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
BIN
app/src/main/res/drawable/menu_recordings.png
Normal file
BIN
app/src/main/res/drawable/menu_recordings.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
BIN
app/src/main/res/drawable/options_rec_default.png
Normal file
BIN
app/src/main/res/drawable/options_rec_default.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
BIN
app/src/main/res/drawable/options_rec_selected.png
Normal file
BIN
app/src/main/res/drawable/options_rec_selected.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
BIN
app/src/main/res/drawable/recording.png
Normal file
BIN
app/src/main/res/drawable/recording.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
|
@ -181,6 +181,19 @@
|
|||
android:layout_gravity="center"/>
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/recording"
|
||||
android:src="@drawable/recording"
|
||||
android:background="@drawable/round_orange_button_background"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:padding="8dp"
|
||||
android:layout_margin="20dp"
|
||||
android:contentDescription="@string/content_description_record_call"
|
||||
android:visibility="gone"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentBottom="true" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
|
@ -369,10 +382,21 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/record_call"
|
||||
android:src="@drawable/options_rec_default"
|
||||
android:background="@drawable/button_background"
|
||||
android:contentDescription="@string/content_description_record_call"
|
||||
android:visibility="gone"
|
||||
android:padding="15dp"
|
||||
android:layout_above="@id/options"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/add_call"
|
||||
android:visibility="gone"
|
||||
android:layout_above="@id/options"
|
||||
android:layout_above="@id/record_call"
|
||||
android:src="@drawable/options_add_call"
|
||||
android:background="@drawable/button_background"
|
||||
android:contentDescription="@string/content_description_add_call"
|
||||
|
|
|
@ -181,6 +181,19 @@
|
|||
android:layout_gravity="center"/>
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/recording"
|
||||
android:src="@drawable/recording"
|
||||
android:background="@drawable/round_orange_button_background"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:padding="10dp"
|
||||
android:layout_margin="20dp"
|
||||
android:contentDescription="@string/content_description_record_call"
|
||||
android:visibility="gone"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentBottom="true" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
|
@ -310,10 +323,21 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/record_call"
|
||||
android:src="@drawable/options_rec_default"
|
||||
android:background="@drawable/button_background"
|
||||
android:contentDescription="@string/content_description_record_call"
|
||||
android:visibility="gone"
|
||||
android:padding="15dp"
|
||||
android:layout_above="@id/options"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/add_call"
|
||||
android:visibility="gone"
|
||||
android:layout_above="@id/options"
|
||||
android:layout_above="@id/record_call"
|
||||
android:src="@drawable/options_add_call"
|
||||
android:background="@drawable/button_background"
|
||||
android:contentDescription="@string/content_description_add_call"
|
||||
|
|
|
@ -250,6 +250,7 @@
|
|||
<!-- Side Menu -->
|
||||
<string name="menu_assistant">Assistant</string>
|
||||
<string name="menu_settings">Settings</string>
|
||||
<string name="menu_recordings">My recordings</string>
|
||||
<string name="menu_about">About</string>
|
||||
<string name="quit">Quit</string>
|
||||
|
||||
|
@ -286,6 +287,9 @@
|
|||
<string name="call_stats_display_filter">Display filter:</string>
|
||||
<string name="call">Call</string>
|
||||
|
||||
<!-- Recordings -->
|
||||
<string name="no_recordings">No recordings.</string>
|
||||
|
||||
<!-- About -->
|
||||
<string name="menu_send_log">Send log</string>
|
||||
<string name="menu_reset_log">Reset log</string>
|
||||
|
@ -546,4 +550,5 @@
|
|||
<string name="content_title_notification">Linphone instant messages notifications</string>
|
||||
<string name="content_description_conversation_subject">Group chat room subject</string>
|
||||
<string name="content_description_conversation_infos">Group chat room info</string>
|
||||
<string name="content_description_record_call">Record call</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue