From b06834e63017392e7900a93c6792b0d298a8bf86 Mon Sep 17 00:00:00 2001 From: Jenny Makadiya Date: Tue, 19 Mar 2024 20:57:29 +0530 Subject: [PATCH 01/24] Android SDK Update, Background Recording Support, Permission Fixes, UI changes, Added Time Durations, Minor Bug Fixes and Save File with Custom Name as requested by the client. --- .idea/.gitignore | 3 + .idea/compiler.xml | 6 + .idea/deploymentTargetDropDown.xml | 10 + .idea/gradle.xml | 19 ++ .idea/migrations.xml | 10 + .idea/misc.xml | 9 + .idea/vcs.xml | 6 + SaidIt/build.gradle | 32 ++- SaidIt/src/main/AndroidManifest.xml | 44 ++-- .../java/eu/mrogalski/saidit/FakeService.java | 50 +++- .../mrogalski/saidit/RecordingDoneDialog.java | 42 ++- .../eu/mrogalski/saidit/SaidItActivity.java | 145 ++++++++++- .../eu/mrogalski/saidit/SaidItFragment.java | 166 ++++++++---- .../eu/mrogalski/saidit/SaidItService.java | 172 ++++++++----- .../eu/mrogalski/saidit/SettingsActivity.java | 7 +- .../eu/mrogalski/saidit/ThemedDialog.java | 2 + SaidIt/src/main/res/drawable/bg_et.xml | 17 ++ .../src/main/res/layout/activity_settings.xml | 3 +- .../main/res/layout/dialog_save_recording.xml | 36 +++ .../layout/fragment_background_recorder.xml | 45 +++- .../main/res/layout/recording_done_dialog.xml | 70 ++--- SaidIt/src/main/res/values-pl/strings.xml | 11 +- SaidIt/src/main/res/values/dimens.xml | 2 +- SaidIt/src/main/res/values/strings.xml | 13 +- SaidIt/src/main/res/values/styles.xml | 8 +- SaidIt/src/main/res/xml/path_provider.xml | 6 + gradle.properties | 7 +- gradle/wrapper/gradle-wrapper.properties | 5 + gradlew | 240 ++++++++++++++++++ gradlew.bat | 91 +++++++ .../saidit/BackgroundRecorderActivity.java | 2 +- 31 files changed, 1079 insertions(+), 200 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/compiler.xml create mode 100644 .idea/deploymentTargetDropDown.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/migrations.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/vcs.xml create mode 100644 SaidIt/src/main/res/drawable/bg_et.xml create mode 100644 SaidIt/src/main/res/layout/dialog_save_recording.xml create mode 100644 SaidIt/src/main/res/xml/path_provider.xml create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 00000000..26d33521 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 00000000..b589d56e --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml new file mode 100644 index 00000000..35910060 --- /dev/null +++ b/.idea/deploymentTargetDropDown.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 00000000..a7353902 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 00000000..f8051a6f --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..8978d23d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..35eb1ddf --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/SaidIt/build.gradle b/SaidIt/build.gradle index 4debc777..5550c99b 100644 --- a/SaidIt/build.gradle +++ b/SaidIt/build.gradle @@ -1,21 +1,31 @@ buildscript { repositories { + google() + mavenCentral() maven { url "https://repo.maven.apache.org/maven2" } } dependencies { - classpath 'com.android.tools.build:gradle:0.11.+' + classpath 'com.android.tools.build:gradle:8.2.2' } } -apply plugin: 'android' +apply plugin: 'com.android.application' repositories { - jcenter() + mavenCentral() maven { url "https://maven.google.com" } } android { - compileSdkVersion 21 - buildToolsVersion "21.0.2" + namespace 'eu.mrogalski.saidit' + compileSdk 34 + + defaultConfig{ + applicationId "eu.mrogalski.saidit" + minSdk 21 + targetSdk 34 + versionCode 14 + versionName "1.3.39" + } signingConfigs { release { @@ -28,14 +38,14 @@ android { buildTypes { release { - runProguard true + minifyEnabled true proguardFile file('proguard.cfg') proguardFile getDefaultProguardFile('proguard-android-optimize.txt') signingConfig signingConfigs.release } debug { - signingConfig signingConfigs.release + //signingConfig signingConfigs.release } } lintOptions { @@ -47,8 +57,8 @@ android { } dependencies { - compile fileTree(dir: 'libs', include: '*.jar') - compile 'com.android.support:appcompat-v7:21.0.3' - compile 'com.nineoldandroids:library:2.4.0' - compile 'com.android.support:support-v4:21.0.3' + implementation fileTree(dir: 'libs', include: '*.jar') + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'com.nineoldandroids:library:2.4.0' + implementation 'androidx.legacy:legacy-support-v4:1.0.0' } diff --git a/SaidIt/src/main/AndroidManifest.xml b/SaidIt/src/main/AndroidManifest.xml index 41d47927..7c8498e8 100644 --- a/SaidIt/src/main/AndroidManifest.xml +++ b/SaidIt/src/main/AndroidManifest.xml @@ -1,18 +1,15 @@ - - - + + - + + + + + android:label="@string/app_name" + android:exported="true"> @@ -49,16 +48,19 @@ + android:exported="false"> - - + --> - + @@ -71,6 +73,18 @@ android:name="android.support.PARENT_ACTIVITY" android:value="SaidItActivity" /> + + + + + + diff --git a/SaidIt/src/main/java/eu/mrogalski/saidit/FakeService.java b/SaidIt/src/main/java/eu/mrogalski/saidit/FakeService.java index 92c42ae2..4fd07431 100644 --- a/SaidIt/src/main/java/eu/mrogalski/saidit/FakeService.java +++ b/SaidIt/src/main/java/eu/mrogalski/saidit/FakeService.java @@ -8,7 +8,18 @@ /** * Created by marek on 15.12.13. */ +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.Service; +import android.content.Intent; +import android.os.Build; +import android.os.IBinder; + public class FakeService extends Service { + private static final int NOTIFICATION_ID = 42; + private static final String CHANNEL_ID = "ForegroundServiceChannel"; + @Override public IBinder onBind(Intent intent) { return null; @@ -16,15 +27,44 @@ public IBinder onBind(Intent intent) { @Override public int onStartCommand(Intent intent, int flags, int startId) { + startForeground(NOTIFICATION_ID, createNotification()); - - Notification note = new Notification( 0, null, System.currentTimeMillis() ); - note.flags |= Notification.FLAG_NO_CLEAR; - startForeground(42, note); stopForeground(true); - stopSelf(); return super.onStartCommand(intent, flags, startId); } + + private Notification createNotification() { + NotificationManager notificationManager = + (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationChannel channel = new NotificationChannel( + CHANNEL_ID, + "Foreground Service Channel", + NotificationManager.IMPORTANCE_DEFAULT + ); + if (notificationManager != null) { + notificationManager.createNotificationChannel(channel); + } + } + + Notification.Builder builder; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + builder = new Notification.Builder(this, CHANNEL_ID); + } else { + builder = new Notification.Builder(this); + } + + Notification notification = builder + .setSmallIcon(android.R.drawable.ic_dialog_info) + .setContentTitle("Foreground Service") + .setContentText("Service is running in the background") + .setPriority(Notification.PRIORITY_DEFAULT) // Set appropriate priority + .build(); + + return notification; + } } + diff --git a/SaidIt/src/main/java/eu/mrogalski/saidit/RecordingDoneDialog.java b/SaidIt/src/main/java/eu/mrogalski/saidit/RecordingDoneDialog.java index 4a33bca9..b6dc2ff3 100644 --- a/SaidIt/src/main/java/eu/mrogalski/saidit/RecordingDoneDialog.java +++ b/SaidIt/src/main/java/eu/mrogalski/saidit/RecordingDoneDialog.java @@ -1,14 +1,20 @@ package eu.mrogalski.saidit; import android.app.Activity; +import android.content.ActivityNotFoundException; import android.content.Intent; import android.content.res.Resources; import android.net.Uri; import android.os.Bundle; +import android.os.Environment; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; +import android.widget.Toast; + +import androidx.core.content.FileProvider; import java.io.File; import java.net.URLConnection; @@ -64,10 +70,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa root.findViewById(R.id.recording_done_open_dir).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - Intent intent = new Intent(Intent.ACTION_VIEW); - Uri uri = Uri.fromFile(file.getParentFile()); - intent.setData(uri); - startActivity(Intent.createChooser(intent, "Open folder")); + openFolder(); } }); @@ -76,9 +79,12 @@ public void onClick(View v) { public void onClick(View v) { Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); - shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file)); - shareIntent.setType(URLConnection.guessContentTypeFromName(file.getAbsolutePath())); + Uri fileUri = FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + ".provider", file); + shareIntent.putExtra(Intent.EXTRA_STREAM, fileUri); + shareIntent.setType(activity.getContentResolver().getType(fileUri)); // Get MIME type from content resolver + shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // Grant read permission startActivity(Intent.createChooser(shareIntent, "Send to")); + } }); @@ -87,7 +93,10 @@ public void onClick(View v) { public void onClick(View v) { Intent intent = new Intent(); intent.setAction(android.content.Intent.ACTION_VIEW); - intent.setDataAndType(Uri.fromFile(file), "audio/*"); + Uri fileUri = FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + ".provider", file); + intent.setDataAndType(fileUri, "audio/*"); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // Grant read permission + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); } }); @@ -104,4 +113,23 @@ public RecordingDoneDialog setRuntime(float runtime) { this.runtime = runtime; return this; } + + public void openFolder() { + File folder = file.getParentFile(); + if (folder.exists() && folder.isDirectory()) { + Uri uri = Uri.parse(folder.getAbsolutePath()); + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setDataAndType(uri, "*/*"); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + } else { + Log.e("OpenFolder", "Folder does not exist or is not a directory"); + } + } + + + private static boolean isExternalStorageWritable() { + String state = Environment.getExternalStorageState(); + return Environment.MEDIA_MOUNTED.equals(state); + } } diff --git a/SaidIt/src/main/java/eu/mrogalski/saidit/SaidItActivity.java b/SaidIt/src/main/java/eu/mrogalski/saidit/SaidItActivity.java index 949cc111..e5523217 100644 --- a/SaidIt/src/main/java/eu/mrogalski/saidit/SaidItActivity.java +++ b/SaidIt/src/main/java/eu/mrogalski/saidit/SaidItActivity.java @@ -1,28 +1,155 @@ package eu.mrogalski.saidit; +import android.Manifest; import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.PackageManager; import android.net.Uri; +import android.os.Build; import android.os.Bundle; +import android.os.Environment; +import android.provider.Settings; -public class SaidItActivity extends Activity { +import androidx.annotation.NonNull; +import androidx.core.app.ActivityCompat; - static final String TAG = SaidItActivity.class.getSimpleName(); +public class SaidItActivity extends Activity { + private static final int PERMISSION_REQUEST_CODE = 5465; + private boolean isFragmentSet = false; + private AlertDialog permissionDeniedDialog; + private AlertDialog storagePermissionDialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_background_recorder); + } - if (savedInstanceState == null) { - getFragmentManager().beginTransaction() - .add(R.id.container, new SaidItFragment(), "main-fragment") - .commit(); + @Override + protected void onStart() { + super.onStart(); + if(permissionDeniedDialog != null) { + permissionDeniedDialog.dismiss(); + } + if(storagePermissionDialog != null) { + storagePermissionDialog.dismiss(); } + requestPermissions(); + } + @Override + protected void onRestart() { + super.onRestart(); + if(permissionDeniedDialog != null) { + permissionDeniedDialog.dismiss(); + } + if(storagePermissionDialog != null) { + storagePermissionDialog.dismiss(); + } + requestPermissions(); + } + + private void requestPermissions() { + // Ask for storage permission + + String[] permissions = {Manifest.permission.RECORD_AUDIO, Manifest.permission.FOREGROUND_SERVICE}; + if(Build.VERSION.SDK_INT >= 33) { + permissions = new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.FOREGROUND_SERVICE, Manifest.permission.POST_NOTIFICATIONS}; + } + if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) { + permissions = new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.FOREGROUND_SERVICE, Manifest.permission.WRITE_EXTERNAL_STORAGE}; + } + ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_CODE); } @Override - protected void onStart() { - super.onStart(); + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == PERMISSION_REQUEST_CODE) { + // Check if all permissions are granted + boolean allPermissionsGranted = true; + for (int result : grantResults) { + if (result != PackageManager.PERMISSION_GRANTED) { + allPermissionsGranted = false; + break; + } + } + if (allPermissionsGranted) { + // All permissions are granted + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + if (Environment.isExternalStorageManager()) { + // Permission already granted + if(storagePermissionDialog != null) { + storagePermissionDialog.dismiss(); + } + showFragment(); + } else { + // Request MANAGE_EXTERNAL_STORAGE permission + storagePermissionDialog = new AlertDialog.Builder(this) + .setTitle(R.string.permission_required) + .setMessage(R.string.permission_required_message) + .setPositiveButton(R.string.allow, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + // Open app settings + Intent intent = new Intent(); + intent.setAction(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION); + intent.setData(Uri.fromParts("package", getPackageName(), null)); + startActivity(intent); + } + }) + .setNegativeButton(R.string.exit, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }) + .setCancelable(false) + .show(); + } + } else { + // For devices below Android 10, request WRITE_EXTERNAL_STORAGE permission + // Use the code snippet from the previous response + } + } else { + if(permissionDeniedDialog == null || !permissionDeniedDialog.isShowing()) { + showPermissionDeniedDialog(); + } + } + } + } + + private void showFragment() { + if (!isFragmentSet) { + isFragmentSet = true; + getFragmentManager().beginTransaction() + .replace(R.id.container, new SaidItFragment(), "main-fragment") + .commit(); + } + } + private void showPermissionDeniedDialog() { + permissionDeniedDialog = new AlertDialog.Builder(this) + .setTitle(R.string.permission_required) + .setMessage(R.string.permission_required_message) + .setPositiveButton(R.string.allow, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + // Open app settings + Intent intent = new Intent(); + intent.setAction(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.fromParts("package", getPackageName(), null)); + startActivity(intent); + } + }) + .setNegativeButton(R.string.exit, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }) + .setCancelable(false) + .show(); } -} +} \ No newline at end of file diff --git a/SaidIt/src/main/java/eu/mrogalski/saidit/SaidItFragment.java b/SaidIt/src/main/java/eu/mrogalski/saidit/SaidItFragment.java index f772a563..d0ed2e0c 100644 --- a/SaidIt/src/main/java/eu/mrogalski/saidit/SaidItFragment.java +++ b/SaidIt/src/main/java/eu/mrogalski/saidit/SaidItFragment.java @@ -1,14 +1,19 @@ package eu.mrogalski.saidit; +import android.annotation.SuppressLint; import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; import android.app.Fragment; import android.app.Notification; -import android.app.NotificationManager; import android.app.PendingIntent; +import android.app.ProgressDialog; import android.content.ComponentName; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.ServiceConnection; +import android.content.pm.PackageManager; import android.content.res.AssetManager; import android.content.res.Resources; import android.graphics.Typeface; @@ -17,8 +22,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.IBinder; -import android.support.v4.app.NotificationCompat; -import android.support.v4.view.ViewCompat; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; @@ -26,10 +29,18 @@ import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.Button; +import android.widget.EditText; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import android.widget.Toast; + +import androidx.core.app.ActivityCompat; +import androidx.core.app.NotificationCompat; +import androidx.core.app.NotificationManagerCompat; +import androidx.core.content.FileProvider; +import androidx.core.view.ViewCompat; import java.io.File; @@ -39,7 +50,7 @@ public class SaidItFragment extends Fragment { private static final String TAG = SaidItFragment.class.getSimpleName(); - + private static final String YOUR_NOTIFICATION_CHANNEL_ID = "SaidItServiceChannel"; private Button record_pause_button; private Button listenButton; @@ -53,7 +64,9 @@ public class SaidItFragment extends Fragment { private Button recordLastFiveMinutesButton; private Button recordMaxButton; private Button recordLastMinuteButton; - + private Button recordLastThirtyMinuteButton; + private Button recordLastTwoHrsButton; + private Button recordLastSixHrsButton; private TextView history_limit; private TextView history_size; private TextView history_size_title; @@ -68,14 +81,16 @@ public class SaidItFragment extends Fragment { @Override public void onStart() { super.onStart(); - final Activity activity = getActivity(); assert activity != null; + final Activity activity = getActivity(); + assert activity != null; activity.bindService(new Intent(activity, SaidItService.class), echoConnection, Context.BIND_AUTO_CREATE); } @Override public void onStop() { super.onStop(); - final Activity activity = getActivity(); assert activity != null; + final Activity activity = getActivity(); + assert activity != null; activity.unbindService(echoConnection); } @@ -95,8 +110,8 @@ class ActivityResult { @Override public void run() { final View view = getView(); - if(view == null) return; - if(echo == null) return; + if (view == null) return; + if (echo == null) return; echo.getState(serviceStateCallback); } }; @@ -129,15 +144,15 @@ public int getStatusBarHeight() { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { + Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_background_recorder, container, false); - if(rootView == null) return null; + if (rootView == null) return null; final Activity activity = getActivity(); final AssetManager assets = activity.getAssets(); - final Typeface robotoCondensedBold = Typeface.createFromAsset(assets,"RobotoCondensedBold.ttf"); + final Typeface robotoCondensedBold = Typeface.createFromAsset(assets, "RobotoCondensedBold.ttf"); final Typeface robotoCondensedRegular = Typeface.createFromAsset(assets, "RobotoCondensed-Regular.ttf"); final float density = activity.getResources().getDisplayMetrics().density; @@ -170,11 +185,11 @@ public void onView(View view, ViewGroup parent) { history_size.setTypeface(robotoCondensedBold); listenButton = (Button) rootView.findViewById(R.id.listen_button); - if(listenButton != null) { + if (listenButton != null) { listenButton.setOnClickListener(listenButtonClickListener); } - if(Build.VERSION.SDK_INT >= 19) { + if (Build.VERSION.SDK_INT >= 19) { final int statusBarHeight = getStatusBarHeight(); listenButton.setPadding(listenButton.getPaddingLeft(), listenButton.getPaddingTop() + statusBarHeight, listenButton.getPaddingRight(), listenButton.getPaddingBottom()); final ViewGroup.LayoutParams layoutParams = listenButton.getLayoutParams(); @@ -194,6 +209,18 @@ public void onView(View view, ViewGroup parent) { recordLastFiveMinutesButton.setOnClickListener(recordButtonClickListener); recordLastFiveMinutesButton.setOnLongClickListener(recordButtonClickListener); + recordLastThirtyMinuteButton = (Button) rootView.findViewById(R.id.record_last_30_minutes); + recordLastThirtyMinuteButton.setOnClickListener(recordButtonClickListener); + recordLastThirtyMinuteButton.setOnLongClickListener(recordButtonClickListener); + + recordLastTwoHrsButton = (Button) rootView.findViewById(R.id.record_last_2_hrs); + recordLastTwoHrsButton.setOnClickListener(recordButtonClickListener); + recordLastTwoHrsButton.setOnLongClickListener(recordButtonClickListener); + + recordLastSixHrsButton = (Button) rootView.findViewById(R.id.record_last_6_hrs); + recordLastSixHrsButton.setOnClickListener(recordButtonClickListener); + recordLastSixHrsButton.setOnLongClickListener(recordButtonClickListener); + recordMaxButton = (Button) rootView.findViewById(R.id.record_last_max); recordMaxButton.setOnClickListener(recordButtonClickListener); recordMaxButton.setOnLongClickListener(recordButtonClickListener); @@ -212,7 +239,11 @@ public void onView(View view, ViewGroup parent) { rate_on_google_play.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + activity.getPackageName()))); + try { + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + activity.getPackageName()))); + } catch (android.content.ActivityNotFoundException anfe) { + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + activity.getPackageName()))); + } } }); @@ -224,7 +255,12 @@ public void onClick(View v) { handler.postDelayed(new Runnable() { @Override public void run() { - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + activity.getPackageName()))); + //rate app + try { + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + activity.getPackageName()))); + } catch (android.content.ActivityNotFoundException anfe) { + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + activity.getPackageName()))); + } } }, 1000); handler.postDelayed(new Runnable() { @@ -246,9 +282,7 @@ public void onClick(View v) { startActivity(new Intent(activity, SettingsActivity.class)); } }); - serviceStateCallback.state(isListening, isRecording, 0, 0, 0); - return rootView; } @@ -256,10 +290,10 @@ public void onClick(View v) { @Override public void state(final boolean listeningEnabled, final boolean recording, final float memorized, final float totalMemory, final float recorded) { final Activity activity = getActivity(); - if(activity == null) return; + if (activity == null) return; final Resources resources = activity.getResources(); - if((isRecording != recording) || (isListening != listeningEnabled)) { - if(recording != isRecording) { + if ((isRecording != recording) || (isListening != listeningEnabled)) { + if (recording != isRecording) { isRecording = recording; if (recording) { rec_section.setVisibility(View.VISIBLE); @@ -268,7 +302,7 @@ public void state(final boolean listeningEnabled, final boolean recording, final } } - if(listeningEnabled != isListening) { + if (listeningEnabled != isListening) { isListening = listeningEnabled; if (listeningEnabled) { listenButton.setText(R.string.listening_enabled_disable); @@ -280,7 +314,7 @@ public void state(final boolean listeningEnabled, final boolean recording, final listenButton.setShadowLayer(0.01f, 0, resources.getDimensionPixelOffset(R.dimen.shadow_offset), 0xff666666); } - if(Build.VERSION.SDK_INT >= 19) { + if (Build.VERSION.SDK_INT >= 19) { final int statusBarHeight = getStatusBarHeight(); listenButton.setPadding(listenButton.getPaddingLeft(), listenButton.getPaddingTop() + statusBarHeight, listenButton.getPaddingRight(), listenButton.getPaddingBottom()); } @@ -296,13 +330,13 @@ public void state(final boolean listeningEnabled, final boolean recording, final TimeFormat.naturalLanguage(resources, totalMemory, timeFormatResult); - if(!history_limit.getText().equals(timeFormatResult.text)) { + if (!history_limit.getText().equals(timeFormatResult.text)) { history_limit.setText(timeFormatResult.text); } TimeFormat.naturalLanguage(resources, memorized, timeFormatResult); - if(!history_size.getText().equals(timeFormatResult.text)) { + if (!history_size.getText().equals(timeFormatResult.text)) { history_size_title.setText(resources.getQuantityText(R.plurals.history_size_title, timeFormatResult.count)); history_size.setText(timeFormatResult.text); recordMaxButton.setText(TimeFormat.shortTimer(memorized)); @@ -310,7 +344,7 @@ public void state(final boolean listeningEnabled, final boolean recording, final TimeFormat.naturalLanguage(resources, recorded, timeFormatResult); - if(!rec_time.getText().equals(timeFormatResult.text)) { + if (!rec_time.getText().equals(timeFormatResult.text)) { rec_indicator.setText(resources.getQuantityText(R.plurals.recorded, timeFormatResult.count)); rec_time.setText(timeFormatResult.text); } @@ -322,10 +356,9 @@ public void state(final boolean listeningEnabled, final boolean recording, final final TimeFormat.Result timeFormatResult = new TimeFormat.Result(); - - private class ListenButtonClickListener implements View.OnClickListener { + @SuppressLint("ValidFragment") final WorkingDialog dialog = new WorkingDialog() { @Override public void onStart() { @@ -385,13 +418,33 @@ public void state(final boolean listeningEnabled, final boolean recording, float @Override public void run() { if (recording) { - echo.stopRecording(new PromptFileReceiver(getActivity())); + echo.stopRecording(new PromptFileReceiver(getActivity()),""); } else { + ProgressDialog pd = new ProgressDialog(getActivity()); + pd.setMessage("Recording..."); + pd.show(); final float seconds = getPrependedSeconds(button); if (keepRecording) { echo.startRecording(seconds); } else { - echo.dumpRecording(seconds, new PromptFileReceiver(getActivity())); + //create alert dialog with exittext to name the file + View dialogView = View.inflate(getActivity(), R.layout.dialog_save_recording, null); + EditText fileName = dialogView.findViewById(R.id.recording_name); + new AlertDialog.Builder(getActivity()) + .setView(dialogView) + .setPositiveButton("Save", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if(fileName.getText().toString().length() > 0){ + echo.dumpRecording(seconds, new PromptFileReceiver(getActivity()),fileName.getText().toString()); + } else { + Toast.makeText(getActivity(), "Please enter a file name", Toast.LENGTH_SHORT).show(); + } + } + }) + .setNegativeButton("Cancel", null) + .show(); + pd.dismiss(); } } } @@ -402,27 +455,40 @@ public void run() { float getPrependedSeconds(View button) { switch (button.getId()) { - case R.id.record_last_minute: return 60; - case R.id.record_last_5_minutes: return 60 * 5; - case R.id.record_last_max: return 60 * 60 * 24 * 365; + case R.id.record_last_minute: + return 60; + case R.id.record_last_5_minutes: + return 60 * 5; + case R.id.record_last_30_minutes: + return 60 * 30; + case R.id.record_last_2_hrs: + return 60 * 60 * 2; + case R.id.record_last_6_hrs: + return 60 * 60 * 6; + case R.id.record_last_max: + return 60 * 60 * 24 * 365; } return 0; } } - static Notification buildNotificationForFile(Context context, File outFile) { Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(Uri.fromFile(outFile), "audio/wav"); - PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); - - NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context); - notificationBuilder.setContentTitle(context.getString(R.string.recording_saved)); - notificationBuilder.setContentText(outFile.getName()); - notificationBuilder.setSmallIcon(R.drawable.ic_stat_notify_recorded); - notificationBuilder.setTicker(outFile.getName()); - notificationBuilder.setContentIntent(pendingIntent); - notificationBuilder.setAutoCancel(true); + Uri fileUri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", outFile); + intent.setDataAndType(fileUri, "audio/wav"); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // Grant read permission to the receiving app + + PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE); + + NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, YOUR_NOTIFICATION_CHANNEL_ID) + .setContentTitle(context.getString(R.string.recording_saved)) + .setContentText(outFile.getName()) + .setSmallIcon(R.drawable.ic_stat_notify_recorded) + .setTicker(outFile.getName()) + .setContentIntent(pendingIntent) + .setAutoCancel(true); + notificationBuilder.setPriority(NotificationCompat.PRIORITY_DEFAULT); + notificationBuilder.setCategory(NotificationCompat.CATEGORY_MESSAGE); return notificationBuilder.build(); } @@ -436,7 +502,17 @@ public NotifyFileReceiver(Context context) { @Override public void fileReady(final File file, float runtime) { - NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context); + if (ActivityCompat.checkSelfPermission(context, android.Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { + // TODO: Consider calling + // ActivityCompat#requestPermissions + // here to request the missing permissions, and then overriding + // public void onRequestPermissionsResult(int requestCode, String[] permissions, + // int[] grantResults) + // to handle the case where the user grants the permission. See the documentation + // for ActivityCompat#requestPermissions for more details. + return; + } notificationManager.notify(43, buildNotificationForFile(context, file)); } } diff --git a/SaidIt/src/main/java/eu/mrogalski/saidit/SaidItService.java b/SaidIt/src/main/java/eu/mrogalski/saidit/SaidItService.java index 3b3023ac..39a15462 100644 --- a/SaidIt/src/main/java/eu/mrogalski/saidit/SaidItService.java +++ b/SaidIt/src/main/java/eu/mrogalski/saidit/SaidItService.java @@ -1,23 +1,28 @@ package eu.mrogalski.saidit; +import android.annotation.SuppressLint; import android.app.AlarmManager; import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.content.SharedPreferences; +import android.content.pm.ServiceInfo; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioRecord; import android.media.AudioTrack; import android.media.MediaRecorder; import android.os.Binder; +import android.os.Build; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.SystemClock; -import android.support.v4.app.NotificationCompat; +import androidx.core.app.NotificationCompat; import android.text.format.DateUtils; import android.util.Log; import android.widget.Toast; @@ -31,6 +36,8 @@ public class SaidItService extends Service { static final String TAG = SaidItService.class.getSimpleName(); + private static final int FOREGROUND_NOTIFICATION_ID = 458; + private static final String YOUR_NOTIFICATION_CHANNEL_ID = "SaidItServiceChannel"; volatile int SAMPLE_RATE; volatile int FILL_RATE; @@ -67,8 +74,9 @@ public void onCreate() { @Override public void onDestroy() { - stopRecording(null); + stopRecording(null, ""); innerStopListening(); + stopForeground(true); } @Override @@ -124,11 +132,16 @@ private void innerStartListening() { final long memorySize = getSharedPreferences(PACKAGE_NAME, MODE_PRIVATE).getLong(AUDIO_MEMORY_SIZE_KEY, Runtime.getRuntime().maxMemory() / 4); - Notification note = new Notification( 0, null, System.currentTimeMillis() ); + /*Notification note = new Notification( 0, null, System.currentTimeMillis() ); note.flags |= Notification.FLAG_NO_CLEAR; - startForeground(42, note); - startService(new Intent(this, FakeService.class)); + startForeground(42, note);*/ + /*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + startForegroundService(new Intent(this, FakeService.class)); + }else{ + startService(new Intent(this, FakeService.class)); + }*/ audioHandler.post(new Runnable() { + @SuppressLint("MissingPermission") @Override public void run() { Log.d(TAG, "Executing: START LISTENING"); @@ -188,7 +201,7 @@ public void run() { } - public void dumpRecording(final float memorySeconds, final WavFileReceiver wavFileReceiver) { + public void dumpRecording(final float memorySeconds, final WavFileReceiver wavFileReceiver, String newFileName) { if(state != STATE_LISTENING) throw new IllegalStateException("Not listening!"); audioHandler.post(new Runnable() { @@ -204,22 +217,44 @@ public void run() { final int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_SHOW_DATE; final String dateTime = DateUtils.formatDateTime(SaidItService.this, millis, flags); String filename = "Echo - " + dateTime + ".wav"; + if(!newFileName.equals("")){ + filename = newFileName + ".wav"; + } - final String storagePath = Environment.getExternalStorageDirectory().getAbsolutePath(); - String path = storagePath + "/" + filename; + File storageDir; + if(isExternalStorageWritable()){ + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { + // For Android 10 (API level 29) and above, use MediaStore for public storage + //file = new File(getExternalFilesDir(Environment.DIRECTORY_MUSIC), filename); + storageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC), "Echo"); + } else { + // For older versions, use the traditional external storage directory + storageDir = new File(Environment.getExternalStorageDirectory(), "Echo"); + } + }else{ + storageDir = new File(getFilesDir(), "Echo"); + } - File file = new File(path); - try { - file.createNewFile(); - } catch (IOException e) { - filename = filename.replace(':', '.'); - path = storagePath + "/" + filename; - file = new File(path); + if(!storageDir.exists()){ + storageDir.mkdir(); } - final WavAudioFormat format = new WavAudioFormat.Builder().sampleRate(SAMPLE_RATE).build(); - try { - final WavFileWriter writer = new WavFileWriter(format, file); + File file = new File(storageDir, filename); + // Create the file if it doesn't exist + if (!file.exists()) { + try { + if (!file.createNewFile()) { + // Handle file creation failure + throw new IOException("Failed to create file"); + } + } catch (IOException e) { + e.printStackTrace(); + // Handle IOException + showToast(getString(R.string.cant_create_file) + file.getAbsolutePath()); + } + } + final WavAudioFormat format = new WavAudioFormat.Builder().sampleRate(SAMPLE_RATE).build(); + try (WavFileWriter writer = new WavFileWriter(format, file)) { try { audioMemory.read(skipBytes, new AudioMemory.Consumer() { @Override @@ -229,36 +264,29 @@ public int consume(byte[] array, int offset, int count) throws IOException { } }); } catch (IOException e) { - final String errorMessage = getString(R.string.error_during_writing_history_into) + path; - Toast.makeText(SaidItService.this, errorMessage, Toast.LENGTH_LONG).show(); - Log.e(TAG, errorMessage, e); - - try { - writer.close(); - } catch (IOException e2) { - Log.e(TAG, "CLOSING ERROR", e2); - } - if(wavFileReceiver != null) - wavFileReceiver.fileReady(file, writer.getTotalSampleBytesWritten() * getBytesToSeconds()); + // Handle error during file writing + showToast(getString(R.string.error_during_writing_history_into) + file.getAbsolutePath()); + Log.e(TAG, "Error during writing history into " + file.getAbsolutePath(), e); } - - try { - writer.close(); - } catch (IOException e) { - Log.e(TAG, "CLOSING ERROR", e); - } - if(wavFileReceiver != null) { + if (wavFileReceiver != null) { wavFileReceiver.fileReady(file, writer.getTotalSampleBytesWritten() * getBytesToSeconds()); } } catch (IOException e) { - final String errorMessage = getString(R.string.cant_create_file) + path; - Toast.makeText(SaidItService.this, errorMessage, Toast.LENGTH_LONG).show(); - Log.e(TAG, errorMessage, e); + // Handle error during file creation or closing writer + showToast(getString(R.string.cant_create_file) + file.getAbsolutePath()); + Log.e(TAG, "Can't create file " + file.getAbsolutePath(), e); } } }); } + private static boolean isExternalStorageWritable() { + String state = Environment.getExternalStorageState(); + return Environment.MEDIA_MOUNTED.equals(state); + } + private void showToast(String message) { + Toast.makeText(SaidItService.this, message, Toast.LENGTH_LONG).show(); + } public void startRecording(final float prependedMemorySeconds) { switch(state) { @@ -286,7 +314,21 @@ public void run() { final String dateTime = DateUtils.formatDateTime(SaidItService.this, millis, flags); String filename = "Echo - " + dateTime + ".wav"; - final String storagePath = Environment.getExternalStorageDirectory().getAbsolutePath(); + File storageDir; + if(isExternalStorageWritable()){ + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { + // For Android 10 (API level 29) and above, use MediaStore for public storage + //file = new File(getExternalFilesDir(Environment.DIRECTORY_MUSIC), filename); + storageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC), "Echo"); + } else { + // For older versions, use the traditional external storage directory + storageDir = new File(Environment.getExternalStorageDirectory(), "Echo"); + } + }else{ + storageDir = new File(getFilesDir(), "Echo"); + } + final String storagePath = storageDir.getAbsolutePath(); + String path = storagePath + "/" + filename; wavFile = new File(path); @@ -322,14 +364,14 @@ public int consume(byte[] array, int offset, int count) throws IOException { final String errorMessage = getString(R.string.error_during_writing_history_into) + finalPath; Toast.makeText(SaidItService.this, errorMessage, Toast.LENGTH_LONG).show(); Log.e(TAG, errorMessage, e); - stopRecording(new SaidItFragment.NotifyFileReceiver(SaidItService.this)); + stopRecording(new SaidItFragment.NotifyFileReceiver(SaidItService.this), ""); } } } }); - final Notification notification = buildNotification(); - startForeground(42, notification); + /*final Notification notification = buildNotification(); + startForeground(42, notification);*/ } @@ -377,7 +419,7 @@ public interface WavFileReceiver { public void fileReady(File file, float runtime); } - public void stopRecording(final WavFileReceiver wavFileReceiver) { + public void stopRecording(final WavFileReceiver wavFileReceiver, String newFileName) { switch(state) { case STATE_READY: case STATE_LISTENING: @@ -445,7 +487,7 @@ public void run() { final String errorMessage = getString(R.string.error_during_recording_into) + wavFile.getName(); Toast.makeText(SaidItService.this, errorMessage, Toast.LENGTH_LONG).show(); Log.e(TAG, errorMessage, e); - stopRecording(new SaidItFragment.NotifyFileReceiver(SaidItService.this)); + stopRecording(new SaidItFragment.NotifyFileReceiver(SaidItService.this), ""); } } }; @@ -502,7 +544,12 @@ public SaidItService getService() { @Override public int onStartCommand(Intent intent, int flags, int startId) { - return super.onStartCommand(intent, flags, startId); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + startForeground(FOREGROUND_NOTIFICATION_ID, buildNotification(), ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE); + }else{ + startForeground(FOREGROUND_NOTIFICATION_ID, buildNotification()); + } + return START_STICKY; } // Workaround for bug where recent app removal caused service to stop @@ -511,7 +558,7 @@ public void onTaskRemoved(Intent rootIntent) { Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass()); restartServiceIntent.setPackage(getPackageName()); - PendingIntent restartServicePendingIntent = PendingIntent.getService(this, 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT); + PendingIntent restartServicePendingIntent = PendingIntent.getService(this, 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT| PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); AlarmManager alarmService = (AlarmManager) getSystemService(ALARM_SERVICE); alarmService.set( AlarmManager.ELAPSED_REALTIME, @@ -520,17 +567,28 @@ public void onTaskRemoved(Intent rootIntent) { } private Notification buildNotification() { - Intent intent = new Intent(this, SaidItActivity.class); - PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0); - - NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this); - notificationBuilder.setContentTitle(getString(R.string.recording)); - notificationBuilder.setUsesChronometer(true); - notificationBuilder.setProgress(100, 50, true); - notificationBuilder.setSmallIcon(R.drawable.ic_stat_notify_recording); - notificationBuilder.setTicker(getString(R.string.recording)); - notificationBuilder.setContentIntent(pendingIntent); + PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE); + + NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, YOUR_NOTIFICATION_CHANNEL_ID) + .setContentTitle(getString(R.string.recording)) + .setSmallIcon(R.drawable.ic_stat_notify_recording) + .setTicker(getString(R.string.recording)) + .setContentIntent(pendingIntent) + .setPriority(NotificationCompat.PRIORITY_DEFAULT) + .setOngoing(true); // Ensure notification is ongoing + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + // Create the notification channel + NotificationChannel channel = new NotificationChannel( + YOUR_NOTIFICATION_CHANNEL_ID, + "Recording Channel", + NotificationManager.IMPORTANCE_DEFAULT + ); + NotificationManager notificationManager = getSystemService(NotificationManager.class); + notificationManager.createNotificationChannel(channel); + } + return notificationBuilder.build(); } diff --git a/SaidIt/src/main/java/eu/mrogalski/saidit/SettingsActivity.java b/SaidIt/src/main/java/eu/mrogalski/saidit/SettingsActivity.java index 23762ffe..9554821f 100644 --- a/SaidIt/src/main/java/eu/mrogalski/saidit/SettingsActivity.java +++ b/SaidIt/src/main/java/eu/mrogalski/saidit/SettingsActivity.java @@ -70,9 +70,14 @@ public void onServiceDisconnected(ComponentName arg0) { private void syncUI() { final long maxMemory = Runtime.getRuntime().maxMemory(); + System.out.println("maxMemory = " + maxMemory); + System.out.println("totalMemory = " + Runtime.getRuntime().totalMemory()); + ((Button) findViewById(R.id.memory_low)).setText(StringFormat.shortFileSize(maxMemory / 4)); ((Button) findViewById(R.id.memory_medium)).setText(StringFormat.shortFileSize(maxMemory / 2)); - ((Button) findViewById(R.id.memory_high)).setText(StringFormat.shortFileSize(maxMemory * 3 / 4)); +// ((Button) findViewById(R.id.memory_high)).setText(StringFormat.shortFileSize(maxMemory * 3 / 4)); + ((Button) findViewById(R.id.memory_high)).setText(StringFormat.shortFileSize((long) (maxMemory * 0.90))); + TimeFormat.naturalLanguage(getResources(), service.getBytesToSeconds() * service.getMemorySize(), timeFormatResult); ((TextView)findViewById(R.id.history_limit)).setText(timeFormatResult.text); diff --git a/SaidIt/src/main/java/eu/mrogalski/saidit/ThemedDialog.java b/SaidIt/src/main/java/eu/mrogalski/saidit/ThemedDialog.java index 28b6fd9c..8c41db8c 100644 --- a/SaidIt/src/main/java/eu/mrogalski/saidit/ThemedDialog.java +++ b/SaidIt/src/main/java/eu/mrogalski/saidit/ThemedDialog.java @@ -23,6 +23,8 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { final Dialog dialog = super.onCreateDialog(savedInstanceState); dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); dialog.getWindow().getDecorView().setBackgroundDrawable(null); + //set dialog width to 90% of screen width + dialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); return dialog; } diff --git a/SaidIt/src/main/res/drawable/bg_et.xml b/SaidIt/src/main/res/drawable/bg_et.xml new file mode 100644 index 00000000..8bdd24d6 --- /dev/null +++ b/SaidIt/src/main/res/drawable/bg_et.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SaidIt/src/main/res/layout/activity_settings.xml b/SaidIt/src/main/res/layout/activity_settings.xml index 0787018b..b0f30d56 100644 --- a/SaidIt/src/main/res/layout/activity_settings.xml +++ b/SaidIt/src/main/res/layout/activity_settings.xml @@ -189,7 +189,8 @@ android:layout_gravity="center" android:text="@string/settings_return" android:layout_width="wrap_content" - android:layout_height="wrap_content" /> + android:layout_height="wrap_content" + style="@style/Button"/> diff --git a/SaidIt/src/main/res/layout/dialog_save_recording.xml b/SaidIt/src/main/res/layout/dialog_save_recording.xml new file mode 100644 index 00000000..5611c2b6 --- /dev/null +++ b/SaidIt/src/main/res/layout/dialog_save_recording.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/SaidIt/src/main/res/layout/fragment_background_recorder.xml b/SaidIt/src/main/res/layout/fragment_background_recorder.xml index 5431f9f0..e9044406 100644 --- a/SaidIt/src/main/res/layout/fragment_background_recorder.xml +++ b/SaidIt/src/main/res/layout/fragment_background_recorder.xml @@ -76,7 +76,8 @@ android:text="@string/record_one_minute" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_weight="1"/> + android:layout_weight="1" + style="@style/Button"/>