From 219b870aa9e9c4046ca1dd915d586010eec1b69f Mon Sep 17 00:00:00 2001 From: wangqi Date: Tue, 13 Feb 2018 09:34:41 -0800 Subject: Add simulator RTT call. This change will also: 1. Disable proximity sensor for RTT call 2. Update RTT call screen, including colors and banner buttons Bug: 67596257 Test: presubmit PiperOrigin-RevId: 185541897 Change-Id: I571373efbb8ced4ee2ad94879e9d37bed33b6a28 --- .../android/dialer/common/res/values/strings.xml | 2 + java/com/android/dialer/simulator/Simulator.java | 6 + .../simulator/impl/SimulatorConferenceCreator.java | 3 +- .../dialer/simulator/impl/SimulatorConnection.java | 18 ++ .../dialer/simulator/impl/SimulatorMainMenu.java | 7 +- .../simulator/impl/SimulatorMissedCallCreator.java | 3 +- .../dialer/simulator/impl/SimulatorRttCall.java | 138 +++++++++++++ .../simulator/impl/SimulatorSimCallManager.java | 52 +++-- .../dialer/simulator/impl/SimulatorVideoCall.java | 6 +- .../dialer/simulator/impl/SimulatorVoiceCall.java | 27 ++- java/com/android/incallui/InCallActivity.java | 104 ++++++++-- java/com/android/incallui/ProximitySensor.java | 10 +- java/com/android/incallui/RttCallPresenter.java | 43 ++++ .../incallui/answer/bindings/AnswerBindings.java | 2 + .../incallui/answer/impl/AnswerFragment.java | 10 + .../impl/answermethod/AnswerMethodHolder.java | 2 + .../impl/answermethod/FlingUpDownMethod.java | 2 + .../incallui/answer/protocol/AnswerScreen.java | 2 + java/com/android/incallui/call/DialerCall.java | 36 ++++ .../android/incallui/rtt/bindings/RttBindings.java | 28 +++ .../android/incallui/rtt/impl/AndroidManifest.xml | 11 +- .../android/incallui/rtt/impl/RttChatActivity.java | 41 ---- .../android/incallui/rtt/impl/RttChatFragment.java | 223 +++++++++++++++++++-- .../incallui/rtt/impl/res/layout/activity_rtt.xml | 26 --- .../incallui/rtt/impl/res/layout/frag_rtt_chat.xml | 5 +- .../incallui/rtt/impl/res/layout/rtt_banner.xml | 64 +++--- .../incallui/rtt/impl/res/values/colors.xml | 3 +- .../incallui/rtt/impl/res/values/strings.xml | 3 - .../incallui/rtt/protocol/AndroidManifest.xml | 22 ++ .../incallui/rtt/protocol/RttCallScreen.java | 31 +++ .../rtt/protocol/RttCallScreenDelegate.java | 29 +++ .../rtt/protocol/RttCallScreenDelegateFactory.java | 23 +++ 32 files changed, 792 insertions(+), 190 deletions(-) create mode 100644 java/com/android/dialer/simulator/impl/SimulatorRttCall.java create mode 100644 java/com/android/incallui/RttCallPresenter.java create mode 100644 java/com/android/incallui/rtt/bindings/RttBindings.java delete mode 100644 java/com/android/incallui/rtt/impl/RttChatActivity.java delete mode 100644 java/com/android/incallui/rtt/impl/res/layout/activity_rtt.xml create mode 100644 java/com/android/incallui/rtt/protocol/AndroidManifest.xml create mode 100644 java/com/android/incallui/rtt/protocol/RttCallScreen.java create mode 100644 java/com/android/incallui/rtt/protocol/RttCallScreenDelegate.java create mode 100644 java/com/android/incallui/rtt/protocol/RttCallScreenDelegateFactory.java (limited to 'java') diff --git a/java/com/android/dialer/common/res/values/strings.xml b/java/com/android/dialer/common/res/values/strings.xml index 770f42f37..53a2b56d7 100644 --- a/java/com/android/dialer/common/res/values/strings.xml +++ b/java/com/android/dialer/common/res/values/strings.xml @@ -17,4 +17,6 @@ Wifi Mobile + + More options diff --git a/java/com/android/dialer/simulator/Simulator.java b/java/com/android/dialer/simulator/Simulator.java index 3c2526be7..11a07d974 100644 --- a/java/com/android/dialer/simulator/Simulator.java +++ b/java/com/android/dialer/simulator/Simulator.java @@ -101,6 +101,9 @@ public interface Simulator { MERGE, SEPARATE, SWAP, + START_RTT, + STOP_RTT, + HANDLE_RTT_UPGRADE_RESPONSE, }) public @interface Type {} @@ -118,6 +121,9 @@ public interface Simulator { public static final int MERGE = 11; public static final int SEPARATE = 12; public static final int SWAP = 13; + public static final int START_RTT = 14; + public static final int STOP_RTT = 15; + public static final int HANDLE_RTT_UPGRADE_RESPONSE = 16; @Type public final int type; /** Holds event specific information. For example, for DTMF this could be the keycode. */ diff --git a/java/com/android/dialer/simulator/impl/SimulatorConferenceCreator.java b/java/com/android/dialer/simulator/impl/SimulatorConferenceCreator.java index 2bfa98247..81a3d30de 100644 --- a/java/com/android/dialer/simulator/impl/SimulatorConferenceCreator.java +++ b/java/com/android/dialer/simulator/impl/SimulatorConferenceCreator.java @@ -97,7 +97,8 @@ final class SimulatorConferenceCreator default: break; } - SimulatorSimCallManager.addNewIncomingCall(context, number, false /* isVideo */, extras); + SimulatorSimCallManager.addNewIncomingCall( + context, number, SimulatorSimCallManager.CALL_TYPE_VOICE, extras); } @Override diff --git a/java/com/android/dialer/simulator/impl/SimulatorConnection.java b/java/com/android/dialer/simulator/impl/SimulatorConnection.java index d7427dd12..c832a5051 100644 --- a/java/com/android/dialer/simulator/impl/SimulatorConnection.java +++ b/java/com/android/dialer/simulator/impl/SimulatorConnection.java @@ -121,6 +121,24 @@ public final class SimulatorConnection extends Connection { onEvent(new Event(Event.DTMF, Character.toString(c), null)); } + @Override + public void onStartRtt(@NonNull RttTextStream rttTextStream) { + LogUtil.enterBlock("SimulatorConnection.onStartRtt"); + onEvent(new Event(Event.START_RTT)); + } + + @Override + public void onStopRtt() { + LogUtil.enterBlock("SimulatorConnection.onStopRtt"); + onEvent(new Event(Event.STOP_RTT)); + } + + @Override + public void handleRttUpgradeResponse(RttTextStream rttTextStream) { + LogUtil.enterBlock("SimulatorConnection.handleRttUpgradeResponse"); + onEvent(new Event(Event.HANDLE_RTT_UPGRADE_RESPONSE)); + } + void onEvent(@NonNull Event event) { events.add(Assert.isNotNull(event)); for (Listener listener : new ArrayList<>(listeners)) { diff --git a/java/com/android/dialer/simulator/impl/SimulatorMainMenu.java b/java/com/android/dialer/simulator/impl/SimulatorMainMenu.java index 0bd1c0f22..1bf4b2a00 100644 --- a/java/com/android/dialer/simulator/impl/SimulatorMainMenu.java +++ b/java/com/android/dialer/simulator/impl/SimulatorMainMenu.java @@ -33,7 +33,6 @@ import com.android.dialer.enrichedcall.simulator.EnrichedCallSimulatorActivity; import com.android.dialer.persistentlog.PersistentLogger; import com.android.dialer.preferredsim.PreferredSimFallbackContract; import com.android.dialer.simulator.SimulatorComponent; -import com.android.incallui.rtt.impl.RttChatActivity; /** Implements the top level simulator menu. */ final class SimulatorMainMenu { @@ -42,9 +41,9 @@ final class SimulatorMainMenu { SimulatorSubMenu simulatorSubMenu = new SimulatorSubMenu(activity.getApplicationContext()); simulatorSubMenu .addItem("Voice call", SimulatorVoiceCall.getActionProvider(activity)) + .addItem("Rtt call", SimulatorRttCall.getActionProvider(activity.getApplicationContext())) .addItem( "IMS video", SimulatorVideoCall.getActionProvider(activity.getApplicationContext())) - .addItem("Rtt call mock", () -> simulateRttCallMock(activity.getApplicationContext())) .addItem( "Notifications", SimulatorNotifications.getActionProvider(activity.getApplicationContext())) @@ -79,10 +78,6 @@ final class SimulatorMainMenu { return simulatorSubMenu; } - private static void simulateRttCallMock(@NonNull Context context) { - context.startActivity(new Intent(context, RttChatActivity.class)); - } - private static void populateDatabase(@NonNull Context context) { DialerExecutorComponent.get(context) .dialerExecutorFactory() diff --git a/java/com/android/dialer/simulator/impl/SimulatorMissedCallCreator.java b/java/com/android/dialer/simulator/impl/SimulatorMissedCallCreator.java index 6d4a26278..b8556156b 100644 --- a/java/com/android/dialer/simulator/impl/SimulatorMissedCallCreator.java +++ b/java/com/android/dialer/simulator/impl/SimulatorMissedCallCreator.java @@ -78,7 +78,8 @@ final class SimulatorMissedCallCreator implements SimulatorConnectionService.Lis extras.putInt(EXTRA_CALL_COUNT, callCount - 1); extras.putBoolean(EXTRA_IS_MISSED_CALL_CONNECTION, true); - SimulatorSimCallManager.addNewIncomingCall(context, callerId, false /* isVideo */, extras); + SimulatorSimCallManager.addNewIncomingCall( + context, callerId, SimulatorSimCallManager.CALL_TYPE_VOICE, extras); } private static boolean isMissedCallConnection(@NonNull Connection connection) { diff --git a/java/com/android/dialer/simulator/impl/SimulatorRttCall.java b/java/com/android/dialer/simulator/impl/SimulatorRttCall.java new file mode 100644 index 000000000..7b0066719 --- /dev/null +++ b/java/com/android/dialer/simulator/impl/SimulatorRttCall.java @@ -0,0 +1,138 @@ +/* + * 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 + */ + +package com.android.dialer.simulator.impl; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.telecom.Connection; +import android.telecom.DisconnectCause; +import android.view.ActionProvider; +import com.android.dialer.common.Assert; +import com.android.dialer.common.LogUtil; +import com.android.dialer.common.concurrent.ThreadUtil; +import com.android.dialer.simulator.Simulator; +import com.android.dialer.simulator.Simulator.Event; + +/** Entry point in the simulator to create voice calls. */ +final class SimulatorRttCall + implements SimulatorConnectionService.Listener, SimulatorConnection.Listener { + + @NonNull private final Context context; + @Nullable private String connectionTag; + + static ActionProvider getActionProvider(@NonNull Context context) { + return new SimulatorSubMenu(context) + .addItem("Incoming call", () -> new SimulatorRttCall(context).addNewIncomingCall(false)) + .addItem("Outgoing call", () -> new SimulatorRttCall(context).addNewOutgoingCall()) + .addItem("Emergency call", () -> new SimulatorRttCall(context).addNewEmergencyCall()); + } + + private SimulatorRttCall(@NonNull Context context) { + this.context = Assert.isNotNull(context); + SimulatorConnectionService.addListener(this); + SimulatorConnectionService.addListener( + new SimulatorConferenceCreator(context, Simulator.CONFERENCE_TYPE_GSM)); + } + + private void addNewIncomingCall(boolean isSpam) { + String callerId = + isSpam + ? "+1-661-778-3020" /* Blacklisted custom spam number */ + : "+44 (0) 20 7031 3000" /* Google London office */; + connectionTag = + SimulatorSimCallManager.addNewIncomingCall( + context, callerId, SimulatorSimCallManager.CALL_TYPE_RTT); + } + + private void addNewOutgoingCall() { + String callerId = "+55-31-2128-6800"; // Brazil office. + connectionTag = + SimulatorSimCallManager.addNewOutgoingCall( + context, callerId, SimulatorSimCallManager.CALL_TYPE_RTT); + } + + private void addNewEmergencyCall() { + String callerId = "911"; + connectionTag = + SimulatorSimCallManager.addNewIncomingCall( + context, callerId, SimulatorSimCallManager.CALL_TYPE_RTT); + } + + @Override + public void onNewOutgoingConnection(@NonNull SimulatorConnection connection) { + if (isMyConnection(connection)) { + LogUtil.i("SimulatorRttCall.onNewOutgoingConnection", "connection created"); + handleNewConnection(connection); + + // Telecom will force the connection to switch to Dialing when we return it. Wait until after + // we're returned it before changing call state. + ThreadUtil.postOnUiThread(connection::setActive); + } + } + + @Override + public void onNewIncomingConnection(@NonNull SimulatorConnection connection) { + if (isMyConnection(connection)) { + LogUtil.i("SimulatorRttCall.onNewIncomingConnection", "connection created"); + handleNewConnection(connection); + } + } + + @Override + public void onConference( + @NonNull SimulatorConnection connection1, @NonNull SimulatorConnection connection2) {} + + private void handleNewConnection(@NonNull SimulatorConnection connection) { + connection.addListener(this); + connection.setConnectionProperties( + connection.getConnectionProperties() | Connection.PROPERTY_IS_RTT); + } + + private boolean isMyConnection(@NonNull Connection connection) { + return connection.getExtras().getBoolean(connectionTag); + } + + @Override + public void onEvent(@NonNull SimulatorConnection connection, @NonNull Event event) { + switch (event.type) { + case Event.NONE: + throw Assert.createIllegalStateFailException(); + case Event.ANSWER: + connection.setActive(); + break; + case Event.REJECT: + connection.setDisconnected(new DisconnectCause(DisconnectCause.REJECTED)); + break; + case Event.HOLD: + connection.setOnHold(); + break; + case Event.UNHOLD: + connection.setActive(); + break; + case Event.DISCONNECT: + connection.setDisconnected(new DisconnectCause(DisconnectCause.LOCAL)); + break; + case Event.SESSION_MODIFY_REQUEST: + ThreadUtil.postDelayedOnUiThread(() -> connection.handleSessionModifyRequest(event), 2000); + break; + default: + LogUtil.i("SimulatorRttCall.onEvent", "unexpected event: " + event.type); + break; + } + } +} diff --git a/java/com/android/dialer/simulator/impl/SimulatorSimCallManager.java b/java/com/android/dialer/simulator/impl/SimulatorSimCallManager.java index f28393c0c..d51e06816 100644 --- a/java/com/android/dialer/simulator/impl/SimulatorSimCallManager.java +++ b/java/com/android/dialer/simulator/impl/SimulatorSimCallManager.java @@ -20,6 +20,7 @@ import android.content.ComponentName; import android.content.Context; import android.net.Uri; import android.os.Bundle; +import android.support.annotation.IntDef; import android.support.annotation.NonNull; import android.telecom.Connection; import android.telecom.ConnectionRequest; @@ -30,6 +31,8 @@ import android.telephony.TelephonyManager; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.strictmode.StrictModeUtils; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.List; import java.util.Random; @@ -46,10 +49,20 @@ import java.util.Random; */ public class SimulatorSimCallManager { + public static final int CALL_TYPE_VOICE = 1; + public static final int CALL_TYPE_VIDEO = 2; + public static final int CALL_TYPE_RTT = 3; + + /** Call type of a simulator call. */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({CALL_TYPE_VOICE, CALL_TYPE_VIDEO, CALL_TYPE_RTT}) + public @interface CallType {} + private static final String SIM_CALL_MANAGER_ACCOUNT_ID = "SIMULATOR_ACCOUNT_ID"; private static final String VIDEO_PROVIDER_ACCOUNT_ID = "SIMULATOR_VIDEO_ACCOUNT_ID"; private static final String EXTRA_IS_SIMULATOR_CONNECTION = "is_simulator_connection"; private static final String EXTRA_CONNECTION_TAG = "connection_tag"; + private static final String EXTRA_CONNECTION_CALL_TYPE = "connection_call_type"; static void register(@NonNull Context context) { LogUtil.enterBlock("SimulatorSimCallManager.register"); @@ -75,15 +88,15 @@ public class SimulatorSimCallManager { @NonNull public static String addNewOutgoingCall( - @NonNull Context context, @NonNull String phoneNumber, boolean isVideo) { - return addNewOutgoingCall(context, phoneNumber, isVideo, new Bundle()); + @NonNull Context context, @NonNull String phoneNumber, @CallType int callType) { + return addNewOutgoingCall(context, phoneNumber, callType, new Bundle()); } @NonNull public static String addNewOutgoingCall( @NonNull Context context, @NonNull String phoneNumber, - boolean isVideo, + @CallType int callType, @NonNull Bundle extras) { LogUtil.enterBlock("SimulatorSimCallManager.addNewOutgoingCall"); Assert.isNotNull(context); @@ -94,13 +107,18 @@ public class SimulatorSimCallManager { register(context); extras = new Bundle(extras); - extras.putAll(createSimulatorConnectionExtras()); + extras.putAll(createSimulatorConnectionExtras(callType)); Bundle outgoingCallExtras = new Bundle(); outgoingCallExtras.putBundle(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras); outgoingCallExtras.putParcelable( TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, - isVideo ? getVideoProviderHandle(context) : getSystemPhoneAccountHandle(context)); + callType == CALL_TYPE_VIDEO + ? getVideoProviderHandle(context) + : getSystemPhoneAccountHandle(context)); + if (callType == CALL_TYPE_RTT) { + outgoingCallExtras.putBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, true); + } TelecomManager telecomManager = context.getSystemService(TelecomManager.class); try { @@ -114,13 +132,16 @@ public class SimulatorSimCallManager { @NonNull public static String addNewIncomingCall( - @NonNull Context context, @NonNull String callerId, boolean isVideo) { - return addNewIncomingCall(context, callerId, isVideo, new Bundle()); + @NonNull Context context, @NonNull String callerId, @CallType int callType) { + return addNewIncomingCall(context, callerId, callType, new Bundle()); } @NonNull public static String addNewIncomingCall( - @NonNull Context context, @NonNull String callerId, boolean isVideo, @NonNull Bundle extras) { + @NonNull Context context, + @NonNull String callerId, + @CallType int callType, + @NonNull Bundle extras) { LogUtil.enterBlock("SimulatorSimCallManager.addNewIncomingCall"); Assert.isNotNull(context); Assert.isNotNull(callerId); @@ -130,18 +151,21 @@ public class SimulatorSimCallManager { extras = new Bundle(extras); extras.putString(TelephonyManager.EXTRA_INCOMING_NUMBER, callerId); - extras.putAll(createSimulatorConnectionExtras()); + extras.putAll(createSimulatorConnectionExtras(callType)); TelecomManager telecomManager = context.getSystemService(TelecomManager.class); telecomManager.addNewIncomingCall( - isVideo ? getVideoProviderHandle(context) : getSystemPhoneAccountHandle(context), extras); + callType == CALL_TYPE_VIDEO + ? getVideoProviderHandle(context) + : getSystemPhoneAccountHandle(context), + extras); return extras.getString(EXTRA_CONNECTION_TAG); } @NonNull private static PhoneAccount buildSimCallManagerAccount(Context context) { return new PhoneAccount.Builder(getSimCallManagerHandle(context), "Simulator SIM call manager") - .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER) + .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER | PhoneAccount.CAPABILITY_RTT) .setShortDescription("Simulator SIM call manager") .setSupportedUriSchemes(Arrays.asList(PhoneAccount.SCHEME_TEL)) .build(); @@ -218,12 +242,16 @@ public class SimulatorSimCallManager { } @NonNull - static Bundle createSimulatorConnectionExtras() { + static Bundle createSimulatorConnectionExtras(@CallType int callType) { Bundle extras = new Bundle(); extras.putBoolean(EXTRA_IS_SIMULATOR_CONNECTION, true); String connectionTag = createUniqueConnectionTag(); extras.putString(EXTRA_CONNECTION_TAG, connectionTag); extras.putBoolean(connectionTag, true); + extras.putInt(EXTRA_CONNECTION_CALL_TYPE, callType); + if (callType == CALL_TYPE_RTT) { + extras.putBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, true); + } return extras; } diff --git a/java/com/android/dialer/simulator/impl/SimulatorVideoCall.java b/java/com/android/dialer/simulator/impl/SimulatorVideoCall.java index f7256a11c..0bb56f1f9 100644 --- a/java/com/android/dialer/simulator/impl/SimulatorVideoCall.java +++ b/java/com/android/dialer/simulator/impl/SimulatorVideoCall.java @@ -77,7 +77,8 @@ final class SimulatorVideoCall } String callerId = "+44 (0) 20 7031 3000"; // Google London office connectionTag = - SimulatorSimCallManager.addNewIncomingCall(context, callerId, true /* isVideo */); + SimulatorSimCallManager.addNewIncomingCall( + context, callerId, SimulatorSimCallManager.CALL_TYPE_VIDEO); } private void addNewOutgoingCall() { @@ -87,7 +88,8 @@ final class SimulatorVideoCall } String phoneNumber = "+44 (0) 20 7031 3000"; // Google London office connectionTag = - SimulatorSimCallManager.addNewOutgoingCall(context, phoneNumber, true /* isVideo */); + SimulatorSimCallManager.addNewOutgoingCall( + context, phoneNumber, SimulatorSimCallManager.CALL_TYPE_VIDEO); } @Override diff --git a/java/com/android/dialer/simulator/impl/SimulatorVoiceCall.java b/java/com/android/dialer/simulator/impl/SimulatorVoiceCall.java index 67a2db804..d4c7ee458 100644 --- a/java/com/android/dialer/simulator/impl/SimulatorVoiceCall.java +++ b/java/com/android/dialer/simulator/impl/SimulatorVoiceCall.java @@ -104,7 +104,10 @@ final class SimulatorVoiceCall extras.putBoolean(Simulator.IS_ENRICHED_CALL, true); connectionTag = SimulatorSimCallManager.addNewIncomingCall( - context, Simulator.ENRICHED_CALL_INCOMING_NUMBER, false, extras); + context, + Simulator.ENRICHED_CALL_INCOMING_NUMBER, + SimulatorSimCallManager.CALL_TYPE_VOICE, + extras); }, DialerExecutorComponent.get(context).uiExecutor()); } @@ -119,7 +122,10 @@ final class SimulatorVoiceCall extras.putBoolean(Simulator.IS_ENRICHED_CALL, true); connectionTag = SimulatorSimCallManager.addNewOutgoingCall( - context, Simulator.ENRICHED_CALL_OUTGOING_NUMBER, false, extras); + context, + Simulator.ENRICHED_CALL_OUTGOING_NUMBER, + SimulatorSimCallManager.CALL_TYPE_VOICE, + extras); }, DialerExecutorComponent.get(context).uiExecutor()); } @@ -127,7 +133,8 @@ final class SimulatorVoiceCall private void addNewIncomingCall() { String callerId = "+44 (0) 20 7031 3000" /* Google London office */; connectionTag = - SimulatorSimCallManager.addNewIncomingCall(context, callerId, false /* isVideo */); + SimulatorSimCallManager.addNewIncomingCall( + context, callerId, SimulatorSimCallManager.CALL_TYPE_VOICE); } private void addNewIncomingCall(AppCompatActivity activity) { @@ -137,7 +144,7 @@ final class SimulatorVoiceCall extras.putInt(Simulator.PRESENTATION_CHOICE, callerIdPresentation); connectionTag = SimulatorSimCallManager.addNewIncomingCall( - context, callerId, false /* isVideo */, extras); + context, callerId, SimulatorSimCallManager.CALL_TYPE_VOICE, extras); }) .show(activity.getSupportFragmentManager(), "SimulatorDialog"); } @@ -145,7 +152,8 @@ final class SimulatorVoiceCall private void addNewOutgoingCall() { String callerId = "+55-31-2128-6800"; // Brazil office. connectionTag = - SimulatorSimCallManager.addNewOutgoingCall(context, callerId, false /* isVideo */); + SimulatorSimCallManager.addNewOutgoingCall( + context, callerId, SimulatorSimCallManager.CALL_TYPE_VOICE); } private void addNewOutgoingCall(AppCompatActivity activity) { @@ -155,7 +163,7 @@ final class SimulatorVoiceCall extras.putInt(Simulator.PRESENTATION_CHOICE, callerIdPresentation); connectionTag = SimulatorSimCallManager.addNewOutgoingCall( - context, callerId, false /* isVideo */, extras); + context, callerId, SimulatorSimCallManager.CALL_TYPE_VOICE, extras); }) .show(activity.getSupportFragmentManager(), "SimulatorDialog"); } @@ -163,12 +171,15 @@ final class SimulatorVoiceCall private void addSpamIncomingCall() { String callerId = "+1-661-778-3020"; /* Blacklisted custom spam number */ connectionTag = - SimulatorSimCallManager.addNewIncomingCall(context, callerId, false /* isVideo */); + SimulatorSimCallManager.addNewIncomingCall( + context, callerId, SimulatorSimCallManager.CALL_TYPE_VOICE); } private void addNewEmergencyCallBack() { String callerId = "911"; - connectionTag = SimulatorSimCallManager.addNewIncomingCall(context, callerId, false); + connectionTag = + SimulatorSimCallManager.addNewIncomingCall( + context, callerId, SimulatorSimCallManager.CALL_TYPE_VOICE); } @Override diff --git a/java/com/android/incallui/InCallActivity.java b/java/com/android/incallui/InCallActivity.java index 8769be5d9..67f5cfe4f 100644 --- a/java/com/android/incallui/InCallActivity.java +++ b/java/com/android/incallui/InCallActivity.java @@ -83,6 +83,10 @@ import com.android.incallui.incall.protocol.InCallScreen; import com.android.incallui.incall.protocol.InCallScreenDelegate; import com.android.incallui.incall.protocol.InCallScreenDelegateFactory; import com.android.incallui.incalluilock.InCallUiLock; +import com.android.incallui.rtt.bindings.RttBindings; +import com.android.incallui.rtt.protocol.RttCallScreen; +import com.android.incallui.rtt.protocol.RttCallScreenDelegate; +import com.android.incallui.rtt.protocol.RttCallScreenDelegateFactory; import com.android.incallui.telecomeventui.InternationalCallOnWifiDialogFragment; import com.android.incallui.video.bindings.VideoBindings; import com.android.incallui.video.protocol.VideoCallScreen; @@ -100,6 +104,7 @@ public class InCallActivity extends TransactionSafeFragmentActivity InCallScreenDelegateFactory, InCallButtonUiDelegateFactory, VideoCallScreenDelegateFactory, + RttCallScreenDelegateFactory, PseudoScreenState.StateChangedListener { @Retention(RetentionPolicy.SOURCE) @@ -136,6 +141,7 @@ public class InCallActivity extends TransactionSafeFragmentActivity private boolean didShowAnswerScreen; private boolean didShowInCallScreen; private boolean didShowVideoCallScreen; + private boolean didShowRttCallScreen; private boolean dismissKeyguard; private boolean isInShowMainInCallFragment; private boolean isRecreating; // whether the activity is going to be recreated @@ -1220,37 +1226,47 @@ public class InCallActivity extends TransactionSafeFragmentActivity isInShowMainInCallFragment = true; ShouldShowUiResult shouldShowAnswerUi = getShouldShowAnswerUi(); ShouldShowUiResult shouldShowVideoUi = getShouldShowVideoUi(); + ShouldShowUiResult shouldShowRttUi = getShouldShowRttUi(); LogUtil.i( "InCallActivity.showMainInCallFragment", - "shouldShowAnswerUi: %b, shouldShowVideoUi: %b, " - + "didShowAnswerScreen: %b, didShowInCallScreen: %b, didShowVideoCallScreen: %b", + "shouldShowAnswerUi: %b, shouldShowRttUi: %b, shouldShowVideoUi: %b " + + "didShowAnswerScreen: %b, didShowInCallScreen: %b, didShowRttCallScreen: %b, " + + "didShowVideoCallScreen: %b", shouldShowAnswerUi.shouldShow, + shouldShowRttUi.shouldShow, shouldShowVideoUi.shouldShow, didShowAnswerScreen, didShowInCallScreen, + didShowRttCallScreen, didShowVideoCallScreen); // Only video call ui allows orientation change. setAllowOrientationChange(shouldShowVideoUi.shouldShow); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); - boolean didChangeInCall; - boolean didChangeVideo; - boolean didChangeAnswer; + boolean didChange; if (shouldShowAnswerUi.shouldShow) { - didChangeInCall = hideInCallScreenFragment(transaction); - didChangeVideo = hideVideoCallScreenFragment(transaction); - didChangeAnswer = showAnswerScreenFragment(transaction, shouldShowAnswerUi.call); + didChange = hideInCallScreenFragment(transaction); + didChange |= hideVideoCallScreenFragment(transaction); + didChange |= hideRttCallScreenFragment(transaction); + didChange |= showAnswerScreenFragment(transaction, shouldShowAnswerUi.call); } else if (shouldShowVideoUi.shouldShow) { - didChangeInCall = hideInCallScreenFragment(transaction); - didChangeVideo = showVideoCallScreenFragment(transaction, shouldShowVideoUi.call); - didChangeAnswer = hideAnswerScreenFragment(transaction); + didChange = hideInCallScreenFragment(transaction); + didChange |= showVideoCallScreenFragment(transaction, shouldShowVideoUi.call); + didChange |= hideRttCallScreenFragment(transaction); + didChange |= hideAnswerScreenFragment(transaction); + } else if (shouldShowRttUi.shouldShow) { + didChange = hideInCallScreenFragment(transaction); + didChange |= hideVideoCallScreenFragment(transaction); + didChange |= hideAnswerScreenFragment(transaction); + didChange |= showRttCallScreenFragment(transaction, shouldShowRttUi.call); } else { - didChangeInCall = showInCallScreenFragment(transaction); - didChangeVideo = hideVideoCallScreenFragment(transaction); - didChangeAnswer = hideAnswerScreenFragment(transaction); + didChange = showInCallScreenFragment(transaction); + didChange |= hideVideoCallScreenFragment(transaction); + didChange |= hideRttCallScreenFragment(transaction); + didChange |= hideAnswerScreenFragment(transaction); } - if (didChangeInCall || didChangeVideo || didChangeAnswer) { + if (didChange) { Trace.beginSection("InCallActivity.commitTransaction"); transaction.commitNow(); Trace.endSection(); @@ -1308,6 +1324,26 @@ public class InCallActivity extends TransactionSafeFragmentActivity return new ShouldShowUiResult(false, null); } + private static ShouldShowUiResult getShouldShowRttUi() { + DialerCall call = CallList.getInstance().getFirstCall(); + if (call == null) { + LogUtil.i("InCallActivity.getShouldShowRttUi", "null call"); + return new ShouldShowUiResult(false, null); + } + + if (call.isRttCall()) { + LogUtil.i("InCallActivity.getShouldShowRttUi", "found rtt call"); + return new ShouldShowUiResult(true, call); + } + + if (call.hasSentRttUpgradeRequest()) { + LogUtil.i("InCallActivity.getShouldShowRttUi", "upgrading to rtt"); + return new ShouldShowUiResult(true, call); + } + + return new ShouldShowUiResult(false, null); + } + private boolean showAnswerScreenFragment(FragmentTransaction transaction, DialerCall call) { // When rejecting a call the active call can become null in which case we should continue // showing the answer screen. @@ -1347,6 +1383,7 @@ public class InCallActivity extends TransactionSafeFragmentActivity AnswerScreen answerScreen = AnswerBindings.createAnswerScreen( call.getId(), + call.isRttCall(), call.isVideoCall(), isVideoUpgradeRequest, call.getVideoTech().isSelfManagedCamera(), @@ -1418,6 +1455,33 @@ public class InCallActivity extends TransactionSafeFragmentActivity return true; } + private boolean showRttCallScreenFragment(FragmentTransaction transaction, DialerCall call) { + if (didShowRttCallScreen) { + // This shouldn't happen since only one RTT call is allow at same time. + if (!getRttCallScreen().getCallId().equals(call.getId())) { + LogUtil.e("InCallActivity.showRttCallScreenFragment", "RTT call id doesn't match"); + } + return false; + } + RttCallScreen rttCallScreen = RttBindings.createRttCallScreen(call.getId()); + transaction.add(R.id.main, rttCallScreen.getRttCallScreenFragment(), Tags.RTT_CALL_SCREEN); + Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this); + didShowRttCallScreen = true; + return true; + } + + private boolean hideRttCallScreenFragment(FragmentTransaction transaction) { + if (!didShowRttCallScreen) { + return false; + } + RttCallScreen rttCallScreen = getRttCallScreen(); + if (rttCallScreen != null) { + transaction.remove(rttCallScreen.getRttCallScreenFragment()); + } + didShowRttCallScreen = false; + return true; + } + private boolean showVideoCallScreenFragment(FragmentTransaction transaction, DialerCall call) { if (didShowVideoCallScreen) { VideoCallScreen videoCallScreen = getVideoCallScreen(); @@ -1467,6 +1531,10 @@ public class InCallActivity extends TransactionSafeFragmentActivity return (VideoCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.VIDEO_CALL_SCREEN); } + private RttCallScreen getRttCallScreen() { + return (RttCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.RTT_CALL_SCREEN); + } + @Override public void onPseudoScreenStateChanged(boolean isOn) { LogUtil.i("InCallActivity.onPseudoScreenStateChanged", "isOn: " + isOn); @@ -1499,6 +1567,11 @@ public class InCallActivity extends TransactionSafeFragmentActivity return super.dispatchTouchEvent(event); } + @Override + public RttCallScreenDelegate newRttCallScreenDelegate(RttCallScreen videoCallScreen) { + return new RttCallPresenter(); + } + private static class ShouldShowUiResult { public final boolean shouldShow; public final DialerCall call; @@ -1536,6 +1609,7 @@ public class InCallActivity extends TransactionSafeFragmentActivity static final String INTERNATIONAL_CALL_ON_WIFI = "tag_international_call_on_wifi"; static final String SELECT_ACCOUNT_FRAGMENT = "tag_select_account_fragment"; static final String VIDEO_CALL_SCREEN = "tag_video_call_screen"; + static final String RTT_CALL_SCREEN = "tag_rtt_call_screen"; static final String POST_CHAR_DIALOG_FRAGMENT = "tag_post_char_dialog_fragment"; } diff --git a/java/com/android/incallui/ProximitySensor.java b/java/com/android/incallui/ProximitySensor.java index f82b75d06..4b033441d 100644 --- a/java/com/android/incallui/ProximitySensor.java +++ b/java/com/android/incallui/ProximitySensor.java @@ -55,6 +55,7 @@ public class ProximitySensor private boolean dialpadVisible; private boolean isAttemptingVideoCall; private boolean isVideoCall; + private boolean isRttCall; public ProximitySensor( @NonNull Context context, @@ -112,10 +113,14 @@ public class ProximitySensor DialerCall activeCall = callList.getActiveCall(); boolean isVideoCall = activeCall != null && activeCall.isVideoCall(); + boolean isRttCall = activeCall != null && activeCall.isRttCall(); - if (isOffhook != isPhoneOffhook || this.isVideoCall != isVideoCall) { + if (isOffhook != isPhoneOffhook + || this.isVideoCall != isVideoCall + || this.isRttCall != isRttCall) { isPhoneOffhook = isOffhook; this.isVideoCall = isVideoCall; + this.isRttCall = isRttCall; orientation = AccelerometerListener.ORIENTATION_UNKNOWN; accelerometerListener.enable(isPhoneOffhook); @@ -217,7 +222,8 @@ public class ProximitySensor || CallAudioState.ROUTE_SPEAKER == audioRoute || CallAudioState.ROUTE_BLUETOOTH == audioRoute || isAttemptingVideoCall - || isVideoCall); + || isVideoCall + || isRttCall); // We do not keep the screen off when the user is outside in-call screen and we are // horizontal, but we do not force it on when we become horizontal until the diff --git a/java/com/android/incallui/RttCallPresenter.java b/java/com/android/incallui/RttCallPresenter.java new file mode 100644 index 000000000..b90d56b36 --- /dev/null +++ b/java/com/android/incallui/RttCallPresenter.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 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. + */ + +package com.android.incallui; + +import android.content.Context; +import com.android.incallui.rtt.protocol.RttCallScreen; +import com.android.incallui.rtt.protocol.RttCallScreenDelegate; + +/** + * Logic related to the {@link RttCallScreen} and for managing changes to the RTT calling surfaces + * based on other user interface events and incoming events. + */ +public class RttCallPresenter implements RttCallScreenDelegate { + + private Context appContext; + private RttCallScreen rttCallScreen; + + @Override + public void initRttCallScreenDelegate(Context context, RttCallScreen rttCallScreen) { + this.appContext = context.getApplicationContext(); + this.rttCallScreen = rttCallScreen; + } + + @Override + public void onRttCallScreenUiReady() {} + + @Override + public void onRttCallScreenUiUnready() {} +} diff --git a/java/com/android/incallui/answer/bindings/AnswerBindings.java b/java/com/android/incallui/answer/bindings/AnswerBindings.java index 0b546db63..9f4199b7b 100644 --- a/java/com/android/incallui/answer/bindings/AnswerBindings.java +++ b/java/com/android/incallui/answer/bindings/AnswerBindings.java @@ -24,6 +24,7 @@ public class AnswerBindings { public static AnswerScreen createAnswerScreen( String callId, + boolean isRttCall, boolean isVideoCall, boolean isVideoUpgradeRequest, boolean isSelfManagedCamera, @@ -31,6 +32,7 @@ public class AnswerBindings { boolean hasCallOnHold) { return AnswerFragment.newInstance( callId, + isRttCall, isVideoCall, isVideoUpgradeRequest, isSelfManagedCamera, diff --git a/java/com/android/incallui/answer/impl/AnswerFragment.java b/java/com/android/incallui/answer/impl/AnswerFragment.java index d687b6e01..8626e6d0e 100644 --- a/java/com/android/incallui/answer/impl/AnswerFragment.java +++ b/java/com/android/incallui/answer/impl/AnswerFragment.java @@ -103,6 +103,8 @@ public class AnswerFragment extends Fragment @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) static final String ARG_CALL_ID = "call_id"; + static final String ARG_IS_RTT_CALL = "is_rtt_call"; + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) static final String ARG_IS_VIDEO_CALL = "is_video_call"; @@ -344,6 +346,7 @@ public class AnswerFragment extends Fragment public static AnswerFragment newInstance( String callId, + boolean isRttCall, boolean isVideoCall, boolean isVideoUpgradeRequest, boolean isSelfManagedCamera, @@ -351,6 +354,7 @@ public class AnswerFragment extends Fragment boolean hasCallOnHold) { Bundle bundle = new Bundle(); bundle.putString(ARG_CALL_ID, Assert.isNotNull(callId)); + bundle.putBoolean(ARG_IS_RTT_CALL, isRttCall); bundle.putBoolean(ARG_IS_VIDEO_CALL, isVideoCall); bundle.putBoolean(ARG_IS_VIDEO_UPGRADE_REQUEST, isVideoUpgradeRequest); bundle.putBoolean(ARG_IS_SELF_MANAGED_CAMERA, isSelfManagedCamera); @@ -663,6 +667,7 @@ public class AnswerFragment extends Fragment Trace.beginSection("AnswerFragment.onCreateView"); Bundle arguments = getArguments(); Assert.checkState(arguments.containsKey(ARG_CALL_ID)); + Assert.checkState(arguments.containsKey(ARG_IS_RTT_CALL)); Assert.checkState(arguments.containsKey(ARG_IS_VIDEO_CALL)); Assert.checkState(arguments.containsKey(ARG_IS_VIDEO_UPGRADE_REQUEST)); @@ -835,6 +840,11 @@ public class AnswerFragment extends Fragment restoreBackgroundMaskColor(); } + @Override + public boolean isRttCall() { + return getArguments().getBoolean(ARG_IS_RTT_CALL); + } + @Override public boolean isVideoCall() { return getArguments().getBoolean(ARG_IS_VIDEO_CALL); diff --git a/java/com/android/incallui/answer/impl/answermethod/AnswerMethodHolder.java b/java/com/android/incallui/answer/impl/answermethod/AnswerMethodHolder.java index afa194f2e..0f1455c74 100644 --- a/java/com/android/incallui/answer/impl/answermethod/AnswerMethodHolder.java +++ b/java/com/android/incallui/answer/impl/answermethod/AnswerMethodHolder.java @@ -46,4 +46,6 @@ public interface AnswerMethodHolder { boolean isVideoCall(); boolean isVideoUpgradeRequest(); + + boolean isRttCall(); } diff --git a/java/com/android/incallui/answer/impl/answermethod/FlingUpDownMethod.java b/java/com/android/incallui/answer/impl/answermethod/FlingUpDownMethod.java index fe6bbbca5..b5dbc0c20 100644 --- a/java/com/android/incallui/answer/impl/answermethod/FlingUpDownMethod.java +++ b/java/com/android/incallui/answer/impl/answermethod/FlingUpDownMethod.java @@ -335,6 +335,8 @@ public class FlingUpDownMethod extends AnswerMethod implements OnProgressChanged } if (getParent().isVideoCall() || getParent().isVideoUpgradeRequest()) { contactPuckIcon.setImageResource(R.drawable.quantum_ic_videocam_white_24); + } else if (getParent().isRttCall()) { + contactPuckIcon.setImageResource(R.drawable.quantum_ic_call_white_24); } else { contactPuckIcon.setImageResource(R.drawable.quantum_ic_call_white_24); } diff --git a/java/com/android/incallui/answer/protocol/AnswerScreen.java b/java/com/android/incallui/answer/protocol/AnswerScreen.java index 5ad500200..f030ce984 100644 --- a/java/com/android/incallui/answer/protocol/AnswerScreen.java +++ b/java/com/android/incallui/answer/protocol/AnswerScreen.java @@ -24,6 +24,8 @@ public interface AnswerScreen { String getCallId(); + boolean isRttCall(); + boolean isVideoCall(); boolean isVideoUpgradeRequest(); diff --git a/java/com/android/incallui/call/DialerCall.java b/java/com/android/incallui/call/DialerCall.java index 1785eceb4..cbe7c57a6 100644 --- a/java/com/android/incallui/call/DialerCall.java +++ b/java/com/android/incallui/call/DialerCall.java @@ -32,6 +32,7 @@ import android.support.annotation.VisibleForTesting; import android.support.v4.os.BuildCompat; import android.telecom.Call; import android.telecom.Call.Details; +import android.telecom.Call.RttCall; import android.telecom.CallAudioState; import android.telecom.Connection; import android.telecom.DisconnectCause; @@ -262,6 +263,28 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa update(); } + @Override + public void onRttModeChanged(Call call, int mode) { + LogUtil.v("TelecomCallCallback.onRttModeChanged", "mode=%d", mode); + } + + @Override + public void onRttRequest(Call call, int id) { + LogUtil.v("TelecomCallCallback.onRttRequest", "id=%d", id); + } + + @Override + public void onRttInitiationFailure(Call call, int reason) { + LogUtil.v("TelecomCallCallback.onRttInitiationFailure", "reason=%d", reason); + update(); + } + + @Override + public void onRttStatusChanged(Call call, boolean enabled, RttCall rttCall) { + LogUtil.v("TelecomCallCallback.onRttStatusChanged", "enabled=%b", enabled); + update(); + } + @Override public void onConnectionEvent(android.telecom.Call call, String event, Bundle extras) { LogUtil.v( @@ -906,6 +929,14 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa return getVideoTech().isTransmittingOrReceiving() || VideoProfile.isVideo(getVideoState()); } + public boolean isRttCall() { + if (BuildCompat.isAtLeastP()) { + return getTelecomCall().isRttActive(); + } else { + return false; + } + } + public boolean hasReceivedVideoUpgradeRequest() { return VideoUtils.hasReceivedVideoUpgradeRequest(getVideoTech().getSessionModificationState()); } @@ -914,6 +945,11 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa return VideoUtils.hasSentVideoUpgradeRequest(getVideoTech().getSessionModificationState()); } + public boolean hasSentRttUpgradeRequest() { + // TODO(wangqi): Implement this. + return false; + } + /** * Determines if the call handle is an emergency number or not and caches the result to avoid * repeated calls to isEmergencyNumber. diff --git a/java/com/android/incallui/rtt/bindings/RttBindings.java b/java/com/android/incallui/rtt/bindings/RttBindings.java new file mode 100644 index 000000000..8f9a1437e --- /dev/null +++ b/java/com/android/incallui/rtt/bindings/RttBindings.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 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 + */ + +package com.android.incallui.rtt.bindings; + +import com.android.incallui.rtt.impl.RttChatFragment; +import com.android.incallui.rtt.protocol.RttCallScreen; + +/** Bindings for RTT module. */ +public class RttBindings { + + public static RttCallScreen createRttCallScreen(String callId) { + return RttChatFragment.newInstance(callId); + } +} diff --git a/java/com/android/incallui/rtt/impl/AndroidManifest.xml b/java/com/android/incallui/rtt/impl/AndroidManifest.xml index fc0705d7e..7f58f71e5 100644 --- a/java/com/android/incallui/rtt/impl/AndroidManifest.xml +++ b/java/com/android/incallui/rtt/impl/AndroidManifest.xml @@ -13,14 +13,5 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License --> - - - - + diff --git a/java/com/android/incallui/rtt/impl/RttChatActivity.java b/java/com/android/incallui/rtt/impl/RttChatActivity.java deleted file mode 100644 index 96056f746..000000000 --- a/java/com/android/incallui/rtt/impl/RttChatActivity.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2018 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 - */ - -package com.android.incallui.rtt.impl; - -import android.os.Bundle; -import android.os.SystemClock; -import android.support.annotation.Nullable; -import android.support.v4.app.FragmentActivity; -import android.view.View; - -/** Activity to for RTT chat window. */ -public class RttChatActivity extends FragmentActivity { - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_rtt); - getSupportFragmentManager() - .beginTransaction() - .add( - R.id.fragment_rtt, - RttChatFragment.newInstance("", "Jane Williamson", SystemClock.elapsedRealtime())) - .commit(); - getWindow().setStatusBarColor(getColor(R.color.rtt_status_bar_color)); - getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); - } -} diff --git a/java/com/android/incallui/rtt/impl/RttChatFragment.java b/java/com/android/incallui/rtt/impl/RttChatFragment.java index 0b0ad2a8e..82dce3ed4 100644 --- a/java/com/android/incallui/rtt/impl/RttChatFragment.java +++ b/java/com/android/incallui/rtt/impl/RttChatFragment.java @@ -16,21 +16,25 @@ package com.android.incallui.rtt.impl; +import android.app.Activity; import android.os.Bundle; import android.os.SystemClock; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView.OnScrollListener; +import android.telecom.CallAudioState; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; -import android.view.View.OnClickListener; import android.view.ViewGroup; +import android.view.Window; +import android.view.accessibility.AccessibilityEvent; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.widget.Chronometer; @@ -38,11 +42,31 @@ import android.widget.EditText; import android.widget.ImageButton; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; +import com.android.dialer.common.Assert; +import com.android.dialer.common.FragmentUtils; +import com.android.dialer.common.LogUtil; +import com.android.incallui.incall.protocol.InCallButtonUi; +import com.android.incallui.incall.protocol.InCallButtonUiDelegate; +import com.android.incallui.incall.protocol.InCallButtonUiDelegateFactory; +import com.android.incallui.incall.protocol.InCallScreen; +import com.android.incallui.incall.protocol.InCallScreenDelegate; +import com.android.incallui.incall.protocol.InCallScreenDelegateFactory; +import com.android.incallui.incall.protocol.PrimaryCallState; +import com.android.incallui.incall.protocol.PrimaryInfo; +import com.android.incallui.incall.protocol.SecondaryInfo; import com.android.incallui.rtt.impl.RttChatAdapter.MessageListener; +import com.android.incallui.rtt.protocol.RttCallScreen; +import com.android.incallui.rtt.protocol.RttCallScreenDelegate; +import com.android.incallui.rtt.protocol.RttCallScreenDelegateFactory; /** RTT chat fragment to show chat bubbles. */ public class RttChatFragment extends Fragment - implements OnClickListener, OnEditorActionListener, TextWatcher, MessageListener { + implements OnEditorActionListener, + TextWatcher, + MessageListener, + RttCallScreen, + InCallScreen, + InCallButtonUi { private static final String ARG_CALL_ID = "call_id"; private static final String ARG_NAME_OR_NUMBER = "name_or_number"; @@ -63,27 +87,58 @@ public class RttChatFragment extends Fragment } } }; + private InCallScreenDelegate inCallScreenDelegate; + private RttCallScreenDelegate rttCallScreenDelegate; + private InCallButtonUiDelegate inCallButtonUiDelegate; + private View endCallButton; /** * Create a new instance of RttChatFragment. * * @param callId call id of the RTT call. - * @param nameOrNumber name or number of the caller to be displayed - * @param sessionStartTimeMillis start time of RTT session in terms of {@link - * SystemClock#elapsedRealtime}. * @return new RttChatFragment */ - public static RttChatFragment newInstance( - String callId, String nameOrNumber, long sessionStartTimeMillis) { + public static RttChatFragment newInstance(String callId) { Bundle bundle = new Bundle(); bundle.putString(ARG_CALL_ID, callId); - bundle.putString(ARG_NAME_OR_NUMBER, nameOrNumber); - bundle.putLong(ARG_SESSION_START_TIME, sessionStartTimeMillis); + bundle.putString(ARG_NAME_OR_NUMBER, "Jane Williamson"); + bundle.putLong(ARG_SESSION_START_TIME, SystemClock.elapsedRealtime()); RttChatFragment instance = new RttChatFragment(); instance.setArguments(bundle); return instance; } + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + LogUtil.i("RttChatFragment.onCreate", null); + inCallButtonUiDelegate = + FragmentUtils.getParent(this, InCallButtonUiDelegateFactory.class) + .newInCallButtonUiDelegate(); + if (savedInstanceState != null) { + inCallButtonUiDelegate.onRestoreInstanceState(savedInstanceState); + } + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle bundle) { + super.onViewCreated(view, bundle); + LogUtil.i("RttChatFragment.onViewCreated", null); + + inCallScreenDelegate = + FragmentUtils.getParentUnsafe(this, InCallScreenDelegateFactory.class) + .newInCallScreenDelegate(); + rttCallScreenDelegate = + FragmentUtils.getParentUnsafe(this, RttCallScreenDelegateFactory.class) + .newRttCallScreenDelegate(this); + + rttCallScreenDelegate.initRttCallScreenDelegate(getContext(), this); + + inCallScreenDelegate.onInCallScreenDelegateInit(this); + inCallScreenDelegate.onInCallScreenReady(); + inCallButtonUiDelegate.onInCallButtonUiReady(this); + } + @Nullable @Override public View onCreateView( @@ -101,8 +156,20 @@ public class RttChatFragment extends Fragment recyclerView.setAdapter(adapter); recyclerView.addOnScrollListener(onScrollListener); submitButton = view.findViewById(R.id.rtt_chat_submit_button); - submitButton.setOnClickListener(this); + submitButton.setOnClickListener( + v -> { + adapter.submitLocalMessage(); + isClearingInput = true; + editText.setText(""); + isClearingInput = false; + }); submitButton.setEnabled(false); + endCallButton = view.findViewById(R.id.rtt_end_call_button); + endCallButton.setOnClickListener( + v -> { + LogUtil.i("RttChatFragment.onClick", "end call button clicked"); + inCallButtonUiDelegate.onEndCallClicked(); + }); String nameOrNumber = null; Bundle bundle = getArguments(); @@ -122,16 +189,6 @@ public class RttChatFragment extends Fragment return view; } - @Override - public void onClick(View v) { - if (v.getId() == R.id.rtt_chat_submit_button) { - adapter.submitLocalMessage(); - isClearingInput = true; - editText.setText(""); - isClearingInput = false; - } - } - @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { if (actionId == EditorInfo.IME_ACTION_DONE) { @@ -166,6 +223,20 @@ public class RttChatFragment extends Fragment recyclerView.smoothScrollToPosition(adapter.getItemCount()); } + @Override + public void onStart() { + LogUtil.enterBlock("RttChatFragment.onStart"); + super.onStart(); + onRttScreenStart(); + } + + @Override + public void onStop() { + LogUtil.enterBlock("RttChatFragment.onStop"); + super.onStop(); + onRttScreenStop(); + } + private void hideKeyboard() { InputMethodManager inputMethodManager = getContext().getSystemService(InputMethodManager.class); if (inputMethodManager.isAcceptingText()) { @@ -173,4 +244,116 @@ public class RttChatFragment extends Fragment getActivity().getCurrentFocus().getWindowToken(), 0); } } + + @Override + public void onRttScreenStart() { + rttCallScreenDelegate.onRttCallScreenUiReady(); + Activity activity = getActivity(); + Window window = getActivity().getWindow(); + window.setStatusBarColor(activity.getColor(R.color.rtt_status_bar_color)); + window.setNavigationBarColor(activity.getColor(R.color.rtt_navigation_bar_color)); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR); + } + + @Override + public void onRttScreenStop() { + rttCallScreenDelegate.onRttCallScreenUiUnready(); + } + + @Override + public Fragment getRttCallScreenFragment() { + return this; + } + + @Override + public String getCallId() { + return Assert.isNotNull(getArguments().getString(ARG_CALL_ID)); + } + + @Override + public void setPrimary(@NonNull PrimaryInfo primaryInfo) { + LogUtil.i("RttChatFragment.setPrimary", primaryInfo.toString()); + } + + @Override + public void setSecondary(@NonNull SecondaryInfo secondaryInfo) {} + + @Override + public void setCallState(@NonNull PrimaryCallState primaryCallState) {} + + @Override + public void setEndCallButtonEnabled(boolean enabled, boolean animate) {} + + @Override + public void showManageConferenceCallButton(boolean visible) {} + + @Override + public boolean isManageConferenceVisible() { + return false; + } + + @Override + public void dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {} + + @Override + public void showNoteSentToast() {} + + @Override + public void updateInCallScreenColors() {} + + @Override + public void onInCallScreenDialpadVisibilityChange(boolean isShowing) {} + + @Override + public int getAnswerAndDialpadContainerResourceId() { + return 0; + } + + @Override + public void showLocationUi(Fragment locationUi) {} + + @Override + public boolean isShowingLocationUi() { + return false; + } + + @Override + public Fragment getInCallScreenFragment() { + return this; + } + + @Override + public void showButton(int buttonId, boolean show) {} + + @Override + public void enableButton(int buttonId, boolean enable) {} + + @Override + public void setEnabled(boolean on) {} + + @Override + public void setHold(boolean on) {} + + @Override + public void setCameraSwitched(boolean isBackFacingCamera) {} + + @Override + public void setVideoPaused(boolean isPaused) {} + + @Override + public void setAudioState(CallAudioState audioState) {} + + @Override + public void updateButtonStates() {} + + @Override + public void updateInCallButtonUiColors(int color) {} + + @Override + public Fragment getInCallButtonUiFragment() { + return this; + } + + @Override + public void showAudioRouteSelector() {} } diff --git a/java/com/android/incallui/rtt/impl/res/layout/activity_rtt.xml b/java/com/android/incallui/rtt/impl/res/layout/activity_rtt.xml deleted file mode 100644 index b48e8d43f..000000000 --- a/java/com/android/incallui/rtt/impl/res/layout/activity_rtt.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/java/com/android/incallui/rtt/impl/res/layout/frag_rtt_chat.xml b/java/com/android/incallui/rtt/impl/res/layout/frag_rtt_chat.xml index 7ba6a09e3..5ba9f4ee8 100644 --- a/java/com/android/incallui/rtt/impl/res/layout/frag_rtt_chat.xml +++ b/java/com/android/incallui/rtt/impl/res/layout/frag_rtt_chat.xml @@ -17,7 +17,8 @@ + android:background="@color/dialer_theme_color" + android:fitsSystemWindows="true"> @@ -52,6 +53,8 @@ android:inputType="textMultiLine|text" android:maxLines="4" android:minHeight="53dp" + android:textColor="#DD000000" + android:textColorHint="#757575" android:textSize="16sp"/> + android:contentDescription="@string/incall_content_description_end_call" + android:scaleType="fitXY" + android:src="@drawable/quantum_ic_call_end_vd_theme_24" + android:tint="#FFDF0000"/> - - + android:contentDescription="@string/content_description_overflow" + android:scaleType="fitXY" + android:src="@drawable/quantum_ic_more_vert_vd_theme_24" + android:tint="#FFFFFF"/> \ No newline at end of file diff --git a/java/com/android/incallui/rtt/impl/res/values/colors.xml b/java/com/android/incallui/rtt/impl/res/values/colors.xml index 402cac4a0..c25ad21f2 100644 --- a/java/com/android/incallui/rtt/impl/res/values/colors.xml +++ b/java/com/android/incallui/rtt/impl/res/values/colors.xml @@ -15,5 +15,6 @@ ~ limitations under the License --> - #E0E0E0 + #03165C + #FAFAFA \ No newline at end of file diff --git a/java/com/android/incallui/rtt/impl/res/values/strings.xml b/java/com/android/incallui/rtt/impl/res/values/strings.xml index 523abdcbc..0b9eb71f4 100644 --- a/java/com/android/incallui/rtt/impl/res/values/strings.xml +++ b/java/com/android/incallui/rtt/impl/res/values/strings.xml @@ -18,9 +18,6 @@ Go ahead - - Back - Type a message diff --git a/java/com/android/incallui/rtt/protocol/AndroidManifest.xml b/java/com/android/incallui/rtt/protocol/AndroidManifest.xml new file mode 100644 index 000000000..52514a501 --- /dev/null +++ b/java/com/android/incallui/rtt/protocol/AndroidManifest.xml @@ -0,0 +1,22 @@ + + + + + \ No newline at end of file diff --git a/java/com/android/incallui/rtt/protocol/RttCallScreen.java b/java/com/android/incallui/rtt/protocol/RttCallScreen.java new file mode 100644 index 000000000..afacbae48 --- /dev/null +++ b/java/com/android/incallui/rtt/protocol/RttCallScreen.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2018 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 + */ + +package com.android.incallui.rtt.protocol; + +import android.support.v4.app.Fragment; + +/** Interface for call RTT call module. */ +public interface RttCallScreen { + + void onRttScreenStart(); + + void onRttScreenStop(); + + Fragment getRttCallScreenFragment(); + + String getCallId(); +} diff --git a/java/com/android/incallui/rtt/protocol/RttCallScreenDelegate.java b/java/com/android/incallui/rtt/protocol/RttCallScreenDelegate.java new file mode 100644 index 000000000..e29c43d70 --- /dev/null +++ b/java/com/android/incallui/rtt/protocol/RttCallScreenDelegate.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2018 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 + */ + +package com.android.incallui.rtt.protocol; + +import android.content.Context; + +/** Callbacks from the module out to the container. */ +public interface RttCallScreenDelegate { + + void initRttCallScreenDelegate(Context context, RttCallScreen rttCallScreen); + + void onRttCallScreenUiReady(); + + void onRttCallScreenUiUnready(); +} diff --git a/java/com/android/incallui/rtt/protocol/RttCallScreenDelegateFactory.java b/java/com/android/incallui/rtt/protocol/RttCallScreenDelegateFactory.java new file mode 100644 index 000000000..0dbcc9135 --- /dev/null +++ b/java/com/android/incallui/rtt/protocol/RttCallScreenDelegateFactory.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2018 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 + */ + +package com.android.incallui.rtt.protocol; + +/** Callbacks from the module out to the container. */ +public interface RttCallScreenDelegateFactory { + + RttCallScreenDelegate newRttCallScreenDelegate(RttCallScreen rttCallScreen); +} -- cgit v1.2.3