summaryrefslogtreecommitdiff
path: root/java/com/android
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/android')
-rw-r--r--java/com/android/dialer/app/calllog/PhoneCallDetailsHelper.java2
-rw-r--r--java/com/android/dialer/calllog/database/Coalescer.java35
-rw-r--r--java/com/android/dialer/calllog/ui/menu/Modules.java12
-rw-r--r--java/com/android/dialer/calllogutils/res/values/strings.xml4
-rw-r--r--java/com/android/dialer/constants/ActivityRequestCodes.java6
-rw-r--r--java/com/android/dialer/database/DialerDatabaseHelper.java38
-rw-r--r--java/com/android/dialer/duo/PlaceDuoCallNotifier.java45
-rw-r--r--java/com/android/dialer/duo/PlaceDuoCallReceiver.java77
-rw-r--r--java/com/android/dialer/historyitemactions/DuoCallModule.java80
-rw-r--r--java/com/android/dialer/historyitemactions/IntentModule.java2
-rw-r--r--java/com/android/dialer/main/impl/MainActivity.java8
-rw-r--r--java/com/android/dialer/main/impl/OldMainActivityPeer.java58
-rw-r--r--java/com/android/dialer/main/impl/bottomnav/MissedCallCountObserver.java79
-rw-r--r--java/com/android/dialer/oem/AndroidManifest.xml4
-rw-r--r--java/com/android/dialer/rootcomponentgenerator/processor/MetadataGeneratingStep.java10
-rw-r--r--java/com/android/dialer/rootcomponentgenerator/processor/RootComponentGeneratingStep.java10
-rw-r--r--java/com/android/dialer/rootcomponentgenerator/processor/RootComponentProcessor.java1
-rw-r--r--java/com/android/dialer/telecom/TelecomUtil.java6
-rw-r--r--java/com/android/incallui/CallButtonPresenter.java2
-rw-r--r--java/com/android/incallui/InCallActivity.java8
-rw-r--r--java/com/android/incallui/InCallPresenter.java7
-rw-r--r--java/com/android/incallui/RttRequestDialogFragment.java149
-rw-r--r--java/com/android/incallui/call/CallList.java13
-rw-r--r--java/com/android/incallui/call/DialerCall.java8
-rw-r--r--java/com/android/incallui/call/DialerCallListener.java2
-rw-r--r--java/com/android/incallui/res/layout/frag_rtt_request_dialog.xml81
-rw-r--r--java/com/android/incallui/res/values/strings.xml15
-rw-r--r--java/com/android/incallui/rtt/impl/res/values/strings.xml2
28 files changed, 693 insertions, 71 deletions
diff --git a/java/com/android/dialer/app/calllog/PhoneCallDetailsHelper.java b/java/com/android/dialer/app/calllog/PhoneCallDetailsHelper.java
index 680424a78..bca4265b6 100644
--- a/java/com/android/dialer/app/calllog/PhoneCallDetailsHelper.java
+++ b/java/com/android/dialer/app/calllog/PhoneCallDetailsHelper.java
@@ -279,7 +279,7 @@ public class PhoneCallDetailsHelper
return;
}
- if (PhoneNumberUtils.isEmergencyNumber(details.number.toString())) {
+ if (PhoneNumberUtils.isEmergencyNumber(details.displayNumber)) {
views.nameView.setText(R.string.emergency_number);
views.nameView.setTextDirection(View.TEXT_DIRECTION_INHERIT);
return;
diff --git a/java/com/android/dialer/calllog/database/Coalescer.java b/java/com/android/dialer/calllog/database/Coalescer.java
index ed09eea68..6b1a9e1f5 100644
--- a/java/com/android/dialer/calllog/database/Coalescer.java
+++ b/java/com/android/dialer/calllog/database/Coalescer.java
@@ -18,6 +18,7 @@ package com.android.dialer.calllog.database;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.MatrixCursor;
+import android.provider.CallLog.Calls;
import android.support.annotation.NonNull;
import android.support.annotation.WorkerThread;
import android.telecom.PhoneAccountHandle;
@@ -151,7 +152,6 @@ public class Coalescer {
TelecomUtil.composePhoneAccountHandle(
row2.getAsString(AnnotatedCallLog.PHONE_ACCOUNT_COMPONENT_NAME),
row2.getAsString(AnnotatedCallLog.PHONE_ACCOUNT_ID));
-
if (!Objects.equals(phoneAccount1, phoneAccount2)) {
return false;
}
@@ -161,7 +161,7 @@ public class Coalescer {
return false;
}
- if (!meetsAssistedDialingCriteria(row1, row2)) {
+ if (!meetsCallFeatureCriteria(row1, row2)) {
return false;
}
@@ -185,20 +185,25 @@ public class Coalescer {
}
/**
- * Returns a boolean indicating whether or not FEATURES_ASSISTED_DIALING is mutually exclusive
- * between two rows.
+ * Returns true if column {@link AnnotatedCallLog#FEATURES} of the two given rows indicate that
+ * they can be coalesced.
*/
- private static boolean meetsAssistedDialingCriteria(ContentValues row1, ContentValues row2) {
- int row1Assisted =
- row1.getAsInteger(AnnotatedCallLog.FEATURES)
- & TelephonyManagerCompat.FEATURES_ASSISTED_DIALING;
- int row2Assisted =
- row2.getAsInteger(AnnotatedCallLog.FEATURES)
- & TelephonyManagerCompat.FEATURES_ASSISTED_DIALING;
-
- // FEATURES_ASSISTED_DIALING should not be combined with calls that are
- // !FEATURES_ASSISTED_DIALING
- return row1Assisted == row2Assisted;
+ private static boolean meetsCallFeatureCriteria(ContentValues row1, ContentValues row2) {
+ int row1Features = row1.getAsInteger(AnnotatedCallLog.FEATURES);
+ int row2Features = row2.getAsInteger(AnnotatedCallLog.FEATURES);
+
+ // A row with FEATURES_ASSISTED_DIALING should not be combined with one without it.
+ if ((row1Features & TelephonyManagerCompat.FEATURES_ASSISTED_DIALING)
+ != (row2Features & TelephonyManagerCompat.FEATURES_ASSISTED_DIALING)) {
+ return false;
+ }
+
+ // A video call should not be combined with one that is not a video call.
+ if ((row1Features & Calls.FEATURES_VIDEO) != (row2Features & Calls.FEATURES_VIDEO)) {
+ return false;
+ }
+
+ return true;
}
/**
diff --git a/java/com/android/dialer/calllog/ui/menu/Modules.java b/java/com/android/dialer/calllog/ui/menu/Modules.java
index aeb69a7a8..e316f66b5 100644
--- a/java/com/android/dialer/calllog/ui/menu/Modules.java
+++ b/java/com/android/dialer/calllog/ui/menu/Modules.java
@@ -27,8 +27,10 @@ import com.android.dialer.callintent.CallInitiationType;
import com.android.dialer.calllog.model.CoalescedRow;
import com.android.dialer.calllogutils.CallLogEntryText;
import com.android.dialer.calllogutils.NumberAttributesConverter;
+import com.android.dialer.duo.DuoConstants;
import com.android.dialer.glidephotomanager.PhotoInfo;
import com.android.dialer.historyitemactions.DividerModule;
+import com.android.dialer.historyitemactions.DuoCallModule;
import com.android.dialer.historyitemactions.HistoryItemActionModule;
import com.android.dialer.historyitemactions.IntentModule;
import com.android.dialer.historyitemactions.SharedModules;
@@ -134,9 +136,15 @@ final class Modules {
// Add a video item if (1) the call log entry is for a video call, and (2) the call is not spam.
if ((row.getFeatures() & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO
&& !row.getNumberAttributes().getIsSpam()) {
+ boolean isDuoCall =
+ DuoConstants.PHONE_ACCOUNT_COMPONENT_NAME
+ .flattenToString()
+ .equals(row.getPhoneAccountComponentName());
modules.add(
- IntentModule.newVideoCallModule(
- context, normalizedNumber, phoneAccountHandle, CallInitiationType.Type.CALL_LOG));
+ isDuoCall
+ ? new DuoCallModule(context, normalizedNumber, CallInitiationType.Type.CALL_LOG)
+ : IntentModule.newCarrierVideoCallModule(
+ context, normalizedNumber, phoneAccountHandle, CallInitiationType.Type.CALL_LOG));
}
// TODO(zachh): Also show video option if the call log entry is for an audio call but video
diff --git a/java/com/android/dialer/calllogutils/res/values/strings.xml b/java/com/android/dialer/calllogutils/res/values/strings.xml
index bc19ce22a..1c1f31446 100644
--- a/java/com/android/dialer/calllogutils/res/values/strings.xml
+++ b/java/com/android/dialer/calllogutils/res/values/strings.xml
@@ -131,7 +131,7 @@
<!-- String to be displayed to indicate in the call log that a call just now occurred. -->
<string name="just_now">Just now</string>
- <!-- Text to show in call log for a carrier video call. [CHAR LIMIT=30] -->
+ <!-- Text to show in call log for a carrier video call. [CHAR LIMIT=31] -->
<string name="new_call_log_carrier_video">Carrier video</string>
<!-- Text to show in call log for a duo video call. [CHAR LIMIT=30] -->
@@ -145,4 +145,4 @@
<!-- String used to display calls from spam numbers in the call log. [CHAR LIMIT=30] -->
<string name="new_call_log_secondary_spam">Spam</string>
-</resources> \ No newline at end of file
+</resources>
diff --git a/java/com/android/dialer/constants/ActivityRequestCodes.java b/java/com/android/dialer/constants/ActivityRequestCodes.java
index 66c38fa64..7fd619ba9 100644
--- a/java/com/android/dialer/constants/ActivityRequestCodes.java
+++ b/java/com/android/dialer/constants/ActivityRequestCodes.java
@@ -16,8 +16,6 @@
package com.android.dialer.constants;
-import com.android.dialer.duo.Duo;
-
/**
* Class containing {@link android.app.Activity#onActivityResult(int, int, android.content.Intent)}
* request codes.
@@ -32,7 +30,9 @@ public final class ActivityRequestCodes {
/** Request code for {@link com.android.dialer.callcomposer.CallComposerActivity} intent. */
public static final int DIALTACTS_CALL_COMPOSER = 2;
- /** Request code for {@link Duo#getIntent(android.content.Context, String)}. */
+ /**
+ * Request code for {@link com.android.dialer.duo.Duo#getIntent(android.content.Context, String)}.
+ */
public static final int DIALTACTS_DUO = 3;
/** Request code for {@link com.android.dialer.calldetails.OldCallDetailsActivity} intent. */
diff --git a/java/com/android/dialer/database/DialerDatabaseHelper.java b/java/com/android/dialer/database/DialerDatabaseHelper.java
index efff11ecc..b172d7039 100644
--- a/java/com/android/dialer/database/DialerDatabaseHelper.java
+++ b/java/com/android/dialer/database/DialerDatabaseHelper.java
@@ -32,21 +32,23 @@ import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.Directory;
-import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.support.annotation.WorkerThread;
import android.text.TextUtils;
import com.android.contacts.common.R;
import com.android.contacts.common.util.StopWatch;
import com.android.dialer.common.LogUtil;
-import com.android.dialer.common.concurrent.DialerExecutor.Worker;
+import com.android.dialer.common.concurrent.DefaultFutureCallback;
import com.android.dialer.common.concurrent.DialerExecutorComponent;
+import com.android.dialer.common.concurrent.DialerFutureSerializer;
import com.android.dialer.common.database.Selection;
import com.android.dialer.configprovider.ConfigProviderBindings;
import com.android.dialer.database.FilteredNumberContract.FilteredNumberColumns;
import com.android.dialer.smartdial.util.SmartDialNameMatcher;
import com.android.dialer.smartdial.util.SmartDialPrefix;
import com.android.dialer.util.PermissionsUtil;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.MoreExecutors;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Objects;
@@ -85,6 +87,8 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper {
private static final int MAX_ENTRIES = 20;
private final Context context;
+ private final DialerFutureSerializer dialerFutureSerializer = new DialerFutureSerializer();
+
private boolean isTestInstance = false;
protected DialerDatabaseHelper(Context context, String databaseName, int dbVersion) {
@@ -344,11 +348,19 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper {
*/
public void startSmartDialUpdateThread(boolean forceUpdate) {
if (PermissionsUtil.hasContactsReadPermissions(context)) {
- DialerExecutorComponent.get(context)
- .dialerExecutorFactory()
- .createNonUiTaskBuilder(new UpdateSmartDialWorker())
- .build()
- .executeParallel(forceUpdate);
+ Futures.addCallback(
+ // Serialize calls to updateSmartDialDatabase. Use FutureSerializer instead of
+ // synchronizing on the method to prevent deadlocking thread pool. FutureSerializer
+ // provides the guarantee that the next AsyncCallable won't even be submitted until the
+ // ListenableFuture returned by the previous one completes. See a bug.
+ dialerFutureSerializer.submit(
+ () -> {
+ updateSmartDialDatabase(forceUpdate);
+ return null;
+ },
+ DialerExecutorComponent.get(context).backgroundExecutor()),
+ new DefaultFutureCallback<>(),
+ MoreExecutors.directExecutor());
}
}
@@ -657,7 +669,7 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper {
* @param forceUpdate If set to true, update the database by reloading all contacts.
*/
@WorkerThread
- public synchronized void updateSmartDialDatabase(boolean forceUpdate) {
+ public void updateSmartDialDatabase(boolean forceUpdate) {
LogUtil.enterBlock("DialerDatabaseHelper.updateSmartDialDatabase");
final SQLiteDatabase db = getWritableDatabase();
@@ -1296,14 +1308,4 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper {
return false;
}
}
-
- private class UpdateSmartDialWorker implements Worker<Boolean, Void> {
-
- @Nullable
- @Override
- public Void doInBackground(Boolean forceUpdate) throws Throwable {
- updateSmartDialDatabase(forceUpdate);
- return null;
- }
- }
}
diff --git a/java/com/android/dialer/duo/PlaceDuoCallNotifier.java b/java/com/android/dialer/duo/PlaceDuoCallNotifier.java
new file mode 100644
index 000000000..8fde981a0
--- /dev/null
+++ b/java/com/android/dialer/duo/PlaceDuoCallNotifier.java
@@ -0,0 +1,45 @@
+/*
+ * 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.dialer.duo;
+
+import android.content.Context;
+import android.content.Intent;
+import android.support.v4.content.LocalBroadcastManager;
+import com.android.dialer.common.LogUtil;
+
+/** Notifies that a Duo video call should be started. */
+public final class PlaceDuoCallNotifier {
+
+ private PlaceDuoCallNotifier() {}
+
+ /**
+ * Broadcasts an intent notifying that a Duo call should be started.
+ *
+ * <p>See {@link PlaceDuoCallReceiver} for how the intent is handled.
+ *
+ * @param phoneNumber The number to start a Duo call. It can be of any format.
+ */
+ public static void notify(Context context, String phoneNumber) {
+ LogUtil.enterBlock("PlaceDuoCallNotifier.notify");
+
+ Intent intent = new Intent();
+ intent.setAction(PlaceDuoCallReceiver.ACTION_START_DUO_CALL);
+ intent.putExtra(PlaceDuoCallReceiver.EXTRA_PHONE_NUMBER, phoneNumber);
+
+ LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
+ }
+}
diff --git a/java/com/android/dialer/duo/PlaceDuoCallReceiver.java b/java/com/android/dialer/duo/PlaceDuoCallReceiver.java
new file mode 100644
index 000000000..913132c88
--- /dev/null
+++ b/java/com/android/dialer/duo/PlaceDuoCallReceiver.java
@@ -0,0 +1,77 @@
+/*
+ * 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.dialer.duo;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import com.android.dialer.common.Assert;
+import com.android.dialer.common.LogUtil;
+import com.android.dialer.constants.ActivityRequestCodes;
+
+/** A {@link BroadcastReceiver} that starts a Duo video call. */
+public final class PlaceDuoCallReceiver extends BroadcastReceiver {
+
+ static final String ACTION_START_DUO_CALL = "start_duo_call";
+ static final String EXTRA_PHONE_NUMBER = "phone_number";
+
+ /**
+ * {@link Activity} needed to launch Duo.
+ *
+ * <p>A Duo call can only be placed via {@link Activity#startActivityForResult(Intent, int)}.
+ */
+ private final Activity activity;
+
+ /** Returns an {@link IntentFilter} containing all actions accepted by this broadcast receiver. */
+ public static IntentFilter getIntentFilter() {
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(ACTION_START_DUO_CALL);
+ return intentFilter;
+ }
+
+ public PlaceDuoCallReceiver(Activity activity) {
+ this.activity = activity;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ LogUtil.enterBlock("PlaceDuoCallReceiver.onReceive");
+
+ String action = intent.getAction();
+
+ switch (Assert.isNotNull(action)) {
+ case ACTION_START_DUO_CALL:
+ startDuoCall(context, intent);
+ break;
+ default:
+ throw new IllegalStateException("Unsupported action: " + action);
+ }
+ }
+
+ private void startDuoCall(Context context, Intent intent) {
+ LogUtil.enterBlock("PlaceDuoCallReceiver.startDuoCall");
+
+ Assert.checkArgument(intent.hasExtra(EXTRA_PHONE_NUMBER));
+ String phoneNumber = intent.getStringExtra(EXTRA_PHONE_NUMBER);
+
+ Duo duo = DuoComponent.get(context).getDuo();
+ activity.startActivityForResult(
+ duo.getIntent(context, phoneNumber), ActivityRequestCodes.DIALTACTS_DUO);
+ }
+}
diff --git a/java/com/android/dialer/historyitemactions/DuoCallModule.java b/java/com/android/dialer/historyitemactions/DuoCallModule.java
new file mode 100644
index 000000000..b0d6a11fc
--- /dev/null
+++ b/java/com/android/dialer/historyitemactions/DuoCallModule.java
@@ -0,0 +1,80 @@
+/*
+ * 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.dialer.historyitemactions;
+
+import android.Manifest.permission;
+import android.content.Context;
+import android.support.annotation.RequiresPermission;
+import com.android.dialer.callintent.CallInitiationType;
+import com.android.dialer.callintent.CallIntentBuilder;
+import com.android.dialer.duo.Duo;
+import com.android.dialer.duo.DuoComponent;
+import com.android.dialer.duo.PlaceDuoCallNotifier;
+import com.android.dialer.precall.PreCall;
+
+/** {@link HistoryItemActionModule} for making a Duo call. */
+public class DuoCallModule implements HistoryItemActionModule {
+
+ private final Context context;
+ private final String phoneNumber;
+ private final CallInitiationType.Type callInitiationType;
+
+ /**
+ * Creates a module for making a Duo call.
+ *
+ * @param phoneNumber The number to start a Duo call. It can be of any format.
+ */
+ public DuoCallModule(
+ Context context, String phoneNumber, CallInitiationType.Type callInitiationType) {
+ this.context = context;
+ this.phoneNumber = phoneNumber;
+ this.callInitiationType = callInitiationType;
+ }
+
+ @Override
+ public int getStringId() {
+ return R.string.video_call;
+ }
+
+ @Override
+ public int getDrawableId() {
+ return R.drawable.quantum_ic_videocam_vd_white_24;
+ }
+
+ @Override
+ @RequiresPermission(permission.READ_PHONE_STATE)
+ public boolean onClick() {
+ if (canPlaceDuoCall(context, phoneNumber)) {
+ PlaceDuoCallNotifier.notify(context, phoneNumber);
+ } else {
+ // If a Duo call can't be placed, fall back to an IMS video call.
+ PreCall.start(
+ context, new CallIntentBuilder(phoneNumber, callInitiationType).setIsVideoCall(true));
+ }
+
+ return true; // Close the bottom sheet.
+ }
+
+ private boolean canPlaceDuoCall(Context context, String phoneNumber) {
+ Duo duo = DuoComponent.get(context).getDuo();
+
+ return duo.isInstalled(context)
+ && duo.isEnabled(context)
+ && duo.isActivated(context)
+ && duo.isReachable(context, phoneNumber);
+ }
+}
diff --git a/java/com/android/dialer/historyitemactions/IntentModule.java b/java/com/android/dialer/historyitemactions/IntentModule.java
index efb10e8bb..a5236c57a 100644
--- a/java/com/android/dialer/historyitemactions/IntentModule.java
+++ b/java/com/android/dialer/historyitemactions/IntentModule.java
@@ -77,7 +77,7 @@ public class IntentModule implements HistoryItemActionModule {
R.drawable.quantum_ic_call_white_24);
}
- public static IntentModule newVideoCallModule(
+ public static IntentModule newCarrierVideoCallModule(
Context context,
String number,
@Nullable PhoneAccountHandle phoneAccountHandle,
diff --git a/java/com/android/dialer/main/impl/MainActivity.java b/java/com/android/dialer/main/impl/MainActivity.java
index 2046b048f..3f660f56c 100644
--- a/java/com/android/dialer/main/impl/MainActivity.java
+++ b/java/com/android/dialer/main/impl/MainActivity.java
@@ -24,6 +24,7 @@ import com.android.dialer.blockreportspam.ShowBlockReportSpamDialogReceiver;
import com.android.dialer.calllog.config.CallLogConfigComponent;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
+import com.android.dialer.duo.PlaceDuoCallReceiver;
import com.android.dialer.interactions.PhoneNumberInteraction.DisambigDialogDismissedListener;
import com.android.dialer.interactions.PhoneNumberInteraction.InteractionErrorCode;
import com.android.dialer.interactions.PhoneNumberInteraction.InteractionErrorListener;
@@ -47,6 +48,9 @@ public class MainActivity extends TransactionSafeActivity
*/
private ShowBlockReportSpamDialogReceiver showBlockReportSpamDialogReceiver;
+ /** {@link android.content.BroadcastReceiver} that starts a Duo call. */
+ private PlaceDuoCallReceiver placeDuoCallReceiver;
+
public static Intent getShowCallLogIntent(Context context) {
return getShowTabIntent(context, TabIndex.CALL_LOG);
}
@@ -79,6 +83,7 @@ public class MainActivity extends TransactionSafeActivity
activePeer.onActivityCreate(savedInstanceState);
showBlockReportSpamDialogReceiver = new ShowBlockReportSpamDialogReceiver(getFragmentManager());
+ placeDuoCallReceiver = new PlaceDuoCallReceiver(/* activity = */ this);
}
protected MainActivityPeer getNewPeer() {
@@ -104,6 +109,8 @@ public class MainActivity extends TransactionSafeActivity
LocalBroadcastManager.getInstance(this)
.registerReceiver(
showBlockReportSpamDialogReceiver, ShowBlockReportSpamDialogReceiver.getIntentFilter());
+ LocalBroadcastManager.getInstance(this)
+ .registerReceiver(placeDuoCallReceiver, PlaceDuoCallReceiver.getIntentFilter());
}
@Override
@@ -118,6 +125,7 @@ public class MainActivity extends TransactionSafeActivity
activePeer.onActivityPause();
LocalBroadcastManager.getInstance(this).unregisterReceiver(showBlockReportSpamDialogReceiver);
+ LocalBroadcastManager.getInstance(this).unregisterReceiver(placeDuoCallReceiver);
}
@Override
diff --git a/java/com/android/dialer/main/impl/OldMainActivityPeer.java b/java/com/android/dialer/main/impl/OldMainActivityPeer.java
index 6d78a5171..c15d7c1a8 100644
--- a/java/com/android/dialer/main/impl/OldMainActivityPeer.java
+++ b/java/com/android/dialer/main/impl/OldMainActivityPeer.java
@@ -68,10 +68,12 @@ import com.android.dialer.callcomposer.CallComposerActivity;
import com.android.dialer.calldetails.OldCallDetailsActivity;
import com.android.dialer.callintent.CallIntentBuilder;
import com.android.dialer.callintent.CallSpecificAppData;
+import com.android.dialer.calllog.CallLogComponent;
import com.android.dialer.calllog.config.CallLogConfigComponent;
import com.android.dialer.calllog.ui.NewCallLogFragment;
import com.android.dialer.common.FragmentUtils.FragmentUtilListener;
import com.android.dialer.common.LogUtil;
+import com.android.dialer.common.concurrent.DefaultFutureCallback;
import com.android.dialer.common.concurrent.DialerExecutorComponent;
import com.android.dialer.common.concurrent.ThreadUtil;
import com.android.dialer.common.concurrent.UiListener;
@@ -96,6 +98,7 @@ import com.android.dialer.main.MainActivityPeer;
import com.android.dialer.main.impl.bottomnav.BottomNavBar;
import com.android.dialer.main.impl.bottomnav.BottomNavBar.OnBottomNavTabSelectedListener;
import com.android.dialer.main.impl.bottomnav.BottomNavBar.TabIndex;
+import com.android.dialer.main.impl.bottomnav.MissedCallCountObserver;
import com.android.dialer.main.impl.toolbar.MainToolbar;
import com.android.dialer.metrics.Metrics;
import com.android.dialer.metrics.MetricsComponent;
@@ -113,7 +116,9 @@ import com.android.dialer.voicemail.listui.error.VoicemailStatusCorruptionHandle
import com.android.dialer.voicemailstatus.VisualVoicemailEnabledChecker;
import com.android.dialer.voicemailstatus.VoicemailStatusHelper;
import com.android.voicemail.VoicemailComponent;
+import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
@@ -184,7 +189,9 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
private BottomNavBar bottomNav;
private MainBottomNavBarBottomNavTabListener bottomNavTabListener;
private View snackbarContainer;
+ private MissedCallCountObserver missedCallCountObserver;
private UiListener<String> getLastOutgoingCallListener;
+ private UiListener<Integer> missedCallObserverUiListener;
public static Intent getShowTabIntent(Context context, @TabIndex int tabIndex) {
Intent intent = new Intent(context, MainActivity.class);
@@ -219,6 +226,9 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
getLastOutgoingCallListener =
DialerExecutorComponent.get(activity)
.createUiListener(activity.getFragmentManager(), "Query last phone number");
+ missedCallObserverUiListener =
+ DialerExecutorComponent.get(activity)
+ .createUiListener(activity.getFragmentManager(), "Missed call observer");
}
private void initLayout(Bundle savedInstanceState) {
@@ -247,9 +257,13 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
boolean showVoicemailTab = canVoicemailTabBeShown(activity);
bottomNav.showVoicemail(showVoicemailTab);
+ missedCallCountObserver =
+ new MissedCallCountObserver(
+ activity.getApplicationContext(), bottomNav, missedCallObserverUiListener);
+
callLogFragmentListener =
new MainCallLogFragmentListener(
- activity, activity.getContentResolver(), bottomNav, toolbar);
+ activity, activity.getContentResolver(), bottomNav, toolbar, bottomNavTabListener);
bottomNav.addOnTabSelectedListener(callLogFragmentListener);
searchController =
@@ -471,6 +485,13 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
*/
bottomNavTabListener.ensureCorrectCallLogShown();
+ if (bottomNavTabListener.newCallLogFragmentActive()) {
+ missedCallCountObserver.onChange(false); // Set the initial value for the badge
+ activity
+ .getContentResolver()
+ .registerContentObserver(Calls.CONTENT_URI, true, missedCallCountObserver);
+ }
+
// add 1 sec delay to get memory snapshot so that dialer wont react slowly on resume.
ThreadUtil.postDelayedOnUiThread(
() ->
@@ -489,6 +510,7 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
public void onActivityPause() {
searchController.onActivityPause();
LocalBroadcastManager.getInstance(activity).unregisterReceiver(disableNewCallLogReceiver);
+ activity.getContentResolver().unregisterContentObserver(missedCallCountObserver);
}
@Override
@@ -819,6 +841,7 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
private final Context context;
private final BottomNavBar bottomNavBar;
private final Toolbar toolbar;
+ private final MainBottomNavBarBottomNavTabListener bottomNavTabListener;
private @TabIndex int currentTab = TabIndex.SPEED_DIAL;
private long timeSelected = -1;
@@ -837,11 +860,13 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
Context context,
ContentResolver contentResolver,
BottomNavBar bottomNavBar,
- Toolbar toolbar) {
+ Toolbar toolbar,
+ MainBottomNavBarBottomNavTabListener bottomNavTabListener) {
callLogQueryHandler = new CallLogQueryHandler(context, contentResolver, this);
this.context = context;
this.bottomNavBar = bottomNavBar;
this.toolbar = toolbar;
+ this.bottomNavTabListener = bottomNavTabListener;
}
private void registerVoicemailStatusContentObserver(Context context) {
@@ -953,8 +978,15 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
}
private void markMissedCallsAsReadAndRemoveNotification() {
- callLogQueryHandler.markMissedCallsAsRead();
- CallLogNotificationsService.cancelAllMissedCalls(context);
+ if (bottomNavTabListener.newCallLogFragmentActive()) {
+ Futures.addCallback(
+ CallLogComponent.get(context).getClearMissedCalls().clearAll(),
+ new DefaultFutureCallback<>(),
+ MoreExecutors.directExecutor());
+ } else {
+ callLogQueryHandler.markMissedCallsAsRead();
+ CallLogNotificationsService.cancelAllMissedCalls(context);
+ }
}
private void setCurrentTab(@TabIndex int tabIndex) {
@@ -969,7 +1001,9 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
activityIsAlive = true;
registerVoicemailStatusContentObserver(context);
callLogQueryHandler.fetchVoicemailStatus();
- callLogQueryHandler.fetchMissedCallsUnreadCount();
+ if (!bottomNavTabListener.newCallLogFragmentActive()) {
+ callLogQueryHandler.fetchMissedCallsUnreadCount();
+ }
// Reset the tab on resume to restart the timer
setCurrentTab(bottomNavBar.getSelectedTab());
}
@@ -978,7 +1012,11 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
public void onActivityStop(boolean changingConfigurations, boolean keyguardLocked) {
context.getContentResolver().unregisterContentObserver(voicemailStatusObserver);
activityIsAlive = false;
- if (viewedCallLogTabPastTimeThreshold() && !changingConfigurations && !keyguardLocked) {
+ // The new call log fragment handles this on its own.
+ if (!bottomNavTabListener.newCallLogFragmentActive()
+ && viewedCallLogTabPastTimeThreshold()
+ && !changingConfigurations
+ && !keyguardLocked) {
markMissedCallsAsReadAndRemoveNotification();
}
}
@@ -1239,6 +1277,14 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
}
}
+ boolean newCallLogFragmentActive() {
+ return supportFragmentManager.findFragmentByTag(CALL_LOG_TAG) != null
+ || (fragmentManager.findFragmentByTag(CALL_LOG_TAG) == null
+ && CallLogConfigComponent.get(activity)
+ .callLogConfig()
+ .isNewCallLogFragmentEnabled());
+ }
+
@Override
public void onContactsSelected() {
LogUtil.enterBlock("MainBottomNavBarBottomNavTabListener.onContactsSelected");
diff --git a/java/com/android/dialer/main/impl/bottomnav/MissedCallCountObserver.java b/java/com/android/dialer/main/impl/bottomnav/MissedCallCountObserver.java
new file mode 100644
index 000000000..276063474
--- /dev/null
+++ b/java/com/android/dialer/main/impl/bottomnav/MissedCallCountObserver.java
@@ -0,0 +1,79 @@
+/*
+ * 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.dialer.main.impl.bottomnav;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.provider.CallLog.Calls;
+import com.android.dialer.common.concurrent.DialerExecutorComponent;
+import com.android.dialer.common.concurrent.UiListener;
+import com.android.dialer.main.impl.bottomnav.BottomNavBar.TabIndex;
+import com.android.dialer.util.PermissionsUtil;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Observes the call log and updates the badge count to show the number of unread missed calls.
+ *
+ * <p>Used only when the new call log fragment is enabled.
+ */
+public final class MissedCallCountObserver extends ContentObserver {
+ private final Context appContext;
+ private final BottomNavBar bottomNavBar;
+ private final UiListener<Integer> uiListener;
+
+ public MissedCallCountObserver(
+ Context appContext, BottomNavBar bottomNavBar, UiListener<Integer> uiListener) {
+ super(null);
+ this.appContext = appContext;
+ this.bottomNavBar = bottomNavBar;
+ this.uiListener = uiListener;
+ }
+
+ @SuppressLint("MissingPermission")
+ @Override
+ public void onChange(boolean selfChange) {
+ ListenableFuture<Integer> countFuture =
+ DialerExecutorComponent.get(appContext)
+ .backgroundExecutor()
+ .submit(
+ () -> {
+ if (!PermissionsUtil.hasCallLogReadPermissions(appContext)) {
+ return 0;
+ }
+ try (Cursor cursor =
+ appContext
+ .getContentResolver()
+ .query(
+ Calls.CONTENT_URI,
+ new String[] {Calls._ID},
+ Calls.IS_READ + " = ? AND " + Calls.TYPE + " = ?",
+ new String[] {"0", Integer.toString(Calls.MISSED_TYPE)},
+ /* sortOrder= */ null)) {
+ return cursor == null ? 0 : cursor.getCount();
+ }
+ });
+ uiListener.listen(
+ appContext,
+ countFuture,
+ count -> bottomNavBar.setNotificationCount(TabIndex.CALL_LOG, count == null ? 0 : count),
+ throwable -> {
+ throw new RuntimeException(throwable);
+ });
+ }
+}
diff --git a/java/com/android/dialer/oem/AndroidManifest.xml b/java/com/android/dialer/oem/AndroidManifest.xml
index a781521c6..94cd4fcba 100644
--- a/java/com/android/dialer/oem/AndroidManifest.xml
+++ b/java/com/android/dialer/oem/AndroidManifest.xml
@@ -19,5 +19,5 @@
<uses-permission android:name="com.cequint.ecid.CALLER_ID_LOOKUP"/>
<!-- This is used by MotorolaInCallUiNotifier to send broadcasts. -->
- <uses-permission android:name="com.motorola.incallui.action.INCOMING_CALL_VISIBILITY_CHANGED"/>
-</manifest> \ No newline at end of file
+ <uses-permission android:name="com.motorola.incallui.permission.INCOMING_CALL_VISIBILITY_CHANGED"/>
+</manifest>
diff --git a/java/com/android/dialer/rootcomponentgenerator/processor/MetadataGeneratingStep.java b/java/com/android/dialer/rootcomponentgenerator/processor/MetadataGeneratingStep.java
index 70ad1b2e7..b7d31c0e9 100644
--- a/java/com/android/dialer/rootcomponentgenerator/processor/MetadataGeneratingStep.java
+++ b/java/com/android/dialer/rootcomponentgenerator/processor/MetadataGeneratingStep.java
@@ -18,7 +18,6 @@ package com.android.dialer.rootcomponentgenerator.processor;
import static javax.tools.Diagnostic.Kind.ERROR;
-import com.android.dialer.rootcomponentgenerator.annotation.DialerComponent;
import com.android.dialer.rootcomponentgenerator.annotation.InstallIn;
import com.android.dialer.rootcomponentgenerator.annotation.RootComponentGeneratorMetadata;
import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep;
@@ -26,6 +25,7 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.SetMultimap;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.TypeSpec;
+import dagger.Subcomponent;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.Set;
@@ -33,7 +33,7 @@ import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
/**
- * Genereates metadata for every type annotated by {@link InstallIn} and {@link DialerComponent}.
+ * Genereates metadata for every type annotated by {@link InstallIn} and {@link Subcomponent}.
*
* <p>The metadata has the information where the annotated types are and it is used by annotation
* processor when the processor tries to generate root component.
@@ -48,15 +48,15 @@ final class MetadataGeneratingStep implements ProcessingStep {
@Override
public Set<? extends Class<? extends Annotation>> annotations() {
- return ImmutableSet.of(DialerComponent.class, InstallIn.class);
+ return ImmutableSet.of(Subcomponent.class, InstallIn.class);
}
@Override
public Set<? extends Element> process(
SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
- for (Element element : elementsByAnnotation.get(DialerComponent.class)) {
- generateMetadataFor(DialerComponent.class, element);
+ for (Element element : elementsByAnnotation.get(Subcomponent.class)) {
+ generateMetadataFor(Subcomponent.class, element);
}
for (Element element : elementsByAnnotation.get(InstallIn.class)) {
if (element.getAnnotation(InstallIn.class).variants().length == 0) {
diff --git a/java/com/android/dialer/rootcomponentgenerator/processor/RootComponentGeneratingStep.java b/java/com/android/dialer/rootcomponentgenerator/processor/RootComponentGeneratingStep.java
index 86a030856..9b97adafd 100644
--- a/java/com/android/dialer/rootcomponentgenerator/processor/RootComponentGeneratingStep.java
+++ b/java/com/android/dialer/rootcomponentgenerator/processor/RootComponentGeneratingStep.java
@@ -20,7 +20,6 @@ import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
import static com.google.auto.common.MoreElements.getAnnotationMirror;
import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import com.android.dialer.rootcomponentgenerator.annotation.DialerComponent;
import com.android.dialer.rootcomponentgenerator.annotation.DialerRootComponent;
import com.android.dialer.rootcomponentgenerator.annotation.DialerVariant;
import com.android.dialer.rootcomponentgenerator.annotation.InstallIn;
@@ -36,6 +35,7 @@ import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.TypeSpec;
import dagger.Component;
+import dagger.Subcomponent;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collections;
@@ -90,11 +90,7 @@ final class RootComponentGeneratingStep implements ProcessingStep {
.addAnnotation(Singleton.class);
for (TypeElement componentWithSuperInterface : componentList) {
rootComponentClassBuilder.addSuperinterface(
- ClassName.get(componentWithSuperInterface)
- .peerClass(
- RootComponentUtils.GENERATED_COMPONENT_PREFIX
- + componentWithSuperInterface.getSimpleName())
- .nestedClass("HasComponent"));
+ ClassName.get(componentWithSuperInterface).nestedClass("HasComponent"));
}
AnnotationSpec.Builder componentAnnotation = AnnotationSpec.builder(Component.class);
for (TypeElement annotatedElement : componentModuleMap.get(dialerVariant)) {
@@ -108,7 +104,7 @@ final class RootComponentGeneratingStep implements ProcessingStep {
private List<TypeElement> generateComponentList() {
List<TypeElement> list = new ArrayList<>();
- extractInfoFromMetadata(DialerComponent.class, list::add);
+ extractInfoFromMetadata(Subcomponent.class, list::add);
return list;
}
diff --git a/java/com/android/dialer/rootcomponentgenerator/processor/RootComponentProcessor.java b/java/com/android/dialer/rootcomponentgenerator/processor/RootComponentProcessor.java
index 5e083d29d..56caa9ea4 100644
--- a/java/com/android/dialer/rootcomponentgenerator/processor/RootComponentProcessor.java
+++ b/java/com/android/dialer/rootcomponentgenerator/processor/RootComponentProcessor.java
@@ -29,7 +29,6 @@ public class RootComponentProcessor extends BasicAnnotationProcessor {
@Override
protected Iterable<? extends ProcessingStep> initSteps() {
return ImmutableList.of(
- new ComponentGeneratingStep(processingEnv),
new MetadataGeneratingStep(processingEnv),
new RootComponentGeneratingStep(processingEnv));
}
diff --git a/java/com/android/dialer/telecom/TelecomUtil.java b/java/com/android/dialer/telecom/TelecomUtil.java
index f05ec202d..2608cb2aa 100644
--- a/java/com/android/dialer/telecom/TelecomUtil.java
+++ b/java/com/android/dialer/telecom/TelecomUtil.java
@@ -26,7 +26,6 @@ import android.net.Uri;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.provider.CallLog.Calls;
-import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresPermission;
@@ -300,11 +299,6 @@ public abstract class TelecomUtil {
return instance.isDefaultDialer(context);
}
- public static boolean isRttEnabled(Context context) {
- return Settings.System.getInt(context.getContentResolver(), Settings.System.RTT_CALLING_MODE, 0)
- != 0;
- }
-
/** @return the other SIM based PhoneAccountHandle that is not {@code currentAccount} */
@Nullable
@RequiresPermission(permission.READ_PHONE_STATE)
diff --git a/java/com/android/incallui/CallButtonPresenter.java b/java/com/android/incallui/CallButtonPresenter.java
index 38c8da898..833460398 100644
--- a/java/com/android/incallui/CallButtonPresenter.java
+++ b/java/com/android/incallui/CallButtonPresenter.java
@@ -479,7 +479,7 @@ public class CallButtonPresenter
// Most devices cannot make calls on 2 SIMs at the same time.
&& InCallPresenter.getInstance().getCallList().getAllCalls().size() == 1;
- boolean showUpgradeToRtt = TelecomUtil.isRttEnabled(context) && call.canUpgradeToRttCall();
+ boolean showUpgradeToRtt = call.canUpgradeToRttCall();
inCallButtonUi.showButton(InCallButtonIds.BUTTON_AUDIO, true);
inCallButtonUi.showButton(InCallButtonIds.BUTTON_SWAP, showSwap);
diff --git a/java/com/android/incallui/InCallActivity.java b/java/com/android/incallui/InCallActivity.java
index 1ba3683f0..65ef323fe 100644
--- a/java/com/android/incallui/InCallActivity.java
+++ b/java/com/android/incallui/InCallActivity.java
@@ -35,6 +35,7 @@ import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
+import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
@@ -1221,6 +1222,12 @@ public class InCallActivity extends TransactionSafeFragmentActivity
fragment.show(getSupportFragmentManager(), Tags.INTERNATIONAL_CALL_ON_WIFI);
}
+ public void showDialogForRttRequest(DialerCall call, int rttRequestId) {
+ LogUtil.enterBlock("InCallActivity.showDialogForRttRequest");
+ DialogFragment fragment = RttRequestDialogFragment.newInstance(call.getId(), rttRequestId);
+ fragment.show(getSupportFragmentManager(), Tags.RTT_REQUEST_DIALOG);
+ }
+
@Override
public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
super.onMultiWindowModeChanged(isInMultiWindowMode);
@@ -1763,6 +1770,7 @@ public class InCallActivity extends TransactionSafeFragmentActivity
static final String RTT_CALL_SCREEN = "tag_rtt_call_screen";
static final String POST_CHAR_DIALOG_FRAGMENT = "tag_post_char_dialog_fragment";
static final String SPEAK_EASY_SCREEN = "tag_speak_easy_screen";
+ static final String RTT_REQUEST_DIALOG = "tag_rtt_request_dialog";
}
private static final class ConfigNames {
diff --git a/java/com/android/incallui/InCallPresenter.java b/java/com/android/incallui/InCallPresenter.java
index e11b376c1..6300dac75 100644
--- a/java/com/android/incallui/InCallPresenter.java
+++ b/java/com/android/incallui/InCallPresenter.java
@@ -894,6 +894,13 @@ public class InCallPresenter implements CallList.Listener, AudioModeProvider.Aud
}
@Override
+ public void onUpgradeToRtt(DialerCall call, int rttRequestId) {
+ if (inCallActivity != null) {
+ inCallActivity.showDialogForRttRequest(call, rttRequestId);
+ }
+ }
+
+ @Override
public void onSessionModificationStateChange(DialerCall call) {
int newState = call.getVideoTech().getSessionModificationState();
LogUtil.i("InCallPresenter.onSessionModificationStateChange", "state: %d", newState);
diff --git a/java/com/android/incallui/RttRequestDialogFragment.java b/java/com/android/incallui/RttRequestDialogFragment.java
new file mode 100644
index 000000000..fa9b0e5db
--- /dev/null
+++ b/java/com/android/incallui/RttRequestDialogFragment.java
@@ -0,0 +1,149 @@
+/*
+ * 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.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.DialogFragment;
+import android.telephony.PhoneNumberUtils;
+import android.text.BidiFormatter;
+import android.text.TextDirectionHeuristics;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.TextView;
+import com.android.contacts.common.util.ContactDisplayUtils;
+import com.android.dialer.common.Assert;
+import com.android.dialer.common.LogUtil;
+import com.android.incallui.ContactInfoCache.ContactCacheEntry;
+import com.android.incallui.ContactInfoCache.ContactInfoCacheCallback;
+import com.android.incallui.call.CallList;
+import com.android.incallui.call.DialerCall;
+import java.lang.ref.WeakReference;
+
+/** Dialog that shown to user when receiving RTT request mid call. */
+public class RttRequestDialogFragment extends DialogFragment {
+
+ /**
+ * Returns a new instance of {@link RttRequestDialogFragment} with the given callback.
+ *
+ * <p>Prefer this method over the default constructor.
+ */
+ public static RttRequestDialogFragment newInstance(String callId, int rttRequestId) {
+ RttRequestDialogFragment fragment = new RttRequestDialogFragment();
+ Bundle args = new Bundle();
+ args.putString(ARG_CALL_ID, Assert.isNotNull(callId));
+ args.putInt(ARG_RTT_REQUEST_ID, rttRequestId);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ /** Key in the arguments bundle for call id. */
+ private static final String ARG_CALL_ID = "call_id";
+
+ private static final String ARG_RTT_REQUEST_ID = "rtt_request_id";
+
+ private TextView detailsTextView;
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle bundle) {
+ super.onCreateDialog(bundle);
+ LogUtil.enterBlock("RttRequestDialogFragment.onCreateDialog");
+
+ View dialogView = View.inflate(getActivity(), R.layout.frag_rtt_request_dialog, null);
+ detailsTextView = dialogView.findViewById(R.id.details);
+
+ ContactInfoCache cache = ContactInfoCache.getInstance(getContext());
+ DialerCall dialerCall =
+ CallList.getInstance().getCallById(getArguments().getString(ARG_CALL_ID));
+ cache.findInfo(dialerCall, false, new ContactLookupCallback(this));
+
+ dialogView
+ .findViewById(R.id.rtt_button_decline_request)
+ .setOnClickListener(v -> onNegativeButtonClick());
+ dialogView
+ .findViewById(R.id.rtt_button_accept_request)
+ .setOnClickListener(v -> onPositiveButtonClick());
+
+ AlertDialog alertDialog =
+ new AlertDialog.Builder(getActivity(), R.style.AlertDialogTheme)
+ .setCancelable(false)
+ .setView(dialogView)
+ .setTitle(R.string.rtt_request_dialog_title)
+ .create();
+
+ alertDialog.setCanceledOnTouchOutside(false);
+ return alertDialog;
+ }
+
+ private void onPositiveButtonClick() {
+ LogUtil.enterBlock("RttRequestDialogFragment.onPositiveButtonClick");
+
+ DialerCall call = CallList.getInstance().getCallById(getArguments().getString(ARG_CALL_ID));
+ call.respondToRttRequest(true, getArguments().getInt(ARG_RTT_REQUEST_ID));
+ dismiss();
+ }
+
+ private void onNegativeButtonClick() {
+ LogUtil.enterBlock("RttRequestDialogFragment.onNegativeButtonClick");
+
+ DialerCall call = CallList.getInstance().getCallById(getArguments().getString(ARG_CALL_ID));
+ call.respondToRttRequest(false, getArguments().getInt(ARG_RTT_REQUEST_ID));
+ dismiss();
+ }
+
+ private void setNameOrNumber(CharSequence nameOrNumber) {
+ detailsTextView.setText(getString(R.string.rtt_request_dialog_details, nameOrNumber));
+ }
+
+ private static class ContactLookupCallback implements ContactInfoCacheCallback {
+ private final WeakReference<RttRequestDialogFragment> rttRequestDialogFragmentWeakReference;
+
+ private ContactLookupCallback(RttRequestDialogFragment rttRequestDialogFragment) {
+ rttRequestDialogFragmentWeakReference = new WeakReference<>(rttRequestDialogFragment);
+ }
+
+ @Override
+ public void onContactInfoComplete(String callId, ContactCacheEntry entry) {
+ RttRequestDialogFragment fragment = rttRequestDialogFragmentWeakReference.get();
+ if (fragment != null) {
+ fragment.setNameOrNumber(getNameOrNumber(entry, fragment.getContext()));
+ }
+ }
+
+ private CharSequence getNameOrNumber(ContactCacheEntry entry, Context context) {
+ String preferredName =
+ ContactDisplayUtils.getPreferredDisplayName(
+ entry.namePrimary,
+ entry.nameAlternative,
+ ContactsPreferencesFactory.newContactsPreferences(context));
+ if (TextUtils.isEmpty(preferredName)) {
+ return TextUtils.isEmpty(entry.number)
+ ? null
+ : PhoneNumberUtils.createTtsSpannable(
+ BidiFormatter.getInstance().unicodeWrap(entry.number, TextDirectionHeuristics.LTR));
+ }
+ return preferredName;
+ }
+
+ @Override
+ public void onImageLoadComplete(String callId, ContactCacheEntry entry) {}
+ }
+}
diff --git a/java/com/android/incallui/call/CallList.java b/java/com/android/incallui/call/CallList.java
index 01f3b9d29..eccdceeca 100644
--- a/java/com/android/incallui/call/CallList.java
+++ b/java/com/android/incallui/call/CallList.java
@@ -784,6 +784,12 @@ public class CallList implements DialerCallDelegate {
*/
void onUpgradeToVideo(DialerCall call);
+ /**
+ * Called when a new RTT call request comes in This is the only method that gets called for RTT
+ * requests.
+ */
+ default void onUpgradeToRtt(DialerCall call, int rttRequestId) {}
+
/** Called when the session modification state of a call changes. */
void onSessionModificationStateChange(DialerCall call);
@@ -855,6 +861,13 @@ public class CallList implements DialerCallDelegate {
public void onDialerCallLastForwardedNumberChange() {}
@Override
+ public void onDialerCallUpgradeToRtt(int rttRequestId) {
+ for (Listener listener : listeners) {
+ listener.onUpgradeToRtt(call, rttRequestId);
+ }
+ }
+
+ @Override
public void onDialerCallUpgradeToVideo() {
for (Listener listener : listeners) {
listener.onUpgradeToVideo(call);
diff --git a/java/com/android/incallui/call/DialerCall.java b/java/com/android/incallui/call/DialerCall.java
index e08c926d8..35f9481c5 100644
--- a/java/com/android/incallui/call/DialerCall.java
+++ b/java/com/android/incallui/call/DialerCall.java
@@ -282,6 +282,9 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa
@Override
public void onRttRequest(Call call, int id) {
LogUtil.v("TelecomCallCallback.onRttRequest", "id=%d", id);
+ for (DialerCallListener listener : listeners) {
+ listener.onDialerCallUpgradeToRtt(id);
+ }
}
@Override
@@ -1033,6 +1036,11 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa
getTelecomCall().sendRttRequest();
}
+ @TargetApi(28)
+ public void respondToRttRequest(boolean accept, int rttRequestId) {
+ getTelecomCall().respondToRttRequest(rttRequestId, accept);
+ }
+
public boolean hasReceivedVideoUpgradeRequest() {
return VideoUtils.hasReceivedVideoUpgradeRequest(getVideoTech().getSessionModificationState());
}
diff --git a/java/com/android/incallui/call/DialerCallListener.java b/java/com/android/incallui/call/DialerCallListener.java
index 5d24a4d4b..37c30d30c 100644
--- a/java/com/android/incallui/call/DialerCallListener.java
+++ b/java/com/android/incallui/call/DialerCallListener.java
@@ -29,6 +29,8 @@ public interface DialerCallListener {
void onDialerCallUpgradeToVideo();
+ default void onDialerCallUpgradeToRtt(int rttRequestId) {}
+
void onDialerCallSessionModificationStateChange();
void onWiFiToLteHandover();
diff --git a/java/com/android/incallui/res/layout/frag_rtt_request_dialog.xml b/java/com/android/incallui/res/layout/frag_rtt_request_dialog.xml
new file mode 100644
index 000000000..ab743eb89
--- /dev/null
+++ b/java/com/android/incallui/res/layout/frag_rtt_request_dialog.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/details"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="20dp"
+ android:paddingBottom="12dp"
+ android:paddingStart="24dp"
+ android:paddingEnd="24dp"
+ android:textColor="#DE000000"
+ android:textSize="16sp"/>
+
+ <TextView
+ android:id="@+id/more_information"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="16dp"
+ android:paddingStart="24dp"
+ android:paddingEnd="24dp"
+ android:text="@string/rtt_request_dialog_more_information"
+ android:textColor="#8A000000"
+ android:textSize="14sp"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:orientation="horizontal">
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"/>
+ <Button
+ android:id="@+id/rtt_button_decline_request"
+ style="@style/Widget.AppCompat.Button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end"
+ android:paddingStart="16dp"
+ android:paddingEnd="16dp"
+ android:backgroundTint="@android:color/white"
+ android:fontFamily="sans-serif-medium"
+ android:stateListAnimator="@null"
+ android:text="@string/rtt_button_decline_request"
+ android:textColor="#757575"/>
+ <Button
+ android:id="@+id/rtt_button_accept_request"
+ style="@style/Widget.AppCompat.Button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end"
+ android:paddingStart="16dp"
+ android:paddingEnd="16dp"
+ android:backgroundTint="@color/dialer_theme_color"
+ android:fontFamily="sans-serif-medium"
+ android:stateListAnimator="@null"
+ android:text="@string/rtt_button_accept_request"
+ android:textColor="@android:color/white"/>
+ </LinearLayout>
+
+</LinearLayout>
+
diff --git a/java/com/android/incallui/res/values/strings.xml b/java/com/android/incallui/res/values/strings.xml
index 15cd2e02d..c7e5677c7 100644
--- a/java/com/android/incallui/res/values/strings.xml
+++ b/java/com/android/incallui/res/values/strings.xml
@@ -202,4 +202,19 @@
<!-- Text for bubble return-to-call button -->
<string name="bubble_return_to_call">Back to call</string>
+ <!-- Title for RTT request dialog. [CHAR LIMIT=60] -->
+ <string name="rtt_request_dialog_title">Join RTT call?</string>
+
+ <!-- Details for RTT request dialog. [CHAR LIMIT=NONE] -->
+ <string name="rtt_request_dialog_details"><xliff:g id="caller">%1$s</xliff:g> wants to use messaging within your voice call.</string>
+
+ <!-- More information for RTT request dialog. [CHAR LIMIT=NONE] -->
+ <string name="rtt_request_dialog_more_information">RTT assists callers who are deaf, hard of hearing, have a speech disability, or need more than voice alone.</string>
+
+ <!-- Text for button to decline RTT request. [CHAR LIMIT=20] -->
+ <string name="rtt_button_decline_request">No thanks</string>
+
+ <!-- Text for button to accept RTT request. [CHAR LIMIT=20] -->
+ <string name="rtt_button_accept_request">Join RTT</string>
+
</resources>
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 b0ac2057e..1d09f5446 100644
--- a/java/com/android/incallui/rtt/impl/res/values/strings.xml
+++ b/java/com/android/incallui/rtt/impl/res/values/strings.xml
@@ -27,7 +27,7 @@
<!-- Text for back button. [CHAR LIMIT=20] -->
<string name="rtt_button_back">Back</string>
- <!-- Text for status banner. [CHAT LIMIT=100] -->
+ <!-- Text for status banner. [CHAR LIMIT=100] -->
<string name="rtt_status_banner_text">Waiting for <xliff:g id="name">%s</xliff:g> to join RTT call&#8230;</string>
</resources> \ No newline at end of file