summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Tyler Gunn <tgunn@google.com> 2018-01-30 19:32:32 +0000
committer android-build-merger <android-build-merger@google.com> 2018-01-30 19:32:32 +0000
commited4dd9fbc6bbe76b332c9192d3c385100e6857e0 (patch)
treee8a1831c5992363764f1bafab70fbb51767807c7
parent13d6ac4a353c8f36bb4b7330a1b84798ab576631 (diff)
parent1dfa830bb02f9b30a510e8c487238e6328d2bebc (diff)
Merge "Add handover permission, fill in some missing API gaps."
am: 1dfa830bb0 Change-Id: Ie07c7031c1411b59bbcd250be9517eda51b58310
-rw-r--r--api/current.txt2
-rw-r--r--core/java/android/app/AppOpsManager.java21
-rw-r--r--core/res/AndroidManifest.xml17
-rw-r--r--core/res/res/values/strings.xml11
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java3
-rw-r--r--telecomm/java/android/telecom/Call.java9
-rw-r--r--telecomm/java/android/telecom/Connection.java9
-rw-r--r--telecomm/java/android/telecom/ConnectionService.java62
-rw-r--r--telecomm/java/android/telecom/InCallService.java11
-rw-r--r--telecomm/java/android/telecom/Phone.java7
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java11
-rw-r--r--telecomm/java/com/android/internal/telecom/IConnectionService.aidl2
-rw-r--r--telecomm/java/com/android/internal/telecom/IInCallService.aidl2
13 files changed, 156 insertions, 11 deletions
diff --git a/api/current.txt b/api/current.txt
index 2b8b6f51df28..f6b1cbd5c792 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6,6 +6,7 @@ package android {
public static final class Manifest.permission {
ctor public Manifest.permission();
+ field public static final java.lang.String ACCEPT_HANDOVER = "android.permission.ACCEPT_HANDOVER";
field public static final java.lang.String ACCESS_CHECKIN_PROPERTIES = "android.permission.ACCESS_CHECKIN_PROPERTIES";
field public static final java.lang.String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION";
field public static final java.lang.String ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION";
@@ -39381,6 +39382,7 @@ package android.telecom {
method public void onCallEvent(java.lang.String, android.os.Bundle);
method public void onDisconnect();
method public void onExtrasChanged(android.os.Bundle);
+ method public void onHandoverComplete();
method public void onHold();
method public void onPlayDtmfTone(char);
method public void onPostDialContinue(boolean);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index b331d84010d0..e8fbbd78cffd 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -252,8 +252,10 @@ public class AppOpsManager {
public static final int OP_INSTANT_APP_START_FOREGROUND = 68;
/** @hide Answer incoming phone calls */
public static final int OP_ANSWER_PHONE_CALLS = 69;
+ /** @hide Continue handover of a call from another app */
+ public static final int OP_ACCEPT_HANDOVER = 70;
/** @hide */
- public static final int _NUM_OP = 70;
+ public static final int _NUM_OP = 71;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -365,6 +367,12 @@ public class AppOpsManager {
/** Answer incoming phone calls */
public static final String OPSTR_ANSWER_PHONE_CALLS
= "android:answer_phone_calls";
+ /***
+ * Accept call handover
+ * @hide
+ */
+ public static final String OPSTR_ACCEPT_HANDOVER
+ = "android:accept_handover";
// Warning: If an permission is added here it also has to be added to
// com.android.packageinstaller.permission.utils.EventLogger
@@ -400,6 +408,7 @@ public class AppOpsManager {
OP_USE_SIP,
OP_PROCESS_OUTGOING_CALLS,
OP_ANSWER_PHONE_CALLS,
+ OP_ACCEPT_HANDOVER,
// Microphone
OP_RECORD_AUDIO,
// Camera
@@ -492,7 +501,8 @@ public class AppOpsManager {
OP_REQUEST_INSTALL_PACKAGES,
OP_PICTURE_IN_PICTURE,
OP_INSTANT_APP_START_FOREGROUND,
- OP_ANSWER_PHONE_CALLS
+ OP_ANSWER_PHONE_CALLS,
+ OP_ACCEPT_HANDOVER
};
/**
@@ -570,6 +580,7 @@ public class AppOpsManager {
OPSTR_PICTURE_IN_PICTURE,
OPSTR_INSTANT_APP_START_FOREGROUND,
OPSTR_ANSWER_PHONE_CALLS,
+ OPSTR_ACCEPT_HANDOVER
};
/**
@@ -647,6 +658,7 @@ public class AppOpsManager {
"PICTURE_IN_PICTURE",
"INSTANT_APP_START_FOREGROUND",
"ANSWER_PHONE_CALLS",
+ "ACCEPT_HANDOVER"
};
/**
@@ -724,6 +736,7 @@ public class AppOpsManager {
null, // no permission for entering picture-in-picture on hide
Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE,
Manifest.permission.ANSWER_PHONE_CALLS,
+ Manifest.permission.ACCEPT_HANDOVER
};
/**
@@ -802,6 +815,7 @@ public class AppOpsManager {
null, // ENTER_PICTURE_IN_PICTURE_ON_HIDE
null, // INSTANT_APP_START_FOREGROUND
null, // ANSWER_PHONE_CALLS
+ null, // ACCEPT_HANDOVER
};
/**
@@ -879,6 +893,7 @@ public class AppOpsManager {
false, // ENTER_PICTURE_IN_PICTURE_ON_HIDE
false, // INSTANT_APP_START_FOREGROUND
false, // ANSWER_PHONE_CALLS
+ false, // ACCEPT_HANDOVER
};
/**
@@ -955,6 +970,7 @@ public class AppOpsManager {
AppOpsManager.MODE_ALLOWED, // OP_PICTURE_IN_PICTURE
AppOpsManager.MODE_DEFAULT, // OP_INSTANT_APP_START_FOREGROUND
AppOpsManager.MODE_ALLOWED, // ANSWER_PHONE_CALLS
+ AppOpsManager.MODE_ALLOWED, // ACCEPT_HANDOVER
};
/**
@@ -1035,6 +1051,7 @@ public class AppOpsManager {
false, // OP_PICTURE_IN_PICTURE
false,
false, // ANSWER_PHONE_CALLS
+ false, // ACCEPT_HANDOVER
};
/**
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 07f9530116ca..43d7df302706 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -950,6 +950,23 @@
android:description="@string/permdesc_manageOwnCalls"
android:protectionLevel="normal" />
+ <!-- Allows a calling app to continue a call which was started in another app. An example is a
+ video calling app that wants to continue a voice call on the user's mobile network.<p>
+ When the handover of a call from one app to another takes place, there are two devices
+ which are involved in the handover; the initiating and receiving devices. The initiating
+ device is where the request to handover the call was started, and the receiving device is
+ where the handover request is confirmed by the other party.<p>
+ This permission protects access to
+ {@link android.telecom.TelecomManager#acceptHandover(Uri, int, PhoneAccountHandle)}, which
+ the receiving side of the handover uses to accept a handover.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.ACCEPT_HANDOVER"
+ android:permissionGroup="android.permission-group.PHONE"
+ android.label="@string/permlab_acceptHandover"
+ android:description="@string/permdesc_acceptHandover"
+ android:protectionLevel="dangerous" />
+
<!-- ====================================================================== -->
<!-- Permissions for accessing the device microphone -->
<!-- ====================================================================== -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index befebd9dd00f..0a36ba747520 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1076,6 +1076,17 @@
<string name="permdesc_manageOwnCalls">Allows the app to route its calls through the system in
order to improve the calling experience.</string>
+ <!-- Title of an application permission. When granted to a third party app, the user is giving
+ access to the app to continue a call which originated in another app. For example, the
+ user could be in a voice call over their carrier's mobile network, and a third party video
+ calling app wants to continue that voice call as a video call. -->
+ <string name="permlab_acceptHandover">continue a call from another app</string>
+ <!-- Description of an application permission. When granted to a third party app, the user is
+ giving access to the app to continue a call which originated in another app. For example,
+ the user could be in a voice call over their carrier's mobile network, and a third party
+ video calling app wants to continue that voice call as a video call. -->
+ <string name="permdesc_acceptHandover">Allows the app to continue a call which was started in another app.</string>
+
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_readPhoneNumbers">read phone numbers</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6a53e483b47c..4454c71ab896 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -611,7 +611,8 @@ public class PackageManagerService extends IPackageManager.Stub
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_PHONE_NUMBERS,
- Manifest.permission.ANSWER_PHONE_CALLS);
+ Manifest.permission.ANSWER_PHONE_CALLS,
+ Manifest.permission.ACCEPT_HANDOVER);
/**
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 8c7d6b30ecdc..8a4b046516ec 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -1961,6 +1961,15 @@ public final class Call {
}
}
+ /** {@hide} */
+ final void internalOnHandoverComplete() {
+ for (CallbackRecord<Callback> record : mCallbackRecords) {
+ final Call call = this;
+ final Callback callback = record.getCallback();
+ record.getHandler().post(() -> callback.onHandoverComplete(call));
+ }
+ }
+
private void fireStateChanged(final int newState) {
for (CallbackRecord<Callback> record : mCallbackRecords) {
final Call call = this;
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index d71fde28480c..8150efa72571 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -2800,6 +2800,15 @@ public abstract class Connection extends Conferenceable {
public void onCallEvent(String event, Bundle extras) {}
/**
+ * Notifies this {@link Connection} that a handover has completed.
+ * <p>
+ * A handover is initiated with {@link android.telecom.Call#handoverTo(PhoneAccountHandle, int,
+ * Bundle)} on the initiating side of the handover, and on the receiving side with
+ * {@link TelecomManager#acceptHandover(Uri, int, PhoneAccountHandle)}.
+ */
+ public void onHandoverComplete() {}
+
+ /**
* Notifies this {@link Connection} of a change to the extras made outside the
* {@link ConnectionService}.
* <p>
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index e37aeb47f1a7..990b0b4eefee 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -140,6 +140,7 @@ public abstract class ConnectionService extends Service {
private static final String SESSION_POST_DIAL_CONT = "CS.oPDC";
private static final String SESSION_PULL_EXTERNAL_CALL = "CS.pEC";
private static final String SESSION_SEND_CALL_EVENT = "CS.sCE";
+ private static final String SESSION_HANDOVER_COMPLETE = "CS.hC";
private static final String SESSION_EXTRAS_CHANGED = "CS.oEC";
private static final String SESSION_START_RTT = "CS.+RTT";
private static final String SESSION_STOP_RTT = "CS.-RTT";
@@ -179,6 +180,7 @@ public abstract class ConnectionService extends Service {
private static final int MSG_CONNECTION_SERVICE_FOCUS_LOST = 30;
private static final int MSG_CONNECTION_SERVICE_FOCUS_GAINED = 31;
private static final int MSG_HANDOVER_FAILED = 32;
+ private static final int MSG_HANDOVER_COMPLETE = 33;
private static Connection sNullConnection;
@@ -298,6 +300,19 @@ public abstract class ConnectionService extends Service {
}
@Override
+ public void handoverComplete(String callId, Session.Info sessionInfo) {
+ Log.startSession(sessionInfo, SESSION_HANDOVER_COMPLETE);
+ try {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = Log.createSubsession();
+ mHandler.obtainMessage(MSG_HANDOVER_COMPLETE, args).sendToTarget();
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
public void abort(String callId, Session.Info sessionInfo) {
Log.startSession(sessionInfo, SESSION_ABORT);
try {
@@ -1028,6 +1043,19 @@ public abstract class ConnectionService extends Service {
}
break;
}
+ case MSG_HANDOVER_COMPLETE: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ Log.continueSession((Session) args.arg2,
+ SESSION_HANDLER + SESSION_HANDOVER_COMPLETE);
+ String callId = (String) args.arg1;
+ notifyHandoverComplete(callId);
+ } finally {
+ args.recycle();
+ Log.endSession();
+ }
+ break;
+ }
case MSG_ON_EXTRAS_CHANGED: {
SomeArgs args = (SomeArgs) msg.obj;
try {
@@ -1445,19 +1473,24 @@ public abstract class ConnectionService extends Service {
final ConnectionRequest request,
boolean isIncoming,
boolean isUnknown) {
+ boolean isLegacyHandover = request.getExtras() != null &&
+ request.getExtras().getBoolean(TelecomManager.EXTRA_IS_HANDOVER, false);
+ boolean isHandover = request.getExtras() != null && request.getExtras().getBoolean(
+ TelecomManager.EXTRA_IS_HANDOVER_CONNECTION, false);
Log.d(this, "createConnection, callManagerAccount: %s, callId: %s, request: %s, " +
- "isIncoming: %b, isUnknown: %b", callManagerAccount, callId, request,
- isIncoming,
- isUnknown);
+ "isIncoming: %b, isUnknown: %b, isLegacyHandover: %b, isHandover: %b",
+ callManagerAccount, callId, request, isIncoming, isUnknown, isLegacyHandover,
+ isHandover);
Connection connection = null;
- if (getApplicationContext().getApplicationInfo().targetSdkVersion >
- Build.VERSION_CODES.O_MR1 && request.getExtras() != null &&
- request.getExtras().getBoolean(TelecomManager.EXTRA_IS_HANDOVER,false)) {
+ if (isHandover) {
+ PhoneAccountHandle fromPhoneAccountHandle = request.getExtras() != null
+ ? (PhoneAccountHandle) request.getExtras().getParcelable(
+ TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT) : null;
if (!isIncoming) {
- connection = onCreateOutgoingHandoverConnection(callManagerAccount, request);
+ connection = onCreateOutgoingHandoverConnection(fromPhoneAccountHandle, request);
} else {
- connection = onCreateIncomingHandoverConnection(callManagerAccount, request);
+ connection = onCreateIncomingHandoverConnection(fromPhoneAccountHandle, request);
}
} else {
connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
@@ -1754,6 +1787,19 @@ public abstract class ConnectionService extends Service {
}
/**
+ * Notifies a {@link Connection} that a handover has completed.
+ *
+ * @param callId The ID of the call which completed handover.
+ */
+ private void notifyHandoverComplete(String callId) {
+ Log.d(this, "notifyHandoverComplete(%s)", callId);
+ Connection connection = findConnectionForAction(callId, "notifyHandoverComplete");
+ if (connection != null) {
+ connection.onHandoverComplete();
+ }
+ }
+
+ /**
* Notifies a {@link Connection} or {@link Conference} of a change to the extras from Telecom.
* <p>
* These extra changes can originate from Telecom itself, or from an {@link InCallService} via
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 74fa62d62ccf..fcf04c9a7eef 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -81,6 +81,7 @@ public abstract class InCallService extends Service {
private static final int MSG_ON_RTT_UPGRADE_REQUEST = 10;
private static final int MSG_ON_RTT_INITIATION_FAILURE = 11;
private static final int MSG_ON_HANDOVER_FAILED = 12;
+ private static final int MSG_ON_HANDOVER_COMPLETE = 13;
/** Default Handler used to consolidate binder method calls onto a single thread. */
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@@ -157,6 +158,11 @@ public abstract class InCallService extends Service {
mPhone.internalOnHandoverFailed(callId, error);
break;
}
+ case MSG_ON_HANDOVER_COMPLETE: {
+ String callId = (String) msg.obj;
+ mPhone.internalOnHandoverComplete(callId);
+ break;
+ }
default:
break;
}
@@ -237,6 +243,11 @@ public abstract class InCallService extends Service {
public void onHandoverFailed(String callId, int error) {
mHandler.obtainMessage(MSG_ON_HANDOVER_FAILED, error, 0, callId).sendToTarget();
}
+
+ @Override
+ public void onHandoverComplete(String callId) {
+ mHandler.obtainMessage(MSG_ON_HANDOVER_COMPLETE, callId).sendToTarget();
+ }
}
private Phone.Listener mPhoneListener = new Phone.Listener() {
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index b5394b9b0290..99f94f28b6d3 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -230,6 +230,13 @@ public final class Phone {
}
}
+ final void internalOnHandoverComplete(String callId) {
+ Call call = mCallByTelecomCallId.get(callId);
+ if (call != null) {
+ call.internalOnHandoverComplete();
+ }
+ }
+
/**
* Called to destroy the phone and cleanup any lingering calls.
*/
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 96c6e0a5b743..7e897453ab59 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -379,6 +379,17 @@ public class TelecomManager {
public static final String EXTRA_IS_HANDOVER = "android.telecom.extra.IS_HANDOVER";
/**
+ * When {@code true} indicates that a request to create a new connection is for the purpose of
+ * a handover. Note: This is used with the
+ * {@link android.telecom.Call#handoverTo(PhoneAccountHandle, int, Bundle)} API as part of the
+ * internal communication mechanism with the {@link android.telecom.ConnectionService}. It is
+ * not the same as the legacy {@link #EXTRA_IS_HANDOVER} extra.
+ * @hide
+ */
+ public static final String EXTRA_IS_HANDOVER_CONNECTION =
+ "android.telecom.extra.IS_HANDOVER_CONNECTION";
+
+ /**
* Parcelable extra used with {@link #EXTRA_IS_HANDOVER} to indicate the source
* {@link PhoneAccountHandle} when initiating a handover which {@link ConnectionService}
* the handover is from.
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index 02e1ff818066..3dbc8ddc340f 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -104,6 +104,8 @@ oneway interface IConnectionService {
void handoverFailed(String callId, in ConnectionRequest request,
int error, in Session.Info sessionInfo);
+ void handoverComplete(String callId, in Session.Info sessionInfo);
+
void connectionServiceFocusLost(in Session.Info sessionInfo);
void connectionServiceFocusGained(in Session.Info sessionInfo);
diff --git a/telecomm/java/com/android/internal/telecom/IInCallService.aidl b/telecomm/java/com/android/internal/telecom/IInCallService.aidl
index 110109e6e276..b9563fa7bb18 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallService.aidl
@@ -56,4 +56,6 @@ oneway interface IInCallService {
void onRttInitiationFailure(String callId, int reason);
void onHandoverFailed(String callId, int error);
+
+ void onHandoverComplete(String callId);
}