├── CHANGELOG.md
├── LICENSE.md
├── README.md
├── app
├── build.gradle
├── libs
│ └── Croller
│ │ ├── build.gradle
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── com
│ │ │ └── sdsmdg
│ │ │ └── harjot
│ │ │ └── crollerTest
│ │ │ └── ApplicationTest.java
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── sdsmdg
│ │ │ │ └── harjot
│ │ │ │ └── crollerTest
│ │ │ │ ├── Croller.java
│ │ │ │ ├── OnCrollerChangeListener.java
│ │ │ │ └── utilities
│ │ │ │ └── Utils.java
│ │ └── res
│ │ │ ├── layout
│ │ │ └── croller_view.xml
│ │ │ └── values
│ │ │ ├── attrs.xml
│ │ │ └── strings.xml
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── sdsmdg
│ │ └── harjot
│ │ └── croller
│ │ └── ExampleUnitTest.java
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── net
│ │ └── synapticweb
│ │ └── callrecorder
│ │ └── data
│ │ ├── RecordingTest.java
│ │ └── RepositoryImplTest.java
│ ├── eval
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── net
│ │ │ └── synapticweb
│ │ │ └── callrecorder
│ │ │ └── Config.java
│ └── res
│ │ └── values
│ │ └── strings.xml
│ ├── full
│ ├── AndroidManifest.xml
│ └── java
│ │ └── net
│ │ └── synapticweb
│ │ └── callrecorder
│ │ └── Config.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ ├── assign.png
│ │ ├── common_style.css
│ │ ├── dark_style.css
│ │ ├── deleted_audio.jpg
│ │ ├── dots_menu_dark.png
│ │ ├── dots_menu_light.png
│ │ ├── incognito.png
│ │ ├── info_dark.png
│ │ ├── info_light.png
│ │ ├── ingoing.png
│ │ ├── launcher_icon-web.png
│ │ ├── launcher_icon.png
│ │ ├── light_style.css
│ │ ├── move_dark.png
│ │ ├── move_light.png
│ │ ├── notification_icon_dark.png
│ │ ├── notification_icon_light.png
│ │ ├── outgoing.png
│ │ ├── plus.png
│ │ ├── select_all_dark.png
│ │ ├── select_all_light.png
│ │ ├── selected_rec.jpg
│ │ ├── stop_rec.jpg
│ │ └── top_bar_selected.jpg
│ ├── java
│ │ └── net
│ │ │ └── synapticweb
│ │ │ └── callrecorder
│ │ │ ├── BaseActivity.java
│ │ │ ├── CrApp.java
│ │ │ ├── CrLog.java
│ │ │ ├── HelpActivity.java
│ │ │ ├── Util.java
│ │ │ ├── contactdetail
│ │ │ ├── ContactDetailActivity.java
│ │ │ ├── ContactDetailContract.java
│ │ │ ├── ContactDetailFragment.java
│ │ │ ├── ContactDetailPresenter.java
│ │ │ ├── EditContactActivity.java
│ │ │ ├── MoveAsyncTask.java
│ │ │ └── di
│ │ │ │ ├── ContactDetailComponent.java
│ │ │ │ ├── PresenterModule.java
│ │ │ │ └── ViewModule.java
│ │ │ ├── contactslist
│ │ │ ├── ContactsListActivityMain.java
│ │ │ ├── ContactsListContract.java
│ │ │ ├── ContactsListFragment.java
│ │ │ ├── ContactsListPresenter.java
│ │ │ ├── UnassignedRecordingsFragment.java
│ │ │ └── di
│ │ │ │ ├── ContactsListComponent.java
│ │ │ │ ├── PresenterModule.java
│ │ │ │ └── ViewModule.java
│ │ │ ├── data
│ │ │ ├── CallRecorderDbHelper.java
│ │ │ ├── Contact.java
│ │ │ ├── ContactsContract.java
│ │ │ ├── Recording.java
│ │ │ ├── RecordingsContract.java
│ │ │ ├── Repository.java
│ │ │ └── RepositoryImpl.java
│ │ │ ├── di
│ │ │ ├── AppComponent.java
│ │ │ ├── AppSubcomponents.java
│ │ │ ├── FragmentScope.java
│ │ │ └── RepositoryModule.java
│ │ │ ├── player
│ │ │ ├── AudioPlayer.java
│ │ │ ├── PlaybackListenerInterface.java
│ │ │ ├── PlayerActivity.java
│ │ │ ├── PlayerAdapter.java
│ │ │ └── PlayerException.java
│ │ │ ├── recorder
│ │ │ ├── CallReceiver.java
│ │ │ ├── ControlRecordingReceiver.java
│ │ │ ├── Recorder.java
│ │ │ ├── RecorderService.java
│ │ │ ├── RecordingException.java
│ │ │ ├── RecordingThread.java
│ │ │ ├── RecordingThreadAac.java
│ │ │ └── RecordingThreadWav.java
│ │ │ ├── settings
│ │ │ ├── SettingsActivity.java
│ │ │ └── SettingsFragment.java
│ │ │ └── setup
│ │ │ ├── SetupActivity.java
│ │ │ ├── SetupEulaFragment.java
│ │ │ ├── SetupPermissionsFragment.java
│ │ │ ├── SetupPowerFragment.java
│ │ │ └── ShowEulaActivity.java
│ ├── launcher_icon-web.png
│ └── res
│ │ ├── color
│ │ ├── nav_item_state_list.xml
│ │ ├── text_on_dark.xml
│ │ └── text_on_light.xml
│ │ ├── drawable-anydpi-v24
│ │ └── notification_icon_success.xml
│ │ ├── drawable-hdpi
│ │ ├── baseline_info_black_36.png
│ │ ├── baseline_settings_black_36.png
│ │ ├── ic_album_white_24dp.png
│ │ ├── ic_play_grey600_24dp.png
│ │ ├── notification_icon.png
│ │ ├── notification_icon_error.png
│ │ └── notification_icon_success.png
│ │ ├── drawable-mdpi
│ │ ├── baseline_info_black_36.png
│ │ ├── baseline_more_vert_white_24.png
│ │ ├── baseline_settings_black_36.png
│ │ ├── notification_icon.png
│ │ ├── notification_icon_error.png
│ │ └── notification_icon_success.png
│ │ ├── drawable-xhdpi
│ │ ├── baseline_info_black_36.png
│ │ ├── baseline_more_vert_white_24.png
│ │ ├── baseline_settings_black_36.png
│ │ ├── notification_icon.png
│ │ ├── notification_icon_error.png
│ │ └── notification_icon_success.png
│ │ ├── drawable-xxhdpi
│ │ ├── baseline_info_black_36.png
│ │ ├── baseline_more_vert_white_24.png
│ │ ├── baseline_settings_black_36.png
│ │ ├── notification_icon.png
│ │ ├── notification_icon_error.png
│ │ └── notification_icon_success.png
│ │ ├── drawable-xxxhdpi
│ │ ├── baseline_info_black_36.png
│ │ ├── baseline_more_vert_white_24.png
│ │ ├── baseline_settings_black_36.png
│ │ ├── notification_icon.png
│ │ └── notification_icon_error.png
│ │ ├── drawable
│ │ ├── back.xml
│ │ ├── call.xml
│ │ ├── checkbox_checked.xml
│ │ ├── checkbox_unchecked.xml
│ │ ├── close.xml
│ │ ├── done.xml
│ │ ├── edit.xml
│ │ ├── email.xml
│ │ ├── error.xml
│ │ ├── exclamation.xml
│ │ ├── grid.xml
│ │ ├── header.png
│ │ ├── header_back.png
│ │ ├── help.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_plus.xml
│ │ ├── incognito.xml
│ │ ├── incoming.xml
│ │ ├── info.xml
│ │ ├── launcher.png
│ │ ├── menu.xml
│ │ ├── outgoing_dark.xml
│ │ ├── outgoing_light.xml
│ │ ├── player_pause.xml
│ │ ├── player_play.xml
│ │ ├── player_stop.xml
│ │ ├── question_mark.xml
│ │ ├── recorder.xml
│ │ ├── select_all.xml
│ │ ├── select_export.xml
│ │ ├── settings.png
│ │ ├── sound_bottom.xml
│ │ ├── sound_symbol_aac128_dark.xml
│ │ ├── sound_symbol_aac128_light.xml
│ │ ├── sound_symbol_aac32_dark.xml
│ │ ├── sound_symbol_aac32_light.xml
│ │ ├── sound_symbol_aac64_dark.xml
│ │ ├── sound_symbol_aac64_light.xml
│ │ ├── sound_symbol_wav_dark.xml
│ │ ├── sound_symbol_wav_light.xml
│ │ ├── speaker_phone_off.xml
│ │ ├── speaker_phone_on.xml
│ │ ├── stars.xml
│ │ ├── success.xml
│ │ ├── user_bottom.xml
│ │ ├── user_contact.xml
│ │ └── warning.xml
│ │ ├── layout
│ │ ├── contact.xml
│ │ ├── contact_detail_activity.xml
│ │ ├── contact_detail_fragment.xml
│ │ ├── contacts_list_activity_onepane.xml
│ │ ├── contacts_list_activity_twopane.xml
│ │ ├── edit_contact_activity.xml
│ │ ├── help_activity.xml
│ │ ├── help_fragment.xml
│ │ ├── info_dialog.xml
│ │ ├── info_storage_dialog.xml
│ │ ├── list_contacts_fragment.xml
│ │ ├── navdraw_header.xml
│ │ ├── player_activity.xml
│ │ ├── recording.xml
│ │ ├── settings_layout.xml
│ │ ├── setup_activity.xml
│ │ ├── setup_eula_fragment.xml
│ │ ├── setup_permissions_fragment.xml
│ │ ├── setup_power_fragment.xml
│ │ ├── setup_show_eula_activity.xml
│ │ └── unassigned_recordings_fragment.xml
│ │ ├── menu
│ │ ├── bottom_nav.xml
│ │ ├── contact_popup.xml
│ │ ├── drawer_view.xml
│ │ ├── edit_contact_change_photo.xml
│ │ ├── recording_selected_popup.xml
│ │ └── storage_chooser_options.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── launcher_icon.xml
│ │ └── launcher_icon_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ ├── ic_launcher_round.png
│ │ ├── launcher_icon.png
│ │ └── launcher_icon_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ ├── ic_launcher_round.png
│ │ ├── launcher_icon.png
│ │ └── launcher_icon_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ ├── ic_launcher_round.png
│ │ ├── launcher_icon.png
│ │ └── launcher_icon_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ ├── ic_launcher_round.png
│ │ ├── launcher_icon.png
│ │ └── launcher_icon_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ ├── ic_launcher_round.png
│ │ ├── launcher_icon.png
│ │ └── launcher_icon_round.png
│ │ ├── raw
│ │ ├── eula.html
│ │ ├── help_about.html
│ │ ├── help_licences.html
│ │ ├── help_managing_recordings.html
│ │ ├── help_playing_recordings.html
│ │ ├── help_recording_calls.html
│ │ └── privacy_policy.html
│ │ ├── values-sw380dp
│ │ └── dimens.xml
│ │ ├── values-sw600dp
│ │ └── refs.xml
│ │ ├── values
│ │ ├── arrays.xml
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── refs.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ │ └── xml
│ │ ├── files.xml
│ │ └── preferences.xml
│ └── test
│ └── java
│ └── net
│ └── synapticweb
│ └── callrecorder
│ └── data
│ ├── ContactTest.java
│ ├── ContactTestRobolectric.java
│ ├── FakePhoneLookupProvider.java
│ ├── FakeRepository.java
│ ├── RecordingTest.java
│ └── RecordingTestRobolectric.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 1.1.2
2 | - Audio source is now selectable by the user.
3 |
4 | ## 1.1.1
5 | - Recordings name now contain the full date with year and no "Recording" prefix.
6 | - The recordings listings are now retrieved ordered by date descending.
7 | - Removed arrows (type of call) from hidden number contacts recordings.
8 |
9 |
10 | ## 1.0.0
11 | - Reached production development stage
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SW Call Recorder
2 |
3 | SW Call Recorder is an Android application that automatically records phone calls based on user selected phone numbers.
4 | It has the following main features:
5 |
6 | - The phone numbers are organized into contacts.
7 | - Every contact can have an associated picture selected by the user.
8 | - There are 4 possible recording formats: WAV (Lossless), AAC 128kbs, AAC 64kbps and AAC 32kbps.
9 | - Recordings can be mono or stereo.
10 | - The device can be put automatically on speaker while the application records the call.
11 | - Recordings can be stored in the application's private storage space or in a public accessible location on the device. If they are stored in a public accessible location, they can be easily transferred to other devices, like a laptop. The location of the recordings on the device can be easily changed.
12 | - Phone calls from private (unknown) numbers are supported.
13 | - The user can rename the recordings.
14 | - The recordings can be played from within the application with the help of a dedicated audio player.
15 | - The audio player can modify the sound volume of the device while playing. After the playing finishes, the audio volume of the device automatically comes back to the previous value.
16 | - The audio player can apply a gain to the audio signal to further control how loud the sound is played.
17 | - The application has 2 themes: light and dark.
18 |
19 | Because of the restrictions imposed by Google on requesting permissions from the Call log permission group (https://play.google.com/about/privacy-security-deception/permissions/), the app is currently developed using two branches: the `original-app` branch and the `gpcompliant` (from "google play compliant") branch.
20 |
21 | The `gpcompliant` branch does not use the READ_CALL_LOG and PROCESS_OUTGOING_CALLS permissions and consequently the versions of the app compiled from this source cannot obtain the outgoing phone number in all supported versions of Android and cannot obtain the incoming phone number in Android versions 9 and above. This has consequences on the overall appearance and behavior of the app that are documented in the "Recording phone calls" section of the Help menu. These versions have the substring 'gpcompliant' appended to the version string.
22 |
23 | The `original-app` branch retains all the functions that were removed from the `gpcompliant` branch. The versions of the app compiled from this source have the substring 'original' appended to the version string.
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'com.google.gms.google-services'
3 | apply plugin: 'io.fabric'
4 |
5 | android {
6 | compileSdkVersion 29
7 | buildToolsVersion "30.0.0-rc4"
8 | defaultConfig {
9 | applicationId "net.synapticweb.callrecorder.gpcompliant"
10 | minSdkVersion 21
11 | targetSdkVersion 29
12 | versionCode 13
13 | versionName "1.1.3-gpcompliant"
14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
15 | }
16 | flavorDimensions "version"
17 |
18 | productFlavors {
19 | eval {
20 | dimension "version"
21 | applicationIdSuffix ".eval"
22 | versionNameSuffix "-eval"
23 | }
24 |
25 | full {
26 | dimension "version"
27 | applicationIdSuffix ".full"
28 | versionNameSuffix "-full"
29 | }
30 | }
31 |
32 | buildTypes {
33 | release {
34 | minifyEnabled false
35 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
36 | }
37 | }
38 | compileOptions {
39 | sourceCompatibility JavaVersion.VERSION_1_8
40 | targetCompatibility JavaVersion.VERSION_1_8
41 | }
42 | testOptions {
43 | unitTests {
44 | includeAndroidResources = true
45 | }
46 | }
47 | }
48 |
49 | ext {
50 | assertjVersion = "3.11.1"
51 | acraVersion = "5.5.0"
52 | daggerVersion = "2.27"
53 | robolectricVersion = "4.3.1"
54 | androidXVersion = "1.2.0"
55 | mockitoVersion = "3.3.3"
56 | androidJunitVersion = "1.1.1"
57 | hamcrestVersion = "1.3"
58 | powermockVersion = "2.0.2"
59 | runnerVersion = "1.3.0-rc01"
60 | }
61 |
62 |
63 | dependencies {
64 | implementation fileTree(include: ['*.jar'], dir: 'libs')
65 | // androidTestImplementation('androidx.test.espresso:espresso-core:3.1.1-beta01', {
66 | // exclude group: 'com.android.support', module: 'support-annotations'
67 | // })
68 | implementation 'androidx.appcompat:appcompat:1.1.0'
69 | // implementation 'com.android.support.constraint:constraint-layout:1.1.2'
70 | implementation 'androidx.media:media:1.1.0'
71 | implementation 'com.google.android.material:material:1.1.0'
72 | implementation 'androidx.recyclerview:recyclerview:1.1.0'
73 | implementation 'de.hdodenhof:circleimageview:2.2.0'
74 | implementation 'com.theartofdev.edmodo:android-image-cropper:2.8.0'
75 | implementation 'com.github.codekidX:storage-chooser:2.0.4.4'
76 | implementation 'com.afollestad.material-dialogs:core:0.9.6.0'
77 | implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.4'
78 | // implementation 'androidx.cardview:cardview:1.0.0'
79 | // implementation 'com.github.topjohnwu:libsu:2.0.2'
80 | implementation 'androidx.preference:preference:1.1.1'
81 | implementation 'com.chibde:audiovisualizer:2.2.0'
82 | //Am renunțat la adăugarea dependenței din jitpack deoarece cînd am trecut la definirea dimensiunilor în
83 | // dimens.xml a apărut un bug: la label_size orice dimensiune puneam crăpa. Nu am făcut nicio modificare în
84 | //sursa bibliotecii, dar versiunea din jitpack era veche. (Am folosit sp în loc de plain integer în dimens.xml
85 | // al meu.)
86 | //https://stackoverflow.com/questions/25610727/adding-external-library-in-android-studio/29791082
87 | implementation project(':Croller')
88 | //https://developers.google.com/analytics/devguides/collection/firebase/android/start
89 | //Firebase folosim numai în release, fără debug
90 | releaseImplementation 'com.google.firebase:firebase-analytics:17.4.2'
91 | releaseImplementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
92 |
93 | implementation "ch.acra:acra-http:$acraVersion"
94 | implementation "com.google.dagger:dagger:$daggerVersion"
95 | annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
96 |
97 | //test
98 | //nu este nevoie de hamcrest. Este inclus în test.core, cred.
99 | testImplementation "androidx.test:core:$androidXVersion"
100 | testImplementation "androidx.test.ext:junit:$androidJunitVersion"
101 | testImplementation "org.robolectric:robolectric:$robolectricVersion"
102 | testImplementation "org.mockito:mockito-core:$mockitoVersion"
103 |
104 | //androidTest
105 | androidTestImplementation "androidx.test:runner:$runnerVersion"
106 | androidTestImplementation "androidx.test:core:$androidXVersion"
107 | androidTestImplementation "androidx.test.ext:junit:$androidJunitVersion"
108 | androidTestImplementation "org.assertj:assertj-core:$assertjVersion"
109 | }
--------------------------------------------------------------------------------
/app/libs/Croller/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | ext {
4 | bintrayRepo = 'Croller'
5 | bintrayName = 'croller'
6 |
7 | publishedGroupId = 'com.sdsmdg.harjot'
8 | libraryName = 'Croller'
9 | artifact = 'croller'
10 |
11 | libraryDescription = 'A circular seekbar for Android, with a control knob! (for the lack of a better word).'
12 |
13 | siteUrl = 'https://github.com/harjot-oberai/Croller'
14 | gitUrl = 'https://github.com/harjot-oberai/Croller.git'
15 |
16 | libraryVersion = '1.0.7'
17 |
18 | developerId = 'harjot-oberai'
19 | developerName = 'Harjot Singh Oberai'
20 | developerEmail = 'harjot.oberai@gmail.com'
21 |
22 | licenseName = 'The Apache Software License, Version 2.0'
23 | licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
24 | allLicenses = ["Apache-2.0"]
25 | }
26 |
27 | version = '1.0.1'
28 |
29 | android {
30 | compileSdkVersion 27
31 | buildToolsVersion '28.0.3'
32 |
33 | defaultConfig {
34 | minSdkVersion 16
35 | targetSdkVersion 27
36 | versionCode 1
37 | versionName "1.0"
38 | }
39 | buildTypes {
40 | release {
41 | minifyEnabled false
42 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
43 | }
44 | }
45 | }
46 |
47 | dependencies {
48 | implementation fileTree(dir: 'libs', include: ['*.jar'])
49 | testImplementation 'junit:junit:4.12'
50 | implementation 'androidx.appcompat:appcompat:1.1.0-rc01'
51 | }
52 |
53 | //apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle'
54 | //apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/bintrayv1.gradle'
--------------------------------------------------------------------------------
/app/libs/Croller/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\Users\Harjot\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/libs/Croller/src/androidTest/java/com/sdsmdg/harjot/crollerTest/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.sdsmdg.harjot.crollerTest;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/libs/Croller/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/libs/Croller/src/main/java/com/sdsmdg/harjot/crollerTest/OnCrollerChangeListener.java:
--------------------------------------------------------------------------------
1 | package com.sdsmdg.harjot.crollerTest;
2 |
3 | public interface OnCrollerChangeListener {
4 | void onProgressChanged(Croller croller, int progress);
5 |
6 | void onStartTrackingTouch(Croller croller);
7 |
8 | void onStopTrackingTouch(Croller croller);
9 | }
10 |
--------------------------------------------------------------------------------
/app/libs/Croller/src/main/java/com/sdsmdg/harjot/crollerTest/utilities/Utils.java:
--------------------------------------------------------------------------------
1 | package com.sdsmdg.harjot.crollerTest.utilities;
2 |
3 | import android.content.Context;
4 | import android.content.res.Resources;
5 | import android.util.DisplayMetrics;
6 |
7 | public class Utils {
8 | public static float getDistance(float x1, float y1, float x2, float y2) {
9 | return (float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
10 | }
11 |
12 | public static float convertDpToPixel(float dp, Context context) {
13 | Resources resources = context.getResources();
14 | DisplayMetrics metrics = resources.getDisplayMetrics();
15 | return dp * ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
16 | }
17 |
18 | public static float convertPixelsToDp(float px, Context context) {
19 | Resources resources = context.getResources();
20 | DisplayMetrics metrics = resources.getDisplayMetrics();
21 | return px / ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/app/libs/Croller/src/main/res/layout/croller_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/libs/Croller/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/app/libs/Croller/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Croller
3 |
4 |
--------------------------------------------------------------------------------
/app/libs/Croller/src/test/java/com/sdsmdg/harjot/croller/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.sdsmdg.harjot.crollerTest;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /home/eugen/Android/Sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 | -keep class android.support.v7.widget.** { *; }
--------------------------------------------------------------------------------
/app/src/androidTest/java/net/synapticweb/callrecorder/data/RecordingTest.java:
--------------------------------------------------------------------------------
1 | package net.synapticweb.callrecorder.data;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.core.app.ApplicationProvider;
6 |
7 |
8 | import org.junit.After;
9 | import org.junit.Before;
10 | import org.junit.Test;
11 |
12 |
13 | import java.io.File;
14 | import java.io.FileInputStream;
15 | import java.io.FileOutputStream;
16 | import java.io.IOException;
17 | import java.io.InputStream;
18 | import java.io.OutputStream;
19 | import java.security.MessageDigest;
20 | import java.util.concurrent.ThreadLocalRandom;
21 |
22 | import static org.hamcrest.CoreMatchers.is;
23 |
24 | import static org.junit.Assert.*;
25 |
26 | public class RecordingTest {
27 | private static final String FILE_NAME = "testfile";
28 | private static String RANDOM_FILE_PATH;
29 | private static String DESTINATION_FOLDER;
30 | private static final int FILE_SIZE = 1048576;
31 | private RepositoryImpl repository;
32 |
33 | @Before
34 | public void setup() {
35 | Context context = ApplicationProvider.getApplicationContext();
36 | RANDOM_FILE_PATH = new File(context.getFilesDir() + "/" + FILE_NAME).getAbsolutePath();
37 | DESTINATION_FOLDER = context.getExternalFilesDir(null).getAbsolutePath();
38 | repository = new RepositoryImpl(context, null);
39 | }
40 |
41 | @After
42 | public void removeFile() {
43 | if(new File(DESTINATION_FOLDER + "/" + FILE_NAME).exists())
44 | new File(DESTINATION_FOLDER + "/" + FILE_NAME).delete();
45 | }
46 |
47 | private void createRandomFile() {
48 | try {
49 | OutputStream os = new FileOutputStream(RANDOM_FILE_PATH);
50 | for(int i = 0; i < FILE_SIZE; ++i) {
51 | int number = ThreadLocalRandom.current().nextInt(0, 255 + 1);
52 | os.write(number);
53 | }
54 | os.flush();
55 | }
56 | catch (IOException ignored) {}
57 | }
58 |
59 | private String byteArrayToHexString(byte[] bytes) {
60 | StringBuilder result = new StringBuilder();
61 | for (byte value : bytes) {
62 | result.append(Integer.toString((value & 0xff) + 0x100, 16).substring(1));
63 | }
64 | return result.toString();
65 | }
66 |
67 | private String computeFileSha1(String path) {
68 | String hash = "";
69 | try {
70 | MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
71 | InputStream input = new FileInputStream(path);
72 | byte[] buffer = new byte[8192];
73 | int len = input.read(buffer);
74 |
75 | while (len != -1) {
76 | sha1.update(buffer, 0, len);
77 | len = input.read(buffer);
78 | }
79 | hash = byteArrayToHexString(sha1.digest());
80 | }
81 | catch (Exception ignored) {}
82 | return hash;
83 | }
84 |
85 | @Test
86 | public void move() {
87 | createRandomFile();
88 | String hash1 = computeFileSha1(RANDOM_FILE_PATH);
89 |
90 | Recording recording = new Recording();
91 | recording.setPath(RANDOM_FILE_PATH);
92 | repository.insertRecording(recording);
93 | Long id = recording.getId();
94 |
95 | try {
96 | recording.move(repository, DESTINATION_FOLDER, null, FILE_SIZE);
97 | }
98 | catch (IOException ignored) {}
99 |
100 | assertTrue(new File(DESTINATION_FOLDER + "/" + FILE_NAME).exists());
101 | assertFalse(new File(RANDOM_FILE_PATH).exists());
102 | String hash2 = computeFileSha1(DESTINATION_FOLDER + "/" + FILE_NAME);
103 | assertThat(hash1, is(hash2));
104 |
105 | assertThat(recording.getPath(), is(DESTINATION_FOLDER + "/" + FILE_NAME));
106 | recording = repository.getRecording(id);
107 | assertThat(recording.getPath(), is(DESTINATION_FOLDER + "/" + FILE_NAME));
108 | }
109 | }
--------------------------------------------------------------------------------
/app/src/eval/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
12 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/eval/java/net/synapticweb/callrecorder/Config.java:
--------------------------------------------------------------------------------
1 | package net.synapticweb.callrecorder;
2 |
3 |
4 | public class Config {
5 | static final public String FILE_PROVIDER = "net.synapticweb.callrecorder.eval.fileprovider";
6 | }
--------------------------------------------------------------------------------
/app/src/eval/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SW Call Recorder (evaluation)
3 |
--------------------------------------------------------------------------------
/app/src/full/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
12 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/full/java/net/synapticweb/callrecorder/Config.java:
--------------------------------------------------------------------------------
1 | package net.synapticweb.callrecorder;
2 |
3 |
4 | public class Config {
5 | static final public String FILE_PROVIDER = "net.synapticweb.callrecorder.full.fileprovider";
6 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
31 |
32 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
43 |
44 |
45 |
47 |
48 |
49 |
51 |
52 |
53 |
55 |
56 |
57 |
58 |
60 |
61 |
62 |
64 |
65 |
68 |
69 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/app/src/main/assets/assign.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/assets/assign.png
--------------------------------------------------------------------------------
/app/src/main/assets/common_style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-size: 0.85em;
3 | line-height: 1.3em;
4 | }
5 |
6 | h1 {
7 | font-size: 1.6em;
8 | line-height: 1.1em;
9 | }
10 |
11 | h2 {
12 | font-size: 1.2em;
13 | line-height: 1.1em;
14 | }
15 |
16 | .small-image {
17 | width: 35px;
18 | height: 35px;
19 | vertical-align: middle;
20 | }
21 |
22 | .x-small-image {
23 | width: 25px;
24 | height: 25px;
25 | vertical-align: middle;
26 | }
27 |
28 | .block-image {
29 | width: 250px;
30 | display: block;
31 | margin-top:10px;
32 | margin-bottom: 10px;
33 | }
34 |
35 | .license-head {
36 | text-decoration: underline;
37 | }
38 |
39 | /*https://www.bestcssbuttongenerator.com/#/23*/
40 | .send_logs {
41 | -moz-box-shadow:inset 0px 1px 0px 0px #ffffff;
42 | -webkit-box-shadow:inset 0px 1px 0px 0px #ffffff;
43 | box-shadow:inset 0px 1px 0px 0px #ffffff;
44 | background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #ffffff), color-stop(1, #f6f6f6));
45 | background:-moz-linear-gradient(top, #ffffff 5%, #f6f6f6 100%);
46 | background:-webkit-linear-gradient(top, #ffffff 5%, #f6f6f6 100%);
47 | background:-o-linear-gradient(top, #ffffff 5%, #f6f6f6 100%);
48 | background:-ms-linear-gradient(top, #ffffff 5%, #f6f6f6 100%);
49 | background:linear-gradient(to bottom, #ffffff 5%, #f6f6f6 100%);
50 | filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f6f6f6',GradientType=0);
51 | background-color:#ffffff;
52 | -moz-border-radius:6px;
53 | -webkit-border-radius:6px;
54 | border-radius:6px;
55 | border:1px solid #dcdcdc;
56 | display:inline-block;
57 | cursor:pointer;
58 | color:#666666;
59 | font-family:Arial;
60 | font-size:15px;
61 | font-weight:bold;
62 | padding:6px 24px;
63 | text-decoration:none;
64 | text-shadow:0px 1px 0px #ffffff;
65 | }
66 | .send_logs:hover {
67 | background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #f6f6f6), color-stop(1, #ffffff));
68 | background:-moz-linear-gradient(top, #f6f6f6 5%, #ffffff 100%);
69 | background:-webkit-linear-gradient(top, #f6f6f6 5%, #ffffff 100%);
70 | background:-o-linear-gradient(top, #f6f6f6 5%, #ffffff 100%);
71 | background:-ms-linear-gradient(top, #f6f6f6 5%, #ffffff 100%);
72 | background:linear-gradient(to bottom, #f6f6f6 5%, #ffffff 100%);
73 | filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f6f6f6', endColorstr='#ffffff',GradientType=0);
74 | background-color:#f6f6f6;
75 | }
76 | .send_logs:active {
77 | position:relative;
78 | top:1px;
79 | }
80 |
--------------------------------------------------------------------------------
/app/src/main/assets/dark_style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: rgba(48,48,48,1.0);
3 | color: white;
4 | }
5 |
6 | a {
7 | color:#ff5030;
8 | }
--------------------------------------------------------------------------------
/app/src/main/assets/deleted_audio.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/assets/deleted_audio.jpg
--------------------------------------------------------------------------------
/app/src/main/assets/dots_menu_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/assets/dots_menu_dark.png
--------------------------------------------------------------------------------
/app/src/main/assets/dots_menu_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/assets/dots_menu_light.png
--------------------------------------------------------------------------------
/app/src/main/assets/incognito.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/assets/incognito.png
--------------------------------------------------------------------------------
/app/src/main/assets/info_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/assets/info_dark.png
--------------------------------------------------------------------------------
/app/src/main/assets/info_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/assets/info_light.png
--------------------------------------------------------------------------------
/app/src/main/assets/ingoing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/assets/ingoing.png
--------------------------------------------------------------------------------
/app/src/main/assets/launcher_icon-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/assets/launcher_icon-web.png
--------------------------------------------------------------------------------
/app/src/main/assets/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/assets/launcher_icon.png
--------------------------------------------------------------------------------
/app/src/main/assets/light_style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #faf9f6;
3 | color: rgba(0,0,0,0.62);
4 | }
5 |
6 | a {
7 | color: #D91916;
8 | }
--------------------------------------------------------------------------------
/app/src/main/assets/move_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/assets/move_dark.png
--------------------------------------------------------------------------------
/app/src/main/assets/move_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/assets/move_light.png
--------------------------------------------------------------------------------
/app/src/main/assets/notification_icon_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/assets/notification_icon_dark.png
--------------------------------------------------------------------------------
/app/src/main/assets/notification_icon_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/assets/notification_icon_light.png
--------------------------------------------------------------------------------
/app/src/main/assets/outgoing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/assets/outgoing.png
--------------------------------------------------------------------------------
/app/src/main/assets/plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/assets/plus.png
--------------------------------------------------------------------------------
/app/src/main/assets/select_all_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/assets/select_all_dark.png
--------------------------------------------------------------------------------
/app/src/main/assets/select_all_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/assets/select_all_light.png
--------------------------------------------------------------------------------
/app/src/main/assets/selected_rec.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/assets/selected_rec.jpg
--------------------------------------------------------------------------------
/app/src/main/assets/stop_rec.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/assets/stop_rec.jpg
--------------------------------------------------------------------------------
/app/src/main/assets/top_bar_selected.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/assets/top_bar_selected.jpg
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/BaseActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Eugen Rădulescu - All rights reserved.
3 | *
4 | * You may use, distribute and modify this code only under the conditions
5 | * stated in the SW Call Recorder license. You should have received a copy of the
6 | * SW Call Recorder license along with this file. If not, please write to .
7 | */
8 |
9 | package net.synapticweb.callrecorder;
10 |
11 | import android.content.SharedPreferences;
12 | import android.preference.PreferenceManager;
13 |
14 | import androidx.appcompat.app.AppCompatActivity;
15 | import androidx.fragment.app.Fragment;
16 | import androidx.fragment.app.FragmentManager;
17 |
18 | import net.synapticweb.callrecorder.settings.SettingsFragment;
19 |
20 |
21 | public abstract class BaseActivity extends AppCompatActivity {
22 | private String settedTheme;
23 | public static final String LIGHT_THEME = "light_theme";
24 | public static final String DARK_THEME = "dark_theme";
25 | abstract protected Fragment createFragment();
26 |
27 | public String getSettedTheme() {
28 | return settedTheme;
29 | }
30 |
31 | public enum LayoutType {
32 | SINGLE_PANE,
33 | DOUBLE_PANE
34 | }
35 |
36 | protected void insertFragment(int fragmentId) {
37 | FragmentManager fm = getSupportFragmentManager();
38 | Fragment fragment = fm.findFragmentById(fragmentId);
39 | if(fragment == null) {
40 | fragment = createFragment();
41 | fm.beginTransaction().
42 | add(fragmentId, fragment).
43 | commit();
44 | }
45 | }
46 |
47 | protected void setTheme() {
48 | final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
49 | if(settings.getString(SettingsFragment.APP_THEME, LIGHT_THEME).equals(LIGHT_THEME)) {
50 | settedTheme = LIGHT_THEME;
51 | setTheme(R.style.AppThemeLight);
52 | }
53 | else {
54 | settedTheme = DARK_THEME;
55 | setTheme(R.style.AppThemeDark);
56 | }
57 | }
58 |
59 | protected void checkIfThemeChanged() {
60 | final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
61 | if(!settings.getString(SettingsFragment.APP_THEME, LIGHT_THEME).equals(settedTheme)) {
62 | setTheme();
63 | recreate();
64 | }
65 | }
66 |
67 | public LayoutType getLayoutType() {
68 | boolean listBoxExists = findViewById(R.id.contacts_list_fragment_container) != null;
69 | boolean detailBoxExists = findViewById(R.id.contact_detail_fragment_container) != null;
70 | if(listBoxExists && detailBoxExists)
71 | return LayoutType.DOUBLE_PANE;
72 | else
73 | return LayoutType.SINGLE_PANE;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/CrApp.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Eugen Rădulescu - All rights reserved.
3 | *
4 | * You may use, distribute and modify this code only under the conditions
5 | * stated in the SW Call Recorder license. You should have received a copy of the
6 | * SW Call Recorder license along with this file. If not, please write to .
7 | */
8 |
9 | package net.synapticweb.callrecorder;
10 |
11 | import android.app.Application;
12 | import android.content.Context;
13 | import net.synapticweb.callrecorder.di.AppComponent;
14 | import net.synapticweb.callrecorder.di.DaggerAppComponent;
15 |
16 | import org.acra.ACRA;
17 | import org.acra.annotation.AcraCore;
18 | import org.acra.annotation.AcraHttpSender;
19 | import org.acra.data.StringFormat;
20 | import org.acra.sender.HttpSender;
21 |
22 | //Oferă context cînd nu este nicio activitate disponibilă. Are nevoie ca să funcționeze de
23 | // android:name=".CrApp" în AndroidManifest.xml
24 | //Servește și ca bibliotecă a aplicației.
25 | @AcraCore(reportFormat = StringFormat.KEY_VALUE_LIST)
26 | @AcraHttpSender(uri = "http://crashes.infopsihologia.ro",
27 | httpMethod = HttpSender.Method.POST )
28 | public class CrApp extends Application {
29 | public AppComponent appComponent;
30 |
31 | @Override
32 | protected void attachBaseContext(Context base) {
33 | super.attachBaseContext(base);
34 | if(!BuildConfig.DEBUG)
35 | ACRA.init(this);
36 | appComponent = DaggerAppComponent.factory().create(base);
37 | }
38 |
39 | private static CrApp instance;
40 |
41 | public CrApp() {
42 | instance = this;
43 | }
44 |
45 | @Override
46 | public void onCreate() {
47 | super.onCreate();
48 | // Shell.Config.setFlags(Shell.FLAG_REDIRECT_STDERR);
49 | // Shell.Config.verboseLogging(BuildConfig.DEBUG);
50 | }
51 |
52 | public static CrApp getInstance() {
53 | return instance;
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/contactdetail/ContactDetailActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Eugen Rădulescu - All rights reserved.
3 | *
4 | * You may use, distribute and modify this code only under the conditions
5 | * stated in the SW Call Recorder license. You should have received a copy of the
6 | * SW Call Recorder license along with this file. If not, please write to .
7 | */
8 |
9 | package net.synapticweb.callrecorder.contactdetail;
10 |
11 | import android.content.Intent;
12 | import android.os.Bundle;
13 | import android.widget.TextView;
14 |
15 |
16 | import net.synapticweb.callrecorder.R;
17 | import net.synapticweb.callrecorder.BaseActivity;
18 | import net.synapticweb.callrecorder.contactslist.ContactsListFragment;
19 | import net.synapticweb.callrecorder.data.Contact;
20 |
21 | import androidx.appcompat.app.ActionBar;
22 | import androidx.appcompat.widget.Toolbar;
23 | import androidx.fragment.app.Fragment;
24 |
25 | public class ContactDetailActivity extends BaseActivity {
26 | Contact contact;
27 |
28 | @Override
29 | protected Fragment createFragment() {
30 | return ContactDetailFragment.newInstance(contact);
31 | }
32 |
33 | @Override
34 | protected void onResume() {
35 | super.onResume();
36 | checkIfThemeChanged();
37 | }
38 |
39 | @Override
40 | protected void onCreate(Bundle savedInstanceState) {
41 | super.onCreate(savedInstanceState);
42 | setTheme();
43 | setContentView(R.layout.contact_detail_activity);
44 | Intent intent = getIntent();
45 | contact = intent.getParcelableExtra(ContactsListFragment.ARG_CONTACT);
46 |
47 | insertFragment(R.id.contact_detail_fragment_container);
48 |
49 | Toolbar toolbar = findViewById(R.id.toolbar_detail);
50 |
51 | TextView title = findViewById(R.id.actionbar_title);
52 | title.setText(contact.getContactName());
53 | setSupportActionBar(toolbar);
54 | ActionBar actionBar = getSupportActionBar();
55 | if(actionBar != null) {
56 | actionBar.setDisplayHomeAsUpEnabled(false);
57 | actionBar.setDisplayShowTitleEnabled(false);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/contactdetail/ContactDetailContract.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Eugen Rădulescu - All rights reserved.
3 | *
4 | * You may use, distribute and modify this code only under the conditions
5 | * stated in the SW Call Recorder license. You should have received a copy of the
6 | * SW Call Recorder license along with this file. If not, please write to .
7 | */
8 |
9 | package net.synapticweb.callrecorder.contactdetail;
10 |
11 | import android.app.Activity;
12 | import android.content.Context;
13 | import android.net.Uri;
14 | import net.synapticweb.callrecorder.Util.DialogInfo;
15 | import net.synapticweb.callrecorder.data.Contact;
16 | import net.synapticweb.callrecorder.data.Recording;
17 | import java.util.List;
18 |
19 | public interface ContactDetailContract {
20 | interface View {
21 | void setContact(Contact contact);
22 | void paintViews(List recordings);
23 | boolean isInvalid();
24 | void setInvalid(boolean invalid);
25 | void removeRecording(Recording recording);
26 | Context getContext();
27 | }
28 |
29 | interface Presenter {
30 | void loadRecordings(Contact contact);
31 | DialogInfo deleteContact(Contact contact);
32 | DialogInfo deleteRecordings(List recordings);
33 | DialogInfo renameRecording(CharSequence input, Recording recording);
34 | DialogInfo assignToContact(Context context, Uri numberUri, List recordings, Contact contact);
35 | DialogInfo assignToPrivate(Context context, List recordings, Contact contact);
36 | void moveSelectedRecordings(String path, int totalsize, Activity parentActivity, Recording[] recordings);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/contactdetail/di/ContactDetailComponent.java:
--------------------------------------------------------------------------------
1 | package net.synapticweb.callrecorder.contactdetail.di;
2 |
3 | import net.synapticweb.callrecorder.contactdetail.ContactDetailFragment;
4 | import net.synapticweb.callrecorder.di.FragmentScope;
5 |
6 | import dagger.Subcomponent;
7 |
8 | @Subcomponent(modules = {ViewModule.class, PresenterModule.class})
9 | @FragmentScope
10 | public interface ContactDetailComponent {
11 | @Subcomponent.Factory
12 | interface Factory {
13 | ContactDetailComponent create(ViewModule module);
14 | }
15 |
16 | void inject(ContactDetailFragment fragment);
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/contactdetail/di/PresenterModule.java:
--------------------------------------------------------------------------------
1 | package net.synapticweb.callrecorder.contactdetail.di;
2 |
3 | import net.synapticweb.callrecorder.contactdetail.ContactDetailContract.Presenter;
4 | import net.synapticweb.callrecorder.contactdetail.ContactDetailPresenter;
5 |
6 | import dagger.Binds;
7 | import dagger.Module;
8 |
9 | @Module
10 | public abstract class PresenterModule {
11 | @Binds
12 | abstract Presenter providePresenter(ContactDetailPresenter presenter);
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/contactdetail/di/ViewModule.java:
--------------------------------------------------------------------------------
1 | package net.synapticweb.callrecorder.contactdetail.di;
2 |
3 | import net.synapticweb.callrecorder.contactdetail.ContactDetailContract;
4 | import net.synapticweb.callrecorder.contactdetail.ContactDetailFragment;
5 |
6 | import dagger.Module;
7 | import dagger.Provides;
8 |
9 | @Module
10 | public class ViewModule {
11 | private ContactDetailFragment fragment;
12 | public ViewModule(ContactDetailFragment fragment) {
13 | this.fragment = fragment;
14 | }
15 |
16 | @Provides
17 | public ContactDetailContract.View provideView() {
18 | return fragment;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/contactslist/ContactsListContract.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Eugen Rădulescu - All rights reserved.
3 | *
4 | * You may use, distribute and modify this code only under the conditions
5 | * stated in the SW Call Recorder license. You should have received a copy of the
6 | * SW Call Recorder license along with this file. If not, please write to .
7 | */
8 |
9 | package net.synapticweb.callrecorder.contactslist;
10 | import net.synapticweb.callrecorder.data.Contact;
11 | import java.util.List;
12 |
13 |
14 | public interface ContactsListContract {
15 | interface View {
16 | void showContacts(List contactList);
17 | void resetCurrentPosition();
18 | }
19 |
20 | interface Presenter {
21 | void loadContacts();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/contactslist/ContactsListPresenter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Eugen Rădulescu - All rights reserved.
3 | *
4 | * You may use, distribute and modify this code only under the conditions
5 | * stated in the SW Call Recorder license. You should have received a copy of the
6 | * SW Call Recorder license along with this file. If not, please write to .
7 | */
8 |
9 | package net.synapticweb.callrecorder.contactslist;
10 |
11 | import net.synapticweb.callrecorder.data.Repository;
12 | import net.synapticweb.callrecorder.di.FragmentScope;
13 |
14 | import androidx.annotation.NonNull;
15 | import javax.inject.Inject;
16 |
17 | @FragmentScope
18 | public class ContactsListPresenter implements ContactsListContract.Presenter {
19 | @NonNull private ContactsListContract.View view;
20 | private Repository repository;
21 |
22 | @Inject
23 | ContactsListPresenter(@NonNull ContactsListContract.View view, Repository repository) {
24 | this.view = view;
25 | this.repository = repository;
26 | }
27 |
28 | @Override
29 | public void loadContacts() {
30 | repository.getAllContacts(contacts -> view.showContacts(contacts));
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/contactslist/di/ContactsListComponent.java:
--------------------------------------------------------------------------------
1 | package net.synapticweb.callrecorder.contactslist.di;
2 |
3 | import net.synapticweb.callrecorder.contactslist.ContactsListFragment;
4 | import net.synapticweb.callrecorder.di.FragmentScope;
5 | import dagger.Subcomponent;
6 |
7 | @Subcomponent(modules = {ViewModule.class, PresenterModule.class})
8 | @FragmentScope
9 | public interface ContactsListComponent {
10 |
11 | @Subcomponent.Factory
12 | interface Factory {
13 | ContactsListComponent create(ViewModule module);
14 | }
15 |
16 | void inject(ContactsListFragment fragment);
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/contactslist/di/PresenterModule.java:
--------------------------------------------------------------------------------
1 | package net.synapticweb.callrecorder.contactslist.di;
2 |
3 | import dagger.Binds;
4 | import dagger.Module;
5 | import net.synapticweb.callrecorder.contactslist.ContactsListContract.Presenter;
6 | import net.synapticweb.callrecorder.contactslist.ContactsListPresenter;
7 |
8 | @Module
9 | public abstract class PresenterModule {
10 | @Binds
11 | public abstract Presenter providePresenter(ContactsListPresenter presenter);
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/contactslist/di/ViewModule.java:
--------------------------------------------------------------------------------
1 | package net.synapticweb.callrecorder.contactslist.di;
2 |
3 | import net.synapticweb.callrecorder.contactslist.ContactsListContract;
4 | import net.synapticweb.callrecorder.contactslist.ContactsListFragment;
5 |
6 | import dagger.Module;
7 | import dagger.Provides;
8 |
9 | @Module
10 | public class ViewModule {
11 | private ContactsListFragment fragment;
12 | public ViewModule(ContactsListFragment fragment) {
13 | this.fragment = fragment;
14 | }
15 |
16 | @Provides
17 | public ContactsListContract.View provideView() {
18 | return fragment;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/data/CallRecorderDbHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Eugen Rădulescu - All rights reserved.
3 | *
4 | * You may use, distribute and modify this code only under the conditions
5 | * stated in the SW Call Recorder license. You should have received a copy of the
6 | * SW Call Recorder license along with this file. If not, please write to .
7 | */
8 |
9 | package net.synapticweb.callrecorder.data;
10 |
11 | import android.content.Context;
12 | import android.database.sqlite.SQLiteDatabase;
13 | import android.database.sqlite.SQLiteOpenHelper;
14 | import net.synapticweb.callrecorder.data.RecordingsContract.*;
15 | import net.synapticweb.callrecorder.data.ContactsContract.*;
16 |
17 |
18 | public class CallRecorderDbHelper extends SQLiteOpenHelper {
19 | public static final String SQL_CREATE_RECORDINGS = "CREATE TABLE " +
20 | Recordings.TABLE_NAME + " (" + Recordings._ID + " INTEGER NOT NULL PRIMARY KEY, " +
21 | Recordings.COLUMN_NAME_CONTACT_ID + " INTEGER , " +
22 | Recordings.COLUMN_NAME_INCOMING + " INTEGER , " +
23 | Recordings.COLUMN_NAME_PATH + " TEXT , " +
24 | Recordings.COLUMN_NAME_START_TIMESTAMP + " INTEGER , " +
25 | Recordings.COLUMN_NAME_END_TIMESTAMP + " INTEGER , " +
26 | Recordings.COLUMN_NAME_FORMAT + " TEXT , " +
27 | Recordings.COLUMN_NAME_IS_NAME_SET + " INTEGER DEFAULT 0, " +
28 | Recordings.COLUMN_NAME_MODE + " TEXT , " +
29 | Recordings.COLUMN_NAME_SOURCE + " TEXT DEFAULT 'unknown')";
30 |
31 | public static final String SQL_CREATE_CONTACTS = "CREATE TABLE " + Contacts.TABLE_NAME +
32 | " (" + Contacts._ID + " INTEGER NOT NULL PRIMARY KEY, " +
33 | Contacts.COLUMN_NAME_NUMBER + " TEXT, " +
34 | Contacts.COLUMN_NAME_CONTACT_NAME + " TEXT, " +
35 | Contacts.COLUMN_NAME_PHOTO_URI + " TEXT, " +
36 | Contacts.COLUMN_NAME_PHONE_TYPE + " INTEGER NOT NULL, " +
37 | "CONSTRAINT no_duplicates UNIQUE(" + Contacts.COLUMN_NAME_NUMBER + ") )";
38 |
39 |
40 | private static final int DATABASE_VERSION = 3;
41 |
42 | CallRecorderDbHelper(Context context, String dbName) {
43 | super(context, dbName, null, DATABASE_VERSION);
44 | }
45 |
46 | @Override
47 | public void onCreate(SQLiteDatabase db) {
48 | db.execSQL(SQL_CREATE_RECORDINGS);
49 | db.execSQL(SQL_CREATE_CONTACTS);
50 | }
51 |
52 | @Override
53 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
54 | String version2 = "ALTER TABLE " + Recordings.TABLE_NAME + " ADD COLUMN " + Recordings.COLUMN_NAME_SOURCE +
55 | " TEXT NOT NULL DEFAULT 'unknown'";
56 | String version3a = "ALTER TABLE " + Contacts.TABLE_NAME + " RENAME TO " + Contacts.TABLE_NAME + "_old";
57 | String version3b = "INSERT INTO " + Contacts.TABLE_NAME + "(_id, phone_number, contact_name, photo_uri, phone_type) SELECT _id, phone_number, contact_name, photo_uri, phone_type FROM "
58 | + Contacts.TABLE_NAME + "_old";
59 | String version3c = "DROP TABLE " + Contacts.TABLE_NAME + "_old";
60 | if(oldVersion == 1) {
61 | db.execSQL(version2);
62 | db.execSQL(version3a);
63 | db.execSQL(SQL_CREATE_CONTACTS);
64 | db.execSQL(version3b);
65 | db.execSQL(version3c);
66 | }
67 | if(oldVersion == 2) {
68 | db.execSQL(version3a);
69 | db.execSQL(SQL_CREATE_CONTACTS);
70 | db.execSQL(version3b);
71 | db.execSQL(version3c);
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/data/ContactsContract.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Eugen Rădulescu - All rights reserved.
3 | *
4 | * You may use, distribute and modify this code only under the conditions
5 | * stated in the SW Call Recorder license. You should have received a copy of the
6 | * SW Call Recorder license along with this file. If not, please write to .
7 | */
8 |
9 | package net.synapticweb.callrecorder.data;
10 |
11 | import android.provider.BaseColumns;
12 |
13 | public class ContactsContract {
14 | private ContactsContract(){}
15 |
16 | public static class Contacts implements BaseColumns {
17 | public static final String TABLE_NAME = "contacts";
18 |
19 | public static final String COLUMN_NAME_NUMBER = "phone_number";
20 | public static final String COLUMN_NAME_CONTACT_NAME = "contact_name";
21 | public static final String COLUMN_NAME_PHOTO_URI = "photo_uri";
22 | public static final String COLUMN_NAME_PHONE_TYPE = "phone_type";
23 | public static final String COLUMN_NAME_SHOULD_RECORD = "should_record";
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/data/RecordingsContract.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Eugen Rădulescu - All rights reserved.
3 | *
4 | * You may use, distribute and modify this code only under the conditions
5 | * stated in the SW Call Recorder license. You should have received a copy of the
6 | * SW Call Recorder license along with this file. If not, please write to .
7 | */
8 |
9 | package net.synapticweb.callrecorder.data;
10 |
11 | import android.provider.BaseColumns;
12 |
13 | class RecordingsContract {
14 | private RecordingsContract(){}
15 |
16 | public static class Recordings implements BaseColumns {
17 | public static final String TABLE_NAME = "recordings";
18 | public static final String COLUMN_NAME_CONTACT_ID = "contact_id";
19 | public static final String COLUMN_NAME_INCOMING = "incoming";
20 | public static final String COLUMN_NAME_PATH = "path";
21 | public static final String COLUMN_NAME_START_TIMESTAMP = "start_timestamp";
22 | public static final String COLUMN_NAME_END_TIMESTAMP = "end_timestamp";
23 | public static final String COLUMN_NAME_IS_NAME_SET = "is_name_set";
24 | public static final String COLUMN_NAME_FORMAT = "format";
25 | public static final String COLUMN_NAME_MODE = "mode";
26 | static final String COLUMN_NAME_SOURCE = "source";
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/data/Repository.java:
--------------------------------------------------------------------------------
1 | package net.synapticweb.callrecorder.data;
2 |
3 |
4 | import java.util.List;
5 |
6 | public interface Repository {
7 | //Contacts:
8 | interface LoadContactsCallback {
9 | void onContactsLoaded(List contacts);
10 | }
11 |
12 | List getAllContacts();
13 |
14 | void getAllContacts(LoadContactsCallback callback);
15 |
16 | Long getHiddenNumberContactId();
17 |
18 | void insertContact(Contact contact);
19 |
20 | void updateContact(Contact contact);
21 |
22 | void deleteContact(Contact contact);
23 |
24 | //Recordings:
25 | interface LoadRecordingsCallback {
26 | void onRecordingsLoaded(List recordings);
27 | }
28 |
29 | void getRecordings(Contact contact, LoadRecordingsCallback callback);
30 |
31 | List getRecordings(Contact contact);
32 |
33 | void insertRecording(Recording recording);
34 |
35 | void updateRecording(Recording recording);
36 |
37 | void deleteRecording(Recording recording);
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/di/AppComponent.java:
--------------------------------------------------------------------------------
1 | package net.synapticweb.callrecorder.di;
2 |
3 | import android.content.Context;
4 |
5 | import net.synapticweb.callrecorder.contactdetail.EditContactActivity;
6 | import net.synapticweb.callrecorder.contactdetail.di.ContactDetailComponent;
7 | import net.synapticweb.callrecorder.contactslist.di.ContactsListComponent;
8 | import net.synapticweb.callrecorder.recorder.RecorderService;
9 |
10 | import javax.inject.Singleton;
11 | import dagger.BindsInstance;
12 | import dagger.Component;
13 |
14 | @Singleton
15 | @Component(modules = { RepositoryModule.class, AppSubcomponents.class })
16 | public interface AppComponent {
17 | @Component.Factory
18 | interface Factory {
19 | AppComponent create(@BindsInstance Context context);
20 | }
21 |
22 | void inject(EditContactActivity activity);
23 | void inject(RecorderService service);
24 | ContactsListComponent.Factory contactsListComponent();
25 | ContactDetailComponent.Factory contactDetailComponent();
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/di/AppSubcomponents.java:
--------------------------------------------------------------------------------
1 | package net.synapticweb.callrecorder.di;
2 |
3 | import net.synapticweb.callrecorder.contactdetail.di.ContactDetailComponent;
4 | import net.synapticweb.callrecorder.contactslist.di.ContactsListComponent;
5 |
6 | import dagger.Module;
7 |
8 | @Module(subcomponents = {ContactsListComponent.class, ContactDetailComponent.class})
9 | class AppSubcomponents {
10 | }
11 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/di/FragmentScope.java:
--------------------------------------------------------------------------------
1 | package net.synapticweb.callrecorder.di;
2 |
3 | import java.lang.annotation.Retention;
4 | import java.lang.annotation.RetentionPolicy;
5 |
6 | import javax.inject.Scope;
7 |
8 | @Scope
9 | @Retention(RetentionPolicy.RUNTIME)
10 | public @interface FragmentScope {
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/di/RepositoryModule.java:
--------------------------------------------------------------------------------
1 | package net.synapticweb.callrecorder.di;
2 |
3 | import android.content.Context;
4 |
5 | import net.synapticweb.callrecorder.data.Repository;
6 | import net.synapticweb.callrecorder.data.RepositoryImpl;
7 |
8 | import javax.inject.Singleton;
9 |
10 | import dagger.Module;
11 | import dagger.Provides;
12 |
13 | @Module
14 | class RepositoryModule {
15 | private static final String DATABASE_NAME = "callrecorder.db";
16 |
17 | @Provides
18 | @Singleton
19 | Repository provideRepository(Context context) {
20 | return new RepositoryImpl(context, DATABASE_NAME);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/player/PlaybackListenerInterface.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Eugen Rădulescu - All rights reserved.
3 | *
4 | * You may use, distribute and modify this code only under the conditions
5 | * stated in the SW Call Recorder license. You should have received a copy of the
6 | * SW Call Recorder license along with this file. If not, please write to .
7 | */
8 |
9 | package net.synapticweb.callrecorder.player;
10 |
11 | public interface PlaybackListenerInterface {
12 |
13 | void onDurationChanged(int duration);
14 |
15 | void onPositionChanged(int position);
16 |
17 | void onPlaybackCompleted();
18 |
19 | void onError();
20 |
21 | void onReset();
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/player/PlayerAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Eugen Rădulescu - All rights reserved.
3 | *
4 | * You may use, distribute and modify this code only under the conditions
5 | * stated in the SW Call Recorder license. You should have received a copy of the
6 | * SW Call Recorder license along with this file. If not, please write to .
7 | */
8 |
9 | package net.synapticweb.callrecorder.player;
10 |
11 | import androidx.annotation.IntDef;
12 | import java.lang.annotation.Retention;
13 | import java.lang.annotation.RetentionPolicy;
14 |
15 | interface PlayerAdapter {
16 |
17 | @IntDef({State.UNINITIALIZED, State.INITIALIZED, State.PLAYING, State.PAUSED })
18 | @Retention(RetentionPolicy.SOURCE)
19 | @interface State {
20 | int UNINITIALIZED = 0;
21 | int INITIALIZED = 1;
22 | int PLAYING = 2;
23 | int PAUSED = 3;
24 | int STOPPED = 4;
25 | }
26 |
27 | void setGain(float gain);
28 |
29 | boolean setMediaPosition(int position);
30 |
31 | boolean loadMedia(String mediaPath);
32 |
33 | void stopPlayer();
34 |
35 | void play();
36 |
37 | void reset();
38 |
39 | void pause();
40 |
41 | int getPlayerState();
42 |
43 | void setPlayerState(int state);
44 |
45 | boolean seekTo(int position);
46 |
47 | int getCurrentPosition();
48 |
49 | int getTotalDuration();
50 | }
51 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/player/PlayerException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Eugen Rădulescu - All rights reserved.
3 | *
4 | * You may use, distribute and modify this code only under the conditions
5 | * stated in the SW Call Recorder license. You should have received a copy of the
6 | * SW Call Recorder license along with this file. If not, please write to .
7 | */
8 |
9 | package net.synapticweb.callrecorder.player;
10 |
11 | class PlayerException extends Exception {
12 | PlayerException(String message) {
13 | super(message);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/recorder/ControlRecordingReceiver.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Eugen Rădulescu - All rights reserved.
3 | *
4 | * You may use, distribute and modify this code only under the conditions
5 | * stated in the SW Call Recorder license. You should have received a copy of the
6 | * SW Call Recorder license along with this file. If not, please write to .
7 | */
8 |
9 | package net.synapticweb.callrecorder.recorder;
10 |
11 | import android.app.NotificationManager;
12 | import android.content.BroadcastReceiver;
13 | import android.content.Context;
14 | import android.content.Intent;
15 |
16 |
17 | public class ControlRecordingReceiver extends BroadcastReceiver {
18 | @Override
19 | public void onReceive(Context context, Intent intent) {
20 | NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
21 | RecorderService service = RecorderService.getService();
22 |
23 | if(intent.getAction().equals(RecorderService.ACTION_STOP_SPEAKER)) {
24 | service.putSpeakerOff();
25 | if(nm != null)
26 | nm.notify(RecorderService.NOTIFICATION_ID, service.buildNotification(RecorderService.RECORD_AUTOMMATICALLY, 0));
27 | }
28 |
29 | else if(intent.getAction().equals(RecorderService.ACTION_START_SPEAKER)) {
30 | service.putSpeakerOn();
31 | if(nm != null)
32 | nm.notify(RecorderService.NOTIFICATION_ID, service.buildNotification(RecorderService.RECORD_AUTOMMATICALLY, 0));
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/recorder/RecordingException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Eugen Rădulescu - All rights reserved.
3 | *
4 | * You may use, distribute and modify this code only under the conditions
5 | * stated in the SW Call Recorder license. You should have received a copy of the
6 | * SW Call Recorder license along with this file. If not, please write to .
7 | */
8 |
9 | package net.synapticweb.callrecorder.recorder;
10 |
11 | class RecordingException extends Exception {
12 | RecordingException(String message) {
13 | super(message);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/recorder/RecordingThread.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Eugen Rădulescu - All rights reserved.
3 | *
4 | * You may use, distribute and modify this code only under the conditions
5 | * stated in the SW Call Recorder license. You should have received a copy of the
6 | * SW Call Recorder license along with this file. If not, please write to .
7 | */
8 |
9 | package net.synapticweb.callrecorder.recorder;
10 |
11 | import android.app.NotificationManager;
12 | import android.content.Context;
13 | import android.content.Intent;
14 | import android.content.SharedPreferences;
15 | import android.media.AudioFormat;
16 | import android.media.AudioRecord;
17 | import android.preference.PreferenceManager;
18 | import net.synapticweb.callrecorder.CrLog;
19 | import net.synapticweb.callrecorder.R;
20 | import net.synapticweb.callrecorder.settings.SettingsFragment;
21 |
22 |
23 | import static android.media.MediaRecorder.AudioSource.VOICE_RECOGNITION;
24 |
25 | abstract class RecordingThread {
26 | static final int SAMPLE_RATE = 44100;
27 | final int channels;
28 | final int bufferSize;
29 | final AudioRecord audioRecord;
30 | protected final Recorder recorder;
31 | protected Context context;
32 |
33 | RecordingThread(Context context, String mode, Recorder recorder) throws RecordingException {
34 | this.context = context;
35 | channels = (mode.equals(Recorder.MONO) ? 1 : 2);
36 | this.recorder = recorder;
37 | bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, channels == 1 ? AudioFormat.CHANNEL_IN_MONO : AudioFormat.CHANNEL_IN_STEREO,
38 | AudioFormat.ENCODING_PCM_16BIT);
39 | audioRecord = createAudioRecord();
40 | audioRecord.startRecording();
41 | }
42 |
43 | private AudioRecord createAudioRecord() throws RecordingException {
44 | AudioRecord audioRecord;
45 | SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
46 | int source = Integer.valueOf(settings.getString(SettingsFragment.SOURCE,
47 | String.valueOf(VOICE_RECOGNITION)));
48 | try {
49 | audioRecord = new AudioRecord(source, SAMPLE_RATE,
50 | channels == 1 ? AudioFormat.CHANNEL_IN_MONO : AudioFormat.CHANNEL_IN_STEREO,
51 | AudioFormat.ENCODING_PCM_16BIT, bufferSize * 10);
52 | } catch (Exception e) { //La VOICE_CALL dă IllegalArgumentException. Aplicația nu se oprește, rămîne
53 | //hanging, nu înregistrează nimic.
54 | throw new RecordingException(e.getMessage());
55 | }
56 |
57 | if(audioRecord.getState() == AudioRecord.STATE_INITIALIZED) {
58 | CrLog.log(CrLog.DEBUG, "createAudioRecord(): Audio source chosen: " + source);
59 | recorder.setSource(audioRecord.getAudioSource());
60 | }
61 |
62 | if(audioRecord.getState() != AudioRecord.STATE_INITIALIZED)
63 | throw new RecordingException("Unable to initialize AudioRecord");
64 |
65 | return audioRecord;
66 | }
67 |
68 | void disposeAudioRecord() {
69 | audioRecord.stop();
70 | audioRecord.release();
71 | }
72 |
73 | //e statică ca să poată fi apelată din CopyPcmToWav
74 | static void notifyOnError(Context context) {
75 | RecorderService service = RecorderService.getService();
76 | if (service != null) {
77 | NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
78 | if (nm != null)
79 | nm.notify(RecorderService.NOTIFICATION_ID,
80 | service.buildNotification(RecorderService.RECORD_ERROR,
81 | R.string.error_recorder_failed));
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/settings/SettingsActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Eugen Rădulescu - All rights reserved.
3 | *
4 | * You may use, distribute and modify this code only under the conditions
5 | * stated in the SW Call Recorder license. You should have received a copy of the
6 | * SW Call Recorder license along with this file. If not, please write to .
7 | */
8 |
9 | package net.synapticweb.callrecorder.settings;
10 |
11 | import android.os.Bundle;
12 |
13 |
14 | import net.synapticweb.callrecorder.R;
15 | import net.synapticweb.callrecorder.BaseActivity;
16 |
17 | import androidx.appcompat.app.ActionBar;
18 | import androidx.appcompat.widget.Toolbar;
19 | import androidx.preference.PreferenceFragmentCompat;
20 |
21 | public class SettingsActivity extends BaseActivity {
22 | @Override
23 | protected PreferenceFragmentCompat createFragment() {
24 | return null;
25 | }
26 |
27 | @Override
28 | protected void onCreate(Bundle savedInstanceState) {
29 | super.onCreate(savedInstanceState);
30 | setTheme();
31 | setContentView(R.layout.settings_layout);
32 | Toolbar toolbar = findViewById(R.id.toolbar_settings);
33 | setSupportActionBar(toolbar);
34 | ActionBar actionBar = getSupportActionBar();
35 | if(actionBar != null)
36 | actionBar.setDisplayHomeAsUpEnabled(true);
37 |
38 | getSupportFragmentManager().beginTransaction()
39 | .replace(R.id.settings_container, new SettingsFragment())
40 | .commit();
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/setup/SetupActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Eugen Rădulescu - All rights reserved.
3 | *
4 | * You may use, distribute and modify this code only under the conditions
5 | * stated in the SW Call Recorder license. You should have received a copy of the
6 | * SW Call Recorder license along with this file. If not, please write to .
7 | */
8 |
9 | package net.synapticweb.callrecorder.setup;
10 |
11 | import android.content.Intent;
12 | import android.os.Bundle;
13 |
14 | import androidx.annotation.NonNull;
15 | import androidx.annotation.Nullable;
16 | import androidx.fragment.app.Fragment;
17 | import net.synapticweb.callrecorder.R;
18 | import net.synapticweb.callrecorder.BaseActivity;
19 | import net.synapticweb.callrecorder.contactslist.ContactsListActivityMain;
20 |
21 | public class SetupActivity extends BaseActivity {
22 | private int checkResult;
23 | public static final String EXIT_APP = "exit_app";
24 |
25 | @Override
26 | protected Fragment createFragment() {
27 | if((checkResult & ContactsListActivityMain.EULA_NOT_ACCEPTED) != 0)
28 | return new SetupEulaFragment();
29 | else if((checkResult & ContactsListActivityMain.PERMS_NOT_GRANTED) != 0)
30 | return new SetupPermissionsFragment();
31 | else if((checkResult & ContactsListActivityMain.POWER_OPTIMIZED) != 0)
32 | return new SetupPowerFragment();
33 | else
34 | return null;
35 | }
36 |
37 | @Override
38 | protected void onCreate(@Nullable Bundle savedInstanceState) {
39 | setTheme();
40 | super.onCreate(savedInstanceState);
41 | setContentView(R.layout.setup_activity);
42 | checkResult = getIntent().getIntExtra(ContactsListActivityMain.SETUP_ARGUMENT,
43 | ContactsListActivityMain.EULA_NOT_ACCEPTED & ContactsListActivityMain.PERMS_NOT_GRANTED &
44 | ContactsListActivityMain.POWER_OPTIMIZED);
45 | insertFragment(R.id.setup_fragment_container);
46 | }
47 |
48 | public int getCheckResult() {
49 | return checkResult;
50 | }
51 |
52 | public void cancelSetup() {
53 | Intent intent = new Intent();
54 | intent.putExtra(SetupActivity.EXIT_APP, true);
55 | setResult(RESULT_OK, intent);
56 | finish();
57 | }
58 |
59 | @Override
60 | public void onBackPressed() {
61 | cancelSetup();
62 | }
63 |
64 | @Override
65 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
66 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/setup/SetupEulaFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Eugen Rădulescu - All rights reserved.
3 | *
4 | * You may use, distribute and modify this code only under the conditions
5 | * stated in the SW Call Recorder license. You should have received a copy of the
6 | * SW Call Recorder license along with this file. If not, please write to .
7 | */
8 |
9 | package net.synapticweb.callrecorder.setup;
10 |
11 | import android.content.Intent;
12 | import android.content.SharedPreferences;
13 | import android.os.Bundle;
14 | import android.view.LayoutInflater;
15 | import android.view.View;
16 | import android.view.ViewGroup;
17 | import android.widget.Button;
18 | import android.widget.CheckBox;
19 | import android.widget.TextView;
20 |
21 | import androidx.annotation.NonNull;
22 | import androidx.annotation.Nullable;
23 | import androidx.fragment.app.Fragment;
24 | import androidx.preference.PreferenceManager;
25 |
26 | import net.synapticweb.callrecorder.BuildConfig;
27 | import net.synapticweb.callrecorder.R;
28 | import net.synapticweb.callrecorder.contactslist.ContactsListActivityMain;
29 |
30 | public class SetupEulaFragment extends Fragment {
31 | @Nullable
32 | @Override
33 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
34 | return inflater.inflate(R.layout.setup_eula_fragment, container, false);
35 |
36 | }
37 |
38 | @Override
39 | public void onActivityCreated(@Nullable Bundle savedInstanceState) {
40 | super.onActivityCreated(savedInstanceState);
41 | final SetupActivity parentActivity = (SetupActivity) getActivity();
42 | final int checkResult = parentActivity.getCheckResult();
43 |
44 | TextView version = parentActivity.findViewById(R.id.app_version);
45 | version.setText(String.format(parentActivity.getResources().getString(R.string.version_eula_screen),
46 | BuildConfig.VERSION_NAME) );
47 |
48 | Button showEula = parentActivity.findViewById(R.id.show_eula);
49 | showEula.setOnClickListener(new View.OnClickListener() {
50 | @Override
51 | public void onClick(View view) {
52 | startActivity(new Intent(getActivity(), ShowEulaActivity.class));
53 | }
54 | });
55 |
56 | Button cancelButton = parentActivity.findViewById(R.id.setup_confirm_cancel);
57 | cancelButton.setOnClickListener(new View.OnClickListener() {
58 | @Override
59 | public void onClick(View view) {
60 | parentActivity.cancelSetup();
61 | }
62 | });
63 |
64 | Button nextButton = parentActivity.findViewById(R.id.setup_confirm_next);
65 | nextButton.setOnClickListener(new View.OnClickListener() {
66 | @Override
67 | public void onClick(View view) {
68 | CheckBox hasAccepted = parentActivity.findViewById(R.id.has_accepted);
69 | if(!hasAccepted.isChecked())
70 | return ;
71 |
72 | SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(parentActivity);
73 | SharedPreferences.Editor editor = settings.edit();
74 | editor.putBoolean(ContactsListActivityMain.HAS_ACCEPTED_EULA, true);
75 | editor.apply();
76 |
77 | if((checkResult & ContactsListActivityMain.PERMS_NOT_GRANTED) != 0) {
78 | SetupPermissionsFragment permissionsFragment = new SetupPermissionsFragment();
79 | parentActivity.getSupportFragmentManager().beginTransaction()
80 | .replace(R.id.setup_fragment_container, permissionsFragment)
81 | .commitAllowingStateLoss();
82 |
83 | } //dacă suntem în această metodă înseamnă că ne aflăm la prima rulare. Deci, trebuie să
84 | // se afișeze cel puțin avertismentul "protected apps" sau și controllerul doze, dacă nu avem
85 | //treabă cu permisiunile.
86 | else {
87 | SetupPowerFragment powerFragment = new SetupPowerFragment();
88 | parentActivity.getSupportFragmentManager().beginTransaction()
89 | .replace(R.id.setup_fragment_container, powerFragment)
90 | .commitAllowingStateLoss();
91 | }
92 | }
93 | });
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/app/src/main/java/net/synapticweb/callrecorder/setup/ShowEulaActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Eugen Rădulescu - All rights reserved.
3 | *
4 | * You may use, distribute and modify this code only under the conditions
5 | * stated in the SW Call Recorder license. You should have received a copy of the
6 | * SW Call Recorder license along with this file. If not, please write to .
7 | */
8 |
9 | package net.synapticweb.callrecorder.setup;
10 |
11 | import android.os.Bundle;
12 | import android.view.MenuItem;
13 | import android.webkit.WebView;
14 |
15 | import androidx.annotation.NonNull;
16 | import androidx.annotation.Nullable;
17 | import androidx.appcompat.app.ActionBar;
18 | import androidx.appcompat.widget.Toolbar;
19 | import androidx.fragment.app.Fragment;
20 |
21 | import net.synapticweb.callrecorder.HelpActivity;
22 | import net.synapticweb.callrecorder.R;
23 | import net.synapticweb.callrecorder.BaseActivity;
24 | import net.synapticweb.callrecorder.Util;
25 |
26 | public class ShowEulaActivity extends BaseActivity {
27 | @Override
28 | protected Fragment createFragment() {
29 | return null;
30 | }
31 |
32 | @Override
33 | protected void onCreate(@Nullable Bundle savedInstanceState) {
34 | super.onCreate(savedInstanceState);
35 | setContentView(R.layout.setup_show_eula_activity);
36 |
37 | Toolbar toolbar = findViewById(R.id.toolbar_show_eula);
38 | setSupportActionBar(toolbar);
39 | ActionBar actionBar = getSupportActionBar();
40 | if(actionBar != null)
41 | actionBar.setDisplayHomeAsUpEnabled(true);
42 | String html = Util.rawHtmlToString(R.raw.eula);
43 | html = html.replace(HelpActivity.APP_NAME_PLACEHOLDER, getResources().getString(R.string.app_name));
44 |
45 | WebView eulaHtml = findViewById(R.id.eula_hmtl);
46 | eulaHtml.loadDataWithBaseURL("file:///android_asset/",
47 | html, "text/html", null, null);
48 | }
49 |
50 | @Override
51 | public boolean onOptionsItemSelected(@NonNull MenuItem item) {
52 | if(item.getItemId() == android.R.id.home)
53 | finish();
54 | return true;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/app/src/main/launcher_icon-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/launcher_icon-web.png
--------------------------------------------------------------------------------
/app/src/main/res/color/nav_item_state_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/color/text_on_dark.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/color/text_on_light.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi-v24/notification_icon_success.xml:
--------------------------------------------------------------------------------
1 |
7 |
9 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/baseline_info_black_36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-hdpi/baseline_info_black_36.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/baseline_settings_black_36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-hdpi/baseline_settings_black_36.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_album_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-hdpi/ic_album_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_play_grey600_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-hdpi/ic_play_grey600_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/notification_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-hdpi/notification_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/notification_icon_error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-hdpi/notification_icon_error.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/notification_icon_success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-hdpi/notification_icon_success.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/baseline_info_black_36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-mdpi/baseline_info_black_36.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/baseline_more_vert_white_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-mdpi/baseline_more_vert_white_24.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/baseline_settings_black_36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-mdpi/baseline_settings_black_36.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/notification_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-mdpi/notification_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/notification_icon_error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-mdpi/notification_icon_error.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/notification_icon_success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-mdpi/notification_icon_success.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/baseline_info_black_36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-xhdpi/baseline_info_black_36.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/baseline_more_vert_white_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-xhdpi/baseline_more_vert_white_24.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/baseline_settings_black_36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-xhdpi/baseline_settings_black_36.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/notification_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-xhdpi/notification_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/notification_icon_error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-xhdpi/notification_icon_error.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/notification_icon_success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-xhdpi/notification_icon_success.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/baseline_info_black_36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-xxhdpi/baseline_info_black_36.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/baseline_more_vert_white_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-xxhdpi/baseline_more_vert_white_24.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/baseline_settings_black_36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-xxhdpi/baseline_settings_black_36.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/notification_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-xxhdpi/notification_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/notification_icon_error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-xxhdpi/notification_icon_error.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/notification_icon_success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-xxhdpi/notification_icon_success.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/baseline_info_black_36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-xxxhdpi/baseline_info_black_36.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/baseline_more_vert_white_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-xxxhdpi/baseline_more_vert_white_24.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/baseline_settings_black_36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-xxxhdpi/baseline_settings_black_36.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/notification_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-xxxhdpi/notification_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/notification_icon_error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable-xxxhdpi/notification_icon_error.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/back.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/call.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/checkbox_checked.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
10 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/checkbox_unchecked.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
11 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/close.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
11 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/done.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/email.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/error.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
11 |
14 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/exclamation.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/grid.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
9 |
12 |
15 |
18 |
21 |
24 |
27 |
30 |
33 |
36 |
39 |
42 |
45 |
48 |
51 |
54 |
57 |
58 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable/header.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/header_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable/header_back.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/help.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
10 |
12 |
14 |
16 |
18 |
20 |
22 |
24 |
26 |
28 |
30 |
32 |
34 |
36 |
38 |
40 |
42 |
44 |
46 |
48 |
50 |
52 |
54 |
56 |
58 |
60 |
62 |
64 |
66 |
68 |
70 |
72 |
74 |
75 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_plus.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/incognito.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/incoming.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/info.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable/launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/menu.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/outgoing_dark.xml:
--------------------------------------------------------------------------------
1 |
3 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/outgoing_light.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/player_pause.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/player_play.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/player_stop.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/question_mark.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/recorder.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/select_all.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/select_export.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
11 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/drawable/settings.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sound_bottom.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/speaker_phone_off.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/speaker_phone_on.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/stars.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/success.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
11 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/user_bottom.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/user_contact.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/warning.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
11 |
16 |
21 |
24 |
27 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/contact.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
19 |
20 |
27 |
32 |
33 |
38 |
39 |
40 |
41 |
48 |
49 |
50 |
51 |
57 |
58 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/contact_detail_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
24 |
25 |
31 |
32 |
38 |
39 |
46 |
47 |
48 |
49 |
50 |
61 |
62 |
63 |
71 |
72 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/help_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
26 |
27 |
28 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/help_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/info_storage_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
20 |
27 |
28 |
33 |
34 |
35 |
41 |
48 |
49 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_contacts_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/navdraw_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/recording.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
16 |
17 |
25 |
26 |
34 |
35 |
44 |
45 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/settings_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
21 |
22 |
23 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/setup_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/setup_permissions_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
19 |
20 |
28 |
29 |
35 |
36 |
41 |
42 |
48 |
49 |
55 |
56 |
62 |
63 |
69 |
70 |
71 |
72 |
73 |
74 |
83 |
84 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/setup_power_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
19 |
20 |
27 |
28 |
32 |
33 |
40 |
41 |
48 |
49 |
57 |
58 |
59 |
60 |
66 |
67 |
68 |
69 |
70 |
71 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/setup_show_eula_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
18 |
19 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/unassigned_recordings_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
16 |
17 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/bottom_nav.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/contact_popup.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 | -
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/drawer_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/edit_contact_change_photo.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
8 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/recording_selected_popup.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
6 |
7 | -
10 |
11 |
13 |
14 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/storage_chooser_options.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/launcher_icon.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/launcher_icon_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-hdpi/launcher_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/launcher_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-hdpi/launcher_icon_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-mdpi/launcher_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/launcher_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-mdpi/launcher_icon_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-xhdpi/launcher_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/launcher_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-xhdpi/launcher_icon_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-xxhdpi/launcher_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/launcher_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-xxhdpi/launcher_icon_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/launcher_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/app/src/main/res/mipmap-xxxhdpi/launcher_icon_round.png
--------------------------------------------------------------------------------
/app/src/main/res/raw/help_about.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | About
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
APP_NAME
13 | Version %s
14 |
15 |
16 | APP_NAME is a phone and tablet application that automatically records phone calls organizing the recordings using custom defined contacts.
17 |
18 | Developer: Eugen Rădulescu
19 | Contact: %s
20 |
21 | %s
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/raw/help_licences.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Licenses
5 |
6 |
7 |
8 |
9 | Apache License v2
10 | License for libraries:
11 |
19 |
20 | License text
21 |
22 | Mozilla Public License 2.0
23 | License for libraries:
24 |
27 |
28 | License text
29 |
30 | MIT License
31 | License for libraries:
32 |
35 |
36 | License text
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/raw/help_managing_recordings.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Managing recordings
5 |
6 |
7 |
8 |
9 |
10 | Selecting recordings
11 | While tapping a recording opens the audio player, long pressing a recording selects it. When a recording is selected, the contact details screen enters the select mode . When the select mode is on the following things happen:
12 |
13 | The recordings are decorated with a checkbox at the left extremity. The selected recordings have this checkbox checked.
14 |
15 |
16 | The top bar hides the buttons and the menu for managing the contact and shows instead three buttons and a menu for managing the recording.
17 |
18 |
19 | While the select mode is on, simply tapping a recordings selects it.
20 |
21 | The select mode is cleared when there are no more selected recordings or when one or more recordings are deleted.
22 |
23 |
24 | Select mode actions
25 | While in select mode you can manage the selected recordings in several ways:
26 | Tapping the button will open a dialog which shows some useful information about the currently selected recording, like date and hour of the call, its duration, the file size, the audio format and the location of the audio file. If two or more recordings are selected, this dialog only shows the total file size of the selected recordings.
27 | Tapping the button will select all of the recordings.
28 | Tapping the button will show a menu with 2 options:
29 |
30 | Move to private storage
31 | Move to public storage
32 |
33 | If at least one of the selected recordings is already located in the private space of the application, the first option will be disabled. If you tap the second option a folder chooser dialog will show up assisting you in choosing the folder where you want to move the selected recordings. If you move the recordings in a public storage location you will be able to copy them to a computer or another mobile device.
34 | After the move finishes, a final dialog will inform you if the move was done successfully or if errors have happened during the file move.
35 |
36 |
37 | Tapping the button in the right end of the top bar will show a menu with two entries: "Rename" and "Delete".
38 | "Rename" allows you to give a name of your choice to the recordings. If more than one recording is selected this entry will be disabled.
39 | "Delete" will delete the selected recordings. Caution: this action cannot be undone.
40 |
41 |
42 | Unavailable audio files
43 | If a recording is stored in a public storage you can accidentally delete or move the audio file. When this happens the recording will be grayed out and decorated with an exclamation sign:
44 |
45 | If you cannot recover the associated audio file you should delete the recording.
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/app/src/main/res/raw/help_playing_recordings.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Playing recordings
5 |
6 |
7 |
8 |
9 | To play a recording you simply tap the name of the recording in the contact details screen. This opens the audio player and the recording immediately starts playing. The audio player has support for the standard functions of play, pause, seek and reset.
10 | Volume controls
11 | The audio player has two aditional controls implemented with circular seekbars. The one on the left controls the audio volume of the device - i.e the volume of the speaker.
12 | The one on the right allows you to add gain to the audio signal of the recording while playing, i.e. to boost it.
13 | The two controls can be used simultaneously in order to obtain a fine control of the audio volume of the played recording. This can help circumventing the problem of playing on the device a recording with low voice volume.
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/raw/privacy_policy.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Privacy policy
5 |
6 |
7 |
8 |
9 | Privacy policy
10 | Definitions
11 | "Application" shall mean %s mobile application.
12 | "User" shall mean an individual or organization that makes use of the Application.
13 |
14 | Information collected
15 | The Application collects the following information:
16 |
17 | Information obtained through Google Firebase Analytics. This information may refer to the geographic location of the User, their operating system version, their device model, their pattern of interaction with the Application and the installed version of the Application. This information is anonymous and is used solely for the purpose of improving the Application. This information is not shared with third parties and is not used for advertisement purposes.
18 |
19 | Information obtained by analyzing the logs produced by the Application. This information refer to the hardware capabilities of the User's device, their operating system version, the installed version of the Application, the date and time of the phone calls, the type of the call (incoming or outgoing), the phone numbers involved in calls, the behavior of the Application while recording phone calls. Please keep in mind that unless the User decides to send their logs to the developer, the developer has no possibility to access the application's logs. The information obtained by analyzing the application's logs are used solely for the purpose of debugging and improving the Application. This information are not shared with third parties and are not used for advertisement purposes.
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/values-sw380dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 80dp
4 | 20dp
5 | 30dp
6 | 10dp
7 | 20dp
8 | 10dp
9 | 20dp
10 | 60dp
11 | 20dp
12 | 25dp
13 | 25dp
14 | 150dp
15 | 150dp
16 | 15
17 | 13sp
18 | 25
19 | 15
20 | 170dp
21 | 90dp
22 | 65dp
23 | 110dp
24 | 110dp
25 | 100dp
26 | 26sp
27 | 18sp
28 | 40dp
29 |
--------------------------------------------------------------------------------
/app/src/main/res/values-sw600dp/refs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | - @layout/contacts_list_activity_twopane
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | - @color/primaryDarkColor
6 | - @color/textOnDark
7 | - #252525
8 | - @android:color/white
9 | - #e1e1e1
10 | - @color/colorAccent
11 |
12 |
13 | - @color/colorAccentLight
14 | - #252525
15 | - @android:color/white
16 | - #151515
17 | - @color/chevronBgColor
18 | - @color/white
19 | - @color/colorAccentLighter
20 | - #2c9633
21 | - #151515
22 |
23 |
24 |
25 |
26 | - @color/primaryDarkColor
27 | - @color/textOnDark
28 | - @color/white
29 | - @color/textOnLight
30 | - @color/textOnLight
31 | - @color/colorAccent
32 |
33 |
34 | - @color/colorAccent
35 | - @color/white
36 | - @color/textOnLight
37 | - #151515
38 | - @color/chevronBgColor
39 | - @color/textOnLight
40 | - @color/colorAccentLighter
41 | - #2c9633
42 | - #151515
43 |
44 |
45 |
46 | - @string/settings_storage_names_private
47 | - @string/settings_storage_names_public
-
48 |
49 |
50 |
51 | - private
52 | - public
53 |
54 |
55 |
56 | - @string/settings_theme_light
57 | - @string/settings_theme_dark
58 |
59 |
60 |
61 | - light_theme
62 | - dark_theme
63 |
64 |
65 |
66 | - WAV
67 | - AAC High (128kbps)
68 | - AAC Medium (64kbps)
69 | - AAC Basic (32kbps)
70 |
71 |
72 |
73 | - wav
74 | - aac_hi
75 | - aac_med
76 | - aac_bas
77 |
78 |
79 |
80 | - Mono
81 | - Stereo
82 |
83 |
84 |
85 | - mono
86 | - stereo
87 |
88 |
89 |
90 | - Voice call
91 | - Voice recognition
92 | - Voice communication
93 | - Microphone
94 |
95 |
96 |
97 | - 4
98 | - 6
99 | - 7
100 | - 1
101 |
102 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #6C8C1C
5 | #597317
6 |
7 | #D91916
8 | #FF3633
9 | #ff775f
10 | #ffffff
11 | #ffffff
12 |
13 | #faf9f6
14 | #f5feff
15 | #5f5f5f
16 | #1e1e1e
17 | #f0edec
18 |
19 | #FFFFFF
20 | #FFF
21 | #99ffffff
22 | #ff424242
23 | #ff000000
24 | #fff
25 | #ddd
26 | #52CC52
27 | #008000
28 | #E62222
29 | #a0000000
30 | #f0e2e7
31 | #2e2e2e
32 | #2e2e2e
33 | @color/white
34 | #3c3c3c
35 | #f0f0f0
36 | #D94441
37 | #FF303030
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 70dp
4 | 20dp
5 | 30dp
6 | 10dp
7 | 20dp
8 | 10dp
9 | 20dp
10 | 50dp
11 | 20dp
12 | 25dp
13 | 25dp
14 | 120dp
15 | 120dp
16 | 10
17 | 10sp
18 | 15
19 | 10
20 | 140dp
21 | 75dp
22 | 55dp
23 | 100dp
24 | 90dp
25 | 22sp
26 | 16sp
27 | 50dp
28 | 20dp
29 |
--------------------------------------------------------------------------------
/app/src/main/res/values/refs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | - @layout/contacts_list_activity_onepane
5 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/files.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
11 |
18 |
19 |
22 |
23 |
28 |
29 |
37 |
38 |
45 |
46 |
52 |
53 |
54 |
61 |
--------------------------------------------------------------------------------
/app/src/test/java/net/synapticweb/callrecorder/data/ContactTest.java:
--------------------------------------------------------------------------------
1 | package net.synapticweb.callrecorder.data;
2 |
3 |
4 | import net.synapticweb.callrecorder.Util;
5 |
6 | import org.junit.Before;
7 | import org.junit.Test;
8 | import static org.junit.Assert.*;
9 | import static org.hamcrest.CoreMatchers.*;
10 |
11 |
12 | public class ContactTest {
13 | private FakeRepository repository = new FakeRepository();
14 |
15 | @Before
16 | public void setup() {
17 | repository.addContact("contact", "0744456740");
18 | }
19 |
20 | @Test
21 | public void queryNumberInAppContacts_matches_number() {
22 | String[] numbers = {"0744456740", "0744 456 740", "+40744456740", "+40 744 456740"};
23 | for(String number : numbers) {
24 | Contact foundContact = Contact.queryNumberInAppContacts(repository, number);
25 | assertNotNull(foundContact);
26 | }
27 |
28 | String numberNotInDb = "0723456880";
29 | assertNull(Contact.queryNumberInAppContacts(repository, numberNotInDb));
30 | }
31 |
32 | @Test
33 | public void setPhoneType_StringParam() {
34 | Contact contact = new Contact();
35 | for(Util.PhoneTypeContainer container : Util.PHONE_TYPES) {
36 | contact.setPhoneType(container.getTypeName());
37 | assertThat(contact.getPhoneTypeCode(), is(container.getTypeCode()));
38 | assertThat(contact.getPhoneTypeName(), is(container.getTypeName()));
39 | }
40 |
41 | contact = new Contact();
42 | contact.setPhoneType("random string");
43 | assertThat(contact.getPhoneTypeCode(), is(Util.UNKNOWN_TYPE_PHONE_CODE));
44 | }
45 |
46 | @Test
47 | public void setPhoneType_IntegerParam() {
48 | Contact contact = new Contact();
49 | for(Util.PhoneTypeContainer container : Util.PHONE_TYPES) {
50 | contact.setPhoneType(container.getTypeCode());
51 | assertThat(contact.getPhoneTypeCode(), is(container.getTypeCode()));
52 | assertThat(contact.getPhoneTypeName(), is(container.getTypeName()));
53 | }
54 |
55 | contact = new Contact();
56 | contact.setPhoneType(400);
57 | assertThat(contact.getPhoneTypeCode(), is(Util.UNKNOWN_TYPE_PHONE_CODE));
58 | }
59 | }
--------------------------------------------------------------------------------
/app/src/test/java/net/synapticweb/callrecorder/data/ContactTestRobolectric.java:
--------------------------------------------------------------------------------
1 | package net.synapticweb.callrecorder.data;
2 |
3 | import android.content.ContentResolver;
4 | import android.content.pm.ProviderInfo;
5 | import android.database.MatrixCursor;
6 | import android.net.Uri;
7 | import android.os.Build;
8 |
9 | import androidx.test.core.app.ApplicationProvider;
10 | import androidx.test.ext.junit.runners.AndroidJUnit4;
11 |
12 | import net.synapticweb.callrecorder.Util;
13 | import net.synapticweb.callrecorder.data.FakePhoneLookupProvider.ContactData;
14 |
15 | import org.junit.Test;
16 | import org.junit.runner.RunWith;
17 | import org.robolectric.Robolectric;
18 | import org.robolectric.android.controller.ContentProviderController;
19 | import org.robolectric.annotation.Config;
20 |
21 | import static org.hamcrest.CoreMatchers.is;
22 | import static org.junit.Assert.*;
23 | import static org.mockito.ArgumentMatchers.any;
24 | import static org.mockito.ArgumentMatchers.eq;
25 | import static org.mockito.Mockito.mock;
26 | import static org.mockito.Mockito.when;
27 |
28 | //@RunWith(RobolectricTestRunner.class)
29 | @RunWith(AndroidJUnit4.class)
30 | @Config(sdk = Build.VERSION_CODES.P) //https://stackoverflow.com/questions/56821193/does-robolectric-require-java-9
31 | public class ContactTestRobolectric {
32 | private static final String GOOD_NUMBER = "0736192257";
33 | private static final String BAD_NUMBER = "0744567889";
34 | private static final String CONTACT_NAME = "contact name";
35 | private static final int CONTACT_TYPE = Util.UNKNOWN_TYPE_PHONE_CODE;
36 | private static final String PHOTO_URI = "photo_uri";
37 |
38 | //Cod vechi, ideea de la care am pornit: https://github.com/juanmendez/android_dev/blob/master/16.observers/00.magazineAppWithRx/app/src/test/java/ContentProviderTest.java
39 | //https://stackoverflow.com/questions/18290864/create-a-cursor-from-hardcoded-array-instead-of-db
40 | //Ceea ce m-a lămurit într-un final: https://stackoverflow.com/questions/18022923/robolectric-contentprovider-testing
41 | @Test
42 | public void queryNumberInPhoneContacts_return_ok() {
43 | ContentResolver resolver = ApplicationProvider.getApplicationContext().getContentResolver();
44 | ProviderInfo info = new ProviderInfo();
45 | info.authority = FakePhoneLookupProvider.AUTHORITY;
46 | ContentProviderController controller =
47 | Robolectric.buildContentProvider(FakePhoneLookupProvider.class).create(info);
48 |
49 | FakePhoneLookupProvider provider = controller.get();
50 |
51 | provider.addContact(new ContactData(CONTACT_NAME, GOOD_NUMBER, CONTACT_TYPE, PHOTO_URI));
52 | Contact contact = Contact.queryNumberInPhoneContacts(GOOD_NUMBER, resolver);
53 | assertNotNull(contact);
54 | assertThat(contact.getContactName(), is(CONTACT_NAME));
55 | assertThat(contact.getPhoneNumber(), is(GOOD_NUMBER));
56 | assertThat(contact.getPhoneTypeCode(), is(CONTACT_TYPE));
57 | assertThat(contact.getPhotoUri(), is(Uri.parse(PHOTO_URI)));
58 |
59 | contact = Contact.queryNumberInPhoneContacts(BAD_NUMBER, resolver);
60 | assertNull(contact);
61 | }
62 |
63 | @Test
64 | public void queryNumberInPhoneContacts_with_mock() {
65 | ContentResolver resolver = mock(ContentResolver.class);
66 | Uri goodLookupUri = Uri.withAppendedPath(
67 | android.provider.ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
68 | Uri.encode(GOOD_NUMBER));
69 | Uri badLookupUri = Uri.withAppendedPath(
70 | android.provider.ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
71 | Uri.encode(BAD_NUMBER));
72 | String[] columns = new String[] { android.provider.ContactsContract.PhoneLookup.NUMBER,
73 | android.provider.ContactsContract.PhoneLookup.TYPE,
74 | android.provider.ContactsContract.PhoneLookup.DISPLAY_NAME,
75 | android.provider.ContactsContract.PhoneLookup.PHOTO_URI };
76 | MatrixCursor emptyCursor = new MatrixCursor(columns);
77 | MatrixCursor dataCursor = new MatrixCursor(columns);
78 | dataCursor.addRow(new Object[] {GOOD_NUMBER, Util.UNKNOWN_TYPE_PHONE_CODE, "NAME", null});
79 |
80 | when(resolver.query(eq(goodLookupUri), any(), any(), any(), any()))
81 | .thenReturn(dataCursor);
82 |
83 | when(resolver.query(eq(badLookupUri), any(), any(), any(), any()))
84 | .thenReturn(emptyCursor);
85 |
86 | Contact contact = Contact.queryNumberInPhoneContacts(GOOD_NUMBER, resolver);
87 | assertNotNull(contact);
88 | contact = Contact.queryNumberInPhoneContacts(BAD_NUMBER, resolver);
89 | assertNull(contact);
90 | }
91 | }
--------------------------------------------------------------------------------
/app/src/test/java/net/synapticweb/callrecorder/data/FakePhoneLookupProvider.java:
--------------------------------------------------------------------------------
1 | package net.synapticweb.callrecorder.data;
2 |
3 | import android.content.ContentProvider;
4 | import android.content.ContentValues;
5 | import android.database.Cursor;
6 | import android.database.MatrixCursor;
7 | import android.net.Uri;
8 |
9 | import androidx.annotation.NonNull;
10 | import androidx.annotation.Nullable;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 | public class FakePhoneLookupProvider extends ContentProvider {
16 | private List data = new ArrayList<>();
17 | static final String AUTHORITY = "com.android.contacts";
18 |
19 | void addContact(ContactData contact) {
20 | data.add(contact);
21 | }
22 |
23 | private ContactData findByNumber(String number) {
24 | for(ContactData contact : data)
25 | if(contact.number.equals(number))
26 | return contact;
27 | return null;
28 | }
29 |
30 | @Override
31 | public boolean onCreate() {
32 | return false;
33 | }
34 |
35 | @Nullable
36 | @Override
37 | public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) {
38 | String number = uri.getLastPathSegment();
39 | String[] columns = new String[] { android.provider.ContactsContract.PhoneLookup.NUMBER,
40 | android.provider.ContactsContract.PhoneLookup.TYPE,
41 | android.provider.ContactsContract.PhoneLookup.DISPLAY_NAME,
42 | android.provider.ContactsContract.PhoneLookup.PHOTO_URI };
43 | MatrixCursor cursor = new MatrixCursor(columns);
44 |
45 | ContactData contact;
46 | if((contact = findByNumber(number)) != null ) {
47 | cursor.addRow(new Object[] {contact.number, contact.type, contact.name, contact.photoUri});
48 | }
49 |
50 | return cursor;
51 | }
52 |
53 | @Nullable
54 | @Override
55 | public String getType(@NonNull Uri uri) {
56 | return null;
57 | }
58 |
59 | @Nullable
60 | @Override
61 | public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
62 | return null;
63 | }
64 |
65 | @Override
66 | public int delete(@NonNull Uri uri, @Nullable String s, @Nullable String[] strings) {
67 | return 0;
68 | }
69 |
70 | @Override
71 | public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings) {
72 | return 0;
73 | }
74 |
75 | static class ContactData {
76 | ContactData(String name, String number, int type, String photoUri) {
77 | this.name = name;
78 | this.number = number;
79 | this.type = type;
80 | this.photoUri = photoUri;
81 | }
82 |
83 | String name;
84 | String number;
85 | int type;
86 | String photoUri;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/app/src/test/java/net/synapticweb/callrecorder/data/FakeRepository.java:
--------------------------------------------------------------------------------
1 | package net.synapticweb.callrecorder.data;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | public class FakeRepository implements Repository {
7 | private List contacts = new ArrayList<>();
8 | private List recordings = new ArrayList<>();
9 |
10 | private Long getNextId(List list) {
11 | if(list.size() > 0) {
12 | T last = list.get(list.size() - 1);
13 | if (last instanceof Contact)
14 | return ((Contact) last).getId() + 1;
15 | else
16 | return ((Recording) last).getId() + 1;
17 | }
18 | else
19 | return 1L;
20 | }
21 |
22 | void addContact(String name, String number) {
23 | Contact contact = new Contact(getNextId(contacts), number, name, null, null);
24 | contacts.add(contact);
25 | }
26 |
27 | @Override
28 | public List getAllContacts() {
29 | return contacts;
30 | }
31 |
32 | @Override
33 | public void getAllContacts(LoadContactsCallback callback) {
34 |
35 | }
36 |
37 | @Override
38 | public Long getHiddenNumberContactId() {
39 | return null;
40 | }
41 |
42 | @Override
43 | public void insertContact(Contact contact) {
44 |
45 | }
46 |
47 | @Override
48 | public void updateContact(Contact contact) {
49 |
50 | }
51 |
52 | @Override
53 | public void deleteContact(Contact contact) {
54 |
55 | }
56 |
57 | @Override
58 | public void getRecordings(Contact contact, LoadRecordingsCallback callback) {
59 |
60 | }
61 |
62 | @Override
63 | public List getRecordings(Contact contact) {
64 | return null;
65 | }
66 |
67 | @Override
68 | public void insertRecording(Recording recording) {
69 |
70 | }
71 |
72 | @Override
73 | public void updateRecording(Recording recording) {
74 |
75 | }
76 |
77 | @Override
78 | public void deleteRecording(Recording recording) {
79 |
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/app/src/test/java/net/synapticweb/callrecorder/data/RecordingTest.java:
--------------------------------------------------------------------------------
1 | package net.synapticweb.callrecorder.data;
2 |
3 | import org.junit.Test;
4 | import static org.junit.Assert.*;
5 |
6 | public class RecordingTest {
7 | @Test
8 | public void hasIllegalCharacter_IllegalChar_returnsTrue() {
9 | String illegals = "~!@#$%^&*()+=?|\\':;\"><{}[]/";
10 | for(int i = 0; i < illegals.length(); ++i) {
11 | char c = illegals.charAt(i);
12 | assertTrue(Recording.hasIllegalChar(Character.toString(c)));
13 | }
14 | }
15 |
16 | @Test
17 | public void hasIllegalCharacter_legalChars_returnsFalse() {
18 | String legalChars = "abcde10ABC.-";
19 | assertFalse(Recording.hasIllegalChar(legalChars));
20 | }
21 |
22 | }
--------------------------------------------------------------------------------
/app/src/test/java/net/synapticweb/callrecorder/data/RecordingTestRobolectric.java:
--------------------------------------------------------------------------------
1 | package net.synapticweb.callrecorder.data;
2 |
3 | import android.content.Context;
4 | import android.os.Build;
5 |
6 | import androidx.test.core.app.ApplicationProvider;
7 | import androidx.test.ext.junit.runners.AndroidJUnit4;
8 |
9 | import org.junit.Before;
10 | import org.junit.Test;
11 | import org.junit.runner.RunWith;
12 | import org.robolectric.annotation.Config;
13 |
14 | import static org.hamcrest.CoreMatchers.is;
15 | import static org.junit.Assert.*;
16 |
17 | @RunWith(AndroidJUnit4.class)
18 | @Config(sdk = Build.VERSION_CODES.P)
19 | public class RecordingTestRobolectric {
20 | private Context context;
21 |
22 | @Before
23 | public void setup() {
24 | context = ApplicationProvider.getApplicationContext(); //nu merge în @BeforeClass
25 | }
26 |
27 | @Test
28 | public void isSavedInPrivateSpace_PrivatePath_ReturnsTrue() {
29 | String privatePath = context.getFilesDir() + "/testpath";
30 | Recording recording = new Recording();
31 | recording.setPath(privatePath);
32 | assertTrue(recording.isSavedInPrivateSpace(context));
33 | }
34 |
35 | @Test
36 | public void isSavedInPrivateSpace_PublicPath_ReturnsFalse() {
37 | String publicPath = context.getCacheDir() + "/testpath";
38 | Recording recording = new Recording();
39 | recording.setPath(publicPath);
40 | assertFalse(recording.isSavedInPrivateSpace(context));
41 | }
42 |
43 | @Test
44 | public void getName_NameSet_returnsFileName() {
45 | String path = context.getFilesDir() + "/testfile.aac";
46 | Recording recording = new Recording();
47 | recording.setIsNameSet(true);
48 | recording.setPath(path);
49 | assertThat(recording.getName(), is("testfile"));
50 | }
51 |
52 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | google()
7 | maven {
8 | url 'https://maven.fabric.io/public'
9 | }
10 |
11 | }
12 | dependencies {
13 | classpath 'com.android.tools.build:gradle:4.0.0'
14 | classpath 'com.google.gms:google-services:4.3.3'
15 | classpath 'io.fabric.tools:gradle:1.31.2'
16 | // NOTE: Do not place your application dependencies here; they belong
17 | // in the individual module build.gradle files
18 | }
19 | }
20 |
21 | allprojects {
22 | repositories {
23 | jcenter()
24 | maven { url "https://jitpack.io" }
25 | maven {
26 | url "https://maven.google.com"
27 | }
28 | google()
29 | }
30 | }
31 |
32 | task clean(type: Delete) {
33 | delete rootProject.buildDir
34 | }
35 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 | android.useAndroidX=true
19 | android.enableJetifier=true
20 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/synapticweb/CallRecorder/b90f2a5c79bd338e25f34264e75e969604e3d10f/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Jun 03 21:26:42 EEST 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':Croller'
2 | project(':Croller').projectDir = new File('app/libs/Croller')
--------------------------------------------------------------------------------