1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.dialer.calldetails; 18 19 import android.app.AlertDialog; 20 import android.app.Dialog; 21 import android.app.DialogFragment; 22 import android.content.Context; 23 import android.content.DialogInterface; 24 import android.os.Bundle; 25 import android.support.annotation.Nullable; 26 import android.support.v4.util.Pair; 27 import android.view.LayoutInflater; 28 import android.view.View; 29 import android.widget.TextView; 30 import android.widget.Toast; 31 import com.android.dialer.common.LogUtil; 32 import com.android.dialer.common.concurrent.DialerExecutor.SuccessListener; 33 import com.android.dialer.common.concurrent.DialerExecutor.Worker; 34 import com.android.dialer.common.concurrent.DialerExecutorComponent; 35 import com.android.dialer.logging.DialerImpression; 36 import com.android.dialer.logging.Logger; 37 import com.android.dialer.phonenumbercache.CachedNumberLookupService; 38 import com.android.dialer.phonenumbercache.CachedNumberLookupService.CachedContactInfo; 39 import com.android.dialer.phonenumbercache.PhoneNumberCache; 40 41 /** Dialog for reporting an inaccurate caller id information in {@link CallDetailsActivity}. */ 42 public class ReportDialogFragment extends DialogFragment { 43 44 private static final String KEY_NUMBER = "number"; 45 private TextView name; 46 private TextView numberView; 47 48 private CachedNumberLookupService cachedNumberLookupService; 49 private CachedNumberLookupService.CachedContactInfo info; 50 private String number; 51 52 public static ReportDialogFragment newInstance(String number) { 53 ReportDialogFragment fragment = new ReportDialogFragment(); 54 Bundle bundle = new Bundle(); 55 bundle.putString(KEY_NUMBER, number); 56 fragment.setArguments(bundle); 57 return fragment; 58 } 59 60 @Override 61 public void onCreate(@Nullable Bundle bundle) { 62 super.onCreate(bundle); 63 setRetainInstance(true); 64 number = getArguments().getString(KEY_NUMBER); 65 cachedNumberLookupService = PhoneNumberCache.get(getContext()).getCachedNumberLookupService(); 66 } 67 68 @Override 69 public Dialog onCreateDialog(Bundle savedInstanceState) { 70 LayoutInflater inflater = getActivity().getLayoutInflater(); 71 View view = inflater.inflate(R.layout.caller_id_report_dialog, null, false); 72 name = view.findViewById(R.id.name); 73 numberView = view.findViewById(R.id.number); 74 75 lookupContactInfo(number); 76 77 AlertDialog reportDialog = 78 new AlertDialog.Builder(getActivity()) 79 .setTitle(R.string.report_caller_id_dialog_title) 80 .setPositiveButton(android.R.string.ok, (dialog, which) -> positiveClick(dialog)) 81 .setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.dismiss()) 82 .setView(view) 83 .create(); 84 85 reportDialog.setOnShowListener(dialog -> onShow(getContext(), reportDialog)); 86 return reportDialog; 87 } 88 89 private void positiveClick(DialogInterface dialog) { 90 startReportCallerIdWorker(); 91 dialog.dismiss(); 92 } 93 94 private static void onShow(Context context, AlertDialog dialog) { 95 int buttonTextColor = context.getColor(R.color.dialer_theme_color); 96 dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(buttonTextColor); 97 dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(buttonTextColor); 98 } 99 100 private void lookupContactInfo(String number) { 101 Worker<String, CachedContactInfo> worker = 102 number1 -> cachedNumberLookupService.lookupCachedContactFromNumber(getContext(), number1); 103 SuccessListener<CachedContactInfo> successListener = this::setCachedContactInfo; 104 DialerExecutorComponent.get(getContext()) 105 .dialerExecutorFactory() 106 .createUiTaskBuilder(getFragmentManager(), "lookup_contact_info", worker) 107 .onSuccess(successListener) 108 .build() 109 .executeParallel(number); 110 } 111 112 private void setCachedContactInfo(CachedContactInfo info) { 113 this.info = info; 114 if (info != null) { 115 name.setText(info.getContactInfo().name); 116 numberView.setText(info.getContactInfo().number); 117 } else { 118 numberView.setText(number); 119 name.setVisibility(View.GONE); 120 } 121 } 122 123 private void startReportCallerIdWorker() { 124 Worker<Context, Pair<Context, Boolean>> worker = this::reportCallerId; 125 SuccessListener<Pair<Context, Boolean>> successListener = this::onReportCallerId; 126 DialerExecutorComponent.get(getContext()) 127 .dialerExecutorFactory() 128 .createUiTaskBuilder(getFragmentManager(), "report_caller_id", worker) 129 .onSuccess(successListener) 130 .build() 131 .executeParallel(getActivity()); 132 } 133 134 private Pair<Context, Boolean> reportCallerId(Context context) { 135 if (cachedNumberLookupService.reportAsInvalid(context, info)) { 136 info.getContactInfo().isBadData = true; 137 cachedNumberLookupService.addContact(context, info); 138 LogUtil.d("ReportUploadTask.doInBackground", "Contact reported."); 139 return new Pair<>(context, true); 140 } else { 141 return new Pair<>(context, false); 142 } 143 } 144 145 private void onReportCallerId(Pair<Context, Boolean> output) { 146 Context context = output.first; 147 boolean wasReport = output.second; 148 if (wasReport) { 149 Logger.get(context).logImpression(DialerImpression.Type.CALLER_ID_REPORTED); 150 Toast.makeText(context, R.string.report_caller_id_toast, Toast.LENGTH_SHORT).show(); 151 } else { 152 Logger.get(context).logImpression(DialerImpression.Type.CALLER_ID_REPORT_FAILED); 153 Toast.makeText(context, R.string.report_caller_id_failed, Toast.LENGTH_SHORT).show(); 154 } 155 } 156 157 @Override 158 public void onDestroyView() { 159 if (getDialog() != null && getRetainInstance()) { 160 // Prevent dialog from dismissing on rotate. 161 getDialog().setDismissMessage(null); 162 } 163 super.onDestroyView(); 164 } 165 } 166