diff options
author | linyuh <linyuh@google.com> | 2017-11-22 10:58:56 -0800 |
---|---|---|
committer | Copybara-Service <copybara-piper@google.com> | 2017-11-22 16:26:29 -0800 |
commit | 7ba72d2d5b4061cf55d5440d4434a660c9108d2e (patch) | |
tree | c2de078bec6bbc96654c1032d016cdb19ac004c0 /java | |
parent | 1fb1c697a2b71ed629df76c4be129729f3cb6aea (diff) |
Allow deleting a call log entry in the call log UI and the call details UI.
In the call log UI, an entry can be deleted by selecting "delete" in its context menu.
In the call details UI, a "delete" button is added at the bottom.
The "delete" icon at the top right of the call details UI is removed.
Public-Origin-Change-Id: Iabe1310fb9a97a277cf482a3fd61ffccbec125fe
Signed-off-by: Linyu He <linyuh@google.com>
Author: Masafumi Miya <masafumi.miya@sony.com>
Bug: 38188896
Test: CallLogActivityIntegrationTest, CallDetailsActivityIntegrationTest
PiperOrigin-RevId: 176677167
Change-Id: I2e31cd112efdfb83393f5e68ce016dcf36ac4858
Diffstat (limited to 'java')
8 files changed, 164 insertions, 60 deletions
diff --git a/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java b/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java index 1c106a720..26ca5bd26 100644 --- a/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java +++ b/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java @@ -16,6 +16,8 @@ package com.android.dialer.app.calllog; +import android.Manifest.permission; +import android.annotation.SuppressLint; import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.Context; @@ -28,6 +30,7 @@ import android.provider.CallLog.Calls; import android.provider.ContactsContract.CommonDataKinds.Phone; import android.support.annotation.IntDef; import android.support.annotation.Nullable; +import android.support.annotation.RequiresPermission; import android.support.annotation.VisibleForTesting; import android.support.v7.widget.CardView; import android.support.v7.widget.RecyclerView; @@ -68,6 +71,7 @@ import com.android.dialer.calllogutils.CallbackActionHelper.CallbackAction; import com.android.dialer.clipboard.ClipboardUtils; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; +import com.android.dialer.common.concurrent.AsyncTaskExecutors; import com.android.dialer.compat.CompatUtils; import com.android.dialer.configprovider.ConfigProviderBindings; import com.android.dialer.constants.ActivityRequestCodes; @@ -95,6 +99,7 @@ import com.android.dialer.util.DialerUtils; import com.android.dialer.util.UriUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.ref.WeakReference; /** * This is an object containing references to views contained by the call log list item. This @@ -107,6 +112,9 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, MenuItem.OnMenuItemClickListener, View.OnCreateContextMenuListener { + + private static final String TASK_DELETE = "task_delete"; + /** The root view of the call log list item */ public final View rootView; /** The quick contact badge for the contact. */ @@ -431,6 +439,9 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder .logImpression(DialerImpression.Type.CALL_LOG_CONTEXT_MENU_REPORT_AS_NOT_SPAM); mBlockReportListener.onReportNotSpam( displayNumber, number, countryIso, callType, info.sourceType); + } else if (resId == R.id.context_menu_delete) { + AsyncTaskExecutors.createAsyncTaskExecutor() + .submit(TASK_DELETE, new DeleteCallTask(mContext, callIds)); } return false; } @@ -1217,6 +1228,11 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder } } + if (callType != CallLog.Calls.VOICEMAIL_TYPE) { + menu.add(ContextMenu.NONE, R.id.context_menu_delete, ContextMenu.NONE, R.string.delete) + .setOnMenuItemClickListener(this); + } + Logger.get(mContext).logScreenView(ScreenEvent.Type.CALL_LOG_CONTEXT_MENU, (Activity) mContext); } @@ -1261,4 +1277,58 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder int callType, ContactSource.Type contactSourceType); } + + private static class DeleteCallTask extends AsyncTask<Void, Void, Void> { + // Using a weak reference to hold the Context so that there is no memory leak. + private final WeakReference<Context> contextWeakReference; + + private final String callIdsStr; + + DeleteCallTask(Context context, long[] callIdsArray) { + this.contextWeakReference = new WeakReference<>(context); + this.callIdsStr = concatCallIds(callIdsArray); + } + + @Override + // Suppress the lint check here as the user will not be able to see call log entries if + // permission.WRITE_CALL_LOG is not granted. + @SuppressLint("MissingPermission") + @RequiresPermission(value = permission.WRITE_CALL_LOG) + protected Void doInBackground(Void... params) { + Context context = contextWeakReference.get(); + if (context == null) { + return null; + } + + if (callIdsStr != null) { + context + .getContentResolver() + .delete( + Calls.CONTENT_URI, + CallLog.Calls._ID + " IN (" + callIdsStr + ")" /* where */, + null /* selectionArgs */); + } + + return null; + } + + @Override + public void onPostExecute(Void result) {} + + private String concatCallIds(long[] callIds) { + if (callIds == null || callIds.length == 0) { + return null; + } + + StringBuilder str = new StringBuilder(); + for (long callId : callIds) { + if (str.length() != 0) { + str.append(","); + } + str.append(callId); + } + + return str.toString(); + } + } } diff --git a/java/com/android/dialer/app/res/values/ids.xml b/java/com/android/dialer/app/res/values/ids.xml index 8566f26b6..ca5f854de 100644 --- a/java/com/android/dialer/app/res/values/ids.xml +++ b/java/com/android/dialer/app/res/values/ids.xml @@ -15,7 +15,7 @@ --> <resources> - <item name="call_detail_delete_menu_item" type="id"/> + <item name="call_detail_action_delete" type="id"/> <item name="context_menu_copy_to_clipboard" type="id"/> <item name="context_menu_copy_transcript_to_clipboard" type="id"/> <item name="context_menu_edit_before_call" type="id"/> @@ -23,6 +23,7 @@ <item name="context_menu_block" type="id"/> <item name="context_menu_unblock" type="id"/> <item name="context_menu_report_not_spam" type="id"/> + <item name="context_menu_delete" type="id"/> <item name="settings_header_sounds_and_vibration" type="id"/> <item name="block_id" type="id"/> </resources> diff --git a/java/com/android/dialer/calldetails/CallDetailsActivity.java b/java/com/android/dialer/calldetails/CallDetailsActivity.java index 7a117a3f1..06b6a1040 100644 --- a/java/com/android/dialer/calldetails/CallDetailsActivity.java +++ b/java/com/android/dialer/calldetails/CallDetailsActivity.java @@ -16,6 +16,9 @@ package com.android.dialer.calldetails; +import android.Manifest.permission; +import android.annotation.SuppressLint; +import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; @@ -25,14 +28,14 @@ import android.provider.CallLog; import android.provider.CallLog.Calls; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.annotation.RequiresPermission; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; -import android.support.v7.widget.Toolbar.OnMenuItemClickListener; -import android.view.MenuItem; import android.widget.Toast; import com.android.dialer.calldetails.CallDetailsEntries.CallDetailsEntry; +import com.android.dialer.calldetails.CallDetailsFooterViewHolder.DeleteCallDetailsListener; import com.android.dialer.callintent.CallInitiationType; import com.android.dialer.callintent.CallIntentBuilder; import com.android.dialer.common.Assert; @@ -52,15 +55,16 @@ import com.android.dialer.performancereport.PerformanceReport; import com.android.dialer.postcall.PostCall; import com.android.dialer.precall.PreCall; import com.android.dialer.protos.ProtoParsers; +import java.lang.ref.WeakReference; import java.util.Collections; import java.util.List; import java.util.Map; /** Displays the details of a specific call log entry. */ public class CallDetailsActivity extends AppCompatActivity - implements OnMenuItemClickListener, - CallDetailsHeaderViewHolder.CallbackActionListener, + implements CallDetailsHeaderViewHolder.CallbackActionListener, CallDetailsFooterViewHolder.ReportCallIdListener, + DeleteCallDetailsListener, HistoricalDataChangedListener { public static final String EXTRA_PHONE_NUMBER = "phone_number"; @@ -102,8 +106,6 @@ public class CallDetailsActivity extends AppCompatActivity super.onCreate(savedInstanceState); setContentView(R.layout.call_details_activity); Toolbar toolbar = findViewById(R.id.toolbar); - toolbar.inflateMenu(R.menu.call_details_menu); - toolbar.setOnMenuItemClickListener(this); toolbar.setTitle(R.string.call_details); toolbar.setNavigationOnClickListener( v -> { @@ -160,7 +162,8 @@ public class CallDetailsActivity extends AppCompatActivity contact, entries.getEntriesList(), this /* callbackListener */, - this /* reportCallIdListener */); + this /* reportCallIdListener */, + this /* callDetailDeletionListener */); RecyclerView recyclerView = findViewById(R.id.recycler_view); recyclerView.setLayoutManager(new LinearLayoutManager(this)); @@ -169,17 +172,6 @@ public class CallDetailsActivity extends AppCompatActivity } @Override - public boolean onMenuItemClick(MenuItem item) { - if (item.getItemId() == R.id.call_detail_delete_menu_item) { - Logger.get(this).logImpression(DialerImpression.Type.USER_DELETED_CALL_LOG_ITEM); - AsyncTaskExecutors.createAsyncTaskExecutor().submit(TASK_DELETE, new DeleteCallsTask()); - item.setEnabled(false); - return true; - } - return false; - } - - @Override public void onBackPressed() { PerformanceReport.recordClick(UiAction.Type.PRESS_ANDROID_BACK_BUTTON); super.onBackPressed(); @@ -246,6 +238,12 @@ public class CallDetailsActivity extends AppCompatActivity PreCall.start(this, callIntentBuilder); } + @Override + public void delete() { + AsyncTaskExecutors.createAsyncTaskExecutor() + .submit(TASK_DELETE, new DeleteCallsTask(this, contact, entries)); + } + @NonNull private Map<CallDetailsEntry, List<HistoryResult>> getAllHistoricalData( @Nullable String number, @NonNull CallDetailsEntries entries) { @@ -287,13 +285,22 @@ public class CallDetailsActivity extends AppCompatActivity } /** Delete specified calls from the call log. */ - private class DeleteCallsTask extends AsyncTask<Void, Void, Void> { + private static class DeleteCallsTask extends AsyncTask<Void, Void, Void> { + // Use a weak reference to hold the Activity so that there is no memory leak. + private final WeakReference<Activity> activityWeakReference; + private final DialerContact contact; + private final CallDetailsEntries callDetailsEntries; private final String callIds; - DeleteCallsTask() { + DeleteCallsTask( + Activity activity, DialerContact contact, CallDetailsEntries callDetailsEntries) { + this.activityWeakReference = new WeakReference<>(activity); + this.contact = contact; + this.callDetailsEntries = callDetailsEntries; + StringBuilder callIds = new StringBuilder(); - for (CallDetailsEntry entry : entries.getEntriesList()) { + for (CallDetailsEntry entry : callDetailsEntries.getEntriesList()) { if (callIds.length() != 0) { callIds.append(","); } @@ -303,24 +310,43 @@ public class CallDetailsActivity extends AppCompatActivity } @Override + // Suppress the lint check here as the user will not be able to see call log entries if + // permission.WRITE_CALL_LOG is not granted. + @SuppressLint("MissingPermission") + @RequiresPermission(value = permission.WRITE_CALL_LOG) protected Void doInBackground(Void... params) { - getContentResolver() - .delete(Calls.CONTENT_URI, CallLog.Calls._ID + " IN (" + callIds + ")", null); + Activity activity = activityWeakReference.get(); + if (activity == null) { + return null; + } + + activity + .getContentResolver() + .delete( + Calls.CONTENT_URI, + CallLog.Calls._ID + " IN (" + callIds + ")" /* where */, + null /* selectionArgs */); return null; } @Override public void onPostExecute(Void result) { + Activity activity = activityWeakReference.get(); + if (activity == null) { + return; + } + Intent data = new Intent(); data.putExtra(EXTRA_PHONE_NUMBER, contact.getNumber()); - for (CallDetailsEntry entry : entries.getEntriesList()) { + for (CallDetailsEntry entry : callDetailsEntries.getEntriesList()) { if (entry.getHistoryResultsCount() > 0) { data.putExtra(EXTRA_HAS_ENRICHED_CALL_DATA, true); break; } } - setResult(RESULT_OK, data); - finish(); + + activity.setResult(RESULT_OK, data); + activity.finish(); } } } diff --git a/java/com/android/dialer/calldetails/CallDetailsAdapter.java b/java/com/android/dialer/calldetails/CallDetailsAdapter.java index b39fa0fb3..07590597e 100644 --- a/java/com/android/dialer/calldetails/CallDetailsAdapter.java +++ b/java/com/android/dialer/calldetails/CallDetailsAdapter.java @@ -23,6 +23,7 @@ import android.support.v7.widget.RecyclerView.ViewHolder; import android.view.LayoutInflater; import android.view.ViewGroup; import com.android.dialer.calldetails.CallDetailsEntries.CallDetailsEntry; +import com.android.dialer.calldetails.CallDetailsFooterViewHolder.DeleteCallDetailsListener; import com.android.dialer.calldetails.CallDetailsHeaderViewHolder.CallbackActionListener; import com.android.dialer.calllogutils.CallTypeHelper; import com.android.dialer.calllogutils.CallbackActionHelper; @@ -42,6 +43,7 @@ final class CallDetailsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol private final DialerContact contact; private final CallbackActionListener callbackActionListener; private final CallDetailsFooterViewHolder.ReportCallIdListener reportCallIdListener; + private final DeleteCallDetailsListener deleteCallDetailsListener; private final CallTypeHelper callTypeHelper; private List<CallDetailsEntry> callDetailsEntries; @@ -50,11 +52,13 @@ final class CallDetailsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol @NonNull DialerContact contact, @NonNull List<CallDetailsEntry> callDetailsEntries, CallbackActionListener callbackActionListener, - CallDetailsFooterViewHolder.ReportCallIdListener reportCallIdListener) { + CallDetailsFooterViewHolder.ReportCallIdListener reportCallIdListener, + DeleteCallDetailsListener deleteCallDetailsListener) { this.contact = Assert.isNotNull(contact); this.callDetailsEntries = callDetailsEntries; this.callbackActionListener = callbackActionListener; this.reportCallIdListener = reportCallIdListener; + this.deleteCallDetailsListener = deleteCallDetailsListener; callTypeHelper = new CallTypeHelper(context.getResources(), DuoComponent.get(context).getDuo()); } @@ -70,7 +74,9 @@ final class CallDetailsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol inflater.inflate(R.layout.call_details_entry, parent, false)); case FOOTER_VIEW_TYPE: return new CallDetailsFooterViewHolder( - inflater.inflate(R.layout.call_details_footer, parent, false), reportCallIdListener); + inflater.inflate(R.layout.call_details_footer, parent, false), + reportCallIdListener, + deleteCallDetailsListener); default: throw Assert.createIllegalStateFailException( "No ViewHolder available for viewType: " + viewType); diff --git a/java/com/android/dialer/calldetails/CallDetailsFooterViewHolder.java b/java/com/android/dialer/calldetails/CallDetailsFooterViewHolder.java index 6a5188e56..eeb19a862 100644 --- a/java/com/android/dialer/calldetails/CallDetailsFooterViewHolder.java +++ b/java/com/android/dialer/calldetails/CallDetailsFooterViewHolder.java @@ -34,32 +34,39 @@ import com.android.dialer.util.DialerUtils; /** ViewHolder container for {@link CallDetailsActivity} footer. */ final class CallDetailsFooterViewHolder extends RecyclerView.ViewHolder implements OnClickListener { - private final ReportCallIdListener listener; + private final ReportCallIdListener reportCallIdListener; + private final DeleteCallDetailsListener deleteCallDetailsListener; private final View container; private final View copy; private final View edit; private final View reportCallerId; + private final View delete; private String number; - CallDetailsFooterViewHolder(View view, ReportCallIdListener listener) { + CallDetailsFooterViewHolder( + View view, + ReportCallIdListener reportCallIdListener, + DeleteCallDetailsListener deleteCallDetailsListener) { super(view); - this.listener = listener; + this.reportCallIdListener = reportCallIdListener; + this.deleteCallDetailsListener = deleteCallDetailsListener; container = view.findViewById(R.id.footer_container); copy = view.findViewById(R.id.call_detail_action_copy); edit = view.findViewById(R.id.call_detail_action_edit_before_call); reportCallerId = view.findViewById(R.id.call_detail_action_report_caller_id); - + delete = view.findViewById(R.id.call_detail_action_delete); copy.setOnClickListener(this); edit.setOnClickListener(this); reportCallerId.setOnClickListener(this); + delete.setOnClickListener(this); } public void setPhoneNumber(String number) { this.number = number; if (TextUtils.isEmpty(number)) { container.setVisibility(View.GONE); - } else if (listener.canReportCallerId(number)) { + } else if (reportCallIdListener.canReportCallerId(number)) { reportCallerId.setVisibility(View.VISIBLE); } } @@ -81,7 +88,9 @@ final class CallDetailsFooterViewHolder extends RecyclerView.ViewHolder implemen Intent dialIntent = new Intent(Intent.ACTION_DIAL, CallUtil.getCallUri(number)); DialerUtils.startActivityWithErrorToast(context, dialIntent); } else if (view == reportCallerId) { - listener.reportCallId(number); + reportCallIdListener.reportCallId(number); + } else if (view == delete) { + deleteCallDetailsListener.delete(); } else { Assert.fail("View on click not implemented: " + view); } @@ -96,4 +105,11 @@ final class CallDetailsFooterViewHolder extends RecyclerView.ViewHolder implemen /** returns true if the number can be reported as inaccurate. */ boolean canReportCallerId(String number); } + + /** Listener for deleting call details */ + interface DeleteCallDetailsListener { + + /** Delete call details */ + void delete(); + } } diff --git a/java/com/android/dialer/calldetails/res/layout/call_details_footer.xml b/java/com/android/dialer/calldetails/res/layout/call_details_footer.xml index fbca3f8fe..dddb45156 100644 --- a/java/com/android/dialer/calldetails/res/layout/call_details_footer.xml +++ b/java/com/android/dialer/calldetails/res/layout/call_details_footer.xml @@ -50,4 +50,13 @@ android:drawableStart="@drawable/quantum_ic_report_grey600_24" android:text="@string/call_details_report_call_id" android:visibility="gone"/> + + <TextView + android:id="@+id/call_detail_action_delete" + style="@style/CallDetailsActionItemStyle" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:drawableStart="@drawable/quantum_ic_delete_vd_theme_24" + android:tint="@color/dialer_secondary_text_color" + android:text="@string/delete"/> </LinearLayout> diff --git a/java/com/android/dialer/calldetails/res/menu/call_details_menu.xml b/java/com/android/dialer/calldetails/res/menu/call_details_menu.xml deleted file mode 100644 index df0c34827..000000000 --- a/java/com/android/dialer/calldetails/res/menu/call_details_menu.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2017 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License - --> -<menu xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto"> - <item - android:id="@+id/call_detail_delete_menu_item" - android:icon="@drawable/quantum_ic_delete_white_24" - android:title="@string/delete" - app:showAsAction="ifRoom"/> -</menu>
\ No newline at end of file diff --git a/java/com/android/dialer/calldetails/res/values/strings.xml b/java/com/android/dialer/calldetails/res/values/strings.xml index 1441efdcd..74ac71c32 100644 --- a/java/com/android/dialer/calldetails/res/values/strings.xml +++ b/java/com/android/dialer/calldetails/res/values/strings.xml @@ -18,7 +18,7 @@ <!-- Title bar for call detail screen --> <string name="call_details">Call details</string> - <!-- Menu item in call details used to remove a call or voicemail from the call log. --> + <!-- Text for the action item to remove a call or voicemail from the call log. --> <string name="delete">Delete</string> <!-- Option displayed in context menu to copy long pressed phone number. [CHAR LIMIT=48] --> |