Self-Managed Incoming Call Disambiguation UX.
- Handle auto-disconnect of foreground call when answering a self-managed
call.
- Enforce restriction that the PhoneAccount associated with a self-managed
CS must have a label which is the app's name.
- Ensure self-managed phone accounts can't be registered with
call provider, connection manager, or sim sub capabilities.
- Add "incoming call" UX which is shown when a new incoming call from a
self-managed CS comes in and there is an existing call for another CS.
Test: Unit, manual
Bug: 34159263
Change-Id: I371be9baa6f56c77aa83349977c0131f0e319047
diff --git a/testapps/AndroidManifest.xml b/testapps/AndroidManifest.xml
index cc6470e..ec49696 100644
--- a/testapps/AndroidManifest.xml
+++ b/testapps/AndroidManifest.xml
@@ -169,7 +169,8 @@
<activity android:name="com.android.server.telecom.testapps.SelfManagedCallingActivity"
android:label="@string/selfManagedCallingActivityLabel"
- android:process="com.android.server.telecom.testapps.SelfMangingCallingApp">
+ android:process="com.android.server.telecom.testapps.SelfMangingCallingApp"
+ android:theme="@android:style/Theme.Material.Light">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
diff --git a/testapps/res/layout/self_managed_sample_main.xml b/testapps/res/layout/self_managed_sample_main.xml
index 144d6ec..e30ef42 100644
--- a/testapps/res/layout/self_managed_sample_main.xml
+++ b/testapps/res/layout/self_managed_sample_main.xml
@@ -24,63 +24,80 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/checkIfPermittedBeforeCallingButton" />
- <TableLayout
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="This app provides two sample implementations of the self-managed ConnectionService API. Use this UI to add simulated self-managed calls:" />
+
+ <RadioGroup
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <RadioButton
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Sample Source 1"
+ android:id="@+id/useAcct1Button"
+ android:background="@color/test_call_a_color"/>
+ <RadioButton
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Sample Source 2"
+ android:id="@+id/useAcct2Button"
+ android:background="@color/test_call_b_color"/>
+ </RadioGroup>
+
+ <RadioGroup
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <RadioButton
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Video Call"
+ android:id="@+id/videoCallButton"/>
+ <RadioButton
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Audio Call"
+ android:id="@+id/audioCallButton"/>
+ </RadioGroup>
+
+ <LinearLayout android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
- <TableRow android:layout_span="2">
- <RadioGroup>
- <RadioButton
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Acct 1"
- android:id="@+id/useAcct1Button"/>
- <RadioButton
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Acct 2"
- android:id="@+id/useAcct2Button"/>
- </RadioGroup>
- </TableRow>
- <TableRow android:layout_span="2">
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Place call:" />
- </TableRow>
- <TableRow>
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Number:" />
- <EditText
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/phoneNumber" />
- </TableRow>
- <TableRow>
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Outgoing Call"
- android:id="@+id/placeOutgoingCallButton" />
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Incoming Call"
- android:id="@+id/placeIncomingCallButton" />
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Incoming Call (Delay)"
- android:id="@+id/placeIncomingCallDelayButton" />
- </TableRow>
- <TableRow android:layout_span="2">
- <ListView
- android:id="@+id/callList"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:listSelector="@null"
- android:divider="@null" />
- </TableRow>
- </TableLayout>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Number:" />
+ <EditText
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/phoneNumber"
+ android:text="tel:555-1212"/>
+ </LinearLayout>
+
+ <LinearLayout android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Outgoing Call"
+ android:id="@+id/placeOutgoingCallButton" />
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Incoming Call"
+ android:id="@+id/placeIncomingCallButton" />
+ </LinearLayout>
+
+ <ListView
+ android:id="@+id/callList"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:listSelector="@null"
+ android:divider="@null" />
</LinearLayout>
\ No newline at end of file
diff --git a/testapps/res/values/colors.xml b/testapps/res/values/colors.xml
new file mode 100644
index 0000000..3939e78
--- /dev/null
+++ b/testapps/res/values/colors.xml
@@ -0,0 +1,20 @@
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<resources>
+ <color name="test_call_a_color">#f2eebf</color>
+ <color name="test_call_b_color">#afc5e6</color>
+</resources>
diff --git a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java
index 1d6367e..4275079 100644
--- a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java
+++ b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java
@@ -43,6 +43,8 @@
public static String SELF_MANAGED_ACCOUNT_1 = "1";
public static String SELF_MANAGED_ACCOUNT_2 = "2";
+ public static String SELF_MANAGED_NAME_1 = "SuperCall";
+ public static String SELF_MANAGED_NAME_2 = "Mega Call";
private static SelfManagedCallList sInstance;
private static ComponentName COMPONENT_NAME = new ComponentName(
@@ -89,20 +91,23 @@
}
public void registerPhoneAccounts(Context context) {
- registerPhoneAccount(context, SELF_MANAGED_ACCOUNT_1, SELF_MANAGED_ADDRESS_1);
- registerPhoneAccount(context, SELF_MANAGED_ACCOUNT_2, SELF_MANAGED_ADDRESS_2);
+ registerPhoneAccount(context, SELF_MANAGED_ACCOUNT_1, SELF_MANAGED_ADDRESS_1,
+ SELF_MANAGED_NAME_1);
+ registerPhoneAccount(context, SELF_MANAGED_ACCOUNT_2, SELF_MANAGED_ADDRESS_2,
+ SELF_MANAGED_NAME_2);
}
- public void registerPhoneAccount(Context context, String id, Uri address) {
+ public void registerPhoneAccount(Context context, String id, Uri address, String name) {
PhoneAccountHandle handle = new PhoneAccountHandle(COMPONENT_NAME, id);
mPhoneAccounts.put(id, handle);
- PhoneAccount.Builder builder = PhoneAccount.builder(handle, id)
+ PhoneAccount.Builder builder = PhoneAccount.builder(handle, name)
.addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
.addSupportedUriScheme(PhoneAccount.SCHEME_SIP)
.setAddress(address)
.setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED |
PhoneAccount.CAPABILITY_VIDEO_CALLING |
- PhoneAccount.CAPABILITY_SUPPORTS_VIDEO_CALLING);
+ PhoneAccount.CAPABILITY_SUPPORTS_VIDEO_CALLING)
+ .setShortDescription(name);
TelecomManager.from(context).registerPhoneAccount(builder.build());
}
diff --git a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallListAdapter.java b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallListAdapter.java
index 29d3c5f..b46d5e1 100644
--- a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallListAdapter.java
+++ b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallListAdapter.java
@@ -26,6 +26,8 @@
import android.widget.BaseAdapter;
import android.widget.TextView;
+import com.android.server.telecom.testapps.R;
+
import java.util.List;
public class SelfManagedCallListAdapter extends BaseAdapter {
@@ -124,6 +126,12 @@
SelfManagedConnection connection = mConnections.get(position);
PhoneAccountHandle phoneAccountHandle = connection.getExtras().getParcelable(
SelfManagedConnection.EXTRA_PHONE_ACCOUNT_HANDLE);
+ if (phoneAccountHandle.getId().equals(SelfManagedCallList.SELF_MANAGED_ACCOUNT_1)) {
+ result.setBackgroundColor(result.getContext().getColor(R.color.test_call_a_color));
+ } else {
+ result.setBackgroundColor(result.getContext().getColor(R.color.test_call_b_color));
+ }
+
CallAudioState audioState = connection.getCallAudioState();
String audioRoute = "?";
if (audioState != null) {
@@ -148,9 +156,9 @@
String callType;
if (connection.isIncomingCall()) {
if (connection.isIncomingCallUiShowing()) {
- callType = "Incoming - Show Incoming UX";
+ callType = "Incoming(our ux) ";
} else {
- callType = "Incoming - DO NOT SHOW Incoming UX";
+ callType = "Incoming(sys ux) ";
}
} else {
callType = "Outgoing";
diff --git a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallingActivity.java b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallingActivity.java
index c8f6157..4dfa012 100644
--- a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallingActivity.java
+++ b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallingActivity.java
@@ -22,6 +22,7 @@
import android.telecom.ConnectionRequest;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
+import android.telecom.VideoProfile;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
@@ -46,9 +47,10 @@
private CheckBox mCheckIfPermittedBeforeCalling;
private Button mPlaceOutgoingCallButton;
private Button mPlaceIncomingCallButton;
- private Button mPlaceIncomingCallDelayButton;
private RadioButton mUseAcct1Button;
private RadioButton mUseAcct2Button;
+ private RadioButton mVideoCallButton;
+ private RadioButton mAudioCallButton;
private EditText mNumber;
private ListView mListView;
private SelfManagedCallListAdapter mListAdapter;
@@ -102,21 +104,10 @@
}
});
- mPlaceIncomingCallDelayButton = (Button) findViewById(R.id.placeIncomingCallDelayButton);
- mPlaceIncomingCallDelayButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // Delay the incoming call so that we can turn off the screen and
- try {
- Thread.sleep(5000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- placeIncomingCall();
- }
- });
mUseAcct1Button = (RadioButton) findViewById(R.id.useAcct1Button);
mUseAcct2Button = (RadioButton) findViewById(R.id.useAcct2Button);
+ mVideoCallButton = (RadioButton) findViewById(R.id.videoCallButton);
+ mAudioCallButton = (RadioButton) findViewById(R.id.audioCallButton);
mNumber = (EditText) findViewById(R.id.phoneNumber);
mListView = (ListView) findViewById(R.id.callList);
mCallList.setListener(mCallListListener);
@@ -150,6 +141,10 @@
Bundle extras = new Bundle();
extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
getSelectedPhoneAccountHandle());
+ if (mVideoCallButton.isChecked()) {
+ extras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
+ VideoProfile.STATE_BIDIRECTIONAL);
+ }
tm.placeCall(Uri.parse(mNumber.getText().toString()), extras);
}
@@ -167,6 +162,10 @@
Bundle extras = new Bundle();
extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS,
Uri.parse(mNumber.getText().toString()));
+ if (mVideoCallButton.isChecked()) {
+ extras.putInt(TelecomManager.EXTRA_INCOMING_VIDEO_STATE,
+ VideoProfile.STATE_BIDIRECTIONAL);
+ }
tm.addNewIncomingCall(getSelectedPhoneAccountHandle(), extras);
}
}
\ No newline at end of file
diff --git a/testapps/src/com/android/server/telecom/testapps/SelfManagedConnection.java b/testapps/src/com/android/server/telecom/testapps/SelfManagedConnection.java
index 051948b..766efa5 100644
--- a/testapps/src/com/android/server/telecom/testapps/SelfManagedConnection.java
+++ b/testapps/src/com/android/server/telecom/testapps/SelfManagedConnection.java
@@ -27,6 +27,7 @@
import android.telecom.Connection;
import android.telecom.ConnectionService;
import android.telecom.DisconnectCause;
+import android.telecom.VideoProfile;
import com.android.server.telecom.testapps.R;
@@ -129,6 +130,36 @@
notificationManager.notify(CALL_NOTIFICATION, mCallId, builder.build());
}
+ @Override
+ public void onHold() {
+ setOnHold();
+ }
+
+ @Override
+ public void onUnhold() {
+ setActive();
+ }
+
+ @Override
+ public void onAnswer(int videoState) {
+ setConnectionActive();
+ }
+
+ @Override
+ public void onAnswer() {
+ onAnswer(VideoProfile.STATE_AUDIO_ONLY);
+ }
+
+ @Override
+ public void onReject() {
+ setConnectionDisconnected(DisconnectCause.REJECTED);
+ }
+
+ @Override
+ public void onDisconnect() {
+ setConnectionDisconnected(DisconnectCause.LOCAL);
+ }
+
public void setConnectionActive() {
mMediaPlayer.start();
setActive();
diff --git a/testapps/src/com/android/server/telecom/testapps/SelfManagedConnectionService.java b/testapps/src/com/android/server/telecom/testapps/SelfManagedConnectionService.java
index e1a01ba..1d52a3b 100644
--- a/testapps/src/com/android/server/telecom/testapps/SelfManagedConnectionService.java
+++ b/testapps/src/com/android/server/telecom/testapps/SelfManagedConnectionService.java
@@ -23,8 +23,10 @@
import android.telecom.Log;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
+import android.telecom.VideoProfile;
import java.util.Objects;
+import java.util.Random;
/**
* Sample implementation of the self-managed {@link ConnectionService} API.
@@ -32,6 +34,8 @@
* See {@link android.telecom} for more information on self-managed {@link ConnectionService}s.
*/
public class SelfManagedConnectionService extends ConnectionService {
+ private static final String[] TEST_NAMES = {"Tom Smith", "Jane Appleseed", "Joseph Engleton",
+ "Claudia McPherson", "Chris P. Bacon", "Seymour Butz", "Hugh Mungus", "Anita Bath"};
private final SelfManagedCallList mCallList = SelfManagedCallList.getInstance();
@Override
@@ -60,13 +64,17 @@
mCallList.notifyCreateOutgoingConnectionFailed(request);
}
-
private Connection createSelfManagedConnection(ConnectionRequest request, boolean isIncoming) {
SelfManagedConnection connection = new SelfManagedConnection(mCallList,
getApplicationContext(), isIncoming);
connection.setListener(mCallList.getConnectionListener());
connection.setConnectionProperties(Connection.PROPERTY_SELF_MANAGED);
connection.setAddress(request.getAddress(), TelecomManager.PRESENTATION_ALLOWED);
+ connection.setAudioModeIsVoip(true);
+ connection.setVideoState(request.getVideoState());
+ Random random = new Random();
+ connection.setCallerDisplayName(TEST_NAMES[random.nextInt(TEST_NAMES.length)],
+ TelecomManager.PRESENTATION_ALLOWED);
connection.setExtras(request.getExtras());
if (isIncoming) {
connection.setIsIncomingCallUiShowing(request.shouldShowIncomingCallUi());