am b788ac53: (-s ours) am 3279c8bb: (-s ours) Import translations. DO NOT MERGE
* commit 'b788ac5367be4805461f025ab568eb44b74a9e5f':
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index ac3799f..56a594b 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -20,6 +20,9 @@
coreApp="true"
android:sharedUserId="android.uid.system">
+
+ <protected-broadcast android:name="android.intent.action.SHOW_MISSED_CALLS_NOTIFICATION" />
+
<!-- Prevents the activity manager from delaying any activity-start
requests by this package, including requests immediately after
the user presses "home". -->
@@ -88,6 +91,7 @@
URL with the schemes "tel", "sip", and "voicemail". It also handles URLs linked to
contacts provider entries. Any data not fitting the schema described is ignored. -->
<activity android:name=".components.UserCallActivity"
+ android:label="@string/userCallActivityLabel"
android:theme="@style/Theme.Telecomm.Transparent"
android:permission="android.permission.CALL_PHONE"
android:excludeFromRecents="true"
diff --git a/res/values/config.xml b/res/values/config.xml
index 365e758..e474d7e 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -38,4 +38,8 @@
<!-- Flag indicating if the tty is enabled -->
<bool name="tty_enabled">false</bool>
+
+ <!-- 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>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 8f73377..26df574 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -18,7 +18,11 @@
<!-- Official label of the Telecomm/Phone app, as seen in "Manage Applications"
and other settings UIs. This is the "app name" used in notification, recents,
and app info screens. -->
- <string name="telecommAppLabel" product="default">Phone - Call Management</string>
+ <string name="telecommAppLabel" product="default">Phone Call Management</string>
+
+ <!-- Title used for the activity for placing a call. This name appears
+ in activity disambig dialogs -->
+ <string name="userCallActivityLabel" product="default">Phone</string>
<!-- Name for an "unknown" caller. -->
<string name="unknown">Unknown</string>
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index dfe5849..91f7c4f 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -48,6 +48,7 @@
import com.android.server.telecom.ContactsAsyncHelper.OnImageLoadCompleteListener;
import com.android.internal.util.Preconditions;
+import java.lang.String;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
@@ -365,7 +366,6 @@
mContactsAsyncHelper = contactsAsyncHelper;
mCallerInfoAsyncQueryFactory = callerInfoAsyncQueryFactory;
setHandle(handle);
- setHandle(handle, TelecomManager.PRESENTATION_ALLOWED);
mGatewayInfo = gatewayInfo;
setConnectionManagerPhoneAccount(connectionManagerPhoneAccountHandle);
setTargetPhoneAccount(targetPhoneAccountHandle);
@@ -634,8 +634,12 @@
}
}
- mIsEmergencyCall = mHandle != null && PhoneNumberUtils.isLocalEmergencyNumber(mContext,
- mHandle.getSchemeSpecificPart());
+ // Let's not allow resetting of the emergency flag. Once a call becomes an emergency
+ // call, it will remain so for the rest of it's lifetime.
+ if (!mIsEmergencyCall) {
+ mIsEmergencyCall = mHandle != null && PhoneNumberUtils.isLocalEmergencyNumber(
+ mContext, mHandle.getSchemeSpecificPart());
+ }
startCallerInfoLookup();
for (Listener l : mListeners) {
l.onHandleChanged(this);
@@ -666,6 +670,10 @@
return mCallerInfo == null ? null : mCallerInfo.name;
}
+ public String getPhoneNumber() {
+ return mCallerInfo == null ? null : mCallerInfo.phoneNumber;
+ }
+
public Bitmap getPhotoIcon() {
return mCallerInfo == null ? null : mCallerInfo.cachedPhotoIcon;
}
@@ -1182,6 +1190,7 @@
if (mConnectionService == null) {
Log.w(this, "conference requested on a call without a connection service.");
} else {
+ Log.event(this, Log.Events.CONFERENCE_WITH, otherCall);
mConnectionService.conference(this, otherCall);
}
}
@@ -1190,6 +1199,7 @@
if (mConnectionService == null) {
Log.w(this, "splitting from conference call without a connection service");
} else {
+ Log.event(this, Log.Events.SPLIT_CONFERENCE);
mConnectionService.splitFromConference(this);
}
}
@@ -1198,6 +1208,7 @@
if (mConnectionService == null) {
Log.w(this, "merging conference calls without a connection service.");
} else if (can(Connection.CAPABILITY_MERGE_CONFERENCE)) {
+ Log.event(this, Log.Events.CONFERENCE_WITH);
mConnectionService.mergeConference(this);
mWasConferencePreviouslyMerged = true;
}
@@ -1207,6 +1218,7 @@
if (mConnectionService == null) {
Log.w(this, "swapping conference calls without a connection service.");
} else if (can(Connection.CAPABILITY_SWAP_CONFERENCE)) {
+ Log.event(this, Log.Events.SWAP);
mConnectionService.swapConference(this);
switch (mChildCalls.size()) {
case 1:
@@ -1245,6 +1257,7 @@
mParentCall.addChildCall(this);
}
+ Log.event(this, Log.Events.SET_PARENT, mParentCall);
for (Listener l : mListeners) {
l.onParentChanged(this);
}
@@ -1274,6 +1287,8 @@
mConferenceLevelActiveCall = call;
mChildCalls.add(call);
+ Log.event(this, Log.Events.ADD_CHILD, call);
+
for (Listener l : mListeners) {
l.onChildrenChanged(this);
}
@@ -1282,6 +1297,7 @@
private void removeChildCall(Call call) {
if (mChildCalls.remove(call)) {
+ Log.event(this, Log.Events.REMOVE_CHILD, call);
for (Listener l : mListeners) {
l.onChildrenChanged(this);
}
diff --git a/src/com/android/server/telecom/CallAudioManager.java b/src/com/android/server/telecom/CallAudioManager.java
index 452ce77..da3deb6 100644
--- a/src/com/android/server/telecom/CallAudioManager.java
+++ b/src/com/android/server/telecom/CallAudioManager.java
@@ -319,6 +319,11 @@
}
if (mCallAudioState.isMuted() != shouldMute) {
+ // We user CallsManager's foreground call so that we dont ignore ringing calls
+ // for logging purposes
+ Log.event(mCallsManager.getForegroundCall(), Log.Events.MUTE,
+ shouldMute ? "on" : "off");
+
setSystemAudioState(shouldMute, mCallAudioState.getRoute(),
mCallAudioState.getSupportedRouteMask());
}
@@ -355,12 +360,17 @@
}
}
- void setIsRinging(boolean isRinging) {
+ /**
+ * Sets the audio stream and mode based on whether a call is ringing.
+ *
+ * @param call The call which changed ringing state.
+ * @param isRinging {@code true} if the call is ringing, {@code false} otherwise.
+ */
+ void setIsRinging(Call call, boolean isRinging) {
if (mIsRinging != isRinging) {
- Log.i(this, "setIsRinging %b -> %b", mIsRinging, isRinging);
+ Log.i(this, "setIsRinging %b -> %b (call = %s)", mIsRinging, isRinging, call);
mIsRinging = isRinging;
-
- updateAudioStreamAndMode();
+ updateAudioStreamAndMode(call);
}
}
@@ -440,7 +450,10 @@
if (!force && Objects.equals(oldAudioState, mCallAudioState)) {
return;
}
+
Log.i(this, "setSystemAudioState: changing from %s to %s", oldAudioState, mCallAudioState);
+ Log.event(mCallsManager.getForegroundCall(), Log.Events.AUDIO_ROUTE,
+ CallAudioState.audioRouteToString(mCallAudioState.getRoute()));
mAudioManagerHandler.obtainMessage(
MSG_AUDIO_MANAGER_SET_MICROPHONE_MUTE,
diff --git a/src/com/android/server/telecom/CallIntentProcessor.java b/src/com/android/server/telecom/CallIntentProcessor.java
index cfec90c..a6840b9 100644
--- a/src/com/android/server/telecom/CallIntentProcessor.java
+++ b/src/com/android/server/telecom/CallIntentProcessor.java
@@ -8,6 +8,7 @@
import android.os.Bundle;
import android.os.Trace;
import android.os.UserHandle;
+import android.telecom.Connection;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
@@ -87,6 +88,12 @@
clientExtras = new Bundle();
}
+ // Ensure call subject is passed on to the connection service.
+ if (intent.hasExtra(TelecomManager.EXTRA_CALL_SUBJECT)) {
+ String callsubject = intent.getStringExtra(TelecomManager.EXTRA_CALL_SUBJECT);
+ clientExtras.putString(TelecomManager.EXTRA_CALL_SUBJECT, callsubject);
+ }
+
final boolean isPrivilegedDialer = intent.getBooleanExtra(KEY_IS_PRIVILEGED_DIALER, false);
// Send to CallsManager to ensure the InCallUI gets kicked off before the broadcast returns
diff --git a/src/com/android/server/telecom/CallLogManager.java b/src/com/android/server/telecom/CallLogManager.java
index 2007f6e..1fe491e 100755
--- a/src/com/android/server/telecom/CallLogManager.java
+++ b/src/com/android/server/telecom/CallLogManager.java
@@ -148,7 +148,8 @@
// TODO(vt): Once data usage is available, wire it up here.
int callFeatures = getCallFeatures(call.getVideoStateHistory());
logCall(call.getCallerInfo(), logNumber, call.getHandlePresentation(),
- callLogType, callFeatures, accountHandle, creationTime, age, null);
+ callLogType, callFeatures, accountHandle, creationTime, age, null,
+ call.isEmergencyCall());
}
/**
@@ -162,6 +163,7 @@
* @param start The start time of the call, in milliseconds.
* @param duration The duration of the call, in milliseconds.
* @param dataUsage The data usage for the call, null if not applicable.
+ * @param isEmergency {@code true} if this is an emergency call, {@code false} otherwise.
*/
private void logCall(
CallerInfo callerInfo,
@@ -172,8 +174,8 @@
PhoneAccountHandle accountHandle,
long start,
long duration,
- Long dataUsage) {
- boolean isEmergencyNumber = PhoneNumberUtils.isLocalEmergencyNumber(mContext, number);
+ Long dataUsage,
+ boolean isEmergency) {
// 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
@@ -182,7 +184,7 @@
mContext.getResources().getBoolean(R.bool.allow_emergency_numbers_in_call_log);
// Don't log emergency numbers if the device doesn't allow it.
- final boolean isOkToLogThisCall = !isEmergencyNumber || okToLogEmergencyNumber;
+ final boolean isOkToLogThisCall = !isEmergency || okToLogEmergencyNumber;
sendAddCallBroadcast(callType, duration);
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 297afa8..5d00924 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -590,9 +590,19 @@
Log.v(this, "startOutgoingCall found accounts = " + accounts);
- if (mForegroundCall != null && mForegroundCall.getTargetPhoneAccount() != null) {
+ if (mForegroundCall != null) {
+ Call ongoingCall = mForegroundCall;
// If there is an ongoing call, use the same phone account to place this new call.
- phoneAccountHandle = mForegroundCall.getTargetPhoneAccount();
+ // If the ongoing call is a conference call, we fetch the phone account from the
+ // child calls because we don't have targetPhoneAccount set on Conference calls.
+ // TODO: Set targetPhoneAccount for all conference calls (b/23035408).
+ if (ongoingCall.getTargetPhoneAccount() == null &&
+ !ongoingCall.getChildCalls().isEmpty()) {
+ ongoingCall = ongoingCall.getChildCalls().get(0);
+ }
+ if (ongoingCall.getTargetPhoneAccount() != null) {
+ phoneAccountHandle = ongoingCall.getTargetPhoneAccount();
+ }
}
// Only dial with the requested phoneAccount if it is still valid. Otherwise treat this call
@@ -613,13 +623,11 @@
call.setTargetPhoneAccount(phoneAccountHandle);
- boolean isEmergencyCall = TelephonyUtil.shouldProcessAsEmergency(mContext,
- call.getHandle());
boolean isPotentialInCallMMICode = isPotentialInCallMMICode(handle);
// Do not support any more live calls. Our options are to move a call to hold, disconnect
// a call, or cancel this call altogether.
- if (!isPotentialInCallMMICode && !makeRoomForOutgoingCall(call, isEmergencyCall)) {
+ if (!isPotentialInCallMMICode && !makeRoomForOutgoingCall(call, call.isEmergencyCall())) {
// just cancel at this point.
Log.i(this, "No remaining room for outgoing call: %s", call);
if (mCalls.contains(call)) {
@@ -631,7 +639,7 @@
}
boolean needsAccountSelection = phoneAccountHandle == null && accounts.size() > 1 &&
- !isEmergencyCall;
+ !call.isEmergencyCall();
if (needsAccountSelection) {
// This is the state where the user is expected to select an account
@@ -696,14 +704,12 @@
}
call.setStartWithSpeakerphoneOn(speakerphoneOn || mDockManager.isDocked());
- boolean isEmergencyCall = TelephonyUtil.shouldProcessAsEmergency(mContext,
- call.getHandle());
- if (isEmergencyCall) {
+ if (call.isEmergencyCall()) {
// Emergency -- CreateConnectionProcessor will choose accounts automatically
call.setTargetPhoneAccount(null);
}
- if (call.getTargetPhoneAccount() != null || isEmergencyCall) {
+ if (call.getTargetPhoneAccount() != null || call.isEmergencyCall()) {
// If the account has been set, proceed to place the outgoing call.
// Otherwise the connection will be initiated when the account is set by the user.
call.startCreateConnection(mPhoneAccountRegistrar);
@@ -1070,6 +1076,14 @@
if (call.isEmergencyCall()) {
// We never support add call if one of the calls is an emergency call.
return false;
+ } else if (!call.getChildCalls().isEmpty() && !call.can(Connection.CAPABILITY_HOLD)) {
+ // This is to deal with CDMA conference calls. CDMA conference calls do not
+ // allow the addition of another call when it is already in a 3 way conference.
+ // So, we detect that it is a CDMA conference call by checking if the call has
+ // some children and it does not support the CAPABILILTY_HOLD
+ // TODO: This maybe cleaner if the lower layers can explicitly signal to telecom
+ // about this limitation (b/22880180).
+ return false;
} else if (call.getParentCall() == null) {
count++;
}
@@ -1486,10 +1500,27 @@
// We have room for at least one more holding call at this point.
+ // TODO: Remove once b/23035408 has been corrected.
+ // If the live call is a conference, it will not have a target phone account set. This
+ // means the check to see if the live call has the same target phone account as the new
+ // call will not cause us to bail early. As a result, we'll end up holding the
+ // ongoing conference call. However, the ConnectionService is already doing that. This
+ // has caused problems with some carriers. As a workaround until b/23035408 is
+ // corrected, we will try and get the target phone account for one of the conference's
+ // children and use that instead.
+ PhoneAccountHandle liveCallPhoneAccount = liveCall.getTargetPhoneAccount();
+ if (liveCallPhoneAccount == null && liveCall.isConference() &&
+ !liveCall.getChildCalls().isEmpty()) {
+ liveCallPhoneAccount = getFirstChildPhoneAccount(liveCall);
+ Log.i(this, "makeRoomForOutgoingCall: using child call PhoneAccount = " +
+ liveCallPhoneAccount);
+ }
+
// First thing, if we are trying to make a call with the same phone account as the live
// call, then allow it so that the connection service can make its own decision about
// how to handle the new call relative to the current one.
- if (Objects.equals(liveCall.getTargetPhoneAccount(), call.getTargetPhoneAccount())) {
+ if (Objects.equals(liveCallPhoneAccount, call.getTargetPhoneAccount())) {
+ Log.i(this, "makeRoomForOutgoingCall: phoneAccount matches.");
return true;
} else if (call.getTargetPhoneAccount() == null) {
// Without a phone account, we can't say reliably that the call will fail.
@@ -1503,6 +1534,7 @@
// Try to hold the live call before attempting the new outgoing call.
if (liveCall.can(Connection.CAPABILITY_HOLD)) {
+ Log.i(this, "makeRoomForOutgoingCall: holding live call.");
liveCall.hold();
return true;
}
@@ -1514,6 +1546,22 @@
}
/**
+ * Given a call, find the first non-null phone account handle of its children.
+ *
+ * @param parentCall The parent call.
+ * @return The first non-null phone account handle of the children, or {@code null} if none.
+ */
+ private PhoneAccountHandle getFirstChildPhoneAccount(Call parentCall) {
+ for (Call childCall : parentCall.getChildCalls()) {
+ PhoneAccountHandle childPhoneAccount = childCall.getTargetPhoneAccount();
+ if (childPhoneAccount != null) {
+ return childPhoneAccount;
+ }
+ }
+ return null;
+ }
+
+ /**
* Checks to see if the call should be on speakerphone and if so, set it.
*/
private void maybeMoveToSpeakerPhone(Call call) {
@@ -1543,7 +1591,8 @@
null /* connectionManagerPhoneAccount */,
connection.getPhoneAccount(), /* targetPhoneAccountHandle */
false /* isIncoming */,
- false /* isConference */);
+ false /* isConference */,
+ connection.getConnectTimeMillis() /* connectTimeMillis */);
setCallState(call, Call.getStateFromConnectionState(connection.getState()),
"existing connection");
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index 96e9255..d5ab5cf 100644
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -663,6 +663,7 @@
gatewayInfo.getOriginalAddress());
}
+ Log.event(call, Log.Events.START_CONNECTION, Log.piiHandle(call.getHandle()));
try {
mServiceInterface.createConnection(
call.getConnectionManagerPhoneAccount(),
@@ -688,7 +689,7 @@
}
};
- mBinder.bind(callback);
+ mBinder.bind(callback, call);
}
/** @see IConnectionService#abort(String) */
@@ -1018,7 +1019,7 @@
setRemoteServices(callback, simServiceComponentNames, simServiceBinders);
}
}
- });
+ }, null);
}
}
diff --git a/src/com/android/server/telecom/CreateConnectionProcessor.java b/src/com/android/server/telecom/CreateConnectionProcessor.java
index a804fe1..b846470 100644
--- a/src/com/android/server/telecom/CreateConnectionProcessor.java
+++ b/src/com/android/server/telecom/CreateConnectionProcessor.java
@@ -206,7 +206,6 @@
mCall.setConnectionService(service);
setTimeoutIfNeeded(service, attempt);
- Log.i(this, "Attempting to call from %s", service.getComponentName());
service.createConnection(mCall, new Response(service));
}
} else {
@@ -298,7 +297,7 @@
// If we are possibly attempting to call a local emergency number, ensure that the
// plain PSTN connection services are listed, and nothing else.
private void adjustAttemptsForEmergency() {
- if (TelephonyUtil.shouldProcessAsEmergency(mContext, mCall.getHandle())) {
+ if (mCall.isEmergencyCall()) {
Log.i(this, "Emergency number detected");
mAttemptRecords.clear();
List<PhoneAccount> allAccounts = mPhoneAccountRegistrar.getAllPhoneAccounts();
diff --git a/src/com/android/server/telecom/CreateConnectionTimeout.java b/src/com/android/server/telecom/CreateConnectionTimeout.java
index 45305d5..8acc2b4 100644
--- a/src/com/android/server/telecom/CreateConnectionTimeout.java
+++ b/src/com/android/server/telecom/CreateConnectionTimeout.java
@@ -53,7 +53,7 @@
boolean isTimeoutNeededForCall(Collection<PhoneAccountHandle> accounts,
PhoneAccountHandle currentAccount) {
// Non-emergency calls timeout automatically at the radio layer. No need for a timeout here.
- if (!TelephonyUtil.shouldProcessAsEmergency(mContext, mCall.getHandle())) {
+ if (!mCall.isEmergencyCall()) {
return false;
}
diff --git a/src/com/android/server/telecom/Log.java b/src/com/android/server/telecom/Log.java
index d605a8f..f0ee3fe 100644
--- a/src/com/android/server/telecom/Log.java
+++ b/src/com/android/server/telecom/Log.java
@@ -70,6 +70,17 @@
public static final String STOP_RINGER = "STOP_RINGER";
public static final String START_CALL_WAITING_TONE = "START_CALL_WAITING_TONE";
public static final String STOP_CALL_WAITING_TONE = "STOP_CALL_WAITING_TONE";
+ public static final String START_CONNECTION = "START_CONNECTION";
+ public static final String BIND_CS = "BIND_CS";
+ public static final String CS_BOUND = "CS_BOUND";
+ public static final String CONFERENCE_WITH = "CONF_WITH";
+ public static final String SPLIT_CONFERENCE = "CONF_SPLIT";
+ public static final String SWAP = "SWAP";
+ public static final String ADD_CHILD = "ADD_CHILD";
+ public static final String REMOVE_CHILD = "REMOVE_CHILD";
+ public static final String SET_PARENT = "SET_PARENT";
+ public static final String MUTE = "MUTE";
+ public static final String AUDIO_ROUTE = "AUDIO_ROUTE";
public static final String ERROR_LOG = "ERROR";
/**
@@ -85,6 +96,8 @@
put(REQUEST_DISCONNECT, SET_DISCONNECTED);
put(REQUEST_HOLD, SET_HOLD);
put(REQUEST_UNHOLD, SET_ACTIVE);
+ put(START_CONNECTION, SET_DIALING);
+ put(BIND_CS, CS_BOUND);
}};
}
@@ -154,7 +167,18 @@
pw.print(event.eventId);
if (event.data != null) {
pw.print(" (");
- pw.print(event.data);
+ Object data = event.data;
+
+ if (data instanceof Call) {
+ // If the data is another call, then change the data to the call's CallEvent
+ // ID instead.
+ CallEventRecord record = mCallEventRecordMap.get(data);
+ if (record != null) {
+ data = "Call " + record.mId;
+ }
+ }
+
+ pw.print(data);
pw.print(")");
}
diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java
index e9fa52a..65847b8 100644
--- a/src/com/android/server/telecom/PhoneAccountRegistrar.java
+++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java
@@ -16,6 +16,7 @@
package com.android.server.telecom;
+import android.app.ActivityManager;
import android.Manifest;
import android.content.ComponentName;
import android.content.Context;
@@ -120,7 +121,7 @@
private static final String FILE_NAME = "phone-account-registrar-state.xml";
@VisibleForTesting
- public static final int EXPECTED_STATE_VERSION = 7;
+ public static final int EXPECTED_STATE_VERSION = 8;
/** Keep in sync with the same in SipSettings.java */
private static final String SIP_SHARED_PREFERENCES = "SIP_PREFERENCES";
@@ -275,8 +276,28 @@
* 3. Otherwise, we return null.
*/
public PhoneAccountHandle getSimCallManager() {
+ long token = Binder.clearCallingIdentity();
+ int user;
+ try {
+ user = ActivityManager.getCurrentUser();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ return getSimCallManager(user);
+ }
+
+ /**
+ * Returns the {@link PhoneAccountHandle} corresponding to the currently active SIM Call
+ * Manager. SIM Call Manager returned corresponds to the following priority order:
+ * 1. If a SIM Call Manager {@link PhoneAccount} is registered for the same package as the
+ * default dialer, then that one is returned.
+ * 2. If there is a SIM Call Manager {@link PhoneAccount} registered which matches the
+ * carrier configuration's default, then that one is returned.
+ * 3. Otherwise, we return null.
+ */
+ public PhoneAccountHandle getSimCallManager(int user) {
// Get the default dialer in case it has a connection manager associated with it.
- String dialerPackage = DefaultDialerManager.getDefaultDialerApplication(mContext);
+ String dialerPackage = DefaultDialerManager.getDefaultDialerApplication(mContext, user);
// Check carrier config.
String defaultSimCallManager = null;
@@ -602,14 +623,15 @@
StringBuffer sb = new StringBuffer();
sb.append("[").append(account1.getAccountHandle());
- appendDiff(sb, "addr", account1.getAddress(), account2.getAddress());
+ appendDiff(sb, "addr", Log.piiHandle(account1.getAddress()),
+ Log.piiHandle(account2.getAddress()));
appendDiff(sb, "cap", account1.getCapabilities(), account2.getCapabilities());
appendDiff(sb, "hl", account1.getHighlightColor(), account2.getHighlightColor());
appendDiff(sb, "icon", account1.getIcon(), account2.getIcon());
appendDiff(sb, "lbl", account1.getLabel(), account2.getLabel());
appendDiff(sb, "desc", account1.getShortDescription(), account2.getShortDescription());
- appendDiff(sb, "subAddr", account1.getSubscriptionAddress(),
- account2.getSubscriptionAddress());
+ appendDiff(sb, "subAddr", Log.piiHandle(account1.getSubscriptionAddress()),
+ Log.piiHandle(account2.getSubscriptionAddress()));
appendDiff(sb, "uris", account1.getSupportedUriSchemes(),
account2.getSupportedUriSchemes());
sb.append("]");
@@ -1238,6 +1260,18 @@
enabled = true;
}
}
+ if (version < 8) {
+ // Migrate the SIP account handle ids to use SIP username instead of SIP URI.
+ if (accountHandle.getComponentName().equals(sipComponentName)) {
+ Uri accountUri = Uri.parse(accountHandle.getId());
+ if (accountUri.getScheme() != null &&
+ accountUri.getScheme().equals(PhoneAccount.SCHEME_SIP)) {
+ accountHandle = new PhoneAccountHandle(accountHandle.getComponentName(),
+ accountUri.getSchemeSpecificPart(),
+ accountHandle.getUserHandle());
+ }
+ }
+ }
PhoneAccount.Builder builder = PhoneAccount.builder(accountHandle, label)
.setAddress(address)
diff --git a/src/com/android/server/telecom/Ringer.java b/src/com/android/server/telecom/Ringer.java
index b2ed8e7..99fb842 100644
--- a/src/com/android/server/telecom/Ringer.java
+++ b/src/com/android/server/telecom/Ringer.java
@@ -196,7 +196,7 @@
Log.event(call, Log.Events.START_RINGER);
mState = STATE_RINGING;
}
- mCallAudioManager.setIsRinging(true);
+ mCallAudioManager.setIsRinging(call, true);
// Because we wait until a contact info query to complete before processing a
// call (for the purposes of direct-to-voicemail), the information about custom
@@ -261,7 +261,7 @@
// Even though stop is asynchronous it's ok to update the audio manager. Things like audio
// focus are voluntary so releasing focus too early is not detrimental.
- mCallAudioManager.setIsRinging(false);
+ mCallAudioManager.setIsRinging(call, false);
}
private void stopCallWaiting(Call call) {
diff --git a/src/com/android/server/telecom/ServiceBinder.java b/src/com/android/server/telecom/ServiceBinder.java
index 4edb4e5..2e63512 100644
--- a/src/com/android/server/telecom/ServiceBinder.java
+++ b/src/com/android/server/telecom/ServiceBinder.java
@@ -62,8 +62,9 @@
* specified callback.
*
* @param callback The callback to notify of the binding's success or failure.
+ * @param call The call for which we are being bound.
*/
- void bind(BindCallback callback) {
+ void bind(BindCallback callback, Call call) {
Log.d(ServiceBinder.this, "bind()");
// Reset any abort request if we're asked to bind again.
@@ -78,9 +79,9 @@
mCallbacks.add(callback);
if (mServiceConnection == null) {
Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);
- ServiceConnection connection = new ServiceBinderConnection();
+ ServiceConnection connection = new ServiceBinderConnection(call);
- Log.d(ServiceBinder.this, "Binding to service with intent: %s", serviceIntent);
+ Log.event(call, Log.Events.BIND_CS, mComponentName);
final int bindingFlags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
final boolean isBound;
if (mUserHandle != null) {
@@ -102,11 +103,23 @@
}
private final class ServiceBinderConnection implements ServiceConnection {
+ /**
+ * The initial call for which the service was bound.
+ */
+ private Call mCall;
+
+ ServiceBinderConnection(Call call) {
+ mCall = call;
+ }
+
@Override
public void onServiceConnected(ComponentName componentName, IBinder binder) {
synchronized (mLock) {
Log.i(this, "Service bound %s", componentName);
+ Log.event(mCall, Log.Events.CS_BOUND, componentName);
+ mCall = null;
+
// Unbind request was queued so unbind immediately.
if (mIsBindingAborted) {
clearAbort();
diff --git a/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java b/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java
index 2b22ea9..89aa2aa 100644
--- a/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java
+++ b/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java
@@ -56,7 +56,7 @@
Intent callIntent = new Intent(Intent.ACTION_SENDTO, intent.getData());
callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivity(callIntent);
+ mContext.startActivityAsUser(callIntent, UserHandle.CURRENT);
// Call back recent caller from the missed call notification.
} else if (ACTION_CALL_BACK_FROM_NOTIFICATION.equals(action)) {
@@ -67,7 +67,7 @@
Intent callIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED, intent.getData());
callIntent.setFlags(
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- mContext.startActivity(callIntent);
+ mContext.startActivityAsUser(callIntent, UserHandle.CURRENT);
// Clear the missed call notification and call log entries.
} else if (ACTION_CLEAR_MISSED_CALLS.equals(action)) {
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 9c5e529..5c498c0 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -19,6 +19,7 @@
import static android.Manifest.permission.CALL_PHONE;
import static android.Manifest.permission.MODIFY_PHONE_STATE;
import static android.Manifest.permission.READ_PHONE_STATE;
+import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
import static android.Manifest.permission.REGISTER_SIM_SUBSCRIPTION;
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
@@ -255,13 +256,25 @@
@Override
public PhoneAccountHandle getSimCallManager() {
+ long token = Binder.clearCallingIdentity();
+ int user;
+ try {
+ user = ActivityManager.getCurrentUser();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ return getSimCallManagerForUser(user);
+ }
+
+ @Override
+ public PhoneAccountHandle getSimCallManagerForUser(int user) {
synchronized (mLock) {
try {
PhoneAccountHandle accountHandle = null;
long token = Binder.clearCallingIdentity();
try {
- accountHandle = mPhoneAccountRegistrar.getSimCallManager();
+ accountHandle = mPhoneAccountRegistrar.getSimCallManager(user);
} finally {
// We restore early so that isVisibleToCaller invocation below uses the
// right user context.
@@ -1110,12 +1123,19 @@
return true;
}
- // Accessing phone state is gated by a special permission.
- mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, message);
+ try {
+ mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, message);
+ // SKIP checking run-time OP_READ_PHONE_STATE since caller or self has PRIVILEGED
+ // permission
+ return true;
+ } catch (SecurityException e) {
+ // Accessing phone state is gated by a special permission.
+ mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, message);
- // Some apps that have the permission can be restricted via app ops.
- return mAppOpsManager.noteOp(AppOpsManager.OP_READ_PHONE_STATE,
- Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED;
+ // Some apps that have the permission can be restricted via app ops.
+ return mAppOpsManager.noteOp(AppOpsManager.OP_READ_PHONE_STATE,
+ Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED;
+ }
}
private boolean canCallPhone(String callingPackage, String message) {
diff --git a/src/com/android/server/telecom/TelephonyUtil.java b/src/com/android/server/telecom/TelephonyUtil.java
index 5827e73..5f43ee9 100644
--- a/src/com/android/server/telecom/TelephonyUtil.java
+++ b/src/com/android/server/telecom/TelephonyUtil.java
@@ -28,8 +28,6 @@
* differently from 3rd party services in some situations (emergency calls, audio focus, etc...).
*/
public final class TelephonyUtil {
- private static final String TAG = TelephonyUtil.class.getSimpleName();
-
private static final String TELEPHONY_PACKAGE_NAME = "com.android.phone";
private static final String PSTN_CALL_SERVICE_CLASS_NAME =
@@ -63,7 +61,7 @@
}
public static boolean shouldProcessAsEmergency(Context context, Uri handle) {
- return handle != null && PhoneNumberUtils.isPotentialLocalEmergencyNumber(
+ return handle != null && PhoneNumberUtils.isLocalEmergencyNumber(
context, handle.getSchemeSpecificPart());
}
}
diff --git a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
index 300137f..ef16e59 100644
--- a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
+++ b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
@@ -16,6 +16,8 @@
package com.android.server.telecom.ui;
+import android.content.ComponentName;
+import android.telecom.TelecomManager;
import com.android.server.telecom.Call;
import com.android.server.telecom.CallState;
import com.android.server.telecom.CallerInfoAsyncQueryFactory;
@@ -54,6 +56,9 @@
import android.text.TextDirectionHeuristics;
import android.text.TextUtils;
+import java.lang.Override;
+import java.lang.String;
+
// TODO: Needed for move to system service: import com.android.internal.R;
/**
@@ -89,6 +94,8 @@
private final Context mContext;
private final NotificationManager mNotificationManager;
+ private final ComponentName mNotificationComponent;
+
// Used to track the number of missed calls.
private int mMissedCallCount = 0;
@@ -96,6 +103,10 @@
mContext = context;
mNotificationManager =
(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ final String notificationComponent = context.getString(R.string.notification_component);
+
+ mNotificationComponent = notificationComponent != null
+ ? ComponentName.unflattenFromString(notificationComponent) : null;
}
/** {@inheritDoc} */
@@ -135,6 +146,44 @@
}
/**
+ * Broadcasts missed call notification to custom component if set.
+ * @param number The phone number associated with the notification. null if
+ * no call.
+ * @param count The number of calls associated with the notification.
+ * @return {@code true} if the broadcast was sent. {@code false} otherwise.
+ */
+ private boolean sendNotificationCustomComponent(Call call, int count) {
+ if (mNotificationComponent != null) {
+ Intent intent = new Intent();
+ intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ intent.setComponent(mNotificationComponent);
+ intent.setAction(TelecomManager.ACTION_SHOW_MISSED_CALLS_NOTIFICATION);
+ intent.putExtra(TelecomManager.EXTRA_NOTIFICATION_COUNT, count);
+ intent.putExtra(TelecomManager.EXTRA_NOTIFICATION_PHONE_NUMBER,
+ call != null ? call.getPhoneNumber() : null);
+ intent.putExtra(TelecomManager.EXTRA_CLEAR_MISSED_CALLS_INTENT,
+ createClearMissedCallsPendingIntent());
+
+
+ if (count == 1 && call != null) {
+ final Uri handleUri = call.getHandle();
+ String handle = handleUri == null ? null : handleUri.getSchemeSpecificPart();
+
+ if (!TextUtils.isEmpty(handle) && !TextUtils.equals(handle,
+ mContext.getString(R.string.handle_restricted))) {
+ intent.putExtra(TelecomManager.EXTRA_CALL_BACK_INTENT,
+ createCallBackPendingIntent(handleUri));
+ }
+ }
+
+ mContext.sendBroadcast(intent);
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
* Create a system notification for the missed call.
*
* @param call The missed call.
@@ -143,6 +192,10 @@
public void showMissedCallNotification(Call call) {
mMissedCallCount++;
+ if (sendNotificationCustomComponent(call, mMissedCallCount)) {
+ return;
+ }
+
final int titleResId;
final String expandedText; // The text in the notification's line 1 and 2.
@@ -218,9 +271,16 @@
private void cancelMissedCallNotification() {
// Reset the number of missed calls to 0.
mMissedCallCount = 0;
+
+
+ if (sendNotificationCustomComponent(null, mMissedCallCount)) {
+ return;
+ }
+
long token = Binder.clearCallingIdentity();
try {
- mNotificationManager.cancel(MISSED_CALL_NOTIFICATION_ID);
+ mNotificationManager.cancelAsUser(null, MISSED_CALL_NOTIFICATION_ID,
+ UserHandle.CURRENT);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -259,7 +319,7 @@
TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(mContext);
taskStackBuilder.addNextIntent(intent);
- return taskStackBuilder.getPendingIntent(0, 0);
+ return taskStackBuilder.getPendingIntent(0, 0, null, UserHandle.CURRENT);
}
/**
@@ -385,6 +445,7 @@
StringBuilder where = new StringBuilder("type=");
where.append(Calls.MISSED_TYPE);
where.append(" AND new=1");
+ where.append(" AND is_read=0");
// start the query
queryHandler.startQuery(0, null, Calls.CONTENT_URI, CALL_LOG_PROJECTION,
diff --git a/testapps/src/com/android/server/telecom/testapps/CallServiceNotifier.java b/testapps/src/com/android/server/telecom/testapps/CallServiceNotifier.java
index cd0800e..c1ced80 100644
--- a/testapps/src/com/android/server/telecom/testapps/CallServiceNotifier.java
+++ b/testapps/src/com/android/server/telecom/testapps/CallServiceNotifier.java
@@ -111,7 +111,8 @@
.setAddress(Uri.parse("tel:555-TEST"))
.setSubscriptionAddress(Uri.parse("tel:555-TEST"))
.setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
- PhoneAccount.CAPABILITY_VIDEO_CALLING)
+ PhoneAccount.CAPABILITY_VIDEO_CALLING |
+ PhoneAccount.CAPABILITY_CALL_SUBJECT)
.setIcon(Icon.createWithResource(
context.getResources(), R.drawable.stat_sys_phone_call))
// TODO: Add icon tint (Color.RED)
@@ -129,7 +130,8 @@
.setSubscriptionAddress(Uri.parse("tel:555-TSIM"))
.setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
- PhoneAccount.CAPABILITY_VIDEO_CALLING)
+ PhoneAccount.CAPABILITY_VIDEO_CALLING |
+ PhoneAccount.CAPABILITY_CALL_SUBJECT)
.setIcon(Icon.createWithResource(
context.getResources(), R.drawable.stat_sys_phone_call))
// TODO: Add icon tint (Color.GREEN)
diff --git a/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java b/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java
index 45896f4..7964355 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java
@@ -36,6 +36,7 @@
import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
import android.util.Log;
+import android.widget.Toast;
import com.android.server.telecom.testapps.R;
@@ -299,6 +300,13 @@
String gatewayPackage = extras.getString(TelecomManager.GATEWAY_PROVIDER_PACKAGE);
Uri originalHandle = extras.getParcelable(TelecomManager.GATEWAY_ORIGINAL_ADDRESS);
+ if (extras.containsKey(TelecomManager.EXTRA_CALL_SUBJECT)) {
+ String callSubject = extras.getString(TelecomManager.EXTRA_CALL_SUBJECT);
+ log("Got subject: " + callSubject);
+ Toast.makeText(getApplicationContext(), "Got subject :" + callSubject,
+ Toast.LENGTH_SHORT).show();
+ }
+
log("gateway package [" + gatewayPackage + "], original handle [" +
originalHandle + "]");
@@ -354,6 +362,24 @@
VideoProfile.STATE_BIDIRECTIONAL :
VideoProfile.STATE_AUDIO_ONLY;
connection.setVideoState(videoState);
+
+ Bundle connectionExtras = connection.getExtras();
+ if (connectionExtras == null) {
+ connectionExtras = new Bundle();
+ }
+
+ // Randomly choose a varying length call subject.
+ int subjectFormat = mRandom.nextInt(3);
+ if (subjectFormat == 0) {
+ connectionExtras.putString(Connection.EXTRA_CALL_SUBJECT,
+ "This is a test of call subject lines. Subjects for a call can be long " +
+ " and can go even longer.");
+ } else if (subjectFormat == 1) {
+ connectionExtras.putString(Connection.EXTRA_CALL_SUBJECT,
+ "This is a test of call subject lines.");
+ }
+ connection.setExtras(connectionExtras);
+
setAddress(connection, address);
addVideoProvider(connection);
diff --git a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
index b7b4ba7..964f014 100644
--- a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
@@ -396,6 +396,7 @@
c.videoState,
false, /* ringback requested */
false, /* voip audio mode */
+ 0, /* Connect Time for conf call on this connection */
c.statusHints,
c.disconnectCause,
c.conferenceableConnectionIds,