Merge "Fix crash during boot."
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 5478e7f..26a8040 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -32,7 +32,7 @@
<string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Te sun mai târziu."</string>
<string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Nu pot acum. Vorbim mai târziu?"</string>
<string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Răspunsuri rapide"</string>
- <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Editaţi răspunsurile rapide"</string>
+ <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Editați răspunsurile rapide"</string>
<string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
<string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Răspuns rapid"</string>
<string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Mesajul a fost trimis la <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
@@ -44,7 +44,7 @@
<string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Dezactivați modul TTY pentru a iniția apeluri video."</string>
<string name="no_vm_number" msgid="4164780423805688336">"Lipseşte numărul mesageriei vocale"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Niciun număr de mesagerie vocală nu este stocat pe cardul SIM."</string>
- <string name="add_vm_number_str" msgid="4676479471644687453">"Adăugaţi numărul"</string>
+ <string name="add_vm_number_str" msgid="4676479471644687453">"Adăugați numărul"</string>
<string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Schimbați aplicația Telefon prestabilită?"</string>
<string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Folosiți <xliff:g id="NEW_APP">%1$s</xliff:g> și nu <xliff:g id="CURRENT_APP">%2$s</xliff:g> ca aplicație de telefonie prestabilită?"</string>
<string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Folosiți <xliff:g id="NEW_APP">%s</xliff:g> ca aplicație de telefonie prestabilită?"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index cdb80cc..8c7d2d4 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -36,7 +36,7 @@
<string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
<string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"快速回复"</string>
<string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"讯息已发送至 <xliff:g id="PHONE_NUMBER">%s</xliff:g>。"</string>
- <string name="enable_account_preference_title" msgid="2021848090086481720">"通话帐户"</string>
+ <string name="enable_account_preference_title" msgid="2021848090086481720">"通话帐号"</string>
<string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"设备机主仅允许拨打紧急呼救电话。"</string>
<string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"此应用没有电话权限,无法拨出电话。"</string>
<string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"要拨打电话,请输入有效的电话号码。"</string>
diff --git a/res/values/config.xml b/res/values/config.xml
index e474d7e..af8cb52 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -42,4 +42,7 @@
<!-- Component name for the notification handler. The presence of this value will disable
MissedCallNotifierImpl's presentation of missed call/voice notifications [DO NOT TRANSLATE] -->
<string name="notification_component" translatable="false"></string>
+
+ <!-- Flag indicating whether audio should be routed to speaker when docked -->
+ <bool name="use_speaker_when_docked">true</bool>
</resources>
diff --git a/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java b/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java
index 9deffbe..dab4545 100644
--- a/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java
+++ b/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java
@@ -767,13 +767,13 @@
case CallState.NEW:
case CallState.ABORTED:
case CallState.DISCONNECTED:
- case CallState.CONNECTING:
- case CallState.SELECT_PHONE_ACCOUNT:
return CALL_STATE_IDLE;
case CallState.ACTIVE:
return CALL_STATE_ACTIVE;
+ case CallState.CONNECTING:
+ case CallState.SELECT_PHONE_ACCOUNT:
case CallState.DIALING:
// Yes, this is correctly returning ALERTING.
// "Dialing" for BT means that we have sent information to the service provider
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index 0228a23..b2ee0bb 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -622,7 +622,8 @@
return mRingbackRequested;
}
- boolean isConference() {
+ @VisibleForTesting
+ public boolean isConference() {
return mIsConference;
}
@@ -758,7 +759,8 @@
}
- PhoneAccountHandle getTargetPhoneAccount() {
+ @VisibleForTesting
+ public PhoneAccountHandle getTargetPhoneAccount() {
return mTargetPhoneAccountHandle;
}
@@ -781,7 +783,8 @@
* period since this call was added to the set pending outgoing calls, see
* mCreationTimeMillis.
*/
- long getAgeMillis() {
+ @VisibleForTesting
+ public long getAgeMillis() {
if (mState == CallState.DISCONNECTED &&
(mDisconnectCause.getCode() == DisconnectCause.REJECTED ||
mDisconnectCause.getCode() == DisconnectCause.MISSED)) {
diff --git a/src/com/android/server/telecom/CallLogManager.java b/src/com/android/server/telecom/CallLogManager.java
index 77c82b7..8a0adfb 100755
--- a/src/com/android/server/telecom/CallLogManager.java
+++ b/src/com/android/server/telecom/CallLogManager.java
@@ -27,6 +27,7 @@
import android.telephony.PhoneNumberUtils;
// TODO: Needed for move to system service: import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.CallerInfo;
/**
@@ -34,7 +35,8 @@
* caller details to the call log. All logging activity will be performed asynchronously in a
* background thread to avoid blocking on the main thread.
*/
-final class CallLogManager extends CallsManagerListenerBase {
+@VisibleForTesting
+public final class CallLogManager extends CallsManagerListenerBase {
/**
* Parameter object to hold the arguments to add a call in the call log DB.
*/
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index f223590..b42ca8e 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -261,8 +261,17 @@
@Override
public void onSuccessfulIncomingCall(Call incomingCall, boolean shouldSendToVoicemail) {
Log.d(this, "onSuccessfulIncomingCall");
- setCallState(incomingCall, CallState.RINGING,
- shouldSendToVoicemail ? "directing to voicemail" : "successful incoming call");
+
+ // Only set the incoming call as ringing if it isn't already disconnected. It is possible
+ // that the connection service disconnected the call before it was even added to Telecom, in
+ // which case it makes no sense to set it back to a ringing state.
+ if (incomingCall.getState() != CallState.DISCONNECTED &&
+ incomingCall.getState() != CallState.DISCONNECTING) {
+ setCallState(incomingCall, CallState.RINGING,
+ shouldSendToVoicemail ? "directing to voicemail" : "successful incoming call");
+ } else {
+ Log.i(this, "onSuccessfulIncomingCall: call already disconnected.");
+ }
if (hasMaximumRingingCalls() || hasMaximumDialingCalls() || shouldSendToVoicemail) {
incomingCall.reject(false, null);
@@ -737,7 +746,12 @@
} else {
Log.i(this, "%s Starting with speakerphone because car is docked.", call);
}
- call.setStartWithSpeakerphoneOn(speakerphoneOn || mDockManager.isDocked());
+
+ final boolean useSpeakerWhenDocked = mContext.getResources().getBoolean(
+ R.bool.use_speaker_when_docked);
+
+ call.setStartWithSpeakerphoneOn(speakerphoneOn
+ || (useSpeakerWhenDocked && mDockManager.isDocked()));
if (call.isEmergencyCall()) {
// Emergency -- CreateConnectionProcessor will choose accounts automatically
diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java
index 8038f62..594d093 100644
--- a/src/com/android/server/telecom/PhoneAccountRegistrar.java
+++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java
@@ -417,21 +417,12 @@
return true;
}
- // Special check for work profiles.
+ // Special check for work profiles, any user could have a profile.
// Unlike in TelecomServiceImpl, we only care about *profiles* here. We want to make sure
// that we don't resolve PhoneAccount across *users*, but resolving across *profiles* is
// fine.
- if (UserHandle.getCallingUserId() == UserHandle.USER_OWNER) {
- List<UserInfo> profileUsers =
- mUserManager.getProfiles(mCurrentUserHandle.getIdentifier());
- for (UserInfo profileInfo : profileUsers) {
- if (profileInfo.getUserHandle().equals(phoneAccountUserHandle)) {
- return true;
- }
- }
- }
-
- return false;
+ return mUserManager.isSameProfileGroup(
+ mCurrentUserHandle.getIdentifier(), phoneAccountUserHandle.getIdentifier());
}
private List<ResolveInfo> resolveComponent(PhoneAccountHandle phoneAccountHandle) {
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index fc8977b..28ea05d 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -320,7 +320,7 @@
Intent intent = new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_REGISTERED);
intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
account.getAccountHandle());
- Log.i(this, "Sending phone-account intent as user");
+ Log.i(this, "Sending phone-account registered intent as user");
mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
PERMISSION_PROCESS_PHONE_ACCOUNT_REGISTRATION);
} finally {
@@ -341,6 +341,19 @@
accountHandle.getComponentName().getPackageName());
enforceUserHandleMatchesCaller(accountHandle);
mPhoneAccountRegistrar.unregisterPhoneAccount(accountHandle);
+
+ // Broadcast an intent indicating the phone account which was unregistered.
+ long token = Binder.clearCallingIdentity();
+ try {
+ Intent intent =
+ new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_UNREGISTERED);
+ intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle);
+ Log.i(this, "Sending phone-account unregistered intent as user");
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
+ PERMISSION_PROCESS_PHONE_ACCOUNT_REGISTRATION);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
} catch (Exception e) {
Log.e(this, e, "unregisterPhoneAccount %s", accountHandle);
throw e;
@@ -530,7 +543,12 @@
}
synchronized (mLock) {
- return mCallsManager.getCallState() == TelephonyManager.CALL_STATE_RINGING;
+ // Note: We are explicitly checking the calls telecom is tracking rather than
+ // relying on mCallsManager#getCallState(). Since getCallState() relies on the
+ // current state as tracked by PhoneStateBroadcaster, any failure to properly
+ // track the current call state there could result in the wrong ringing state being
+ // reported by this API.
+ return mCallsManager.hasRingingCall();
}
}
@@ -970,14 +988,9 @@
return true;
}
- List<UserHandle> profileUserHandles;
- if (UserHandle.getCallingUserId() == UserHandle.USER_OWNER) {
- profileUserHandles = mUserManager.getUserProfiles();
- } else {
- // Otherwise, it has to be owned by the current caller's profile.
- profileUserHandles = new ArrayList<>(1);
- profileUserHandles.add(Binder.getCallingUserHandle());
- }
+ // Any user can have profiles now. Also result from getUserProfiles() includes the calling
+ // user itself.
+ List<UserHandle> profileUserHandles = mUserManager.getUserProfiles();
return profileUserHandles.contains(phoneAccountUserHandle);
}
diff --git a/src/com/android/server/telecom/TelephonyUtil.java b/src/com/android/server/telecom/TelephonyUtil.java
index 5f43ee9..69adaf9 100644
--- a/src/com/android/server/telecom/TelephonyUtil.java
+++ b/src/com/android/server/telecom/TelephonyUtil.java
@@ -23,6 +23,8 @@
import android.telecom.PhoneAccountHandle;
import android.telephony.PhoneNumberUtils;
+import com.android.internal.annotations.VisibleForTesting;
+
/**
* Utilities to deal with the system telephony services. The system telephony services are treated
* differently from 3rd party services in some situations (emergency calls, audio focus, etc...).
@@ -45,7 +47,8 @@
* account are not expected to be displayed in the UI, so the description, etc are not
* populated.
*/
- static PhoneAccount getDefaultEmergencyPhoneAccount() {
+ @VisibleForTesting
+ public static PhoneAccount getDefaultEmergencyPhoneAccount() {
return PhoneAccount.builder(DEFAULT_EMERGENCY_PHONE_ACCOUNT_HANDLE, "E")
.setCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
PhoneAccount.CAPABILITY_CALL_PROVIDER |
diff --git a/src/com/android/server/telecom/components/UserCallIntentProcessor.java b/src/com/android/server/telecom/components/UserCallIntentProcessor.java
index 8f451b5..f7e2191 100644
--- a/src/com/android/server/telecom/components/UserCallIntentProcessor.java
+++ b/src/com/android/server/telecom/components/UserCallIntentProcessor.java
@@ -184,7 +184,7 @@
intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
intent.setClass(mContext, PrimaryCallReceiver.class);
Log.d(this, "Sending broadcast as user to CallReceiver");
- mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
+ mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
return true;
}
diff --git a/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java b/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
new file mode 100644
index 0000000..a1e58ee
--- /dev/null
+++ b/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2015 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.tests;
+
+
+import android.content.ComponentName;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.IContentProvider;
+import android.content.pm.UserInfo;
+import android.net.Uri;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.CallLog;
+import android.telecom.DisconnectCause;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.VideoProfile;
+
+import com.android.server.telecom.Call;
+import com.android.server.telecom.CallLogManager;
+import com.android.server.telecom.CallState;
+import com.android.server.telecom.TelephonyUtil;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.mockito.ArgumentCaptor;
+
+import java.util.Collections;
+
+public class CallLogManagerTest extends TelecomTestCase {
+
+ private CallLogManager mCallLogManager;
+ private IContentProvider mContentProvider;
+ private PhoneAccountHandle mDefaultAccountHandle;
+
+ private static final Uri TEL_PHONEHANDLE = Uri.parse("tel:5555551234");
+
+ private static final PhoneAccountHandle EMERGENCY_ACCT_HANDLE = TelephonyUtil
+ .getDefaultEmergencyPhoneAccount()
+ .getAccountHandle();
+
+ private static final int NO_VIDEO_STATE = VideoProfile.STATE_AUDIO_ONLY;
+ private static final int BIDIRECTIONAL_VIDEO_STATE = VideoProfile.STATE_BIDIRECTIONAL;
+ private static final String POST_DIAL_STRING = ";12345";
+ private static final String TEST_PHONE_ACCOUNT_ID= "testPhoneAccountId";
+
+ private static final int TEST_TIMEOUT_MILLIS = 100;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mContext = mComponentContextFixture.getTestDouble().getApplicationContext();
+ mCallLogManager = new CallLogManager(mContext);
+ mContentProvider = mContext.getContentResolver().acquireProvider("test");
+ mDefaultAccountHandle = new PhoneAccountHandle(
+ new ComponentName("com.android.server.telecom.tests", "CallLogManagerTest"),
+ TEST_PHONE_ACCOUNT_ID
+ );
+
+ UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ UserInfo userInfo = new UserInfo(UserHandle.USER_CURRENT, "test", 0);
+ when(userManager.isUserRunning(any(UserHandle.class))).thenReturn(true);
+ when(userManager.hasUserRestriction(any(String.class), any(UserHandle.class)))
+ .thenReturn(false);
+ when(userManager.getUsers(any(Boolean.class)))
+ .thenReturn(Collections.singletonList(userInfo));
+ }
+
+ public void testDontLogCancelledCall() {
+ Call fakeCall = makeFakeCall(
+ DisconnectCause.CANCELED,
+ false, // isConference
+ false, // isIncoming
+ 1L, // creationTimeMillis
+ 1000L, // ageMillis
+ TEL_PHONEHANDLE, // callHandle
+ mDefaultAccountHandle, // phoneAccountHandle
+ NO_VIDEO_STATE, // callVideoState
+ POST_DIAL_STRING // postDialDigits
+ );
+ mCallLogManager.onCallStateChanged(fakeCall, CallState.DIALING, CallState.DISCONNECTED);
+ verifyNoInsertion();
+ mCallLogManager.onCallStateChanged(fakeCall, CallState.DIALING, CallState.ABORTED);
+ verifyNoInsertion();
+ }
+
+ public void testDontLogChoosingAccountCall() {
+ Call fakeCall = makeFakeCall(
+ DisconnectCause.OTHER, // disconnectCauseCode
+ false, // isConference
+ false, // isIncoming
+ 1L, // creationTimeMillis
+ 1000L, // ageMillis
+ TEL_PHONEHANDLE, // callHandle
+ mDefaultAccountHandle, // phoneAccountHandle
+ NO_VIDEO_STATE, // callVideoState
+ POST_DIAL_STRING // postDialDigits
+ );
+ mCallLogManager.onCallStateChanged(fakeCall, CallState.SELECT_PHONE_ACCOUNT,
+ CallState.DISCONNECTED);
+ verifyNoInsertion();
+ }
+
+ public void testDontLogCallsFromEmergencyAccount() {
+ mComponentContextFixture.putBooleanResource(R.bool.allow_emergency_numbers_in_call_log,
+ false);
+ Call fakeCall = makeFakeCall(
+ DisconnectCause.OTHER, // disconnectCauseCode
+ false, // isConference
+ false, // isIncoming
+ 1L, // creationTimeMillis
+ 1000L, // ageMillis
+ TEL_PHONEHANDLE, // callHandle
+ EMERGENCY_ACCT_HANDLE, // phoneAccountHandle
+ NO_VIDEO_STATE, // callVideoState
+ POST_DIAL_STRING // postDialDigits
+ );
+ mCallLogManager.onCallStateChanged(fakeCall, CallState.ACTIVE, CallState.DISCONNECTED);
+ verifyNoInsertion();
+ }
+
+ public void testLogCallDirectionOutgoing() {
+ Call fakeOutgoingCall = makeFakeCall(
+ DisconnectCause.OTHER, // disconnectCauseCode
+ false, // isConference
+ false, // isIncoming
+ 1L, // creationTimeMillis
+ 1000L, // ageMillis
+ TEL_PHONEHANDLE, // callHandle
+ mDefaultAccountHandle, // phoneAccountHandle
+ NO_VIDEO_STATE, // callVideoState
+ POST_DIAL_STRING // postDialDigits
+ );
+ mCallLogManager.onCallStateChanged(fakeOutgoingCall, CallState.ACTIVE,
+ CallState.DISCONNECTED);
+ ContentValues insertedValues = verifyInsertionWithCapture();
+ assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE),
+ Integer.valueOf(CallLog.Calls.OUTGOING_TYPE));
+ }
+
+ public void testLogCallDirectionIncoming() {
+ Call fakeIncomingCall = makeFakeCall(
+ DisconnectCause.OTHER, // disconnectCauseCode
+ false, // isConference
+ true, // isIncoming
+ 1L, // creationTimeMillis
+ 1000L, // ageMillis
+ TEL_PHONEHANDLE, // callHandle
+ mDefaultAccountHandle, // phoneAccountHandle
+ NO_VIDEO_STATE, // callVideoState
+ POST_DIAL_STRING // postDialDigits
+ );
+ mCallLogManager.onCallStateChanged(fakeIncomingCall, CallState.ACTIVE,
+ CallState.DISCONNECTED);
+ ContentValues insertedValues = verifyInsertionWithCapture();
+ assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE),
+ Integer.valueOf(CallLog.Calls.INCOMING_TYPE));
+ }
+
+ public void testLogCallDirectionMissed() {
+ Call fakeMissedCall = makeFakeCall(
+ DisconnectCause.MISSED, // disconnectCauseCode
+ false, // isConference
+ true, // isIncoming
+ 1L, // creationTimeMillis
+ 1000L, // ageMillis
+ TEL_PHONEHANDLE, // callHandle
+ mDefaultAccountHandle, // phoneAccountHandle
+ NO_VIDEO_STATE, // callVideoState
+ POST_DIAL_STRING // postDialDigits
+ );
+
+ mCallLogManager.onCallStateChanged(fakeMissedCall, CallState.ACTIVE,
+ CallState.DISCONNECTED);
+ ContentValues insertedValues = verifyInsertionWithCapture();
+ assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE),
+ Integer.valueOf(CallLog.Calls.MISSED_TYPE));
+ }
+
+ public void testCreationTimeAndAge() {
+ long currentTime = System.currentTimeMillis();
+ long duration = 1000L;
+ Call fakeCall = makeFakeCall(
+ DisconnectCause.OTHER, // disconnectCauseCode
+ false, // isConference
+ false, // isIncoming
+ currentTime, // creationTimeMillis
+ duration, // ageMillis
+ TEL_PHONEHANDLE, // callHandle
+ mDefaultAccountHandle, // phoneAccountHandle
+ NO_VIDEO_STATE, // callVideoState
+ POST_DIAL_STRING // postDialDigits
+ );
+ mCallLogManager.onCallStateChanged(fakeCall, CallState.ACTIVE, CallState.DISCONNECTED);
+ ContentValues insertedValues = verifyInsertionWithCapture();
+ assertEquals(insertedValues.getAsLong(CallLog.Calls.DATE),
+ Long.valueOf(currentTime));
+ assertEquals(insertedValues.getAsLong(CallLog.Calls.DURATION),
+ Long.valueOf(duration / 1000));
+ }
+
+ public void testLogPhoneAccountId() {
+ Call fakeCall = makeFakeCall(
+ DisconnectCause.OTHER, // disconnectCauseCode
+ false, // isConference
+ true, // isIncoming
+ 1L, // creationTimeMillis
+ 1000L, // ageMillis
+ TEL_PHONEHANDLE, // callHandle
+ mDefaultAccountHandle, // phoneAccountHandle
+ NO_VIDEO_STATE, // callVideoState
+ POST_DIAL_STRING // postDialDigits
+ );
+ mCallLogManager.onCallStateChanged(fakeCall, CallState.ACTIVE, CallState.DISCONNECTED);
+ ContentValues insertedValues = verifyInsertionWithCapture();
+ assertEquals(insertedValues.getAsString(CallLog.Calls.PHONE_ACCOUNT_ID),
+ TEST_PHONE_ACCOUNT_ID);
+ }
+
+ public void testLogCorrectPhoneNumber() {
+ Call fakeCall = makeFakeCall(
+ DisconnectCause.OTHER, // disconnectCauseCode
+ false, // isConference
+ true, // isIncoming
+ 1L, // creationTimeMillis
+ 1000L, // ageMillis
+ TEL_PHONEHANDLE, // callHandle
+ mDefaultAccountHandle, // phoneAccountHandle
+ NO_VIDEO_STATE, // callVideoState
+ POST_DIAL_STRING // postDialDigits
+ );
+ mCallLogManager.onCallStateChanged(fakeCall, CallState.ACTIVE, CallState.DISCONNECTED);
+ ContentValues insertedValues = verifyInsertionWithCapture();
+ assertEquals(insertedValues.getAsString(CallLog.Calls.NUMBER),
+ TEL_PHONEHANDLE.getSchemeSpecificPart());
+ assertEquals(insertedValues.getAsString(CallLog.Calls.POST_DIAL_DIGITS), POST_DIAL_STRING);
+ }
+
+ public void testLogCallVideoFeatures() {
+ Call fakeVideoCall = makeFakeCall(
+ DisconnectCause.OTHER, // disconnectCauseCode
+ false, // isConference
+ true, // isIncoming
+ 1L, // creationTimeMillis
+ 1000L, // ageMillis
+ TEL_PHONEHANDLE, // callHandle
+ mDefaultAccountHandle, // phoneAccountHandle
+ BIDIRECTIONAL_VIDEO_STATE, // callVideoState
+ POST_DIAL_STRING // postDialDigits
+ );
+ mCallLogManager.onCallStateChanged(fakeVideoCall, CallState.ACTIVE, CallState.DISCONNECTED);
+ ContentValues insertedValues = verifyInsertionWithCapture();
+ assertTrue((insertedValues.getAsInteger(CallLog.Calls.FEATURES)
+ & CallLog.Calls.FEATURES_VIDEO) == CallLog.Calls.FEATURES_VIDEO);
+ }
+
+ private void verifyNoInsertion() {
+ try {
+ verify(mContentProvider, timeout(TEST_TIMEOUT_MILLIS).never()).insert(any(String.class),
+ any(Uri.class), any(ContentValues.class));
+ } catch (android.os.RemoteException e) {
+ fail("Remote exception occurred during test execution");
+ }
+ }
+
+ private ContentValues verifyInsertionWithCapture() {
+ ArgumentCaptor<ContentValues> captor = ArgumentCaptor.forClass(ContentValues.class);
+ try {
+ verify(mContentProvider, timeout(TEST_TIMEOUT_MILLIS)).insert(any(String.class),
+ eq(CallLog.Calls.CONTENT_URI), captor.capture());
+ } catch (android.os.RemoteException e) {
+ fail("Remote exception occurred during test execution");
+ }
+
+ return captor.getValue();
+ }
+
+
+ private Call makeFakeCall(int disconnectCauseCode, boolean isConference, boolean isIncoming,
+ long creationTimeMillis, long ageMillis, Uri callHandle,
+ PhoneAccountHandle phoneAccountHandle, int callVideoState,
+ String postDialDigits) {
+ Call fakeCall = mock(Call.class);
+ when(fakeCall.getDisconnectCause()).thenReturn(
+ new DisconnectCause(disconnectCauseCode));
+ when(fakeCall.isConference()).thenReturn(isConference);
+ when(fakeCall.isIncoming()).thenReturn(isIncoming);
+ when(fakeCall.getCreationTimeMillis()).thenReturn(creationTimeMillis);
+ when(fakeCall.getAgeMillis()).thenReturn(ageMillis);
+ when(fakeCall.getOriginalHandle()).thenReturn(callHandle);
+ when(fakeCall.getTargetPhoneAccount()).thenReturn(phoneAccountHandle);
+ when(fakeCall.getVideoStateHistory()).thenReturn(callVideoState);
+ when(fakeCall.getPostDialDigits()).thenReturn(postDialDigits);
+
+ return fakeCall;
+ }
+}
diff --git a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
index 3294923..5a932d9 100644
--- a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
@@ -187,7 +187,7 @@
@Override
protected IContentProvider acquireProvider(Context c, String name) {
Log.i(this, "acquireProvider %s", name);
- return mock(IContentProvider.class);
+ return mContentProvider;
}
@Override
@@ -198,7 +198,7 @@
@Override
protected IContentProvider acquireUnstableProvider(Context c, String name) {
Log.i(this, "acquireUnstableProvider %s", name);
- return mock(IContentProvider.class);
+ return mContentProvider;
}
@Override
@@ -354,6 +354,7 @@
private final StatusBarManager mStatusBarManager = mock(StatusBarManager.class);
private final SubscriptionManager mSubscriptionManager = mock(SubscriptionManager.class);
private final CarrierConfigManager mCarrierConfigManager = mock(CarrierConfigManager.class);
+ private final IContentProvider mContentProvider = mock(IContentProvider.class);
private final Configuration mResourceConfiguration = new Configuration();
private TelecomManager mTelecomManager = null;
@@ -442,6 +443,10 @@
});
}
+ public void putBooleanResource(int id, boolean value) {
+ when(mResources.getBoolean(eq(id))).thenReturn(value);
+ }
+
public void setTelecomManager(TelecomManager telecomManager) {
mTelecomManager = telecomManager;
}