From a6593be278cc0f94387289f99607a050efe7878b Mon Sep 17 00:00:00 2001 From: Danny Baumann Date: Mon, 9 Jul 2018 11:19:24 +0200 Subject: Re-add call recording. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Author: Danny Baumann Date: Mon Jul 9 11:19:24 2018 +0200 Re-add call recording. Change-Id: I53fadf5754b5b6cc3e9920d57480e470e2305ac0 Author: Markus Gruber Date: Sat Oct 13 09:17:01 2018 +0200 Allow call recording for Austria * Call recording is legal in Austria, so it should be available in the UI Change-Id: Iaae0b222d2a1108572832732471e7e063f84dd1f Author: Alexandre Pary Date: Wed Oct 17 11:33:35 2018 +0200 Allow call recording for Belgium * Call recording is legal in Belgium, so it should be available in the UI Change-Id: I0d18c5c31aa5fbde08a849932ac0c8088508dbd8 Author: Arekusu Rin Date: Thu Oct 18 10:20:42 2018 +0200 Allow call recording for Bulgaria. * Call recording is legal, subject to certain restrictions, in Bulgaria. Call recording without notification or one side's consent is not a criminal offense, and only affects the admissibility of said call recording as evidence. Change-Id: Ie35f23056914fb2e7639ea509675e21e7fdfab26 (cherry picked from commit 4cec325c31dbe5894ab576b6161065ad0458612d) Author: Bruno Martins Date: Tue Oct 23 21:03:47 2018 +0100 res: Fix malformed XML * The legal precedent source URL includes double dashes and breaks aapt2 compilation. Replace it by a shortened one. Change-Id: Ic1cb1b6af16d27649e36478ca7597b78b93b1338 Author: Arekusu Rin Date: Thu Oct 25 12:50:57 2018 +0200 Enable or disable call recording for numerous countries via MCC. * This change handles call recording within the Dialer. Changes were made to the template of all of the XML files, and all links were changed to https, where possible. Quotes of the precedents and/or laws can be found within each country's XML file. Countries' whose status was not changed are not explicitly mentioned below, despite any changes to their files. * Call recording is disabled for: Andorra, Iceland, Indonesia, Monaco, Switzerland, the United States of America and some of its territories - Guam, Northern Mariana Islands, Puerto Rico and the United States Virgin Islands. * Call recording is enabled for: Albania, American Samoa, Argentina, Armenia, Aruba, Belarus, Bonaire, Bosnia and Herzegovina, Brazil, Canada, Chile, Croatia, Curaçao, Cyprus, Estonia, Faroe Islands, French Guiana, French Polynesia, Georgia, Greece, Greenland, Guadeloupe, Hungary, India, Ireland, Israel, Japan, Kosovo, Latvia, Liechtenstein, Lithuania, Luxembourg, Malta, Martinique, Mayotte, Moldova, Montenegro, Morocco, New Caledonia, New Zealand, North Macedonia, Peru, Russia, Réunion, Saba, Saint Barthélemy, Saint-Martin, Saint-Pierre-et-Miquelon, Serbia, Singapore, Sint Eustatius, Sint Maarten, Slovakia, Slovenia, South Africa, South Korea, Turkey, Ukraine and Wallis-et-Futuna. Change-Id: Iba5b7028d26cac281099f81bf3d5c21e2ee4d1a9 Author: Arekusu Rin Date: Wed Jun 12 09:58:05 2019 +0200 Enable Call Recording for Sri Lanka and Costa Rica. * Call recording is enabled for: Sri Lanka (413) and Costa Rica (712). * Fixes: Removed newline from Belgium (206) and space from Russia (250). Change-Id: I4c9ecf41e9fd472b97fff5cd03800414737be87a Author: Danny Baumann Date: Thu Nov 7 08:34:44 2019 +0100 Base 'call recording allowed' decision on current country. Selection of resources by MCC happens via the SIM MCC, but what matters for legislation is the current country, not the country the SIM origins from. Because of that, move the decision about whether call recording is allowed or not to the current country instead of SIM MCC. Change-Id: I0ee365d7af8e3392716318e5a51e12e0efe7029a Author: Han Wang <416810799@qq.com> Date: Wed Nov 20 13:27:00 2019 +0200 Enable call recording for China Change-Id: Id51a2e6a119e99ff50696b50513aed323c61565c Author: mhkjahromi Date: Sat Dec 7 18:32:20 2019 +0330 Enable call recording for Iran Change-Id: I5640405d9bd38ac3d83fd618543190c1b0d800fb Author: Danny Baumann Date: Thu Feb 20 13:19:27 2020 +0100 Refactor call recording to use MediaProvider. Change-Id: Id53d43d8bf10715a1597ff754f6c38a992302190 Author: Danny Baumann Date: Fri Jun 5 13:19:46 2020 +0200 Iterate old recordings properly when migrating call recording data. SparseArray.get() expects a key, not an index. Change-Id: I0ba40180dc9df9f8a8f4036ccbe47cc59a50cfbb Change-Id: Ie9e0af8ccadb1bab1c52a5d905344d0c8fcab92c --- .../dialer/calldetails/CallDetailsActivity.java | 7 +- .../calldetails/CallDetailsActivityCommon.java | 16 ++++- .../dialer/calldetails/CallDetailsAdapter.java | 7 +- .../calldetails/CallDetailsAdapterCommon.java | 7 +- .../calldetails/CallDetailsEntryViewHolder.java | 77 ++++++++++++++++++++++ .../dialer/calldetails/OldCallDetailsActivity.java | 7 +- .../dialer/calldetails/OldCallDetailsAdapter.java | 7 +- .../res/drawable/recording_playback_button.xml | 26 ++++++++ .../calldetails/res/layout/call_details_entry.xml | 23 +++++-- .../dialer/calldetails/res/values/cm_strings.xml | 23 +++++++ 10 files changed, 185 insertions(+), 15 deletions(-) create mode 100644 java/com/android/dialer/calldetails/res/drawable/recording_playback_button.xml create mode 100644 java/com/android/dialer/calldetails/res/values/cm_strings.xml (limited to 'java/com/android/dialer/calldetails') diff --git a/java/com/android/dialer/calldetails/CallDetailsActivity.java b/java/com/android/dialer/calldetails/CallDetailsActivity.java index 36b830851..c1acbc373 100644 --- a/java/com/android/dialer/calldetails/CallDetailsActivity.java +++ b/java/com/android/dialer/calldetails/CallDetailsActivity.java @@ -28,6 +28,7 @@ import com.android.dialer.calldetails.CallDetailsFooterViewHolder.DeleteCallDeta import com.android.dialer.calldetails.CallDetailsFooterViewHolder.ReportCallIdListener; import com.android.dialer.calldetails.CallDetailsHeaderViewHolder.CallDetailsHeaderListener; import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.AnnotatedCallLog; +import com.android.dialer.callrecord.CallRecordingDataStore; import com.android.dialer.common.Assert; import com.android.dialer.enrichedcall.EnrichedCallComponent; import com.android.dialer.protos.ProtoParsers; @@ -93,7 +94,8 @@ public final class CallDetailsActivity extends CallDetailsActivityCommon { CallDetailsEntryListener callDetailsEntryListener, CallDetailsHeaderListener callDetailsHeaderListener, ReportCallIdListener reportCallIdListener, - DeleteCallDetailsListener deleteCallDetailsListener) { + DeleteCallDetailsListener deleteCallDetailsListener, + CallRecordingDataStore callRecordingDataStore) { return new CallDetailsAdapter( this, headerInfo, @@ -101,7 +103,8 @@ public final class CallDetailsActivity extends CallDetailsActivityCommon { callDetailsEntryListener, callDetailsHeaderListener, reportCallIdListener, - deleteCallDetailsListener); + deleteCallDetailsListener, + callRecordingDataStore); } @Override diff --git a/java/com/android/dialer/calldetails/CallDetailsActivityCommon.java b/java/com/android/dialer/calldetails/CallDetailsActivityCommon.java index a26f322dd..79e761368 100644 --- a/java/com/android/dialer/calldetails/CallDetailsActivityCommon.java +++ b/java/com/android/dialer/calldetails/CallDetailsActivityCommon.java @@ -38,6 +38,7 @@ import com.android.dialer.assisteddialing.ui.AssistedDialingSettingActivity; import com.android.dialer.calldetails.CallDetailsEntries.CallDetailsEntry; import com.android.dialer.callintent.CallInitiationType; import com.android.dialer.callintent.CallIntentBuilder; +import com.android.dialer.callrecord.CallRecordingDataStore; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.common.concurrent.DialerExecutor.FailureListener; @@ -96,6 +97,7 @@ abstract class CallDetailsActivityCommon extends AppCompatActivity { private CallDetailsAdapterCommon adapter; private CallDetailsEntries callDetailsEntries; private UiListener> checkRttTranscriptAvailabilityListener; + private CallRecordingDataStore callRecordingDataStore; /** * Handles the intent that launches {@link OldCallDetailsActivity} or {@link CallDetailsActivity}, @@ -108,7 +110,8 @@ abstract class CallDetailsActivityCommon extends AppCompatActivity { CallDetailsEntryViewHolder.CallDetailsEntryListener callDetailsEntryListener, CallDetailsHeaderViewHolder.CallDetailsHeaderListener callDetailsHeaderListener, CallDetailsFooterViewHolder.ReportCallIdListener reportCallIdListener, - CallDetailsFooterViewHolder.DeleteCallDetailsListener deleteCallDetailsListener); + CallDetailsFooterViewHolder.DeleteCallDetailsListener deleteCallDetailsListener, + CallRecordingDataStore callRecordingDataStore); /** Returns the phone number of the call details. */ protected abstract String getNumber(); @@ -129,10 +132,18 @@ abstract class CallDetailsActivityCommon extends AppCompatActivity { checkRttTranscriptAvailabilityListener = DialerExecutorComponent.get(this) .createUiListener(getFragmentManager(), "Query RTT transcript availability"); + callRecordingDataStore = new CallRecordingDataStore(); handleIntent(getIntent()); setupRecyclerViewForEntries(); } + @Override + @CallSuper + protected void onDestroy() { + super.onDestroy(); + callRecordingDataStore.close(); + } + @Override @CallSuper protected void onResume() { @@ -205,7 +216,8 @@ abstract class CallDetailsActivityCommon extends AppCompatActivity { callDetailsEntryListener, callDetailsHeaderListener, reportCallIdListener, - deleteCallDetailsListener); + deleteCallDetailsListener, + callRecordingDataStore); RecyclerView recyclerView = findViewById(R.id.recycler_view); recyclerView.setLayoutManager(new LinearLayoutManager(this)); diff --git a/java/com/android/dialer/calldetails/CallDetailsAdapter.java b/java/com/android/dialer/calldetails/CallDetailsAdapter.java index 40d856fa7..7e5ebe170 100644 --- a/java/com/android/dialer/calldetails/CallDetailsAdapter.java +++ b/java/com/android/dialer/calldetails/CallDetailsAdapter.java @@ -23,6 +23,7 @@ import android.view.View; import com.android.dialer.calldetails.CallDetailsEntryViewHolder.CallDetailsEntryListener; import com.android.dialer.calldetails.CallDetailsFooterViewHolder.DeleteCallDetailsListener; import com.android.dialer.calldetails.CallDetailsHeaderViewHolder.CallDetailsHeaderListener; +import com.android.dialer.callrecord.CallRecordingDataStore; import com.android.dialer.glidephotomanager.PhotoInfo; /** @@ -43,14 +44,16 @@ final class CallDetailsAdapter extends CallDetailsAdapterCommon { CallDetailsEntryListener callDetailsEntryListener, CallDetailsHeaderListener callDetailsHeaderListener, CallDetailsFooterViewHolder.ReportCallIdListener reportCallIdListener, - DeleteCallDetailsListener deleteCallDetailsListener) { + DeleteCallDetailsListener deleteCallDetailsListener, + CallRecordingDataStore callRecordingDataStore) { super( context, callDetailsEntries, callDetailsEntryListener, callDetailsHeaderListener, reportCallIdListener, - deleteCallDetailsListener); + deleteCallDetailsListener, + callRecordingDataStore); this.headerInfo = calldetailsHeaderInfo; } diff --git a/java/com/android/dialer/calldetails/CallDetailsAdapterCommon.java b/java/com/android/dialer/calldetails/CallDetailsAdapterCommon.java index ec9263f1f..d33fea816 100644 --- a/java/com/android/dialer/calldetails/CallDetailsAdapterCommon.java +++ b/java/com/android/dialer/calldetails/CallDetailsAdapterCommon.java @@ -32,6 +32,7 @@ import com.android.dialer.calldetails.CallDetailsHeaderViewHolder.CallDetailsHea import com.android.dialer.calllogutils.CallTypeHelper; import com.android.dialer.calllogutils.CallbackActionHelper; import com.android.dialer.calllogutils.CallbackActionHelper.CallbackAction; +import com.android.dialer.callrecord.CallRecordingDataStore; import com.android.dialer.common.Assert; import com.android.dialer.duo.DuoComponent; import com.android.dialer.glidephotomanager.PhotoInfo; @@ -51,6 +52,7 @@ abstract class CallDetailsAdapterCommon extends RecyclerView.Adapter recordings; + if (CallRecorderService.isEnabled(context)) { + callRecordingDataStore.open(context); // opens unless already open + recordings = callRecordingDataStore.getRecordings(number, entry.getDate()); + } else { + recordings = null; + } + + int count = recordings != null ? recordings.size() : 0; + playbackButton.setOnClickListener(v -> handleRecordingClick(v, recordings)); + playbackButton.setText( + context.getResources().getQuantityString(R.plurals.play_recordings, count, count)); + playbackButton.setVisibility(count > 0 ? View.VISIBLE : View.GONE); + setMultimediaDetails(number, entry, showMultimediaDivider); if (isRttCall) { if (entry.getHasRttTranscript()) { @@ -209,6 +246,46 @@ public class CallDetailsEntryViewHolder extends ViewHolder { DialerUtils.startActivityWithErrorToast(context, IntentUtil.getSendSmsIntent(number)); } + private void handleRecordingClick(View v, List recordings) { + final Context context = v.getContext(); + if (recordings.size() == 1) { + playRecording(context, recordings.get(0)); + } else { + PopupMenu menu = new PopupMenu(context, v); + String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), + DateFormat.is24HourFormat(context) ? "Hmss" : "hmssa"); + SimpleDateFormat format = new SimpleDateFormat(pattern); + + for (int i = 0; i < recordings.size(); i++) { + final long startTime = recordings.get(i).startRecordingTime; + final String formattedDate = format.format(new Date(startTime)); + menu.getMenu().add(Menu.NONE, i, i, formattedDate); + } + menu.setOnMenuItemClickListener(item -> { + playRecording(context, recordings.get(item.getItemId())); + return true; + }); + menu.show(); + } + } + + private void playRecording(Context context, CallRecording recording) { + Uri uri = ContentUris.withAppendedId( + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, recording.mediaId); + String extension = MimeTypeMap.getFileExtensionFromUrl(recording.fileName); + String mime = !TextUtils.isEmpty(extension) + ? MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension) : "audio/*"; + try { + Intent intent = new Intent(Intent.ACTION_VIEW) + .setDataAndType(uri, mime) + .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + context.startActivity(intent); + } catch (ActivityNotFoundException e) { + Toast.makeText(context, R.string.call_playback_no_app_found_toast, Toast.LENGTH_LONG) + .show(); + } + } + private static boolean isIncoming(@NonNull HistoryResult historyResult) { return historyResult.getType() == Type.INCOMING_POST_CALL || historyResult.getType() == Type.INCOMING_CALL_COMPOSER; diff --git a/java/com/android/dialer/calldetails/OldCallDetailsActivity.java b/java/com/android/dialer/calldetails/OldCallDetailsActivity.java index 26217ab8a..0f53d6908 100644 --- a/java/com/android/dialer/calldetails/OldCallDetailsActivity.java +++ b/java/com/android/dialer/calldetails/OldCallDetailsActivity.java @@ -22,6 +22,7 @@ import com.android.dialer.calldetails.CallDetailsEntryViewHolder.CallDetailsEntr import com.android.dialer.calldetails.CallDetailsFooterViewHolder.DeleteCallDetailsListener; import com.android.dialer.calldetails.CallDetailsFooterViewHolder.ReportCallIdListener; import com.android.dialer.calldetails.CallDetailsHeaderViewHolder.CallDetailsHeaderListener; +import com.android.dialer.callrecord.CallRecordingDataStore; import com.android.dialer.common.Assert; import com.android.dialer.dialercontact.DialerContact; import com.android.dialer.protos.ProtoParsers; @@ -80,7 +81,8 @@ public final class OldCallDetailsActivity extends CallDetailsActivityCommon { CallDetailsEntryListener callDetailsEntryListener, CallDetailsHeaderListener callDetailsHeaderListener, ReportCallIdListener reportCallIdListener, - DeleteCallDetailsListener deleteCallDetailsListener) { + DeleteCallDetailsListener deleteCallDetailsListener, + CallRecordingDataStore callRecordingDataStore) { return new OldCallDetailsAdapter( /* context = */ this, contact, @@ -88,7 +90,8 @@ public final class OldCallDetailsActivity extends CallDetailsActivityCommon { callDetailsEntryListener, callDetailsHeaderListener, reportCallIdListener, - deleteCallDetailsListener); + deleteCallDetailsListener, + callRecordingDataStore); } @Override diff --git a/java/com/android/dialer/calldetails/OldCallDetailsAdapter.java b/java/com/android/dialer/calldetails/OldCallDetailsAdapter.java index 878803cc3..af54538db 100644 --- a/java/com/android/dialer/calldetails/OldCallDetailsAdapter.java +++ b/java/com/android/dialer/calldetails/OldCallDetailsAdapter.java @@ -23,6 +23,7 @@ import android.view.View; import com.android.dialer.calldetails.CallDetailsEntryViewHolder.CallDetailsEntryListener; import com.android.dialer.calldetails.CallDetailsFooterViewHolder.DeleteCallDetailsListener; import com.android.dialer.calldetails.CallDetailsHeaderViewHolder.CallDetailsHeaderListener; +import com.android.dialer.callrecord.CallRecordingDataStore; import com.android.dialer.dialercontact.DialerContact; import com.android.dialer.glidephotomanager.PhotoInfo; import com.android.dialer.lettertile.LetterTileDrawable; @@ -45,14 +46,16 @@ final class OldCallDetailsAdapter extends CallDetailsAdapterCommon { CallDetailsEntryListener callDetailsEntryListener, CallDetailsHeaderListener callDetailsHeaderListener, CallDetailsFooterViewHolder.ReportCallIdListener reportCallIdListener, - DeleteCallDetailsListener deleteCallDetailsListener) { + DeleteCallDetailsListener deleteCallDetailsListener, + CallRecordingDataStore callRecordingDataStore) { super( context, callDetailsEntries, callDetailsEntryListener, callDetailsHeaderListener, reportCallIdListener, - deleteCallDetailsListener); + deleteCallDetailsListener, + callRecordingDataStore); this.contact = contact; } diff --git a/java/com/android/dialer/calldetails/res/drawable/recording_playback_button.xml b/java/com/android/dialer/calldetails/res/drawable/recording_playback_button.xml new file mode 100644 index 000000000..c6fb87f74 --- /dev/null +++ b/java/com/android/dialer/calldetails/res/drawable/recording_playback_button.xml @@ -0,0 +1,26 @@ + + + + + + + diff --git a/java/com/android/dialer/calldetails/res/layout/call_details_entry.xml b/java/com/android/dialer/calldetails/res/layout/call_details_entry.xml index bfbb4f8a9..ffe3ade5e 100644 --- a/java/com/android/dialer/calldetails/res/layout/call_details_entry.xml +++ b/java/com/android/dialer/calldetails/res/layout/call_details_entry.xml @@ -19,7 +19,8 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingTop="@dimen/call_entry_padding"> + android:paddingTop="@dimen/call_entry_padding" + android:paddingBottom="@dimen/call_entry_bottom_padding"> @@ -56,12 +56,27 @@ android:layout_marginEnd="@dimen/call_entry_padding" android:layout_alignParentEnd="true"/> + + - \ No newline at end of file + diff --git a/java/com/android/dialer/calldetails/res/values/cm_strings.xml b/java/com/android/dialer/calldetails/res/values/cm_strings.xml new file mode 100644 index 000000000..076a49479 --- /dev/null +++ b/java/com/android/dialer/calldetails/res/values/cm_strings.xml @@ -0,0 +1,23 @@ + + + + + Play recording + Play recordings + + No app could be found for playback of the selected recording. + -- cgit v1.2.3