diff options
| author | 2018-01-30 19:32:32 +0000 | |
|---|---|---|
| committer | 2018-01-30 19:32:32 +0000 | |
| commit | ed4dd9fbc6bbe76b332c9192d3c385100e6857e0 (patch) | |
| tree | e8a1831c5992363764f1bafab70fbb51767807c7 | |
| parent | 13d6ac4a353c8f36bb4b7330a1b84798ab576631 (diff) | |
| parent | 1dfa830bb02f9b30a510e8c487238e6328d2bebc (diff) | |
Merge "Add handover permission, fill in some missing API gaps."
am: 1dfa830bb0
Change-Id: Ie07c7031c1411b59bbcd250be9517eda51b58310
| -rw-r--r-- | api/current.txt | 2 | ||||
| -rw-r--r-- | core/java/android/app/AppOpsManager.java | 21 | ||||
| -rw-r--r-- | core/res/AndroidManifest.xml | 17 | ||||
| -rw-r--r-- | core/res/res/values/strings.xml | 11 | ||||
| -rw-r--r-- | services/core/java/com/android/server/pm/PackageManagerService.java | 3 | ||||
| -rw-r--r-- | telecomm/java/android/telecom/Call.java | 9 | ||||
| -rw-r--r-- | telecomm/java/android/telecom/Connection.java | 9 | ||||
| -rw-r--r-- | telecomm/java/android/telecom/ConnectionService.java | 62 | ||||
| -rw-r--r-- | telecomm/java/android/telecom/InCallService.java | 11 | ||||
| -rw-r--r-- | telecomm/java/android/telecom/Phone.java | 7 | ||||
| -rw-r--r-- | telecomm/java/android/telecom/TelecomManager.java | 11 | ||||
| -rw-r--r-- | telecomm/java/com/android/internal/telecom/IConnectionService.aidl | 2 | ||||
| -rw-r--r-- | telecomm/java/com/android/internal/telecom/IInCallService.aidl | 2 |
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); } |