From 97c66ae91c63710a7728e8b8b9a403529fb5a57c Mon Sep 17 00:00:00 2001 From: zoff99 Date: Fri, 30 Aug 2024 14:52:21 +0200 Subject: [PATCH] WIP: audio messages --- android-refimpl-app/app/build.gradle | 3 + .../trifa/GroupMessageListActivity.java | 11 + .../trifa/HelperFiletransfer.java | 18 +- .../trifa/MessageListActivity.java | 212 +++++++++++++++++- .../drawable/baseline_keyboard_voice_24.xml | 5 + .../main/res/drawable/baseline_pending_24.xml | 5 + .../res/drawable/baseline_stop_circle_24.xml | 6 + .../layout/activity_group_message_list.xml | 14 +- .../main/res/layout/activity_message_list.xml | 14 +- 9 files changed, 273 insertions(+), 15 deletions(-) create mode 100644 android-refimpl-app/app/src/main/res/drawable/baseline_keyboard_voice_24.xml create mode 100644 android-refimpl-app/app/src/main/res/drawable/baseline_pending_24.xml create mode 100644 android-refimpl-app/app/src/main/res/drawable/baseline_stop_circle_24.xml diff --git a/android-refimpl-app/app/build.gradle b/android-refimpl-app/app/build.gradle index f673b8994..127c7f7da 100644 --- a/android-refimpl-app/app/build.gradle +++ b/android-refimpl-app/app/build.gradle @@ -301,6 +301,9 @@ dependencies { exclude group: 'com.android.support' } // + implementation 'com.github.piasy:rxandroidaudio:1.7.0' + implementation 'com.github.piasy:AudioProcessor:1.7.0' + // implementation("com.daimajia.swipelayout:library:1.2.0@aar") // implementation('net.zetetic:android-database-sqlcipher:4.5.4@aar') { diff --git a/android-refimpl-app/app/src/main/java/com/zoffcc/applications/trifa/GroupMessageListActivity.java b/android-refimpl-app/app/src/main/java/com/zoffcc/applications/trifa/GroupMessageListActivity.java index 53739010d..e57d97015 100644 --- a/android-refimpl-app/app/src/main/java/com/zoffcc/applications/trifa/GroupMessageListActivity.java +++ b/android-refimpl-app/app/src/main/java/com/zoffcc/applications/trifa/GroupMessageListActivity.java @@ -257,6 +257,7 @@ public class GroupMessageListActivity extends AppCompatActivity static final int NGC_VIDEO_ICON_STATE_ACTIVE = 2; ImageButton ml_phone_icon = null; ImageButton ml_button_01 = null; + ImageButton ml_button_recaudio = null; static ImageButton ml_video_icon = null; static boolean sending_video_to_group = false; static String ngc_video_showing_video_from_peer_pubkey = "-1"; @@ -473,6 +474,7 @@ public boolean onItemClick(View view, int position, IDrawerItem drawerItem) ngc_video_off_button = (ImageButton) findViewById(R.id.ngc_video_off_button); ngc_camera_info_text = findViewById(R.id.ngc_camera_info_text); ml_button_01 = (ImageButton) findViewById(R.id.ml_button_01); + ml_button_recaudio = (ImageButton) findViewById(R.id.ml_button_recaudio); ngc_audio_bar_in_v = (BarLevelDrawable) findViewById(R.id.ngc_audio_bar_in_v); ngc_audio_bar_out_v = (BarLevelDrawable) findViewById(R.id.ngc_audio_bar_out_v); @@ -1023,6 +1025,15 @@ public void onClick(final View v) set_peer_count_header(); set_peer_names_and_avatars(); + ml_button_recaudio.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(final View v) + { + Log.i(TAG, "onCreate:record_audio:start"); + } + }); + Log.i(TAG, "onCreate:099"); oncreate_finished = true; } diff --git a/android-refimpl-app/app/src/main/java/com/zoffcc/applications/trifa/HelperFiletransfer.java b/android-refimpl-app/app/src/main/java/com/zoffcc/applications/trifa/HelperFiletransfer.java index 3453c745b..19f678e0f 100644 --- a/android-refimpl-app/app/src/main/java/com/zoffcc/applications/trifa/HelperFiletransfer.java +++ b/android-refimpl-app/app/src/main/java/com/zoffcc/applications/trifa/HelperFiletransfer.java @@ -1049,6 +1049,7 @@ static outgoing_file_wrapped copy_outgoing_file_to_sdcard_dir(final String filep if (filename_sd_card == null) { + Log.i(TAG, "copy_outgoing_file_to_sdcard_dir:003"); return null; } @@ -1080,6 +1081,7 @@ static outgoing_file_wrapped copy_outgoing_file_to_sdcard_dir(final String filep if (filename2 == null) { + Log.i(TAG, "copy_outgoing_file_to_sdcard_dir:004"); return null; } @@ -1090,6 +1092,7 @@ static outgoing_file_wrapped copy_outgoing_file_to_sdcard_dir(final String filep if (counter > 5000) { + Log.i(TAG, "copy_outgoing_file_to_sdcard_dir:005"); return null; } } @@ -1098,7 +1101,17 @@ static outgoing_file_wrapped copy_outgoing_file_to_sdcard_dir(final String filep ret.filename_wrapped = filename2; // now write that contents of the virtual file to the actual file on SD card ---------------- - InputStream in = context_s.getContentResolver().openInputStream(Uri.parse(filepath)); + // Log.i(TAG, "copy_outgoing_file_to_sdcard_dir:filepath=" + filepath); + InputStream in = null; + try + { + in = context_s.getContentResolver().openInputStream(Uri.parse(filepath)); + } + catch(Exception e) + { + File fin_regular_file = new File(filepath + "/" + filename); + in = new java.io.FileInputStream(fin_regular_file); + } BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream(SD_CARD_FILES_OUTGOING_WRAPPER_DIR + "/" + filename2)); @@ -1120,6 +1133,7 @@ static outgoing_file_wrapped copy_outgoing_file_to_sdcard_dir(final String filep if (ret.file_size_wrapped < 1) { file2.delete(); + Log.i(TAG, "copy_outgoing_file_to_sdcard_dir:006"); return null; } @@ -1127,6 +1141,8 @@ static outgoing_file_wrapped copy_outgoing_file_to_sdcard_dir(final String filep } catch (Exception e) { + Log.i(TAG, "copy_outgoing_file_to_sdcard_dir:007:" + e.getMessage()); + e.printStackTrace(); return null; } } diff --git a/android-refimpl-app/app/src/main/java/com/zoffcc/applications/trifa/MessageListActivity.java b/android-refimpl-app/app/src/main/java/com/zoffcc/applications/trifa/MessageListActivity.java index 877a38d58..78a432a95 100644 --- a/android-refimpl-app/app/src/main/java/com/zoffcc/applications/trifa/MessageListActivity.java +++ b/android-refimpl-app/app/src/main/java/com/zoffcc/applications/trifa/MessageListActivity.java @@ -28,6 +28,7 @@ import android.database.Cursor; import android.graphics.Color; import android.graphics.drawable.Drawable; +import android.media.MediaRecorder; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -41,6 +42,7 @@ import android.util.Log; import android.view.KeyEvent; import android.view.MenuItem; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; @@ -52,6 +54,7 @@ import android.widget.TextView; import android.widget.Toast; +import com.github.piasy.rxandroidaudio.AudioRecorder; import com.mikepenz.fontawesome_typeface_library.FontAwesome; import com.mikepenz.google_material_typeface_library.GoogleMaterial; import com.mikepenz.iconics.IconicsDrawable; @@ -62,10 +65,12 @@ import com.vanniktech.emoji.listeners.OnSoftKeyboardCloseListener; import com.vanniktech.emoji.listeners.OnSoftKeyboardOpenListener; +import java.io.File; import java.util.ArrayList; import java.util.Arrays; import androidx.annotation.Px; +import androidx.annotation.RequiresApi; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.view.ActionMode; import androidx.appcompat.widget.SearchView; @@ -90,6 +95,7 @@ import static com.zoffcc.applications.trifa.HelperGeneric.display_toast; import static com.zoffcc.applications.trifa.HelperGeneric.do_fade_anim_on_fab; import static com.zoffcc.applications.trifa.HelperGeneric.get_g_opts; +import static com.zoffcc.applications.trifa.HelperGeneric.get_uniq_tmp_filename; import static com.zoffcc.applications.trifa.HelperGeneric.set_g_opts; import static com.zoffcc.applications.trifa.HelperGeneric.tox_friend_send_message_wrapper; import static com.zoffcc.applications.trifa.HelperGeneric.trim_to_utf8_length_bytes; @@ -103,6 +109,8 @@ import static com.zoffcc.applications.trifa.MainActivity.PREF__use_software_aec; import static com.zoffcc.applications.trifa.MainActivity.PREF__window_security; import static com.zoffcc.applications.trifa.HelperGeneric.clear_audio_play_buffers; +import static com.zoffcc.applications.trifa.MainActivity.SD_CARD_FILES_OUTGOING_WRAPPER_DIR; +import static com.zoffcc.applications.trifa.MainActivity.SD_CARD_TMP_DIR; import static com.zoffcc.applications.trifa.MainActivity.context_s; import static com.zoffcc.applications.trifa.MainActivity.main_activity_s; import static com.zoffcc.applications.trifa.MainActivity.main_handler_s; @@ -158,6 +166,9 @@ public class MessageListActivity extends AppCompatActivity ImageButton ml_phone_icon = null; ImageButton ml_video_icon = null; ImageButton ml_attach_button_01 = null; + ImageButton ml_button_recaudio = null; + static boolean ml_is_recording = false; + static boolean ml_is_rec_ok = false; static int global_typing = 0; Thread typing_flag_thread = null; final static int TYPING_FLAG_DEACTIVATE_DELAY_IN_MILLIS = 1000; // 1 second @@ -324,6 +335,9 @@ public void onNothingSelected(AdapterView parent) ml_phone_icon = (ImageButton) findViewById(R.id.ml_phone_icon); ml_video_icon = (ImageButton) findViewById(R.id.ml_video_icon); ml_attach_button_01 = (ImageButton) findViewById(R.id.ml_button_01); + ml_button_recaudio = (ImageButton) findViewById(R.id.ml_button_recaudio); + ml_is_recording = false; + ml_is_rec_ok = false; final ImageButton button01_ = ml_attach_button_01; ml_icon.setImageResource(R.drawable.circle_red); set_friend_connection_status_icon(); @@ -618,6 +632,162 @@ public void run() }; t.start(); + ml_button_recaudio.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(final View v) + { + if (ml_is_rec_ok) + { + return; + } + + if (ml_is_recording) + { + ml_is_rec_ok = true; + ml_is_recording = false; + return; + } + + final Thread ml_rec_audio_thread = new Thread() + { + @Override + public void run() + { + String audio_rec_filename_final = null; + ml_is_recording = true; + ml_is_rec_ok = false; + ((ImageButton) v).setImageResource(R.drawable.baseline_stop_circle_24); + + try + { + Log.i(TAG, "onCreate:record_audio:start"); + AudioRecorder mAudioRecorder = AudioRecorder.getInstance(); + final String fpubkey = tox_friend_get_public_key__wrapper(friendnum); + String audio_rec_filename = SD_CARD_TMP_DIR + "/" + fpubkey + "_" + System.nanoTime(); + String audio_rec_filename_uniq_part = get_uniq_tmp_filename(audio_rec_filename ,1000); + audio_rec_filename_final = audio_rec_filename + "_" + audio_rec_filename_uniq_part + ".file.m4a"; + File f = new File(audio_rec_filename_final); + boolean file_exists = true; + try + { + file_exists = f.exists(); + } + catch(Exception e) + { + ((ImageButton) v).setImageResource(R.drawable.baseline_keyboard_voice_24); + ml_is_recording = false; + ml_is_rec_ok = false; + return; + } + + long count = 0; + while(file_exists) + { + audio_rec_filename = SD_CARD_TMP_DIR + "/" + fpubkey + "_" + System.nanoTime(); + audio_rec_filename_uniq_part = get_uniq_tmp_filename(audio_rec_filename ,1000); + audio_rec_filename_final = audio_rec_filename + "_" + audio_rec_filename_uniq_part + ".file.m4a"; + f = new File(audio_rec_filename_final); + try + { + file_exists = f.exists(); + } + catch(Exception e) + { + ((ImageButton) v).setImageResource(R.drawable.baseline_keyboard_voice_24); + ml_is_recording = false; + ml_is_rec_ok = false; + return; + } + + try + { + Thread.sleep(50); + } + catch(Exception e) + { + } + count++; + + if (count > 50) + { + // HINT: just in case of an endless loop, we return here + ((ImageButton) v).setImageResource(R.drawable.baseline_keyboard_voice_24); + ml_is_recording = false; + ml_is_rec_ok = false; + return; + } + } + + File mAudioFile = new File(audio_rec_filename_final); + // Log.i(TAG, "onCreate:record_audio:file=" + audio_rec_filename_final); + mAudioRecorder.prepareRecord(MediaRecorder.AudioSource.MIC, MediaRecorder.OutputFormat.MPEG_4, + MediaRecorder.AudioEncoder.AAC, mAudioFile); + mAudioRecorder.startRecord(); + + while (ml_is_recording) + { + try + { + Thread.sleep(100); + } + catch (Exception ignored) + { + } + + if (mAudioRecorder.progress() > 5) + { + // HINT: stop after x seconds of recording so it does not record endless + Log.i(TAG, "onCreate:record_audio:auto_stop"); + ml_is_rec_ok = true; + ml_is_recording = false; + } + } + ((ImageButton) v).setImageResource(R.drawable.baseline_pending_24); + mAudioRecorder.stopRecord(); + Log.i(TAG, "onCreate:record_audio:finished"); + } + catch(Exception e) + { + Log.i(TAG, "onCreate:record_audio:EE:" + e.getMessage()); + e.printStackTrace(); + } + ((ImageButton) v).setImageResource(R.drawable.baseline_keyboard_voice_24); + + if (ml_is_rec_ok) + { + Log.i(TAG, "onCreate:record_audio:------ OK ------"); + Log.i(TAG, "onCreate:record_audio:------ OK ------"); + Log.i(TAG, "onCreate:record_audio:------ OK ------"); + + if (audio_rec_filename_final != null) + { + Log.i(TAG, "onCreate:record_audio:add to FT queue ..."); + File f2 = new File(audio_rec_filename_final); + add_outgoing_file(v.getContext(), MainActivity.message_list_activity.get_current_friendnum(), + f2.getParent(), f2.getName(), null, f2.length(), + false, true, true); + } + } + + try + { + if ((audio_rec_filename_final != null) && (audio_rec_filename_final.length() > 10)) + { + new File(audio_rec_filename_final).delete(); + } + } + catch (Exception ignored) + { + } + ml_is_rec_ok = false; + ml_is_recording = false; + } + }; + ml_rec_audio_thread.start(); + } + }); + Log.i(TAG, "onCreate:099"); oncreate_finished = true; } @@ -636,6 +806,10 @@ protected void onPause() Log.i(TAG, "onPause"); super.onPause(); + ml_button_recaudio.setImageResource(R.drawable.baseline_keyboard_voice_24); + ml_is_recording = false; + ml_is_rec_ok = false; + stop_self_typing_indicator_s(); if (emojiPopup != null) @@ -654,6 +828,9 @@ protected void onPause() protected void onStop() { super.onStop(); + ml_button_recaudio.setImageResource(R.drawable.baseline_keyboard_voice_24); + ml_is_recording = false; + ml_is_rec_ok = false; } @Override @@ -1295,16 +1472,16 @@ public void run() } add_outgoing_file(c, MainActivity.message_list_activity.get_current_friendnum(), - data.getData().toString(), fileName_, data.getData(), false, - activity_friend_num); + data.getData().toString(), fileName_, data.getData(), 0, false, + activity_friend_num, false); } }; t.start(); } else { - add_outgoing_file(c, friendnum_local, data.getData().toString(), fileName_, data.getData(), false, - activity_friend_num); + add_outgoing_file(c, friendnum_local, data.getData().toString(), fileName_, data.getData(), 0, false, + activity_friend_num, false); } } } @@ -1365,7 +1542,7 @@ static class outgoing_file_wrapped long file_size_wrapped = -1; } - static void add_outgoing_file(Context c, long friendnum, String filepath, String filename, Uri uri, boolean real_file_path, boolean update_message_view) + static void add_outgoing_file(Context c, long friendnum, String filepath, String filename, Uri uri, long file_size_manual, boolean real_file_path, boolean update_message_view, boolean use_file_size_manual) { // Log.i(TAG, "add_outgoing_file:001"); @@ -1376,23 +1553,31 @@ static void add_outgoing_file(Context c, long friendnum, String filepath, String long file_size = -1; try { - - DocumentFile documentFile = DocumentFile.fromSingleUri(c, uri); - String fileName = documentFile.getName(); - // Log.i(TAG, "add_outgoing_file:documentFile:fileName=" + fileName); - // Log.i(TAG, "add_outgoing_file:documentFile:fileLength=" + documentFile.length()); - - file_size = documentFile.length(); + if (use_file_size_manual) + { + file_size = file_size_manual; + // Log.i(TAG, "add_outgoing_file:documentFile:file_size=" + file_size); + } + else + { + DocumentFile documentFile = DocumentFile.fromSingleUri(c, uri); + String fileName = documentFile.getName(); + // Log.i(TAG, "add_outgoing_file:documentFile:fileName=" + fileName); + // Log.i(TAG, "add_outgoing_file:documentFile:fileLength=" + documentFile.length()); + file_size = documentFile.length(); + } } catch (Exception e) { e.printStackTrace(); + Log.i(TAG, "add_outgoing_file:documentFile:EE003:" + e.getMessage()); // file length unknown? return; } if (file_size < 1) { + Log.i(TAG, "file length 0 ?"); // file length "zero"? return; } @@ -1400,15 +1585,18 @@ static void add_outgoing_file(Context c, long friendnum, String filepath, String if (file_size > FT_OUTGOING_FILESIZE_FRIEND_MAX_TOTAL) { display_toast("File too large", true, 100); + Log.i(TAG, "add_outgoing_file:documentFile:file_size=File too large"); return; } if (file_size < FT_OUTGOING_FILESIZE_BYTE_USE_STORAGE_FRAMEWORK) // less than xxx Bytes filesize { + Log.i(TAG, "add_outgoing_file:documentFile:0001"); outgoing_file_wrapped ofw = copy_outgoing_file_to_sdcard_dir(filepath, filename, file_size); if (ofw == null) { + Log.i(TAG, "add_outgoing_file:documentFile:ERR:0002"); return; } diff --git a/android-refimpl-app/app/src/main/res/drawable/baseline_keyboard_voice_24.xml b/android-refimpl-app/app/src/main/res/drawable/baseline_keyboard_voice_24.xml new file mode 100644 index 000000000..b5f9eef1f --- /dev/null +++ b/android-refimpl-app/app/src/main/res/drawable/baseline_keyboard_voice_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/android-refimpl-app/app/src/main/res/drawable/baseline_pending_24.xml b/android-refimpl-app/app/src/main/res/drawable/baseline_pending_24.xml new file mode 100644 index 000000000..4d080b155 --- /dev/null +++ b/android-refimpl-app/app/src/main/res/drawable/baseline_pending_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/android-refimpl-app/app/src/main/res/drawable/baseline_stop_circle_24.xml b/android-refimpl-app/app/src/main/res/drawable/baseline_stop_circle_24.xml new file mode 100644 index 000000000..6a26c29c8 --- /dev/null +++ b/android-refimpl-app/app/src/main/res/drawable/baseline_stop_circle_24.xml @@ -0,0 +1,6 @@ + + + diff --git a/android-refimpl-app/app/src/main/res/layout/activity_group_message_list.xml b/android-refimpl-app/app/src/main/res/layout/activity_group_message_list.xml index 4163d8de9..7d6f5df44 100644 --- a/android-refimpl-app/app/src/main/res/layout/activity_group_message_list.xml +++ b/android-refimpl-app/app/src/main/res/layout/activity_group_message_list.xml @@ -379,7 +379,7 @@ tools:ignore="NestedWeights" /> @@ -397,6 +397,18 @@ android:padding="5dp" android:scaleType="fitCenter" android:src="@android:drawable/ic_menu_send" /> + + diff --git a/android-refimpl-app/app/src/main/res/layout/activity_message_list.xml b/android-refimpl-app/app/src/main/res/layout/activity_message_list.xml index 4d4890a93..466f95a65 100644 --- a/android-refimpl-app/app/src/main/res/layout/activity_message_list.xml +++ b/android-refimpl-app/app/src/main/res/layout/activity_message_list.xml @@ -184,7 +184,7 @@ android:textSize="19sp" /> @@ -202,6 +202,18 @@ android:padding="5dp" android:scaleType="fitCenter" android:src="@android:drawable/ic_menu_send" /> + +