Merge "Change log behavior to log conference calls only when they are disconnected from conference."
diff --git a/src/com/android/server/telecom/NuisanceCallReporter.java b/src/com/android/server/telecom/NuisanceCallReporter.java
new file mode 100644
index 0000000..064527b
--- /dev/null
+++ b/src/com/android/server/telecom/NuisanceCallReporter.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2019 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
+ */
+
+package com.android.server.telecom;
+
+import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.content.ContentProvider;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Process;
+import android.os.UserHandle;
+import android.provider.CallLog;
+import android.telecom.CallScreeningService;
+import android.telecom.Log;
+import android.telecom.PhoneAccountHandle;
+
+import java.util.Arrays;
+
+/**
+ * Responsible for handling reports via
+ * {@link android.telecom.TelecomManager#reportNuisanceCallStatus(Uri, boolean)} as to whether the
+ * user has indicated a call is a nuisance call.
+ *
+ * Since nuisance reports can be initiated from the call log, potentially long after a call has
+ * completed, calls are identified by the {@link Call#getHandle()}. A nuisance report for a call is
+ * only accepted if:
+ * <ul>
+ * <li>A missed, incoming, or rejected call to that number exists in the call log. We want to
+ * avoid a scenario where a user reports a single outgoing call as a nuisance call.</li>
+ * <li>The call occurred via a sim-based phone account; we do not want to report nuisance calls
+ * which only ever took place via a self-managed ConnectionService. It is, however, valid for
+ * a number to be contacted both via a sim-based phone account and a self-managed one.</li>
+ * <li>The {@link CallScreeningService} has provided call identification for calls in the past.
+ * This provides an incentive for {@link CallScreeningService} implementations to use the caller
+ * ID APIs appropriately if they are going to benefit from use reports of nuisance and
+ * non-nuisance calls.</li>
+ * </ul>
+ */
+public class NuisanceCallReporter {
+ /**
+ * Columns we want to retrieve from the call log.
+ */
+ private static final String[] CALL_LOG_PROJECTION = new String[] {
+ CallLog.Calls._ID,
+ CallLog.Calls.DURATION,
+ CallLog.Calls.TYPE,
+ CallLog.Calls.PHONE_ACCOUNT_COMPONENT_NAME,
+ CallLog.Calls.PHONE_ACCOUNT_ID
+ };
+
+ public static final int CALL_LOG_COLUMN_ID =
+ Arrays.asList(CALL_LOG_PROJECTION).indexOf(CallLog.Calls._ID);
+ public static final int CALL_LOG_COLUMN_DURATION =
+ Arrays.asList(CALL_LOG_PROJECTION).indexOf(CallLog.Calls.DURATION);
+ public static final int CALL_LOG_COLUMN_TYPE =
+ Arrays.asList(CALL_LOG_PROJECTION).indexOf(CallLog.Calls.TYPE);
+ public static final int CALL_LOG_COLUMN_PHONE_ACCOUNT_COMPONENT_NAME =
+ Arrays.asList(CALL_LOG_PROJECTION).indexOf(CallLog.Calls.PHONE_ACCOUNT_COMPONENT_NAME);
+ public static final int CALL_LOG_COLUMN_PHONE_ACCOUNT_ID =
+ Arrays.asList(CALL_LOG_PROJECTION).indexOf(CallLog.Calls.PHONE_ACCOUNT_ID);
+
+ /**
+ * Represents information about a nuisance report via
+ * {@link android.telecom.TelecomManager#reportNuisanceCallStatus(Uri, boolean)}.
+ */
+ private static class NuisanceReport {
+ public String callScreeningPackageName;
+ public Uri handle;
+ public boolean isNuisance;
+ public NuisanceReport(String packageName, Uri handle, boolean isNuisance) {
+ this.callScreeningPackageName = packageName;
+ this.handle = handle;
+ this.isNuisance = isNuisance;
+ }
+ }
+
+ /**
+ * Proxy interface to abstract calls to
+ * {@link android.telephony.PhoneNumberUtils#formatNumberToE164(String, String)}.
+ * Facilitates testing.
+ */
+ public interface PhoneNumberUtilsProxy {
+ String formatNumberToE164(String number);
+ }
+
+ /**
+ * Proxy interface to abstract queries to the package manager to determine if a
+ * {@link PhoneAccountHandle} is for a self-managed connection service.
+ */
+ public interface PhoneAccountRegistrarProxy {
+ boolean isSelfManagedConnectionService(PhoneAccountHandle handle);
+ }
+
+ /**
+ * Restrict to call log entries for the specified number where its an incoming, missed, blocked
+ * or rejected call.
+ */
+ private static final String NUMBER_WHERE_CLAUSE =
+ CallLog.Calls.CACHED_NORMALIZED_NUMBER + " = ? AND " + CallLog.Calls.TYPE
+ + " IN (" + CallLog.Calls.INCOMING_TYPE + "," + CallLog.Calls.MISSED_TYPE + ","
+ + CallLog.Calls.BLOCKED_TYPE + "," + CallLog.Calls.REJECTED_TYPE + ")";
+
+ /**
+ * Call log where clause to find entries with call identification reported by a specified call
+ * screening service.
+ */
+ private static final String CALL_ID_PACKAGE_WHERE_CLAUSE =
+ CallLog.Calls.CALL_ID_PACKAGE_NAME + " = ? ";
+
+ private final Context mContext;
+ private final PhoneNumberUtilsProxy mPhoneNumberUtilsProxy;
+ private final PhoneAccountRegistrarProxy mPhoneAccountRegistrarProxy;
+ private UserHandle mCurrentUserHandle;
+
+ public NuisanceCallReporter(Context context, PhoneNumberUtilsProxy phoneNumberUtilsProxy,
+ PhoneAccountRegistrarProxy phoneAccountRegistrarProxy) {
+ mContext = context;
+ mPhoneNumberUtilsProxy = phoneNumberUtilsProxy;
+ mPhoneAccountRegistrarProxy = phoneAccountRegistrarProxy;
+ }
+
+ public void setCurrentUserHandle(UserHandle userHandle) {
+ if (userHandle == null) {
+ Log.d(this, "setCurrentUserHandle, userHandle = null");
+ userHandle = Process.myUserHandle();
+ }
+ Log.d(this, "setCurrentUserHandle, %s", userHandle);
+ mCurrentUserHandle = userHandle;
+ }
+
+ /**
+ * Given a call handle reported by the default dialer, inform the
+ * {@link android.telecom.CallScreeningService} of whether the user has indicated a call is
+ * or is not a nuisance call.
+ *
+ * @param callScreeningPackageName the package name of the call screening service.
+ * @param handle the handle of the call to report nuisance status on.
+ * @param isNuisance {@code true} if the call is a nuisance call, {@code false} otherwise.
+ */
+ public void reportNuisanceCallStatus(@NonNull String callScreeningPackageName,
+ @NonNull Uri handle, boolean isNuisance) {
+
+ // Don't report the nuisance status to a call screening app if it has not provided any
+ // caller id info in the past.
+ if (!hasCallScreeningServiceProvidedCallId(callScreeningPackageName)) {
+ Log.i(this, "reportNuisanceCallStatus: app %s has not provided caller ID; skipping.",
+ callScreeningPackageName);
+ return;
+ }
+
+ maybeSendNuisanceReport(new NuisanceReport(callScreeningPackageName, handle, isNuisance));
+ }
+
+ private void maybeSendNuisanceReport(@NonNull NuisanceReport nuisanceReport) {
+ Uri callsUri = CallLog.Calls.CONTENT_URI;
+ if (mCurrentUserHandle == null) {
+ return;
+ }
+
+ ContentProvider.maybeAddUserId(CallLog.Calls.CONTENT_URI,
+ mCurrentUserHandle.getIdentifier());
+
+ String normalizedNumber = mPhoneNumberUtilsProxy.formatNumberToE164(
+ nuisanceReport.handle.getSchemeSpecificPart());
+
+ // Query the call log for the most recent information about this call.
+ Cursor cursor = mContext.getContentResolver().query(callsUri, CALL_LOG_PROJECTION,
+ NUMBER_WHERE_CLAUSE, new String[] { normalizedNumber },
+ CallLog.Calls.DEFAULT_SORT_ORDER);
+ Log.d(this, "maybeSendNuisanceReport: number=%s, isNuisance=%b",
+ Log.piiHandle(normalizedNumber), nuisanceReport.isNuisance);
+ if (cursor != null) {
+ try {
+ while (cursor.moveToNext()) {
+ final long duration = cursor.getLong(CALL_LOG_COLUMN_DURATION);
+ final int callType = cursor.getInt(CALL_LOG_COLUMN_TYPE);
+ final String phoneAccountComponentName = cursor.getString(
+ CALL_LOG_COLUMN_PHONE_ACCOUNT_COMPONENT_NAME);
+ final String phoneAccountId = cursor.getString(
+ CALL_LOG_COLUMN_PHONE_ACCOUNT_ID);
+
+ PhoneAccountHandle handle = new PhoneAccountHandle(
+ ComponentName.unflattenFromString(phoneAccountComponentName),
+ phoneAccountId);
+
+ if (mPhoneAccountRegistrarProxy.isSelfManagedConnectionService(handle)) {
+ // Skip this call log entry; it was made via a self-managed CS.
+ Log.d(this, "maybeSendNuisanceReport: skip self-mgd CS %s",
+ phoneAccountComponentName);
+ continue;
+ }
+
+ sendNuisanceReportIntent(nuisanceReport, duration, callType);
+ // Stop when we send a nuisance report.
+ break;
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+ }
+
+ /**
+ * Determines if a {@link CallScreeningService} has provided
+ * {@link android.telecom.CallIdentification} for calls in the past.
+ * @param packageName The package name of the {@link CallScreeningService}.
+ * @return {@code true} if the app has provided call identification, {@code false} otherwise.
+ */
+ private boolean hasCallScreeningServiceProvidedCallId(@NonNull String packageName) {
+ // Query the call log for any entries which have call identification provided by the call
+ // screening package.
+ Cursor cursor = mContext.getContentResolver().query(CallLog.Calls.CONTENT_URI,
+ CALL_LOG_PROJECTION, CALL_ID_PACKAGE_WHERE_CLAUSE, new String[] { packageName },
+ CallLog.Calls.DEFAULT_SORT_ORDER + " LIMIT 1");
+
+ return cursor.getCount() > 0;
+ }
+
+ private void sendNuisanceReportIntent(@NonNull NuisanceReport nuisanceReport, long duration,
+ int callType) {
+ Log.i(this, "handleCallLogResult: number=%s, duration=%d, type=%d",
+ Log.piiHandle(nuisanceReport.handle), duration, callType);
+
+ Intent intent = new Intent(CallScreeningService.ACTION_NUISANCE_CALL_STATUS_CHANGED);
+ intent.setPackage(nuisanceReport.callScreeningPackageName);
+ intent.putExtra(CallScreeningService.EXTRA_CALL_HANDLE, nuisanceReport.handle);
+ intent.putExtra(CallScreeningService.EXTRA_IS_NUISANCE, nuisanceReport.isNuisance);
+ intent.putExtra(CallScreeningService.EXTRA_CALL_TYPE, callType);
+ intent.putExtra(CallScreeningService.EXTRA_CALL_DURATION, getCallDurationBucket(duration));
+ mContext.sendBroadcastAsUser(intent, mCurrentUserHandle);
+ }
+
+ /**
+ * Maps a call duration in milliseconds to a call duration bucket.
+ * @param callDuration Call duration, in milliseconds.
+ * @return The call duration bucket
+ */
+ public @CallScreeningService.CallDuration int getCallDurationBucket(long callDuration) {
+ if (callDuration < 3000L) {
+ return CallScreeningService.CALL_DURATION_VERY_SHORT;
+ } else if (callDuration >= 3000L && callDuration < 60000L) {
+ return CallScreeningService.CALL_DURATION_SHORT;
+ } else if (callDuration >= 6000L && callDuration < 120000L) {
+ return CallScreeningService.CALL_DURATION_MEDIUM;
+ } else {
+ return CallScreeningService.CALL_DURATION_LONG;
+ }
+ }
+}
diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java
index 9010913..afe5609 100644
--- a/src/com/android/server/telecom/PhoneAccountRegistrar.java
+++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java
@@ -17,6 +17,7 @@
package com.android.server.telecom;
import android.Manifest;
+import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -650,6 +651,21 @@
return getPhoneAccountHandles(0, null, packageName, false, userHandle);
}
+ /**
+ * Determines if a {@link PhoneAccountHandle} is for a self-managed {@link ConnectionService}.
+ * @param handle The handle.
+ * @return {@code true} if for a self-managed {@link ConnectionService}, {@code false}
+ * otherwise.
+ */
+ public boolean isSelfManagedPhoneAccount(@NonNull PhoneAccountHandle handle) {
+ PhoneAccount account = getPhoneAccountUnchecked(handle);
+ if (account == null) {
+ return false;
+ }
+
+ return account.isSelfManaged();
+ }
+
// TODO: Should we implement an artificial limit for # of accounts associated with a single
// ComponentName?
public void registerPhoneAccount(PhoneAccount account) {
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index f472421..291f9d0 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -1506,6 +1506,36 @@
}
/**
+ * See {@link TelecomManager#reportNuisanceCallStatus(Uri, boolean)}
+ */
+ @Override
+ public void reportNuisanceCallStatus(Uri handle, boolean isNuisance,
+ String callingPackage) {
+ try {
+ Log.startSession("TSI.rNCS");
+ if (!isPrivilegedDialerCalling(callingPackage)) {
+ throw new SecurityException(
+ "Only the default dialer can report nuisance call status");
+ }
+
+ long token = Binder.clearCallingIdentity();
+ try {
+ String callScreeningPackageName =
+ mCallsManager.getRoleManagerAdapter().getDefaultCallScreeningApp();
+
+ if (!TextUtils.isEmpty(callScreeningPackageName)) {
+ mNuisanceCallReporter.reportNuisanceCallStatus(callScreeningPackageName,
+ handle, isNuisance);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ /**
* See {@link TelecomManager#handleCallIntent(Intent)} ()}
*/
@Override
@@ -1678,6 +1708,7 @@
private AppOpsManager mAppOpsManager;
private PackageManager mPackageManager;
private CallsManager mCallsManager;
+ private final NuisanceCallReporter mNuisanceCallReporter;
private final PhoneAccountRegistrar mPhoneAccountRegistrar;
private final CallIntentProcessor.Adapter mCallIntentProcessorAdapter;
private final UserCallIntentProcessorFactory mUserCallIntentProcessorFactory;
@@ -1695,6 +1726,7 @@
DefaultDialerCache defaultDialerCache,
SubscriptionManagerAdapter subscriptionManagerAdapter,
SettingsSecureAdapter settingsSecureAdapter,
+ NuisanceCallReporter nuisanceCallReporter,
TelecomSystem.SyncRoot lock) {
mContext = context;
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
@@ -1709,6 +1741,7 @@
mCallIntentProcessorAdapter = callIntentProcessorAdapter;
mSubscriptionManagerAdapter = subscriptionManagerAdapter;
mSettingsSecureAdapter = settingsSecureAdapter;
+ mNuisanceCallReporter = nuisanceCallReporter;
}
public ITelecomService.Stub getBinder() {
diff --git a/src/com/android/server/telecom/TelecomSystem.java b/src/com/android/server/telecom/TelecomSystem.java
index 2daba61..0e3234e 100644
--- a/src/com/android/server/telecom/TelecomSystem.java
+++ b/src/com/android/server/telecom/TelecomSystem.java
@@ -35,10 +35,15 @@
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.location.Country;
+import android.location.CountryDetector;
import android.net.Uri;
+import android.os.Process;
import android.os.UserHandle;
+import android.os.UserManager;
import android.telecom.Log;
import android.telecom.PhoneAccountHandle;
+import android.telephony.PhoneNumberUtils;
import java.io.FileNotFoundException;
import java.io.InputStream;
@@ -115,6 +120,7 @@
private final TelecomServiceImpl mTelecomServiceImpl;
private final ContactsAsyncHelper mContactsAsyncHelper;
private final DialerCodeReceiver mDialerCodeReceiver;
+ private final NuisanceCallReporter mNuisanceCallReporter;
private boolean mIsBootComplete = false;
@@ -128,6 +134,7 @@
UserHandle currentUserHandle = new UserHandle(userHandleId);
mPhoneAccountRegistrar.setCurrentUserHandle(currentUserHandle);
mCallsManager.onUserSwitch(currentUserHandle);
+ mNuisanceCallReporter.setCurrentUserHandle(currentUserHandle);
}
} finally {
Log.endSession();
@@ -326,6 +333,41 @@
mContext.registerReceiver(mDialerCodeReceiver, DIALER_SECRET_CODE_FILTER,
Manifest.permission.CONTROL_INCALL_EXPERIENCE, null);
+ mNuisanceCallReporter = new NuisanceCallReporter(mContext,
+ new NuisanceCallReporter.PhoneNumberUtilsProxy() {
+ @Override
+ public String formatNumberToE164(String number) {
+ final CountryDetector detector =
+ (CountryDetector) context.getSystemService(
+ Context.COUNTRY_DETECTOR);
+ if (detector != null) {
+ final Country country = detector.detectCountry();
+ if (country != null) {
+ String countryIso = country.getCountryIso();
+ return PhoneNumberUtils.formatNumberToE164(number,
+ countryIso);
+ }
+ }
+ return number;
+ }
+ },
+ new NuisanceCallReporter.PhoneAccountRegistrarProxy() {
+ @Override
+ public boolean isSelfManagedConnectionService(
+ PhoneAccountHandle handle) {
+ // Sync access to the PhoneAccountRegistrar on Telecom lock.
+ synchronized (mLock) {
+ return mPhoneAccountRegistrar.isSelfManagedPhoneAccount(handle);
+ }
+ }
+ });
+
+ // There is no USER_SWITCHED broadcast for user 0, handle it here explicitly.
+ final UserManager userManager = UserManager.get(mContext);
+ if (userManager.isPrimaryUser()) {
+ mNuisanceCallReporter.setCurrentUserHandle(Process.myUserHandle());
+ }
+
mTelecomServiceImpl = new TelecomServiceImpl(
mContext, mCallsManager, mPhoneAccountRegistrar,
new CallIntentProcessor.AdapterImpl(),
@@ -338,6 +380,7 @@
defaultDialerCache,
new TelecomServiceImpl.SubscriptionManagerAdapterImpl(),
new TelecomServiceImpl.SettingsSecureAdapterImpl(),
+ mNuisanceCallReporter,
mLock);
Log.endSession();
}
diff --git a/testapps/AndroidManifest.xml b/testapps/AndroidManifest.xml
index 9cb1992..1373906 100644
--- a/testapps/AndroidManifest.xml
+++ b/testapps/AndroidManifest.xml
@@ -239,6 +239,13 @@
android:process="com.android.server.telecom.testapps.SelfMangingCallingApp"
android:name="com.android.server.telecom.testapps.SelfManagedCallNotificationReceiver" />
+ <receiver android:exported="true"
+ android:name="com.android.server.telecom.testapps.NuisanceReportReceiver">
+ <intent-filter>
+ <action android:name="android.telecom.action.NUISANCE_CALL_STATUS_CHANGED" />
+ </intent-filter>
+ </receiver>
+
<service
android:name=".TestCallScreeningService"
android:permission="android.permission.BIND_SCREENING_SERVICE">
diff --git a/testapps/res/layout/testdialer_main.xml b/testapps/res/layout/testdialer_main.xml
index e6c56b7..9da3789 100644
--- a/testapps/res/layout/testdialer_main.xml
+++ b/testapps/res/layout/testdialer_main.xml
@@ -30,6 +30,16 @@
android:layout_height="wrap_content"
android:text="@string/placeCallButton" />
<Button
+ android:id="@+id/report_nuisance_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Report Nuisance" />
+ <Button
+ android:id="@+id/report_not_nuisance_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Report Not Nuisance" />
+ <Button
android:id="@+id/set_default_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/testapps/src/com/android/server/telecom/testapps/NuisanceReportReceiver.java b/testapps/src/com/android/server/telecom/testapps/NuisanceReportReceiver.java
new file mode 100644
index 0000000..76fff66
--- /dev/null
+++ b/testapps/src/com/android/server/telecom/testapps/NuisanceReportReceiver.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019 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
+ */
+
+package com.android.server.telecom.testapps;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.telecom.CallScreeningService;
+import android.widget.Toast;
+
+/**
+ * Example receiver for nuisance call reports from Telecom.
+ */
+public class NuisanceReportReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(CallScreeningService.ACTION_NUISANCE_CALL_STATUS_CHANGED)) {
+ Uri handle = intent.getParcelableExtra(CallScreeningService.EXTRA_CALL_HANDLE);
+ boolean isNuisance = intent.getBooleanExtra(CallScreeningService.EXTRA_IS_NUISANCE,
+ false);
+ int durationBucket = intent.getIntExtra(CallScreeningService.EXTRA_CALL_DURATION, 0);
+ int callType = intent.getIntExtra(CallScreeningService.EXTRA_CALL_TYPE, 0);
+ handleNuisanceReport(context, handle, isNuisance, durationBucket, callType);
+ }
+ }
+
+ private void handleNuisanceReport(Context context, Uri handle, boolean isNuisance,
+ int durationBucket, int callType) {
+
+ String message = "Nuisance report for: " + handle + " isNuisance=" + isNuisance
+ + " duration=" + durationBucket + " callType=" + callType;
+ Toast.makeText(context,
+ (CharSequence) message,
+ Toast.LENGTH_LONG)
+ .show();
+ }
+}
diff --git a/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java b/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java
index c7eccf7..66a6944 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java
@@ -54,6 +54,20 @@
}
});
+ findViewById(R.id.report_nuisance_button).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ reportNuisance(true);
+ }
+ });
+
+ findViewById(R.id.report_not_nuisance_button).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ reportNuisance(false);
+ }
+ });
+
mNumberView = (EditText) findViewById(R.id.number);
mRttCheckbox = (CheckBox) findViewById(R.id.call_with_rtt_checkbox);
updateMutableUi();
@@ -140,4 +154,11 @@
Log.i("Santos xtr", intentExtras.toString());
return intentExtras;
}
+
+ private void reportNuisance(boolean isNuisance) {
+ final TelecomManager telecomManager =
+ (TelecomManager) getSystemService(Context.TELECOM_SERVICE);
+ telecomManager.reportNuisanceCallStatus(Uri.fromParts(PhoneAccount.SCHEME_TEL,
+ mNumberView.getText().toString(), null), isNuisance);
+ }
}
diff --git a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
index b779ce2..512dbe0 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
@@ -51,6 +51,7 @@
import com.android.server.telecom.CallState;
import com.android.server.telecom.CallsManager;
import com.android.server.telecom.DefaultDialerCache;
+import com.android.server.telecom.NuisanceCallReporter;
import com.android.server.telecom.PhoneAccountRegistrar;
import com.android.server.telecom.TelecomServiceImpl;
import com.android.server.telecom.TelecomSystem;
@@ -166,6 +167,7 @@
private TelecomServiceImpl.SettingsSecureAdapter mSettingsSecureAdapter =
spy(new SettingsSecureAdapterFake());
@Mock private UserCallIntentProcessor mUserCallIntentProcessor;
+ @Mock private NuisanceCallReporter mNuisanceCallReporter;
private final TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() { };
@@ -208,6 +210,7 @@
mDefaultDialerCache,
mSubscriptionManagerAdapter,
mSettingsSecureAdapter,
+ mNuisanceCallReporter,
mLock);
mTSIBinder = telecomServiceImpl.getBinder();
mComponentContextFixture.setTelecomManager(mTelecomManager);