Merge "Use Call Redirection service in Telecom"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 9abe7e7..6aac49e 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -297,18 +297,10 @@
</intent-filter>
</activity>
- <activity android:name="com.android.server.telecom.components.ChangeDefaultCallScreeningApp"
- android:label="@string/change_default_dialer_dialog_title"
- android:excludeFromRecents="true"
- android:theme="@*android:style/Theme.Material.Light.Dialog.Alert"
- android:priority="1000"
- android:process=":ui">
- </activity>
-
<activity android:name=".ui.TelecomDeveloperMenu"
- android:label="@string/developer_title"
- android:exported="false"
- android:process=":ui" />
+ android:label="@string/developer_title"
+ android:exported="false"
+ android:process=":ui" />
<service android:name=".components.BluetoothPhoneService"
android:singleUser="true"
diff --git a/src/com/android/server/telecom/Analytics.java b/src/com/android/server/telecom/Analytics.java
index 61f7a30..1d3a90e 100644
--- a/src/com/android/server/telecom/Analytics.java
+++ b/src/com/android/server/telecom/Analytics.java
@@ -31,6 +31,9 @@
import com.android.server.telecom.nano.TelecomLogClass;
import java.io.PrintWriter;
+import java.time.Instant;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -39,6 +42,7 @@
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
+import java.util.concurrent.LinkedBlockingDeque;
import java.util.stream.Collectors;
import static android.telecom.ParcelableCallAnalytics.AnalyticsEvent;
@@ -578,8 +582,11 @@
public static final long MILLIS_IN_1_SECOND = ParcelableCallAnalytics.MILLIS_IN_1_SECOND;
public static final int MAX_NUM_CALLS_TO_STORE = 100;
+ public static final int MAX_NUM_DUMP_TIMES_TO_STORE = 100;
private static final Object sLock = new Object(); // Coarse lock for all of analytics
+ private static final LinkedBlockingDeque<Long> sDumpTimes =
+ new LinkedBlockingDeque<>(MAX_NUM_DUMP_TIMES_TO_STORE);
private static final Map<String, CallInfoImpl> sCallIdToInfo = new HashMap<>();
private static final LinkedList<String> sActiveCallIds = new LinkedList<>();
private static final List<SessionTiming> sSessionTimings = new LinkedList<>();
@@ -625,6 +632,7 @@
TelecomLogClass.TelecomLog result = new TelecomLogClass.TelecomLog();
synchronized (sLock) {
+ noteDumpTime();
result.callLogs = sCallIdToInfo.values().stream()
.map(CallInfoImpl::toProto)
.toArray(TelecomLogClass.CallLog[]::new);
@@ -680,6 +688,12 @@
.forEach(e -> writer.printf("%s: %.2f\n",
sSessionIdToLogSession.get(e.getKey()), e.getValue()));
writer.println("Hardware Version: " + SystemProperties.get("ro.boot.revision", ""));
+ writer.println("Past analytics dumps: ");
+ writer.increaseIndent();
+ for (long time : sDumpTimes) {
+ writer.println(Instant.ofEpochMilli(time).atZone(ZoneOffset.UTC));
+ }
+ writer.decreaseIndent();
}
}
@@ -689,6 +703,17 @@
}
}
+ public static void noteDumpTime() {
+ if (sDumpTimes.remainingCapacity() == 0) {
+ sDumpTimes.removeLast();
+ }
+ try {
+ sDumpTimes.addFirst(System.currentTimeMillis());
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Failed to note dump time -- full");
+ }
+ }
+
/**
* Returns a copy of callIdToInfo. Use only for testing.
*/
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index 2a7b25d..dfd7b2c 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -32,6 +32,7 @@
import android.os.Trace;
import android.provider.ContactsContract.Contacts;
import android.telecom.CallAudioState;
+import android.telecom.CallIdentification;
import android.telecom.Conference;
import android.telecom.ConnectionService;
import android.telecom.DisconnectCause;
@@ -141,6 +142,7 @@
Bundle extras, boolean isLegacy);
void onHandoverFailed(Call call, int error);
void onHandoverComplete(Call call);
+ void onCallIdentificationChanged(Call call);
}
public abstract static class ListenerBase implements Listener {
@@ -219,6 +221,8 @@
public void onHandoverFailed(Call call, int error) {}
@Override
public void onHandoverComplete(Call call) {}
+ @Override
+ public void onCallIdentificationChanged(Call call) {}
}
private final CallerInfoLookupHelper.OnQueryCompleteListener mCallerInfoQueryListener =
@@ -530,6 +534,11 @@
private boolean mIsUsingCallFiltering = false;
/**
+ * {@link CallIdentification} provided by a {@link android.telecom.CallScreeningService}.
+ */
+ private CallIdentification mCallIdentification = null;
+
+ /**
* Persists the specified parameters and initializes the new instance.
* @param context The context.
* @param repository The connection service repository.
@@ -3126,4 +3135,27 @@
public void setIsUsingCallFiltering(boolean isUsingCallFiltering) {
mIsUsingCallFiltering = isUsingCallFiltering;
}
+
+ /**
+ * Update the {@link CallIdentification} for a call.
+ * @param callIdentification the {@link CallIdentification}.
+ */
+ public void setCallIdentification(CallIdentification callIdentification) {
+ if (callIdentification != null) {
+ Log.addEvent(this, LogUtils.Events.CALL_IDENTIFICATION_SET,
+ callIdentification.getCallScreeningPackageName());
+ }
+ mCallIdentification = callIdentification;
+
+ for (Listener l : mListeners) {
+ l.onCallIdentificationChanged(this);
+ }
+ }
+
+ /**
+ * @return Call identification returned by a {@link android.telecom.CallScreeningService}.
+ */
+ public CallIdentification getCallIdentification() {
+ return mCallIdentification;
+ }
}
diff --git a/src/com/android/server/telecom/CallLogManager.java b/src/com/android/server/telecom/CallLogManager.java
index 1d1a010..778c824 100755
--- a/src/com/android/server/telecom/CallLogManager.java
+++ b/src/com/android/server/telecom/CallLogManager.java
@@ -27,6 +27,7 @@
import android.os.UserHandle;
import android.os.PersistableBundle;
import android.provider.CallLog.Calls;
+import android.telecom.CallIdentification;
import android.telecom.Connection;
import android.telecom.DisconnectCause;
import android.telecom.Log;
@@ -42,12 +43,8 @@
import com.android.server.telecom.callfiltering.CallFilteringResult;
import java.util.Arrays;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Objects;
-import java.util.Set;
-import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
@@ -85,7 +82,8 @@
int features, PhoneAccountHandle accountHandle, long creationDate,
long durationInMillis, Long dataUsage, UserHandle initiatingUser, boolean isRead,
@Nullable LogCallCompletedListener logCallCompletedListener, int callBlockReason,
- String callScreeningAppName, String callScreeningComponentName) {
+ String callScreeningAppName, String callScreeningComponentName,
+ CallIdentification callIdentification) {
this.context = context;
this.callerInfo = callerInfo;
this.number = number;
@@ -104,6 +102,7 @@
this.callBockReason = callBlockReason;
this.callScreeningAppName = callScreeningAppName;
this.callScreeningComponentName = callScreeningComponentName;
+ this.callIdentification = callIdentification;
}
// Since the members are accessed directly, we don't use the
// mXxxx notation.
@@ -128,6 +127,8 @@
public final int callBockReason;
public final String callScreeningAppName;
public final String callScreeningComponentName;
+
+ public final CallIdentification callIdentification;
}
private static final String TAG = CallLogManager.class.getSimpleName();
@@ -256,20 +257,22 @@
Connection.PROPERTY_ASSISTED_DIALING_USED,
call.wasEverRttCall());
+ CallIdentification callIdentification = call.getCallIdentification();
+
if (callLogType == Calls.BLOCKED_TYPE) {
logCall(call.getCallerInfo(), logNumber, call.getPostDialDigits(), formattedViaNumber,
call.getHandlePresentation(), callLogType, callFeatures, accountHandle,
creationTime, age, callDataUsage, call.isEmergencyCall(),
call.getInitiatingUser(), call.isSelfManaged(), logCallCompletedListener,
result.mCallBlockReason, result.mCallScreeningAppName,
- result.mCallScreeningComponentName);
+ result.mCallScreeningComponentName, callIdentification);
} else {
logCall(call.getCallerInfo(), logNumber, call.getPostDialDigits(), formattedViaNumber,
call.getHandlePresentation(), callLogType, callFeatures, accountHandle,
creationTime, age, callDataUsage, call.isEmergencyCall(),
call.getInitiatingUser(), call.isSelfManaged(), logCallCompletedListener,
Calls.BLOCK_REASON_NOT_BLOCKED, null /*callScreeningAppName*/,
- null /*callScreeningComponentName*/);
+ null /*callScreeningComponentName*/, callIdentification);
}
}
@@ -293,6 +296,8 @@
* @param callBlockReason The reason why the call is blocked.
* @param callScreeningAppName The call screening application name which block the call.
* @param callScreeningComponentName The call screening component name which block the call.
+ * @param callIdentification Call identification information, if provided by a call screening
+ * service.
*/
private void logCall(
CallerInfo callerInfo,
@@ -312,7 +317,8 @@
@Nullable LogCallCompletedListener logCallCompletedListener,
int callBlockReason,
String callScreeningAppName,
- String callScreeningComponentName) {
+ String callScreeningComponentName,
+ @Nullable CallIdentification callIdentification) {
// On some devices, to avoid accidental redialing of emergency numbers, we *never* log
// emergency calls to the Call Log. (This behavior is set on a per-product basis, based
@@ -346,7 +352,7 @@
AddCallArgs args = new AddCallArgs(mContext, callerInfo, number, postDialDigits,
viaNumber, presentation, callType, features, accountHandle, start, duration,
dataUsage, initiatingUser, isRead, logCallCompletedListener, callBlockReason,
- callScreeningAppName, callScreeningComponentName);
+ callScreeningAppName, callScreeningComponentName, callIdentification);
logCallAsync(args);
} else {
Log.d(TAG, "Not adding emergency call to call log.");
@@ -508,7 +514,7 @@
c.presentation, c.callType, c.features, c.accountHandle, c.timestamp,
c.durationInSec, c.dataUsage, userToBeInserted == null,
userToBeInserted, c.isRead, c.callBockReason, c.callScreeningAppName,
- c.callScreeningComponentName);
+ c.callScreeningComponentName, c.callIdentification);
}
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index b02804d..cf5bf89 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -696,6 +696,11 @@
public void onRemoteRttRequest(Call call, int requestId) {
notifyRemoteRttRequest(call, requestId);
}
+
+ @Override
+ public void onCallIdentificationChanged(Call call) {
+ updateCall(call);
+ }
};
private final SystemStateListener mSystemStateListener = new SystemStateListener() {
diff --git a/src/com/android/server/telecom/InCallTonePlayer.java b/src/com/android/server/telecom/InCallTonePlayer.java
index d0afe28..5864ce0 100644
--- a/src/com/android/server/telecom/InCallTonePlayer.java
+++ b/src/com/android/server/telecom/InCallTonePlayer.java
@@ -16,10 +16,13 @@
package com.android.server.telecom;
+import android.annotation.Nullable;
+import android.content.Context;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.ToneGenerator;
+import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.telecom.Log;
@@ -87,33 +90,51 @@
public static class MediaPlayerAdapterImpl implements MediaPlayerAdapter {
private MediaPlayer mMediaPlayer;
- public MediaPlayerAdapterImpl(MediaPlayer mediaPlayer) {
+ /**
+ * Create new media player adapter backed by a real mediaplayer.
+ * Note: Its possible for the mediaplayer to be null if
+ * {@link MediaPlayer#create(Context, Uri)} fails for some reason; in this case we can
+ * continue but not bother playing the audio.
+ * @param mediaPlayer The media player.
+ */
+ public MediaPlayerAdapterImpl(@Nullable MediaPlayer mediaPlayer) {
mMediaPlayer = mediaPlayer;
}
@Override
public void setLooping(boolean isLooping) {
- mMediaPlayer.setLooping(isLooping);
+ if (mMediaPlayer != null) {
+ mMediaPlayer.setLooping(isLooping);
+ }
}
@Override
public void setOnCompletionListener(MediaPlayer.OnCompletionListener listener) {
- mMediaPlayer.setOnCompletionListener(listener);
+ if (mMediaPlayer != null) {
+ mMediaPlayer.setOnCompletionListener(listener);
+ }
}
@Override
public void start() {
- mMediaPlayer.start();
+ if (mMediaPlayer != null) {
+ mMediaPlayer.start();
+ }
}
@Override
public void release() {
- mMediaPlayer.release();
+ if (mMediaPlayer != null) {
+ mMediaPlayer.release();
+ }
}
@Override
public int getDuration() {
- return mMediaPlayer.getDuration();
+ if (mMediaPlayer != null) {
+ return mMediaPlayer.getDuration();
+ }
+ return 0;
}
}
diff --git a/src/com/android/server/telecom/LogUtils.java b/src/com/android/server/telecom/LogUtils.java
index 0ebbd2b..bf8dba7 100644
--- a/src/com/android/server/telecom/LogUtils.java
+++ b/src/com/android/server/telecom/LogUtils.java
@@ -111,6 +111,7 @@
public static final String CONTROLLER_SCREENING_COMPLETED =
"CONTROLLER_SCREENING_COMPLETED";
public static final String SCREENING_COMPLETED = "SCREENING_COMPLETED";
+ public static final String CALL_IDENTIFICATION_SET = "CALL_IDENTIFICATION_SET";
public static final String BLOCK_CHECK_INITIATED = "BLOCK_CHECK_INITIATED";
public static final String BLOCK_CHECK_FINISHED = "BLOCK_CHECK_FINISHED";
public static final String DIRECT_TO_VM_INITIATED = "DIRECT_TO_VM_INITIATED";
diff --git a/src/com/android/server/telecom/ParcelableCallUtils.java b/src/com/android/server/telecom/ParcelableCallUtils.java
index 925efae..fe52f4b 100644
--- a/src/com/android/server/telecom/ParcelableCallUtils.java
+++ b/src/com/android/server/telecom/ParcelableCallUtils.java
@@ -194,7 +194,8 @@
conferenceableCallIds,
call.getIntentExtras(),
call.getExtras(),
- call.getCreationTimeMillis());
+ call.getCreationTimeMillis(),
+ call.getCallIdentification());
}
/**
@@ -241,7 +242,8 @@
Collections.emptyList(), /* conferenceableCallIds */
null, /* intentExtras */
null, /* callExtras */
- call.getCreationTimeMillis());
+ call.getCreationTimeMillis(),
+ null /* callIdentification */);
}
private static int getParcelableState(Call call, boolean supportsExternalCalls) {
diff --git a/src/com/android/server/telecom/RoleManagerAdapterImpl.java b/src/com/android/server/telecom/RoleManagerAdapterImpl.java
index c912cc8..a53f475 100644
--- a/src/com/android/server/telecom/RoleManagerAdapterImpl.java
+++ b/src/com/android/server/telecom/RoleManagerAdapterImpl.java
@@ -27,11 +27,11 @@
public class RoleManagerAdapterImpl implements RoleManagerAdapter {
// TODO: replace with actual role manager const.
- private static final String ROLE_CALL_REDIRECTION = "android.app.role.PROXY_CALLING_APP";
+ private static final String ROLE_CALL_REDIRECTION_APP = "android.app.role.PROXY_CALLING_APP";
// TODO: replace with actual role manager const.
private static final String ROLE_CAR_MODE_DIALER = "android.app.role.ROLE_CAR_MODE_DIALER";
// TODO: replace with actual role manager const.
- private static final String ROLE_CALL_SCREENING = "android.app.role.CALL_SCREENING";
+ private static final String ROLE_CALL_SCREENING = "android.app.role.CALL_SCREENING_APP";
// TODO: replace with actual role manager const.
private static final String ROLE_CALL_COMPANION_APP =
"android.app.role.ROLE_CALL_COMPANION_APP";
@@ -105,11 +105,6 @@
mCurrentUserHandle = currentUserHandle;
}
- private String getRoleManagerCallRedirectionApp() {
- // TODO: Link in RoleManager
- return null;
- }
-
private String getRoleManagerCallScreeningApp() {
// TODO: Link in RoleManager
return null;
@@ -125,6 +120,11 @@
return Collections.emptyList();
}
+ private String getRoleManagerCallRedirectionApp() {
+ // TODO: Link in RoleManager
+ return null;
+ }
+
/**
* Dumps the state of the {@link InCallController}.
*
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 8e7303d..f57a0c6 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -58,7 +58,6 @@
import com.android.internal.telecom.ITelecomService;
import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.telecom.components.ChangeDefaultCallScreeningApp;
import com.android.server.telecom.components.UserCallIntentProcessorFactory;
import com.android.server.telecom.settings.BlockedNumbersActivity;
@@ -1346,147 +1345,6 @@
}
}
- /**
- * @see android.telecom.TelecomManager#requestChangeDefaultCallScreeningApp
- */
- @Override
- public void requestChangeDefaultCallScreeningApp(ComponentName componentName, String
- callingPackage) {
- try {
- Log.startSession("TSI.rCDCSA");
- synchronized (mLock) {
- long token = Binder.clearCallingIdentity();
- try {
- if (callingPackage.equals(componentName.getPackageName())) {
- final Intent intent = new Intent(mContext,
- ChangeDefaultCallScreeningApp.class);
- intent.putExtra(
- TelecomManager.EXTRA_DEFAULT_CALL_SCREENING_APP_COMPONENT_NAME,
- componentName.flattenToString());
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivity(intent);
- } else {
- throw new SecurityException(
- "calling package name does't match the package of the passed "
- + "component name.");
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
- } finally {
- Log.endSession();
- }
- }
-
- /**
- * @see android.telecom.TelecomManager#isDefaultCallScreeningApp
- */
- @Override
- public boolean isDefaultCallScreeningApp(ComponentName componentName) {
- try {
- Log.startSession("TSI.iDCSA");
- synchronized (mLock) {
- if (componentName == null) {
- return false;
- }
- mAppOpsManager
- .checkPackage(Binder.getCallingUid(), componentName.getPackageName());
-
- long token = Binder.clearCallingIdentity();
- try {
- final String defaultPackage = mSettingsSecureAdapter
- .getStringForUser(mContext.getContentResolver(),
- Settings.Secure.CALL_SCREENING_DEFAULT_COMPONENT,
- UserHandle.USER_CURRENT);
-
- if (!TextUtils.isEmpty(defaultPackage) && !TextUtils
- .isEmpty(componentName.flattenToString()) && TextUtils
- .equals(defaultPackage, componentName.flattenToString())) {
- return true;
- } else {
- Log.d(this,
- "Provided package name is not the current default Call Screening application.");
- return false;
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
- } finally {
- Log.endSession();
- }
- }
-
- /**
- * @see android.telecom.TelecomManager#setDefaultCallScreeningApp
- */
- @Override
- public void setDefaultCallScreeningApp(ComponentName componentName) {
- try {
- Log.startSession("TSI.sDCSA");
- enforcePermission(MODIFY_PHONE_STATE);
- enforcePermission(WRITE_SECURE_SETTINGS);
- synchronized (mLock) {
- long token = Binder.clearCallingIdentity();
- try {
- try {
- mContext.getPackageManager().getApplicationInfo(
- componentName.getPackageName(), 0);
- } catch (PackageManager.NameNotFoundException e) {
- throw new IllegalArgumentException(
- "the specified package name does't exist componentName = " +
- componentName);
- }
-
- Intent intent = new Intent(CallScreeningService.SERVICE_INTERFACE)
- .setPackage(componentName.getPackageName());
- List<ResolveInfo> entries = mContext.getPackageManager()
- .queryIntentServicesAsUser(intent, 0,
- mCallsManager.getCurrentUserHandle().getIdentifier());
- if (entries.isEmpty()) {
- throw new IllegalArgumentException(
- "The specified package name doesn't have call screening services");
- }
-
- try {
- ServiceInfo serviceInfo = mContext.getPackageManager().getServiceInfo(
- componentName, 0);
- if (!Manifest.permission.BIND_SCREENING_SERVICE.equals(serviceInfo
- .permission)) {
- throw new IllegalArgumentException(
- "The passed component doesn't require " +
- "BIND_SCREENING_SERVICE permission");
- }
-
- } catch (PackageManager.NameNotFoundException e) {
- throw new IllegalArgumentException(
- "the specified component name does't exist componentName = "
- + componentName);
- }
-
- final String oldComponentName = mSettingsSecureAdapter
- .getStringForUser(mContext.getContentResolver(),
- Settings.Secure.CALL_SCREENING_DEFAULT_COMPONENT,
- UserHandle.USER_CURRENT);
-
- broadcastCallScreeningAppChangedIntent(oldComponentName, false);
-
- mSettingsSecureAdapter.putStringForUser(mContext.getContentResolver(),
- Settings.Secure.CALL_SCREENING_DEFAULT_COMPONENT,
- componentName.flattenToString(), UserHandle.USER_CURRENT);
-
- broadcastCallScreeningAppChangedIntent(componentName.flattenToString(),
- true);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
- } finally {
- Log.endSession();
- }
- }
-
@Override
public TelecomAnalytics dumpCallAnalytics() {
try {
diff --git a/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java b/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
index 64e225a..b23cbe9 100644
--- a/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
+++ b/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
@@ -29,6 +29,7 @@
import android.os.UserHandle;
import android.provider.CallLog;
import android.provider.Settings;
+import android.telecom.CallIdentification;
import android.telecom.CallScreeningService;
import android.telecom.Log;
import android.telecom.ParcelableCall;
@@ -150,6 +151,25 @@
Log.endSession();
}
}
+
+ @Override
+ public void provideCallIdentification(String callId,
+ CallIdentification callIdentification) {
+ Log.startSession("CSCR.pCI");
+ long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mTelecomLock) {
+ if (mCall != null && mCall.getId().equals(callId)) {
+ callIdentification.setCallScreeningAppName(mAppName);
+ callIdentification.setCallScreeningPackageName(mPackageName);
+ mCall.setCallIdentification(callIdentification);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ Log.endSession();
+ }
+ }
}
private final Context mContext;
diff --git a/src/com/android/server/telecom/components/ChangeDefaultCallScreeningApp.java b/src/com/android/server/telecom/components/ChangeDefaultCallScreeningApp.java
deleted file mode 100644
index a88c7d1..0000000
--- a/src/com/android/server/telecom/components/ChangeDefaultCallScreeningApp.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2018 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.components;
-
-import com.android.internal.app.AlertActivity;
-import com.android.internal.app.AlertController;
-import com.android.server.telecom.R;
-
-import android.content.ComponentName;
-import android.content.DialogInterface;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.telecom.Log;
-import android.telecom.TelecomManager;
-import android.text.TextUtils;
-
-public class ChangeDefaultCallScreeningApp extends AlertActivity implements
- DialogInterface.OnClickListener {
-
- private static final String TAG = ChangeDefaultCallScreeningApp.class.getSimpleName();
- private ComponentName mNewComponentName;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- mNewComponentName = ComponentName.unflattenFromString(getIntent().getStringExtra(
- TelecomManager.EXTRA_DEFAULT_CALL_SCREENING_APP_COMPONENT_NAME));
-
- if (canChangeDefaultCallScreening()) {
- buildDialog();
- } else {
- finish();
- }
- }
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- switch (which) {
- case BUTTON_POSITIVE:
- try {
- TelecomManager.from(this).setDefaultCallScreeningApp(mNewComponentName);
- } catch (IllegalArgumentException e) {
- Log.e(TAG, e, e.getMessage());
- break;
- }
- break;
- case BUTTON_NEGATIVE:
- break;
- }
- }
-
- private boolean canChangeDefaultCallScreening() {
- boolean canChange;
- String defaultComponentName = Settings.Secure
- .getStringForUser(getApplicationContext().getContentResolver(),
- Settings.Secure.CALL_SCREENING_DEFAULT_COMPONENT, UserHandle.USER_CURRENT);
-
- ComponentName oldComponentName = TextUtils.isEmpty(defaultComponentName) ? null
- : ComponentName.unflattenFromString(defaultComponentName);
-
- canChange = oldComponentName == null || !oldComponentName.getPackageName()
- .equals(mNewComponentName.getPackageName()) || !oldComponentName.flattenToString()
- .equals(mNewComponentName.flattenToString());
-
- return canChange;
- }
-
- private void buildDialog() {
- final String newPackageLabel = getApplicationLabel(mNewComponentName);
- final AlertController.AlertParams p = mAlertParams;
-
- p.mTitle = getString(R.string.change_default_call_screening_dialog_title, newPackageLabel);
- p.mMessage = getDialogBody(newPackageLabel);
- p.mPositiveButtonText = getString(
- R.string.change_default_call_screening_dialog_affirmative);
- p.mNegativeButtonText = getString(R.string.change_default_call_screening_dialog_negative);
- p.mPositiveButtonListener = this;
- p.mNegativeButtonListener = this;
-
- setupAlert();
- }
-
- private String getDialogBody(String newPackageLabel) {
- final String oldPackage = Settings.Secure.getStringForUser(
- getApplicationContext().getContentResolver(),
- Settings.Secure.CALL_SCREENING_DEFAULT_COMPONENT, UserHandle.USER_CURRENT);
- ComponentName oldPackageComponentName = null;
- if (!TextUtils.isEmpty(oldPackage)) {
- oldPackageComponentName = ComponentName.unflattenFromString(oldPackage);
- }
-
- String dialogBody = getString(R.string.change_default_call_screening_warning_message,
- newPackageLabel);
-
- if (oldPackageComponentName != null) {
- dialogBody = getString(
- R.string.change_default_call_screening_warning_message_for_disable_old_app,
- getApplicationLabel(oldPackageComponentName)) + " "
- + dialogBody;
- }
-
- return dialogBody;
- }
-
- /**
- * Returns the application label that corresponds to the given package name
- *
- * @return Application label for the given package name, or null if not found.
- */
- private String getApplicationLabel(ComponentName componentName) {
- final PackageManager pm = getPackageManager();
-
- try {
- ApplicationInfo info = pm.getApplicationInfo(componentName.getPackageName(), 0);
- return pm.getApplicationLabel(info).toString();
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Application info not found for packageName " + componentName
- .getPackageName());
- }
-
- return componentName.getPackageName();
- }
-}
diff --git a/testapps/res/layout/call_list_item.xml b/testapps/res/layout/call_list_item.xml
index c9f2ff7..ecaa237 100644
--- a/testapps/res/layout/call_list_item.xml
+++ b/testapps/res/layout/call_list_item.xml
@@ -39,4 +39,37 @@
android:layout_height="wrap_content"
android:textSize="25dp"
android:text="TextView" />
+ <ImageView
+ android:id="@+id/callIdPhoto"
+ android:layout_gravity="left"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ <TextView
+ android:id="@+id/callIdName"
+ android:layout_gravity="left"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="25dp"
+ android:text="TextView" />
+ <TextView
+ android:id="@+id/callIdDescription"
+ android:layout_gravity="left"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="25dp"
+ android:text="TextView" />
+ <TextView
+ android:id="@+id/callIdDetails"
+ android:layout_gravity="left"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="25dp"
+ android:text="TextView" />
+ <TextView
+ android:id="@+id/callIdType"
+ android:layout_gravity="left"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="25dp"
+ android:text="TextView" />
</LinearLayout>
diff --git a/testapps/src/com/android/server/telecom/testapps/CallListAdapter.java b/testapps/src/com/android/server/telecom/testapps/CallListAdapter.java
index 85785d5..e5b8780 100644
--- a/testapps/src/com/android/server/telecom/testapps/CallListAdapter.java
+++ b/testapps/src/com/android/server/telecom/testapps/CallListAdapter.java
@@ -18,13 +18,16 @@
import android.content.Context;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Handler;
import android.telecom.Call;
+import android.telecom.CallIdentification;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
+import android.widget.ImageView;
import android.widget.TextView;
public class CallListAdapter extends BaseAdapter {
@@ -90,9 +93,14 @@
convertView = mLayoutInflater.inflate(R.layout.call_list_item, parent, false);
}
- TextView phoneNumber = (TextView) convertView.findViewById(R.id.phoneNumber);
- TextView duration = (TextView) convertView.findViewById(R.id.duration);
- TextView state = (TextView) convertView.findViewById(R.id.callState);
+ TextView phoneNumber = convertView.findViewById(R.id.phoneNumber);
+ TextView duration = convertView.findViewById(R.id.duration);
+ TextView state = convertView.findViewById(R.id.callState);
+ TextView callIdName = convertView.findViewById(R.id.callIdName);
+ TextView callIdDescription = convertView.findViewById(R.id.callIdDescription);
+ TextView callIdDetails = convertView.findViewById(R.id.callIdDetails);
+ TextView callIdType = convertView.findViewById(R.id.callIdType);
+ ImageView callIdPhoto = convertView.findViewById(R.id.callIdPhoto);
Call call = mCallList.getCall(position);
Uri handle = call.getDetails().getHandle();
@@ -103,12 +111,36 @@
state.setText(getStateString(call));
+ CallIdentification callIdentification = call.getDetails().getCallIdentification();
+ if (callIdentification != null) {
+ callIdName.setText(callIdentification.getName());
+ callIdDescription.setText(callIdentification.getDescription());
+ callIdDetails.setText(callIdentification.getDetails());
+ callIdType.setText("Call Type: " + callIdentification.getNuisanceConfidence());
+ callIdPhoto.setImageIcon(callIdentification.getPhoto());
+ }
+
Log.i(TAG, "Call found: " + ((handle == null) ? "null" : handle.getSchemeSpecificPart())
+ ", " + durationMs);
+ Log.i(TAG, "Call extras: " + extrasToString(call.getDetails().getExtras()));
+ Log.i(TAG, "Call intent extras: " + extrasToString(call.getDetails().getIntentExtras()));
+
return convertView;
}
+ private String extrasToString(Bundle bundle) {
+ StringBuilder sb = new StringBuilder("[");
+ for (String key : bundle.keySet()) {
+ sb.append(key);
+ sb.append(": ");
+ sb.append(bundle.get(key));
+ sb.append("\n");
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
private static String getStateString(Call call) {
switch (call.getState()) {
case Call.STATE_ACTIVE:
diff --git a/testapps/src/com/android/server/telecom/testapps/TestCallScreeningService.java b/testapps/src/com/android/server/telecom/testapps/TestCallScreeningService.java
index 81a469e..fb231da 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestCallScreeningService.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestCallScreeningService.java
@@ -17,7 +17,9 @@
package com.android.server.telecom.testapps;
import android.content.Intent;
+import android.graphics.drawable.Icon;
import android.telecom.Call;
+import android.telecom.CallIdentification;
import android.telecom.CallScreeningService;
import android.telecom.Log;
@@ -56,6 +58,15 @@
}
public void allowCall() {
+ // Provide call identification
+ CallIdentification callIdentification = new CallIdentification.Builder()
+ .setNuisanceConfidence(CallIdentification.CONFIDENCE_NOT_NUISANCE)
+ .setName("Joe's Laundry")
+ .setDescription("1234 DirtySocks Lane")
+ .setDetails("Open 24 hrs")
+ .setPhoto(Icon.createWithResource(this, R.drawable.ic_android_black_24dp))
+ .build();
+ provideCallIdentification(mDetails, callIdentification);
CallScreeningService.CallResponse
response = new CallScreeningService.CallResponse.Builder()
.setDisallowCall(false)
diff --git a/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java b/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java
index 0fc6666..2b65e07 100644
--- a/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java
@@ -25,11 +25,13 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.graphics.drawable.Icon;
import android.os.IBinder;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.CallLog;
+import android.telecom.CallIdentification;
import android.telecom.CallScreeningService;
import android.telecom.ParcelableCall;
import android.telecom.TelecomManager;
@@ -313,6 +315,37 @@
)), eq(USER_CHOSEN_CALL_SCREENING.getPackageName()));
}
+ /**
+ * Verify that call identification information provided via a {@link CallScreeningService} is
+ * propagated to the Telecom call.
+ * @throws Exception
+ */
+ @SmallTest
+ @Test
+ public void testProvideCallIdentification() throws Exception {
+ mResolveInfo.serviceInfo.packageName = USER_CHOSEN_CALL_SCREENING.getPackageName();
+ mResolveInfo.serviceInfo.name = USER_CHOSEN_CALL_SCREENING.getClassName();
+ when(TelecomManager.from(mContext)).thenReturn(mTelecomManager);
+ when(mTelecomManager.getDefaultDialerPackage()).thenReturn(DEFAULT_DIALER_PACKAGE);
+
+ mFilter.startCallScreeningFilter(mCall, mCallback,
+ USER_CHOSEN_CALL_SCREENING.getPackageName(),
+ USER_CHOSEN_CALL_SCREENING_APP_NAME);
+ ServiceConnection serviceConnection = verifyBindingIntent();
+ serviceConnection.onServiceConnected(COMPONENT_NAME, mBinder);
+ ICallScreeningAdapter csAdapter = getCallScreeningAdapter();
+
+ CallIdentification callIdentification = new CallIdentification.Builder()
+ .setNuisanceConfidence(CallIdentification.CONFIDENCE_NOT_NUISANCE)
+ .setName("Joe's Laundry")
+ .setDescription("1234 DirtySocks Lane")
+ .setDetails("Open 24 hrs")
+ .build();
+ csAdapter.provideCallIdentification(CALL_ID, callIdentification);
+
+ verify(mCall).setCallIdentification(eq(callIdentification));
+ }
+
private ServiceConnection verifyBindingIntent() {
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
ArgumentCaptor<ServiceConnection> serviceCaptor =
diff --git a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
index a459aac..c11811d 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
@@ -764,80 +764,6 @@
@SmallTest
@Test
- public void testRequestChangeDefaultCallScreeningAppCallingPackageMatchComponentName()
- throws Exception {
- String callingPackage = "com.android.thirdparty";
-
- doNothing().when(mContext).startActivity(any(Intent.class));
-
- mTSIBinder.requestChangeDefaultCallScreeningApp(THIRD_PARTY_CALL_SCREENING,
- callingPackage);
-
- ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
- verify(mContext, times(1)).startActivity(intentCaptor.capture());
-
- Intent capturedIntent = intentCaptor.getValue();
- String className = capturedIntent.getComponent().getClassName();
- assertEquals(className,
- "com.android.server.telecom.components.ChangeDefaultCallScreeningApp");
-
- String packageNameExtra = capturedIntent.getStringExtra(
- TelecomManager.EXTRA_DEFAULT_CALL_SCREENING_APP_COMPONENT_NAME);
- assertEquals(packageNameExtra, THIRD_PARTY_CALL_SCREENING.flattenToString());
- }
-
- @SmallTest
- @Test
- public void testRequestChangeDefaultCallScreeningAppCallingPackageNoMatchComponentName()
- throws Exception {
- boolean exceptionThrown = false;
- String callingPackage = "com.android.unknown";
-
- try {
- mTSIBinder
- .requestChangeDefaultCallScreeningApp(THIRD_PARTY_CALL_SCREENING, callingPackage);
- } catch (SecurityException e) {
- exceptionThrown = true;
- }
-
- assertTrue(exceptionThrown);
- }
-
- @SmallTest
- @Test
- public void testIsDefaultCallScreeningApp() throws Exception {
- doNothing().when(mAppOpsManager).checkPackage(anyInt(), anyString());
- assertTrue(mTSIBinder.isDefaultCallScreeningApp(THIRD_PARTY_CALL_SCREENING));
- }
-
- @SmallTest
- @Test
- public void testIsDefaultCallScreeningAppFailure() throws Exception {
- ComponentName unknownComponentName = new ComponentName("com.android.unknown",
- "com.android.unknown.callscreeningserviceimpl");
- assertFalse(mTSIBinder.isDefaultCallScreeningApp(unknownComponentName));
- }
-
- @SmallTest
- @Test
- public void testSetDefaultCallScreeningAppSpecifiedComponentNameNoExist() throws Exception {
- boolean exceptionThrown = false;
-
- when(mContext.getPackageManager()
- .getApplicationInfo(THIRD_PARTY_CALL_SCREENING.getPackageName(), 0))
- .thenThrow(new IllegalArgumentException());
-
- try {
- mTSIBinder.setDefaultCallScreeningApp(THIRD_PARTY_CALL_SCREENING);
- } catch (IllegalArgumentException e) {
- exceptionThrown = true;
- }
-
- assertTrue(exceptionThrown);
- }
-
- @SmallTest
- @Test
public void testSetDefaultDialerNoModifyPhoneStatePermission() throws Exception {
doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
eq(MODIFY_PHONE_STATE), nullable(String.class));