summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Erfanian <erfanian@google.com>2018-04-26 15:34:21 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2018-04-26 15:34:21 +0000
commit52a161148b057ebd4b0c86228b82cba305f1102d (patch)
tree35906c59b5daccce7f7dacd2ca8a01aaa3dcec5c
parent43ed0dc0666e9d2e2837a2019e2765f10f43dff8 (diff)
parentaa9d670a4f076e52418cd5e404435c524713278e (diff)
Merge changes I6883ce15,Ife5e6bad,If5a40a97,I36916560
* changes: Persist contacts pinned positions in speed dial. Fix crash when saving transcript is called multiple times. Show post char dialog without InCallActivity. UI tweak to RTT chat input box.
-rw-r--r--java/com/android/dialer/speeddial/SpeedDialAdapter.java30
-rw-r--r--java/com/android/dialer/speeddial/SpeedDialFragment.java20
-rw-r--r--java/com/android/dialer/speeddial/database/SpeedDialEntry.java8
-rw-r--r--java/com/android/dialer/speeddial/database/SpeedDialEntryDatabaseHelper.java30
-rw-r--r--java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java11
-rw-r--r--java/com/android/dialer/speeddial/loader/SpeedDialUiItemMutator.java (renamed from java/com/android/dialer/speeddial/loader/SpeedDialUiItemLoader.java)91
-rw-r--r--java/com/android/dialer/speeddial/loader/UiItemLoaderComponent.java2
-rw-r--r--java/com/android/incallui/AndroidManifest.xml7
-rw-r--r--java/com/android/incallui/InCallActivity.java21
-rw-r--r--java/com/android/incallui/InCallPresenter.java16
-rw-r--r--java/com/android/incallui/PostCharDialogActivity.java100
-rw-r--r--java/com/android/incallui/PostCharDialogFragment.java3
-rw-r--r--java/com/android/incallui/call/DialerCall.java11
-rw-r--r--java/com/android/incallui/rtt/impl/RttChatFragment.java6
-rw-r--r--java/com/android/incallui/rtt/impl/res/layout/frag_rtt_chat.xml6
15 files changed, 303 insertions, 59 deletions
diff --git a/java/com/android/dialer/speeddial/SpeedDialAdapter.java b/java/com/android/dialer/speeddial/SpeedDialAdapter.java
index 8a37e97dd..a382b1a6b 100644
--- a/java/com/android/dialer/speeddial/SpeedDialAdapter.java
+++ b/java/com/android/dialer/speeddial/SpeedDialAdapter.java
@@ -34,10 +34,10 @@ import com.android.dialer.speeddial.HeaderViewHolder.SpeedDialHeaderListener;
import com.android.dialer.speeddial.SuggestionViewHolder.SuggestedContactsListener;
import com.android.dialer.speeddial.draghelper.SpeedDialItemTouchHelperCallback.ItemTouchHelperAdapter;
import com.android.dialer.speeddial.loader.SpeedDialUiItem;
+import com.google.common.collect.ImmutableList;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -146,7 +146,13 @@ public final class SpeedDialAdapter extends RecyclerView.Adapter<RecyclerView.Vi
public void setSpeedDialUiItems(List<SpeedDialUiItem> immutableSpeedDialUiItems) {
speedDialUiItems = new ArrayList<>();
speedDialUiItems.addAll(immutableSpeedDialUiItems);
- speedDialUiItems.sort((o1, o2) -> Boolean.compare(o2.isStarred(), o1.isStarred()));
+ speedDialUiItems.sort(
+ (o1, o2) -> {
+ if (o1.isStarred() && o2.isStarred()) {
+ return Integer.compare(o1.pinnedPosition().or(-1), o2.pinnedPosition().or(-1));
+ }
+ return Boolean.compare(o2.isStarred(), o1.isStarred());
+ });
positionToRowTypeMap.clear();
if (speedDialUiItems.isEmpty()) {
return;
@@ -168,6 +174,13 @@ public final class SpeedDialAdapter extends RecyclerView.Adapter<RecyclerView.Vi
}
}
+ public ImmutableList<SpeedDialUiItem> getSpeedDialUiItems() {
+ if (speedDialUiItems == null || speedDialUiItems.isEmpty()) {
+ return ImmutableList.of();
+ }
+ return ImmutableList.copyOf(speedDialUiItems);
+ }
+
public SpanSizeLookup getSpanSizeLookup() {
return new SpanSizeLookup() {
@Override
@@ -189,16 +202,9 @@ public final class SpeedDialAdapter extends RecyclerView.Adapter<RecyclerView.Vi
@Override
public void onItemMove(int fromPosition, int toPosition) {
- if (fromPosition < toPosition) {
- for (int i = fromPosition; i < toPosition && i < speedDialUiItems.size() - 1; i++) {
- Collections.swap(speedDialUiItems, i, i + 1);
- }
- } else {
- for (int i = fromPosition - 1; i > toPosition; i--) {
- Collections.swap(speedDialUiItems, i, i - 1);
- }
- }
- // TODO(calderwoodra): store pinned positions
+ // fromPosition/toPosition correspond to adapter position, which is off by 1 from the list
+ // position b/c of the favorites header. So subtract 1 here.
+ speedDialUiItems.add(toPosition - 1, speedDialUiItems.remove(fromPosition - 1));
notifyItemMoved(fromPosition, toPosition);
}
diff --git a/java/com/android/dialer/speeddial/SpeedDialFragment.java b/java/com/android/dialer/speeddial/SpeedDialFragment.java
index b74c06239..b76db1cf3 100644
--- a/java/com/android/dialer/speeddial/SpeedDialFragment.java
+++ b/java/com/android/dialer/speeddial/SpeedDialFragment.java
@@ -36,6 +36,7 @@ import com.android.dialer.callintent.CallInitiationType;
import com.android.dialer.callintent.CallIntentBuilder;
import com.android.dialer.common.FragmentUtils;
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.SupportUiListener;
import com.android.dialer.constants.ActivityRequestCodes;
@@ -54,6 +55,7 @@ import com.android.dialer.speeddial.loader.SpeedDialUiItem;
import com.android.dialer.speeddial.loader.UiItemLoaderComponent;
import com.android.dialer.util.IntentUtil;
import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.Futures;
/**
* Fragment for displaying:
@@ -143,7 +145,7 @@ public class SpeedDialFragment extends Fragment {
speedDialLoaderListener.listen(
getContext(),
- UiItemLoaderComponent.get(getContext()).speedDialUiItemLoader().loadSpeedDialUiItems(),
+ UiItemLoaderComponent.get(getContext()).speedDialUiItemMutator().loadSpeedDialUiItems(),
this::onSpeedDialUiItemListLoaded,
throwable -> {
throw new RuntimeException(throwable);
@@ -158,7 +160,7 @@ public class SpeedDialFragment extends Fragment {
speedDialLoaderListener.listen(
getContext(),
UiItemLoaderComponent.get(getContext())
- .speedDialUiItemLoader()
+ .speedDialUiItemMutator()
.starContact(data.getData()),
this::onSpeedDialUiItemListLoaded,
throwable -> {
@@ -173,7 +175,7 @@ public class SpeedDialFragment extends Fragment {
// TODO(calderwoodra): Use DiffUtil to properly update and animate the change
adapter.setSpeedDialUiItems(
UiItemLoaderComponent.get(getContext())
- .speedDialUiItemLoader()
+ .speedDialUiItemMutator()
.insertDuoChannels(getContext(), speedDialUiItems));
adapter.notifyDataSetChanged();
if (getActivity() != null) {
@@ -187,6 +189,18 @@ public class SpeedDialFragment extends Fragment {
super.onPause();
contextMenu.hideMenu();
contextMenuBackground.setVisibility(View.GONE);
+ Futures.addCallback(
+ DialerExecutorComponent.get(getContext())
+ .backgroundExecutor()
+ .submit(
+ () -> {
+ UiItemLoaderComponent.get(getContext())
+ .speedDialUiItemMutator()
+ .updatePinnedPosition(adapter.getSpeedDialUiItems());
+ return null;
+ }),
+ new DefaultFutureCallback<>(),
+ DialerExecutorComponent.get(getContext()).backgroundExecutor());
}
@Override
diff --git a/java/com/android/dialer/speeddial/database/SpeedDialEntry.java b/java/com/android/dialer/speeddial/database/SpeedDialEntry.java
index 89aed8f37..181f9eca7 100644
--- a/java/com/android/dialer/speeddial/database/SpeedDialEntry.java
+++ b/java/com/android/dialer/speeddial/database/SpeedDialEntry.java
@@ -20,6 +20,7 @@ import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import com.google.auto.value.AutoValue;
+import com.google.common.base.Optional;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -35,6 +36,9 @@ public abstract class SpeedDialEntry {
@Nullable
public abstract Long id();
+ /** Position the contact is pinned to in the UI. Will be absent if it hasn't be set yet. */
+ public abstract Optional<Integer> pinnedPosition();
+
/** @see {@link Contacts#_ID} */
public abstract long contactId();
@@ -53,7 +57,7 @@ public abstract class SpeedDialEntry {
public abstract Builder toBuilder();
public static Builder builder() {
- return new AutoValue_SpeedDialEntry.Builder();
+ return new AutoValue_SpeedDialEntry.Builder().setPinnedPosition(Optional.absent());
}
/** Builder class for speed dial entry. */
@@ -62,6 +66,8 @@ public abstract class SpeedDialEntry {
public abstract Builder setId(Long id);
+ public abstract Builder setPinnedPosition(Optional<Integer> pinnedPosition);
+
public abstract Builder setContactId(long contactId);
public abstract Builder setLookupKey(String lookupKey);
diff --git a/java/com/android/dialer/speeddial/database/SpeedDialEntryDatabaseHelper.java b/java/com/android/dialer/speeddial/database/SpeedDialEntryDatabaseHelper.java
index 544bb3613..1416a203d 100644
--- a/java/com/android/dialer/speeddial/database/SpeedDialEntryDatabaseHelper.java
+++ b/java/com/android/dialer/speeddial/database/SpeedDialEntryDatabaseHelper.java
@@ -25,6 +25,7 @@ import android.text.TextUtils;
import com.android.dialer.common.Assert;
import com.android.dialer.common.database.Selection;
import com.android.dialer.speeddial.database.SpeedDialEntry.Channel;
+import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.util.ArrayList;
@@ -38,12 +39,20 @@ import java.util.List;
public final class SpeedDialEntryDatabaseHelper extends SQLiteOpenHelper
implements SpeedDialEntryDao {
+ /**
+ * If the pinned position is absent, then we need to write an impossible value in the table like
+ * -1 so that it doesn't default to 0. When we read this value from the table, we'll translate it
+ * to Optional.absent() in the resulting {@link SpeedDialEntry}.
+ */
+ private static final int PINNED_POSITION_ABSENT = -1;
+
private static final int DATABASE_VERSION = 2;
private static final String DATABASE_NAME = "CPSpeedDialEntry";
// Column names
private static final String TABLE_NAME = "speed_dial_entries";
private static final String ID = "id";
+ private static final String PINNED_POSITION = "pinned_position";
private static final String CONTACT_ID = "contact_id";
private static final String LOOKUP_KEY = "lookup_key";
private static final String PHONE_NUMBER = "phone_number";
@@ -53,12 +62,13 @@ public final class SpeedDialEntryDatabaseHelper extends SQLiteOpenHelper
// Column positions
private static final int POSITION_ID = 0;
- private static final int POSITION_CONTACT_ID = 1;
- private static final int POSITION_LOOKUP_KEY = 2;
- private static final int POSITION_PHONE_NUMBER = 3;
- private static final int POSITION_PHONE_TYPE = 4;
- private static final int POSITION_PHONE_LABEL = 5;
- private static final int POSITION_PHONE_TECHNOLOGY = 6;
+ private static final int POSITION_PINNED_POSITION = 1;
+ private static final int POSITION_CONTACT_ID = 2;
+ private static final int POSITION_LOOKUP_KEY = 3;
+ private static final int POSITION_PHONE_NUMBER = 4;
+ private static final int POSITION_PHONE_TYPE = 5;
+ private static final int POSITION_PHONE_LABEL = 6;
+ private static final int POSITION_PHONE_TECHNOLOGY = 7;
// Create Table Query
private static final String CREATE_TABLE_SQL =
@@ -66,6 +76,7 @@ public final class SpeedDialEntryDatabaseHelper extends SQLiteOpenHelper
+ TABLE_NAME
+ " ("
+ (ID + " integer primary key, ")
+ + (PINNED_POSITION + " integer, ")
+ (CONTACT_ID + " integer, ")
+ (LOOKUP_KEY + " text, ")
+ (PHONE_NUMBER + " text, ")
@@ -119,11 +130,17 @@ public final class SpeedDialEntryDatabaseHelper extends SQLiteOpenHelper
.build();
}
+ Optional<Integer> pinnedPosition = Optional.of(cursor.getInt(POSITION_PINNED_POSITION));
+ if (pinnedPosition.or(PINNED_POSITION_ABSENT) == PINNED_POSITION_ABSENT) {
+ pinnedPosition = Optional.absent();
+ }
+
SpeedDialEntry entry =
SpeedDialEntry.builder()
.setDefaultChannel(channel)
.setContactId(cursor.getLong(POSITION_CONTACT_ID))
.setLookupKey(cursor.getString(POSITION_LOOKUP_KEY))
+ .setPinnedPosition(pinnedPosition)
.setId(cursor.getLong(POSITION_ID))
.build();
entries.add(entry);
@@ -226,6 +243,7 @@ public final class SpeedDialEntryDatabaseHelper extends SQLiteOpenHelper
if (includeId) {
values.put(ID, entry.id());
}
+ values.put(PINNED_POSITION, entry.pinnedPosition().or(PINNED_POSITION_ABSENT));
values.put(CONTACT_ID, entry.contactId());
values.put(LOOKUP_KEY, entry.lookupKey());
if (entry.defaultChannel() != null) {
diff --git a/java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java b/java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java
index 9bda3fb31..a2bdfb89a 100644
--- a/java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java
+++ b/java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java
@@ -25,6 +25,7 @@ import com.android.dialer.common.Assert;
import com.android.dialer.speeddial.database.SpeedDialEntry;
import com.android.dialer.speeddial.database.SpeedDialEntry.Channel;
import com.google.auto.value.AutoValue;
+import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.List;
@@ -83,7 +84,9 @@ public abstract class SpeedDialUiItem {
}
public static Builder builder() {
- return new AutoValue_SpeedDialUiItem.Builder().setChannels(ImmutableList.of());
+ return new AutoValue_SpeedDialUiItem.Builder()
+ .setChannels(ImmutableList.of())
+ .setPinnedPosition(Optional.absent());
}
/**
@@ -139,6 +142,7 @@ public abstract class SpeedDialUiItem {
public SpeedDialEntry buildSpeedDialEntry() {
return SpeedDialEntry.builder()
.setId(speedDialEntryId())
+ .setPinnedPosition(pinnedPosition())
.setLookupKey(lookupKey())
.setContactId(contactId())
.setDefaultChannel(defaultChannel())
@@ -212,6 +216,9 @@ public abstract class SpeedDialUiItem {
@Nullable
public abstract Long speedDialEntryId();
+ /** @see SpeedDialEntry#pinnedPosition() */
+ public abstract Optional<Integer> pinnedPosition();
+
/** @see android.provider.ContactsContract.Contacts#DISPLAY_NAME */
public abstract String name();
@@ -255,6 +262,8 @@ public abstract class SpeedDialUiItem {
/** Set to null if {@link #isStarred()} is false. */
public abstract Builder setSpeedDialEntryId(@Nullable Long id);
+ public abstract Builder setPinnedPosition(Optional<Integer> pinnedPosition);
+
public abstract Builder setName(String name);
public abstract Builder setContactId(long contactId);
diff --git a/java/com/android/dialer/speeddial/loader/SpeedDialUiItemLoader.java b/java/com/android/dialer/speeddial/loader/SpeedDialUiItemMutator.java
index 921468773..5dae2efab 100644
--- a/java/com/android/dialer/speeddial/loader/SpeedDialUiItemLoader.java
+++ b/java/com/android/dialer/speeddial/loader/SpeedDialUiItemMutator.java
@@ -17,11 +17,14 @@
package com.android.dialer.speeddial.loader;
import android.annotation.TargetApi;
+import android.content.ContentProviderOperation;
import android.content.ContentValues;
import android.content.Context;
+import android.content.OperationApplicationException;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build.VERSION_CODES;
+import android.os.RemoteException;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Contacts;
@@ -43,6 +46,7 @@ import com.android.dialer.speeddial.database.SpeedDialEntry;
import com.android.dialer.speeddial.database.SpeedDialEntry.Channel;
import com.android.dialer.speeddial.database.SpeedDialEntryDao;
import com.android.dialer.speeddial.database.SpeedDialEntryDatabaseHelper;
+import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.util.concurrent.ListenableFuture;
@@ -76,7 +80,7 @@ import javax.inject.Singleton;
@SuppressWarnings("AndroidApiChecker")
@TargetApi(VERSION_CODES.N)
@Singleton
-public final class SpeedDialUiItemLoader {
+public final class SpeedDialUiItemMutator {
private static final int MAX_DUO_SUGGESTIONS = 3;
@@ -87,7 +91,7 @@ public final class SpeedDialUiItemLoader {
private final ContactsPreferences contactsPreferences;
@Inject
- public SpeedDialUiItemLoader(
+ public SpeedDialUiItemMutator(
@ApplicationContext Context appContext,
@BackgroundExecutor ListeningExecutorService backgroundExecutor) {
this.appContext = appContext;
@@ -127,7 +131,7 @@ public final class SpeedDialUiItemLoader {
null,
null)) {
if (cursor == null) {
- LogUtil.e("SpeedDialUiItemLoader.insertNewContactEntry", "Cursor was null");
+ LogUtil.e("SpeedDialUiItemMutator.insertNewContactEntry", "Cursor was null");
return loadSpeedDialUiItemsInternal();
}
Assert.checkArgument(cursor.moveToFirst(), "Cursor should never be empty");
@@ -285,7 +289,7 @@ public final class SpeedDialUiItemLoader {
null,
null)) {
if (cursor == null) {
- LogUtil.e("SpeedDialUiItemLoader.updateContactIdsAndLookupKeys", "null cursor");
+ LogUtil.e("SpeedDialUiItemMutator.updateContactIdsAndLookupKeys", "null cursor");
return new ArrayList<>();
}
if (cursor.getCount() == 0) {
@@ -339,9 +343,11 @@ public final class SpeedDialUiItemLoader {
SpeedDialUiItem item = SpeedDialUiItem.fromCursor(cursor);
for (SpeedDialEntry entry : entries) {
if (entry.contactId() == item.contactId()) {
- // Update the id to match it's corresponding SpeedDialEntry.
+ // Update the id and pinned position to match it's corresponding SpeedDialEntry.
SpeedDialUiItem.Builder entrySpeedDialItem =
- item.toBuilder().setSpeedDialEntryId(entry.id());
+ item.toBuilder()
+ .setSpeedDialEntryId(entry.id())
+ .setPinnedPosition(entry.pinnedPosition());
// Preserve the default channel if it didn't change/still exists
Channel defaultChannel = entry.defaultChannel();
@@ -405,7 +411,7 @@ public final class SpeedDialUiItemLoader {
.getContentResolver()
.query(strequentUri, new String[] {Phone.CONTACT_ID}, null, null, null)) {
if (cursor == null) {
- LogUtil.e("SpeedDialUiItemLoader.getStrequentContacts", "null cursor");
+ LogUtil.e("SpeedDialUiItemMutator.getStrequentContacts", "null cursor");
return new ArrayList<>();
}
if (cursor.getCount() == 0) {
@@ -430,7 +436,7 @@ public final class SpeedDialUiItemLoader {
null)) {
List<SpeedDialUiItem> contacts = new ArrayList<>();
if (cursor == null) {
- LogUtil.e("SpeedDialUiItemLoader.getStrequentContacts", "null cursor");
+ LogUtil.e("SpeedDialUiItemMutator.getStrequentContacts", "null cursor");
return new ArrayList<>();
}
if (cursor.getCount() == 0) {
@@ -444,6 +450,75 @@ public final class SpeedDialUiItemLoader {
}
/**
+ * Persists the position of the {@link SpeedDialUiItem items} as the pinned position according to
+ * the order they were passed in.
+ */
+ @WorkerThread
+ public void updatePinnedPosition(List<SpeedDialUiItem> speedDialUiItems) {
+ Assert.isWorkerThread();
+ if (speedDialUiItems == null || speedDialUiItems.isEmpty()) {
+ return;
+ }
+
+ // Update the positions in the SpeedDialEntry database
+ ImmutableList.Builder<SpeedDialEntry> entriesToUpdate = ImmutableList.builder();
+ for (int i = 0; i < speedDialUiItems.size(); i++) {
+ SpeedDialUiItem item = speedDialUiItems.get(i);
+ if (item.isStarred()) {
+ entriesToUpdate.add(
+ item.buildSpeedDialEntry().toBuilder().setPinnedPosition(Optional.of(i)).build());
+ }
+ }
+ getSpeedDialEntryDao().update(entriesToUpdate.build());
+
+ // Update the positions in CP2
+ // Build a list of SpeedDialUiItems where each contact is only represented once but the order
+ // is maintained. For example, assume you have a list of contacts with contact ids:
+ // > { 1, 1, 2, 1, 2, 3 }
+ // This list will be reduced to:
+ // > { 1, 2, 3 }
+ // and their positions in the resulting list will be written to the CP2 Contacts.PINNED column.
+ List<SpeedDialUiItem> cp2SpeedDialUiItems = new ArrayList<>();
+ Set<Long> contactIds = new ArraySet<>();
+ for (SpeedDialUiItem item : speedDialUiItems) {
+ if (contactIds.add(item.contactId())) {
+ cp2SpeedDialUiItems.add(item);
+ }
+ }
+
+ // Code copied from PhoneFavoritesTileAdapter#handleDrop
+ ArrayList<ContentProviderOperation> operations = new ArrayList<>();
+ for (int i = 0; i < cp2SpeedDialUiItems.size(); i++) {
+ SpeedDialUiItem item = cp2SpeedDialUiItems.get(i);
+ // Pinned positions in the database start from 1 instead of being zero-indexed like
+ // arrays, so offset by 1.
+ int databasePinnedPosition = i + 1;
+ if (item.pinnedPosition().isPresent()
+ && item.pinnedPosition().get() == databasePinnedPosition) {
+ continue;
+ }
+
+ Uri uri = Uri.withAppendedPath(Contacts.CONTENT_URI, String.valueOf(item.contactId()));
+ ContentValues values = new ContentValues();
+ values.put(Contacts.PINNED, databasePinnedPosition);
+ operations.add(ContentProviderOperation.newUpdate(uri).withValues(values).build());
+ }
+ if (operations.isEmpty()) {
+ // Nothing to update
+ return;
+ }
+ try {
+ appContext.getContentResolver().applyBatch(ContactsContract.AUTHORITY, operations);
+ // TODO(calderwoodra): log
+ } catch (RemoteException | OperationApplicationException e) {
+ LogUtil.e(
+ "SpeedDialUiItemMutator.updatePinnedPosition",
+ "Exception thrown when pinning contacts",
+ e);
+ }
+ }
+
+ /**
* Returns a new list with duo reachable channels inserted. Duo channels won't replace ViLTE
* channels.
*/
diff --git a/java/com/android/dialer/speeddial/loader/UiItemLoaderComponent.java b/java/com/android/dialer/speeddial/loader/UiItemLoaderComponent.java
index 7d01b4380..852908409 100644
--- a/java/com/android/dialer/speeddial/loader/UiItemLoaderComponent.java
+++ b/java/com/android/dialer/speeddial/loader/UiItemLoaderComponent.java
@@ -24,7 +24,7 @@ import dagger.Subcomponent;
@Subcomponent
public abstract class UiItemLoaderComponent {
- public abstract SpeedDialUiItemLoader speedDialUiItemLoader();
+ public abstract SpeedDialUiItemMutator speedDialUiItemMutator();
public static UiItemLoaderComponent get(Context context) {
return ((UiItemLoaderComponent.HasComponent)
diff --git a/java/com/android/incallui/AndroidManifest.xml b/java/com/android/incallui/AndroidManifest.xml
index 832a5e874..7286b0db7 100644
--- a/java/com/android/incallui/AndroidManifest.xml
+++ b/java/com/android/incallui/AndroidManifest.xml
@@ -106,6 +106,13 @@
android:theme="@style/Theme.Incall.DialogHolder"
/>
+ <activity
+ android:excludeFromRecents="true"
+ android:exported="false"
+ android:name="com.android.incallui.PostCharDialogActivity"
+ android:noHistory="true"
+ android:theme="@style/Theme.Incall.DialogHolder"/>
+
<!-- BroadcastReceiver for receiving Intents from Notification mechanism. -->
<receiver
android:directBootAware="true"
diff --git a/java/com/android/incallui/InCallActivity.java b/java/com/android/incallui/InCallActivity.java
index 2b6c2b49d..02335b6e4 100644
--- a/java/com/android/incallui/InCallActivity.java
+++ b/java/com/android/incallui/InCallActivity.java
@@ -145,8 +145,6 @@ public class InCallActivity extends TransactionSafeFragmentActivity
private View pseudoBlackScreenOverlay;
private SelectPhoneAccountDialogFragment selectPhoneAccountDialogFragment;
private String dtmfTextToPrepopulate;
- private String showPostCharWaitDialogCallId;
- private String showPostCharWaitDialogChars;
private boolean allowOrientationChange;
private boolean animateDialpadOnShow;
private boolean didShowAnswerScreen;
@@ -160,7 +158,6 @@ public class InCallActivity extends TransactionSafeFragmentActivity
private boolean isRecreating; // whether the activity is going to be recreated
private boolean isVisible;
private boolean needDismissPendingDialogs;
- private boolean showPostCharWaitDialogOnResume;
private boolean touchDownWhenPseudoScreenOff;
private int[] backgroundDrawableColors;
@DialpadRequestType private int showDialpadRequest = DIALPAD_REQUEST_NONE;
@@ -531,10 +528,6 @@ public class InCallActivity extends TransactionSafeFragmentActivity
}
updateNavigationBar(isDialpadVisible());
- if (showPostCharWaitDialogOnResume) {
- showDialogForPostCharWait(showPostCharWaitDialogCallId, showPostCharWaitDialogChars);
- }
-
CallList.getInstance()
.onInCallUiShown(getIntent().getBooleanExtra(IntentExtraNames.FOR_FULL_SCREEN, false));
@@ -1016,18 +1009,8 @@ public class InCallActivity extends TransactionSafeFragmentActivity
}
public void showDialogForPostCharWait(String callId, String chars) {
- if (isVisible) {
- PostCharDialogFragment fragment = new PostCharDialogFragment(callId, chars);
- fragment.show(getSupportFragmentManager(), Tags.POST_CHAR_DIALOG_FRAGMENT);
-
- showPostCharWaitDialogOnResume = false;
- showPostCharWaitDialogCallId = null;
- showPostCharWaitDialogChars = null;
- } else {
- showPostCharWaitDialogOnResume = true;
- showPostCharWaitDialogCallId = callId;
- showPostCharWaitDialogChars = chars;
- }
+ PostCharDialogFragment fragment = new PostCharDialogFragment(callId, chars);
+ fragment.show(getSupportFragmentManager(), Tags.POST_CHAR_DIALOG_FRAGMENT);
}
public void showDialogOrToastForDisconnectedCall(DisconnectMessage disconnectMessage) {
diff --git a/java/com/android/incallui/InCallPresenter.java b/java/com/android/incallui/InCallPresenter.java
index 526cc64d3..6e7daf551 100644
--- a/java/com/android/incallui/InCallPresenter.java
+++ b/java/com/android/incallui/InCallPresenter.java
@@ -1271,8 +1271,22 @@ public class InCallPresenter implements CallList.Listener, AudioModeProvider.Aud
}
public void onPostDialCharWait(String callId, String chars) {
- if (isActivityStarted()) {
+ // If not visible, inCallActivity is stopped. Starting from P, calling recreate() will destroy
+ // the old activity instance and create a new instance immediately. Previously, the old activity
+ // went through its lifecycle from create to destroy before creating a new instance.
+ // So this case doesn't work now: make a call with char WAIT, leave in call UI, call gets
+ // connected, and go back to in call UI to see the dialog.
+ // So we should show dialog in an empty activity if inCallActivity is not visible. And it also
+ // helps with background calling.
+ if (isActivityStarted() && inCallActivity.isVisible()) {
inCallActivity.showDialogForPostCharWait(callId, chars);
+ } else {
+ Intent intent = new Intent(context, PostCharDialogActivity.class);
+ // Prevent showing MainActivity with PostCharDialogActivity on above
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ intent.putExtra(PostCharDialogActivity.EXTRA_CALL_ID, callId);
+ intent.putExtra(PostCharDialogActivity.EXTRA_POST_DIAL_STRING, chars);
+ context.startActivity(intent);
}
}
diff --git a/java/com/android/incallui/PostCharDialogActivity.java b/java/com/android/incallui/PostCharDialogActivity.java
new file mode 100644
index 000000000..dcdc9d663
--- /dev/null
+++ b/java/com/android/incallui/PostCharDialogActivity.java
@@ -0,0 +1,100 @@
+/*
+ * 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.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AppCompatActivity;
+import com.android.incallui.call.CallList;
+import com.android.incallui.call.DialerCall;
+
+/**
+ * Activity that contains an alert dialog with OK and Cancel buttons to allow user to Accept or
+ * Reject the WAIT inserted as part of the Dial string.
+ */
+public class PostCharDialogActivity extends AppCompatActivity implements CallList.Listener {
+
+ public static final String EXTRA_CALL_ID = "extra_call_id";
+ public static final String EXTRA_POST_DIAL_STRING = "extra_post_dial_string";
+ private static final String TAG_INTERNATIONAL_CALL_ON_WIFI = "tag_international_call_on_wifi";
+
+ private String callId;
+
+ @Override
+ protected void onCreate(@Nullable Bundle bundle) {
+ super.onCreate(bundle);
+
+ callId = getIntent().getStringExtra(EXTRA_CALL_ID);
+ String postDialString = getIntent().getStringExtra(EXTRA_POST_DIAL_STRING);
+ if (callId == null || postDialString == null) {
+ finish();
+ return;
+ }
+
+ PostCharDialogFragment fragment = new PostCharDialogFragment(callId, postDialString);
+ fragment.show(getSupportFragmentManager(), TAG_INTERNATIONAL_CALL_ON_WIFI);
+
+ CallList.getInstance().addListener(this);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ CallList.getInstance().removeListener(this);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ // We don't expect the activity to resume, except for orientation change.
+ if (!isChangingConfigurations()) {
+ finish();
+ }
+ }
+
+ @Override
+ public void onDisconnect(DialerCall call) {
+ if (callId.equals(call.getId())) {
+ finish();
+ }
+ }
+
+ @Override
+ public void onIncomingCall(DialerCall call) {}
+
+ @Override
+ public void onUpgradeToVideo(DialerCall call) {}
+
+ @Override
+ public void onUpgradeToRtt(DialerCall call, int rttRequestId) {}
+
+ @Override
+ public void onSessionModificationStateChange(DialerCall call) {}
+
+ @Override
+ public void onCallListChange(CallList callList) {}
+
+ @Override
+ public void onWiFiToLteHandover(DialerCall call) {}
+
+ @Override
+ public void onHandoverToWifiFailed(DialerCall call) {}
+
+ @Override
+ public void onInternationalCallOnWifi(@NonNull DialerCall call) {}
+}
diff --git a/java/com/android/incallui/PostCharDialogFragment.java b/java/com/android/incallui/PostCharDialogFragment.java
index 4bcc68e33..1d06fd487 100644
--- a/java/com/android/incallui/PostCharDialogFragment.java
+++ b/java/com/android/incallui/PostCharDialogFragment.java
@@ -55,7 +55,8 @@ public class PostCharDialogFragment extends DialogFragment {
buf.append(getResources().getText(R.string.wait_prompt_str));
buf.append(postDialStr);
- final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ final AlertDialog.Builder builder =
+ new AlertDialog.Builder(getActivity(), R.style.AlertDialogTheme);
builder.setMessage(buf.toString());
builder.setPositiveButton(
diff --git a/java/com/android/incallui/call/DialerCall.java b/java/com/android/incallui/call/DialerCall.java
index 9dfe7abcb..da05b9d2a 100644
--- a/java/com/android/incallui/call/DialerCall.java
+++ b/java/com/android/incallui/call/DialerCall.java
@@ -192,6 +192,7 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa
private volatile boolean feedbackRequested = false;
@Nullable private PreferredAccountRecorder preferredAccountRecorder;
+ private boolean isCallRemoved;
public static String getNumberFromHandle(Uri handle) {
return handle == null ? "" : handle.getSchemeSpecificPart();
@@ -1608,15 +1609,17 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa
void onRemovedFromCallList() {
LogUtil.enterBlock("DialerCall.onRemovedFromCallList");
// Ensure we clean up when this call is removed.
- videoTechManager.dispatchRemovedFromCallList();
- if (rttTranscript != null) {
+ if (videoTechManager != null) {
+ videoTechManager.dispatchRemovedFromCallList();
+ }
+ // TODO(a bug): Add tests for it to make sure no crash on subsequent call to this method.
+ if (rttTranscript != null && !isCallRemoved) {
Futures.addCallback(
RttTranscriptUtil.saveRttTranscript(context, rttTranscript),
new DefaultFutureCallback<>(),
MoreExecutors.directExecutor());
- // Sets to null so it won't be saved again when called multiple times.
- rttTranscript = null;
}
+ isCallRemoved = true;
}
public com.android.dialer.logging.VideoTech.Type getSelectedAvailableVideoTechType() {
diff --git a/java/com/android/incallui/rtt/impl/RttChatFragment.java b/java/com/android/incallui/rtt/impl/RttChatFragment.java
index 7bfa100ea..47036cd43 100644
--- a/java/com/android/incallui/rtt/impl/RttChatFragment.java
+++ b/java/com/android/incallui/rtt/impl/RttChatFragment.java
@@ -461,6 +461,12 @@ public class RttChatFragment extends Fragment
+ SystemClock.elapsedRealtime());
chronometer.start();
isTimerStarted = true;
+ editText.setVisibility(View.VISIBLE);
+ submitButton.setVisibility(View.VISIBLE);
+ editText.setFocusableInTouchMode(true);
+ if (editText.requestFocus()) {
+ UiUtil.openKeyboardFrom(getContext(), editText);
+ }
}
if (primaryCallState.state() == State.DIALING) {
showWaitingForJoinBanner();
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 ea7ff1095..f995185b1 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
@@ -54,7 +54,8 @@
android:minHeight="53dp"
android:textColor="#DD000000"
android:textColorHint="#757575"
- android:textSize="16sp"/>
+ android:textSize="16sp"
+ android:visibility="gone"/>
<ImageButton
android:id="@+id/rtt_chat_submit_button"
android:layout_width="55dp"
@@ -65,7 +66,8 @@
android:backgroundTintMode="multiply"
android:contentDescription="@string/content_description_rtt_check_button"
android:src="@drawable/quantum_ic_done_vd_theme_24"
- android:tint="@color/submit_button_color"/>
+ android:tint="@color/submit_button_color"
+ android:visibility="gone"/>
</LinearLayout>
<FrameLayout