Merge "Add handover permission, fill in some missing API gaps."
am: 1dfa830bb0
Change-Id: Ie07c7031c1411b59bbcd250be9517eda51b58310
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 -->
|
||||
<!-- ====================================================================== -->
|
||||
|
||||
@@ -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. -->
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -2799,6 +2799,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}.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -297,6 +299,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);
|
||||
@@ -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)
|
||||
@@ -1753,6 +1786,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>
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -378,6 +378,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}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -56,4 +56,6 @@ oneway interface IInCallService {
|
||||
void onRttInitiationFailure(String callId, int reason);
|
||||
|
||||
void onHandoverFailed(String callId, int error);
|
||||
|
||||
void onHandoverComplete(String callId);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user