summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--java/com/android/bubble/res/values-car/values.xml6
-rw-r--r--java/com/android/dialer/app/DialtactsActivity.java4
-rw-r--r--java/com/android/dialer/app/list/SmartDialNumberListAdapter.java6
-rw-r--r--java/com/android/dialer/app/list/SmartDialSearchFragment.java2
-rw-r--r--java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java36
-rw-r--r--java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java25
-rw-r--r--java/com/android/dialer/calllog/ui/NewCallLogFragment.java6
-rw-r--r--java/com/android/dialer/common/concurrent/UiListener.java8
-rw-r--r--java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java14
-rw-r--r--java/com/android/dialer/database/DialerDatabaseHelper.java4
-rw-r--r--java/com/android/dialer/dialpadview/DialpadCharMappings.java17
-rw-r--r--java/com/android/dialer/dialpadview/DialpadView.java29
-rw-r--r--java/com/android/dialer/function/BiConsumer.java24
-rw-r--r--java/com/android/dialer/main/impl/MainPagerAdapter.java4
-rw-r--r--java/com/android/dialer/phonelookup/PhoneLookup.java6
-rw-r--r--java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java10
-rw-r--r--java/com/android/dialer/phonelookup/cp2/Cp2PhoneLookup.java107
-rw-r--r--java/com/android/dialer/precall/impl/AssistedDialAction.java6
-rw-r--r--java/com/android/dialer/searchfragment/cp2/SearchContactsCursorLoader.java2
-rw-r--r--java/com/android/dialer/shortcuts/PinnedShortcuts.java9
-rw-r--r--java/com/android/dialer/simulator/impl/SimulatorDialogFragment.java3
-rw-r--r--java/com/android/dialer/simulator/impl/SimulatorVoiceCall.java3
-rw-r--r--java/com/android/dialer/smartdial/RussianSmartDialMap.java94
-rw-r--r--java/com/android/dialer/smartdial/SmartDialCursorLoader.java (renamed from java/com/android/dialer/dialpadview/SmartDialCursorLoader.java)4
-rw-r--r--java/com/android/dialer/smartdial/map/BulgarianSmartDialMap.java49
-rw-r--r--java/com/android/dialer/smartdial/map/CompositeSmartDialMap.java (renamed from java/com/android/dialer/smartdial/CompositeSmartDialMap.java)16
-rw-r--r--java/com/android/dialer/smartdial/map/LatinSmartDialMap.java (renamed from java/com/android/dialer/smartdial/LatinSmartDialMap.java)43
-rw-r--r--java/com/android/dialer/smartdial/map/RussianSmartDialMap.java49
-rw-r--r--java/com/android/dialer/smartdial/map/SmartDialMap.java (renamed from java/com/android/dialer/smartdial/SmartDialMap.java)2
-rw-r--r--java/com/android/dialer/smartdial/map/UkrainianSmartDialMap.java48
-rw-r--r--java/com/android/dialer/smartdial/util/SmartDialMatchPosition.java (renamed from java/com/android/dialer/smartdial/SmartDialMatchPosition.java)6
-rw-r--r--java/com/android/dialer/smartdial/util/SmartDialNameMatcher.java (renamed from java/com/android/dialer/smartdial/SmartDialNameMatcher.java)5
-rw-r--r--java/com/android/dialer/smartdial/util/SmartDialPrefix.java (renamed from java/com/android/dialer/smartdial/SmartDialPrefix.java)3
-rw-r--r--java/com/android/dialer/telecom/TelecomUtil.java10
-rw-r--r--java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java23
-rw-r--r--java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java22
-rw-r--r--java/com/android/dialer/voicemail/listui/VoicemailCursorLoader.java5
-rw-r--r--java/com/android/dialer/voicemail/model/VoicemailEntry.java7
-rw-r--r--java/com/android/incallui/AndroidManifest.xml3
-rw-r--r--java/com/android/incallui/NewReturnToCallController.java43
-rw-r--r--java/com/android/incallui/call/DialerCall.java43
-rw-r--r--java/com/android/incallui/contactgrid/TopRow.java2
-rw-r--r--java/com/android/incallui/spam/SpamCallListListener.java2
-rw-r--r--java/com/android/newbubble/NewBubble.java17
-rw-r--r--java/com/android/newbubble/res/layout/new_bubble_base.xml1
45 files changed, 572 insertions, 256 deletions
diff --git a/java/com/android/bubble/res/values-car/values.xml b/java/com/android/bubble/res/values-car/values.xml
index cf8839a84..47f20a1bf 100644
--- a/java/com/android/bubble/res/values-car/values.xml
+++ b/java/com/android/bubble/res/values-car/values.xml
@@ -18,10 +18,8 @@
<resources>
<dimen name="bubble_size">64dp</dimen>
- <dimen name="bubble_drawer_margin">54dp</dimen>
+ <dimen name="bubble_drawer_margin">50dp</dimen>
<dimen name="bubble_drawer_padding_start">38dp</dimen>
- <dimen name="bubble_drawer_padding_end">10dp</dimen>
- <dimen name="bubble_icon_padding">18dp</dimen>
- <dimen name="bubble_shadow_padding_size">18dp</dimen>
+ <dimen name="bubble_drawer_padding_end">12dp</dimen>
</resources>
diff --git a/java/com/android/dialer/app/DialtactsActivity.java b/java/com/android/dialer/app/DialtactsActivity.java
index eb95a4ee4..bbb45943a 100644
--- a/java/com/android/dialer/app/DialtactsActivity.java
+++ b/java/com/android/dialer/app/DialtactsActivity.java
@@ -133,8 +133,8 @@ import com.android.dialer.searchfragment.list.NewSearchFragment;
import com.android.dialer.searchfragment.list.NewSearchFragment.SearchFragmentListener;
import com.android.dialer.simulator.Simulator;
import com.android.dialer.simulator.SimulatorComponent;
-import com.android.dialer.smartdial.SmartDialNameMatcher;
-import com.android.dialer.smartdial.SmartDialPrefix;
+import com.android.dialer.smartdial.util.SmartDialNameMatcher;
+import com.android.dialer.smartdial.util.SmartDialPrefix;
import com.android.dialer.storage.StorageComponent;
import com.android.dialer.telecom.TelecomUtil;
import com.android.dialer.util.DialerUtils;
diff --git a/java/com/android/dialer/app/list/SmartDialNumberListAdapter.java b/java/com/android/dialer/app/list/SmartDialNumberListAdapter.java
index 5b48ccfd0..1d2cda3ea 100644
--- a/java/com/android/dialer/app/list/SmartDialNumberListAdapter.java
+++ b/java/com/android/dialer/app/list/SmartDialNumberListAdapter.java
@@ -22,9 +22,9 @@ import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
import com.android.contacts.common.list.ContactListItemView;
import com.android.dialer.common.LogUtil;
-import com.android.dialer.dialpadview.SmartDialCursorLoader;
-import com.android.dialer.smartdial.SmartDialMatchPosition;
-import com.android.dialer.smartdial.SmartDialNameMatcher;
+import com.android.dialer.smartdial.SmartDialCursorLoader;
+import com.android.dialer.smartdial.util.SmartDialMatchPosition;
+import com.android.dialer.smartdial.util.SmartDialNameMatcher;
import com.android.dialer.util.CallUtil;
import java.util.ArrayList;
diff --git a/java/com/android/dialer/app/list/SmartDialSearchFragment.java b/java/com/android/dialer/app/list/SmartDialSearchFragment.java
index e97a16c19..1a7f19515 100644
--- a/java/com/android/dialer/app/list/SmartDialSearchFragment.java
+++ b/java/com/android/dialer/app/list/SmartDialSearchFragment.java
@@ -31,7 +31,7 @@ import com.android.dialer.app.R;
import com.android.dialer.callintent.CallInitiationType;
import com.android.dialer.common.LogUtil;
import com.android.dialer.database.DialerDatabaseHelper;
-import com.android.dialer.dialpadview.SmartDialCursorLoader;
+import com.android.dialer.smartdial.SmartDialCursorLoader;
import com.android.dialer.util.PermissionsUtil;
import com.android.dialer.widget.EmptyContentView;
import java.util.Arrays;
diff --git a/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java b/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java
index fbb58312a..042ff30a2 100644
--- a/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java
+++ b/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java
@@ -110,7 +110,9 @@ public final class PhoneLookupDataSource implements CallLogDataSource {
* <p>This method uses the following algorithm:
*
* <ul>
- * <li>Selects the distinct DialerPhoneNumbers from the AnnotatedCallLog
+ * <li>Finds the phone numbers of interest by taking the union of the distinct
+ * DialerPhoneNumbers from the AnnotatedCallLog and the pending inserts provided in {@code
+ * mutations}
* <li>Uses them to fetch the current information from PhoneLookupHistory, in order to construct
* a map from DialerPhoneNumber to PhoneLookupInfo
* <ul>
@@ -137,9 +139,10 @@ public final class PhoneLookupDataSource implements CallLogDataSource {
phoneLookupHistoryRowsToUpdate.clear();
phoneLookupHistoryRowsToDelete.clear();
- // First query information from annotated call log.
+ // First query information from annotated call log (and include pending inserts).
ListenableFuture<Map<DialerPhoneNumber, Set<Long>>> annotatedCallLogIdsByNumberFuture =
- backgroundExecutorService.submit(() -> queryIdAndNumberFromAnnotatedCallLog(appContext));
+ backgroundExecutorService.submit(
+ () -> collectIdAndNumberFromAnnotatedCallLogAndPendingInserts(appContext, mutations));
// Use it to create the original info map.
ListenableFuture<ImmutableMap<DialerPhoneNumber, PhoneLookupInfo>> originalInfoMapFuture =
@@ -317,9 +320,28 @@ public final class PhoneLookupDataSource implements CallLogDataSource {
return numbers.build();
}
- private Map<DialerPhoneNumber, Set<Long>> queryIdAndNumberFromAnnotatedCallLog(
- Context appContext) {
+ private Map<DialerPhoneNumber, Set<Long>> collectIdAndNumberFromAnnotatedCallLogAndPendingInserts(
+ Context appContext, CallLogMutations mutations) {
Map<DialerPhoneNumber, Set<Long>> idsByNumber = new ArrayMap<>();
+ // First add any pending inserts to the map.
+ for (Entry<Long, ContentValues> entry : mutations.getInserts().entrySet()) {
+ long id = entry.getKey();
+ ContentValues insertedContentValues = entry.getValue();
+ DialerPhoneNumber dialerPhoneNumber;
+ try {
+ dialerPhoneNumber =
+ DialerPhoneNumber.parseFrom(
+ insertedContentValues.getAsByteArray(AnnotatedCallLog.NUMBER));
+ } catch (InvalidProtocolBufferException e) {
+ throw new IllegalStateException(e);
+ }
+ Set<Long> ids = idsByNumber.get(dialerPhoneNumber);
+ if (ids == null) {
+ ids = new ArraySet<>();
+ idsByNumber.put(dialerPhoneNumber, ids);
+ }
+ ids.add(id);
+ }
try (Cursor cursor =
appContext
@@ -332,7 +354,9 @@ public final class PhoneLookupDataSource implements CallLogDataSource {
null)) {
if (cursor == null) {
- LogUtil.e("PhoneLookupDataSource.queryIdAndNumberFromAnnotatedCallLog", "null cursor");
+ LogUtil.e(
+ "PhoneLookupDataSource.collectIdAndNumberFromAnnotatedCallLogAndPendingInserts",
+ "null cursor");
return ImmutableMap.of();
}
diff --git a/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java b/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java
index 0ed185966..95fbf9d04 100644
--- a/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java
+++ b/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java
@@ -27,6 +27,7 @@ import android.os.Build;
import android.os.Handler;
import android.provider.CallLog;
import android.provider.CallLog.Calls;
+import android.provider.VoicemailContract;
import android.support.annotation.ColorInt;
import android.support.annotation.MainThread;
import android.support.annotation.Nullable;
@@ -92,13 +93,21 @@ public class SystemCallLogDataSource implements CallLogDataSource {
}
// TODO(zachh): Need to somehow register observers if user enables permission after launch?
+ CallLogObserver callLogObserver =
+ new CallLogObserver(ThreadUtil.getUiThreadHandler(), appContext, contentObserverCallbacks);
+
appContext
.getContentResolver()
- .registerContentObserver(
- CallLog.Calls.CONTENT_URI_WITH_VOICEMAIL,
- true,
- new CallLogObserver(
- ThreadUtil.getUiThreadHandler(), appContext, contentObserverCallbacks));
+ .registerContentObserver(CallLog.Calls.CONTENT_URI_WITH_VOICEMAIL, true, callLogObserver);
+
+ if (!PermissionsUtil.hasAddVoicemailPermissions(appContext)) {
+ LogUtil.i("SystemCallLogDataSource.registerContentObservers", "no add voicemail permissions");
+ return;
+ }
+ // TODO(uabdullah): Need to somehow register observers if user enables permission after launch?
+ appContext
+ .getContentResolver()
+ .registerContentObserver(VoicemailContract.Status.CONTENT_URI, true, callLogObserver);
}
@Override
@@ -462,7 +471,11 @@ public class SystemCallLogDataSource implements CallLogDataSource {
@Override
public void onChange(boolean selfChange, Uri uri) {
Assert.isMainThread();
- LogUtil.enterBlock("SystemCallLogDataSource.CallLogObserver.onChange");
+ LogUtil.i(
+ "SystemCallLogDataSource.CallLogObserver.onChange",
+ "Uri:%s, SelfChange:%b",
+ String.valueOf(uri),
+ selfChange);
super.onChange(selfChange, uri);
/*
diff --git a/java/com/android/dialer/calllog/ui/NewCallLogFragment.java b/java/com/android/dialer/calllog/ui/NewCallLogFragment.java
index c10b52123..719878cec 100644
--- a/java/com/android/dialer/calllog/ui/NewCallLogFragment.java
+++ b/java/com/android/dialer/calllog/ui/NewCallLogFragment.java
@@ -58,10 +58,10 @@ public final class NewCallLogFragment extends Fragment
}
@Override
- public void onCreate(Bundle state) {
- super.onCreate(state);
+ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
- LogUtil.enterBlock("NewCallLogFragment.onCreate");
+ LogUtil.enterBlock("NewCallLogFragment.onActivityCreated");
CallLogComponent component = CallLogComponent.get(getContext());
CallLogFramework callLogFramework = component.callLogFramework();
diff --git a/java/com/android/dialer/common/concurrent/UiListener.java b/java/com/android/dialer/common/concurrent/UiListener.java
index 9541dbc0c..df791301f 100644
--- a/java/com/android/dialer/common/concurrent/UiListener.java
+++ b/java/com/android/dialer/common/concurrent/UiListener.java
@@ -71,7 +71,10 @@ public class UiListener<OutputT> extends Fragment {
if (uiListener == null) {
LogUtil.i("UiListener.create", "creating new UiListener for " + taskId);
uiListener = new UiListener<>();
- fragmentManager.beginTransaction().add(uiListener, taskId).commit();
+ // When launching an activity with the screen off, its onSaveInstanceState() is called before
+ // its fragments are created, which means we can't use commit() and need to use
+ // commitAllowingStateLoss(). This is not a problem for UiListener which saves no state.
+ fragmentManager.beginTransaction().add(uiListener, taskId).commitAllowingStateLoss();
}
return uiListener;
}
@@ -130,6 +133,9 @@ public class UiListener<OutputT> extends Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
+ // Note: We use commitAllowingStateLoss when attaching the fragment so it may not be safe to
+ // read savedInstanceState in all situations. (But it's not anticipated that this fragment
+ // should need to rely on saved state.)
}
@Override
diff --git a/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java b/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java
index 6bed818da..b01689da4 100644
--- a/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java
+++ b/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java
@@ -57,22 +57,16 @@ public class TelephonyManagerCompat {
*
* <p>This signals to the telephony platform that an outgoing call qualifies for assisted dialing.
*/
- public static final String ALLOW_ASSISTED_DIAL = "android.telecom.extra.ALLOW_ASSISTED_DIAL";
-
- // TODO(erfanian): a bug Replace with the platform/telecom constant when available.
- /**
- * Indicates that an outgoing call has undergone assisted dialing.
- *
- * <p>Unlike {@link ALLOW_ASSISTED_DIAL}, the presence of this key further indicates that a call
- * has undergone Assisted Dialing -- not just that it qualified for Assisted Dialing.
- */
- public static final String IS_ASSISTED_DIALED = "android.telecom.extra.IS_ASSISTED_DIALED";
+ public static final String USE_ASSISTED_DIALING = "android.telecom.extra.USE_ASSISTED_DIALING";
// TODO(erfanian): a bug Replace with the platform/telecom API when available.
/** Additional information relating to the assisted dialing transformation. */
public static final String ASSISTED_DIALING_EXTRAS =
"android.telecom.extra.ASSISTED_DIALING_EXTRAS";
+ /** Indicates the Connection/Call used assisted dialing. */
+ public static final int PROPERTY_ASSISTED_DIALING_USED = 0x00000200;
+
public static final String EXTRA_IS_REFRESH =
BuildCompat.isAtLeastOMR1() ? "android.telephony.extra.IS_REFRESH" : "is_refresh";
diff --git a/java/com/android/dialer/database/DialerDatabaseHelper.java b/java/com/android/dialer/database/DialerDatabaseHelper.java
index b0bd62a34..3fb87304b 100644
--- a/java/com/android/dialer/database/DialerDatabaseHelper.java
+++ b/java/com/android/dialer/database/DialerDatabaseHelper.java
@@ -42,8 +42,8 @@ import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.DialerExecutor.Worker;
import com.android.dialer.common.concurrent.DialerExecutorComponent;
import com.android.dialer.database.FilteredNumberContract.FilteredNumberColumns;
-import com.android.dialer.smartdial.SmartDialNameMatcher;
-import com.android.dialer.smartdial.SmartDialPrefix;
+import com.android.dialer.smartdial.util.SmartDialNameMatcher;
+import com.android.dialer.smartdial.util.SmartDialPrefix;
import com.android.dialer.util.PermissionsUtil;
import java.util.ArrayList;
import java.util.HashSet;
diff --git a/java/com/android/dialer/dialpadview/DialpadCharMappings.java b/java/com/android/dialer/dialpadview/DialpadCharMappings.java
index 03bc2e728..0bb28ae0d 100644
--- a/java/com/android/dialer/dialpadview/DialpadCharMappings.java
+++ b/java/com/android/dialer/dialpadview/DialpadCharMappings.java
@@ -147,6 +147,23 @@ public class DialpadCharMappings {
: null;
}
+ /**
+ * Returns the character-key map of the provided ISO 639-2 language code.
+ *
+ * <p>Note: this method is for implementations of {@link
+ * com.android.dialer.smartdial.map.SmartDialMap} only. {@link #getCharToKeyMap(Context)} should
+ * be used for all other purposes.
+ *
+ * <p>It is the caller's responsibility to ensure the language code is valid and a character
+ * mapping is defined for that language. Otherwise, an exception will be thrown.
+ */
+ public static SimpleArrayMap<Character, Character> getCharToKeyMap(String languageCode) {
+ SimpleArrayMap<Character, Character> charToKeyMap = CHAR_TO_KEY_MAPS.get(languageCode);
+
+ return Assert.isNotNull(
+ charToKeyMap, "No character mappings can be found for language code '%s'", languageCode);
+ }
+
/** Returns the default character-key map (the one that uses the Latin alphabet). */
public static SimpleArrayMap<Character, Character> getDefaultCharToKeyMap() {
return Latin.CHAR_TO_KEY;
diff --git a/java/com/android/dialer/dialpadview/DialpadView.java b/java/com/android/dialer/dialpadview/DialpadView.java
index 2f494e49d..7b95ba7ea 100644
--- a/java/com/android/dialer/dialpadview/DialpadView.java
+++ b/java/com/android/dialer/dialpadview/DialpadView.java
@@ -87,6 +87,7 @@ public class DialpadView extends LinearLayout {
private ViewGroup mRateContainer;
private TextView mIldCountry;
private TextView mIldRate;
+ private boolean mIsLandscapeMode;
public DialpadView(Context context) {
this(context, null);
@@ -125,6 +126,12 @@ public class DialpadView extends LinearLayout {
protected void onFinishInflate() {
super.onFinishInflate();
+ // The orientation obtained at this point should be used as the only truth for DialpadView as we
+ // observed inconsistency between configurations obtained here and in
+ // OnPreDrawListenerForKeyLayoutAdjust under rare circumstances.
+ mIsLandscapeMode =
+ (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);
+
setupKeypad();
mDigits = (EditText) findViewById(R.id.digits);
mDelete = (ImageButton) findViewById(R.id.deleteButton);
@@ -281,7 +288,7 @@ public class DialpadView extends LinearLayout {
final DialpadKeyButton dialpadKey = (DialpadKeyButton) findViewById(BUTTON_IDS[i]);
ViewPropertyAnimator animator = dialpadKey.animate();
- if (isLandscapeMode()) {
+ if (mIsLandscapeMode) {
// Landscape orientation requires translation along the X axis.
// For RTL locales, ensure we translate negative on the X axis.
dialpadKey.setTranslationX((mIsRtl ? -1 : 1) * mTranslateDistance);
@@ -320,7 +327,7 @@ public class DialpadView extends LinearLayout {
* @return The animation delay.
*/
private int getKeyButtonAnimationDelay(int buttonId) {
- if (isLandscapeMode()) {
+ if (mIsLandscapeMode) {
if (mIsRtl) {
if (buttonId == R.id.three) {
return KEY_FRAME_DURATION * 1;
@@ -408,7 +415,7 @@ public class DialpadView extends LinearLayout {
* @return The animation duration.
*/
private int getKeyButtonAnimationDuration(int buttonId) {
- if (isLandscapeMode()) {
+ if (mIsLandscapeMode) {
if (mIsRtl) {
if (buttonId == R.id.one
|| buttonId == R.id.four
@@ -463,10 +470,6 @@ public class DialpadView extends LinearLayout {
return 0;
}
- private boolean isLandscapeMode() {
- return getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
- }
-
/**
* An {@link OnPreDrawListener} that adjusts the height/width of each key layout so that they can
* be properly aligned.
@@ -525,7 +528,7 @@ public class DialpadView extends LinearLayout {
}
private boolean shouldAdjustKeySizes() {
- return isLandscapeMode() ? shouldAdjustKeyWidths() : shouldAdjustDigitKeyHeights();
+ return mIsLandscapeMode ? shouldAdjustKeyWidths() : shouldAdjustDigitKeyHeights();
}
/**
@@ -533,7 +536,7 @@ public class DialpadView extends LinearLayout {
* device is in landscape mode.
*/
private boolean shouldAdjustKeyWidths() {
- Assert.checkState(isLandscapeMode());
+ Assert.checkState(mIsLandscapeMode);
DialpadKeyButton dialpadKeyButton = (DialpadKeyButton) findViewById(BUTTON_IDS[0]);
LinearLayout keyLayout =
@@ -556,7 +559,7 @@ public class DialpadView extends LinearLayout {
* called when the device is in portrait mode.
*/
private boolean shouldAdjustDigitKeyHeights() {
- Assert.checkState(!isLandscapeMode());
+ Assert.checkState(!mIsLandscapeMode);
DialpadKeyButton dialpadKey = (DialpadKeyButton) findViewById(BUTTON_IDS[0]);
LinearLayout keyLayout = (LinearLayout) dialpadKey.findViewById(R.id.dialpad_key_layout);
@@ -576,7 +579,7 @@ public class DialpadView extends LinearLayout {
}
private void adjustKeySizes() {
- if (isLandscapeMode()) {
+ if (mIsLandscapeMode) {
adjustKeyWidths();
} else {
adjustDigitKeyHeights();
@@ -594,7 +597,7 @@ public class DialpadView extends LinearLayout {
* LinearLayout#setLayoutParams(ViewGroup.LayoutParams)}.
*/
private void adjustDigitKeyHeights() {
- Assert.checkState(!isLandscapeMode());
+ Assert.checkState(!mIsLandscapeMode);
int maxHeight = 0;
@@ -638,7 +641,7 @@ public class DialpadView extends LinearLayout {
* View#setLayoutParams(ViewGroup.LayoutParams)}.
*/
private void adjustKeyWidths() {
- Assert.checkState(isLandscapeMode());
+ Assert.checkState(mIsLandscapeMode);
int maxWidth = 0;
for (int buttonId : BUTTON_IDS) {
diff --git a/java/com/android/dialer/function/BiConsumer.java b/java/com/android/dialer/function/BiConsumer.java
new file mode 100644
index 000000000..50052210e
--- /dev/null
+++ b/java/com/android/dialer/function/BiConsumer.java
@@ -0,0 +1,24 @@
+/*
+ * 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.function;
+
+/** Functional interface for consuming two generic values. */
+public interface BiConsumer<T, U> {
+
+ /** Consumes a value. */
+ void accept(T t, U u);
+}
diff --git a/java/com/android/dialer/main/impl/MainPagerAdapter.java b/java/com/android/dialer/main/impl/MainPagerAdapter.java
index 2d224f69c..d294640ee 100644
--- a/java/com/android/dialer/main/impl/MainPagerAdapter.java
+++ b/java/com/android/dialer/main/impl/MainPagerAdapter.java
@@ -20,7 +20,7 @@ import android.content.Context;
import android.support.annotation.IntDef;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentStatePagerAdapter;
+import android.support.v4.app.FragmentPagerAdapter;
import com.android.dialer.calllog.ui.NewCallLogFragment;
import com.android.dialer.common.Assert;
import com.android.dialer.voicemail.listui.NewVoicemailFragment;
@@ -28,7 +28,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/** Adapter for {@link MainActivity} ViewPager. */
-final class MainPagerAdapter extends FragmentStatePagerAdapter {
+final class MainPagerAdapter extends FragmentPagerAdapter {
@Retention(RetentionPolicy.SOURCE)
@IntDef({
diff --git a/java/com/android/dialer/phonelookup/PhoneLookup.java b/java/com/android/dialer/phonelookup/PhoneLookup.java
index eeab4dadd..bb14c1ff6 100644
--- a/java/com/android/dialer/phonelookup/PhoneLookup.java
+++ b/java/com/android/dialer/phonelookup/PhoneLookup.java
@@ -62,6 +62,12 @@ public interface PhoneLookup {
ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> existingInfoMap);
/**
+ * Populates the sub-message that this {@link PhoneLookup} is responsible for by copying the
+ * sub-message value from {@code source} to {@code destination}
+ */
+ void copySubMessage(PhoneLookupInfo.Builder destination, PhoneLookupInfo source);
+
+ /**
* Called when the results of the {@link #getMostRecentPhoneLookupInfo(ImmutableMap)} have been
* applied by the caller.
*
diff --git a/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java b/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java
index ee2244615..bb7856fff 100644
--- a/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java
+++ b/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java
@@ -112,14 +112,15 @@ public final class CompositePhoneLookup implements PhoneLookup {
ImmutableMap.builder();
for (DialerPhoneNumber dialerPhoneNumber : existingInfoMap.keySet()) {
PhoneLookupInfo.Builder combinedInfo = PhoneLookupInfo.newBuilder();
- for (ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> map : allMaps) {
+ for (int i = 0; i < allMaps.size(); i++) {
+ ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> map = allMaps.get(i);
PhoneLookupInfo subInfo = map.get(dialerPhoneNumber);
if (subInfo == null) {
throw new IllegalStateException(
"A sublookup didn't return an info for number: "
+ LogUtil.sanitizePhoneNumber(dialerPhoneNumber.getRawInput().getNumber()));
}
- combinedInfo.mergeFrom(subInfo);
+ phoneLookups.get(i).copySubMessage(combinedInfo, subInfo);
}
combinedMap.put(dialerPhoneNumber, combinedInfo.build());
}
@@ -129,6 +130,11 @@ public final class CompositePhoneLookup implements PhoneLookup {
}
@Override
+ public void copySubMessage(PhoneLookupInfo.Builder destination, PhoneLookupInfo source) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public ListenableFuture<Void> onSuccessfulBulkUpdate() {
List<ListenableFuture<Void>> futures = new ArrayList<>();
for (PhoneLookup phoneLookup : phoneLookups) {
diff --git a/java/com/android/dialer/phonelookup/cp2/Cp2PhoneLookup.java b/java/com/android/dialer/phonelookup/cp2/Cp2PhoneLookup.java
index b31d0e72e..a477e035c 100644
--- a/java/com/android/dialer/phonelookup/cp2/Cp2PhoneLookup.java
+++ b/java/com/android/dialer/phonelookup/cp2/Cp2PhoneLookup.java
@@ -36,6 +36,7 @@ import com.android.dialer.phonelookup.PhoneLookup;
import com.android.dialer.phonelookup.PhoneLookupInfo;
import com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info;
import com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info.Cp2ContactInfo;
+import com.android.dialer.phonelookup.database.contract.PhoneLookupHistoryContract.PhoneLookupHistory;
import com.android.dialer.phonenumberproto.DialerPhoneNumberUtil;
import com.android.dialer.storage.Unencrypted;
import com.android.dialer.telecom.TelecomCallUtil;
@@ -45,6 +46,7 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
+import com.google.protobuf.InvalidProtocolBufferException;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@@ -131,8 +133,25 @@ public final class Cp2PhoneLookup implements PhoneLookup {
private boolean isDirtyInternal(ImmutableSet<DialerPhoneNumber> phoneNumbers) {
long lastModified = sharedPreferences.getLong(PREF_LAST_TIMESTAMP_PROCESSED, 0L);
- return contactsUpdated(queryPhoneTableForContactIds(phoneNumbers), lastModified)
- || contactsDeleted(lastModified);
+ // We are always going to need to do this check and it is pretty cheap so do it first.
+ if (anyContactsDeletedSince(lastModified)) {
+ return true;
+ }
+ // Hopefully the most common case is there are no contacts updated; we can detect this cheaply.
+ if (noContactsModifiedSince(lastModified)) {
+ return false;
+ }
+ // This method is more expensive but is probably the most likely scenario; we are looking for
+ // changes to contacts which have been called.
+ if (contactsUpdated(queryPhoneTableForContactIds(phoneNumbers), lastModified)) {
+ return true;
+ }
+ // This is the most expensive method so do it last; the scenario is that a contact which has
+ // been called got disassociated with a number and we need to clear their information.
+ if (contactsUpdated(queryPhoneLookupHistoryForContactIds(), lastModified)) {
+ return true;
+ }
+ return false;
}
/**
@@ -155,6 +174,46 @@ public final class Cp2PhoneLookup implements PhoneLookup {
return contactIds;
}
+ /** Gets all of the contact ids from PhoneLookupHistory. */
+ private Set<Long> queryPhoneLookupHistoryForContactIds() {
+ Set<Long> contactIds = new ArraySet<>();
+ try (Cursor cursor =
+ appContext
+ .getContentResolver()
+ .query(
+ PhoneLookupHistory.CONTENT_URI,
+ new String[] {
+ PhoneLookupHistory.PHONE_LOOKUP_INFO,
+ },
+ null,
+ null,
+ null)) {
+
+ if (cursor == null) {
+ LogUtil.w("Cp2PhoneLookup.queryPhoneLookupHistoryForContactIds", "null cursor");
+ return contactIds;
+ }
+
+ if (cursor.moveToFirst()) {
+ int phoneLookupInfoColumn =
+ cursor.getColumnIndexOrThrow(PhoneLookupHistory.PHONE_LOOKUP_INFO);
+ do {
+ PhoneLookupInfo phoneLookupInfo;
+ try {
+ phoneLookupInfo = PhoneLookupInfo.parseFrom(cursor.getBlob(phoneLookupInfoColumn));
+ } catch (InvalidProtocolBufferException e) {
+ throw new IllegalStateException(e);
+ }
+ for (Cp2ContactInfo info : phoneLookupInfo.getCp2Info().getCp2ContactInfoList()) {
+ contactIds.add(info.getContactId());
+ }
+ } while (cursor.moveToNext());
+ }
+ }
+
+ return contactIds;
+ }
+
private Set<Long> queryPhoneTableForContactIdsBasedOnE164(Set<String> validE164Numbers) {
Set<Long> contactIds = new ArraySet<>();
if (validE164Numbers.isEmpty()) {
@@ -226,8 +285,26 @@ public final class Cp2PhoneLookup implements PhoneLookup {
null);
}
+ private boolean noContactsModifiedSince(long lastModified) {
+ try (Cursor cursor =
+ appContext
+ .getContentResolver()
+ .query(
+ Contacts.CONTENT_URI,
+ new String[] {Contacts._ID},
+ Contacts.CONTACT_LAST_UPDATED_TIMESTAMP + " > ?",
+ new String[] {Long.toString(lastModified)},
+ Contacts._ID + " limit 1")) {
+ if (cursor == null) {
+ LogUtil.w("Cp2PhoneLookup.noContactsModifiedSince", "null cursor");
+ return false;
+ }
+ return cursor.getCount() == 0;
+ }
+ }
+
/** Returns true if any contacts were deleted after {@code lastModified}. */
- private boolean contactsDeleted(long lastModified) {
+ private boolean anyContactsDeletedSince(long lastModified) {
try (Cursor cursor =
appContext
.getContentResolver()
@@ -236,9 +313,9 @@ public final class Cp2PhoneLookup implements PhoneLookup {
new String[] {DeletedContacts.CONTACT_DELETED_TIMESTAMP},
DeletedContacts.CONTACT_DELETED_TIMESTAMP + " > ?",
new String[] {Long.toString(lastModified)},
- null)) {
+ DeletedContacts.CONTACT_DELETED_TIMESTAMP + " limit 1")) {
if (cursor == null) {
- LogUtil.w("Cp2PhoneLookup.contactsDeleted", "null cursor");
+ LogUtil.w("Cp2PhoneLookup.anyContactsDeletedSince", "null cursor");
return false;
}
return cursor.getCount() > 0;
@@ -253,6 +330,11 @@ public final class Cp2PhoneLookup implements PhoneLookup {
() -> getMostRecentPhoneLookupInfoInternal(existingInfoMap));
}
+ @Override
+ public void copySubMessage(PhoneLookupInfo.Builder destination, PhoneLookupInfo source) {
+ destination.setCp2Info(source.getCp2Info());
+ }
+
private ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> getMostRecentPhoneLookupInfoInternal(
ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> existingInfoMap) {
currentLastTimestampProcessed = null;
@@ -407,6 +489,11 @@ public final class Cp2PhoneLookup implements PhoneLookup {
partitionedNumbers.dialerPhoneNumbersForE164(e164Number);
Cp2ContactInfo info = buildCp2ContactInfoFromPhoneCursor(appContext, cursor);
addInfo(map, dialerPhoneNumbers, info);
+
+ // We are going to remove the numbers that we've handled so that we later can detect
+ // numbers that weren't handled and therefore need to have their contact information
+ // removed.
+ updatedNumbers.removeAll(dialerPhoneNumbers);
}
}
}
@@ -424,10 +511,20 @@ public final class Cp2PhoneLookup implements PhoneLookup {
partitionedNumbers.dialerPhoneNumbersForUnformattable(unformattableNumber);
Cp2ContactInfo info = buildCp2ContactInfoFromPhoneCursor(appContext, cursor);
addInfo(map, dialerPhoneNumbers, info);
+
+ // We are going to remove the numbers that we've handled so that we later can detect
+ // numbers that weren't handled and therefore need to have their contact information
+ // removed.
+ updatedNumbers.removeAll(dialerPhoneNumbers);
}
}
}
}
+ // The leftovers in updatedNumbers that weren't removed are numbers that were previously
+ // associated with contacts, but are no longer. Remove the contact information for them.
+ for (DialerPhoneNumber dialerPhoneNumber : updatedNumbers) {
+ map.put(dialerPhoneNumber, ImmutableSet.of());
+ }
return map;
}
diff --git a/java/com/android/dialer/precall/impl/AssistedDialAction.java b/java/com/android/dialer/precall/impl/AssistedDialAction.java
index c4f61d2dd..dc2510960 100644
--- a/java/com/android/dialer/precall/impl/AssistedDialAction.java
+++ b/java/com/android/dialer/precall/impl/AssistedDialAction.java
@@ -51,10 +51,12 @@ public class AssistedDialAction implements PreCallAction {
AssistedDialingMediator assistedDialingMediator =
ConcreteCreator.createNewAssistedDialingMediator(
context.getSystemService(TelephonyManager.class), context);
+ if (Build.VERSION.SDK_INT > ConcreteCreator.BUILD_CODE_CEILING) {
+ builder.getOutgoingCallExtras().putBoolean(TelephonyManagerCompat.USE_ASSISTED_DIALING, true);
+ }
if (!assistedDialingMediator.isPlatformEligible()) {
return;
}
- builder.getOutgoingCallExtras().putBoolean(TelephonyManagerCompat.ALLOW_ASSISTED_DIAL, true);
String phoneNumber =
builder.getUri().getScheme().equals(PhoneAccount.SCHEME_TEL)
? builder.getUri().getSchemeSpecificPart()
@@ -62,8 +64,8 @@ public class AssistedDialAction implements PreCallAction {
Optional<TransformationInfo> transformedNumber =
assistedDialingMediator.attemptAssistedDial(phoneNumber);
if (transformedNumber.isPresent()) {
+ builder.getOutgoingCallExtras().putBoolean(TelephonyManagerCompat.USE_ASSISTED_DIALING, true);
Bundle assistedDialingExtras = transformedNumber.get().toBundle();
- builder.getOutgoingCallExtras().putBoolean(TelephonyManagerCompat.IS_ASSISTED_DIALED, true);
builder
.getOutgoingCallExtras()
.putBundle(TelephonyManagerCompat.ASSISTED_DIALING_EXTRAS, assistedDialingExtras);
diff --git a/java/com/android/dialer/searchfragment/cp2/SearchContactsCursorLoader.java b/java/com/android/dialer/searchfragment/cp2/SearchContactsCursorLoader.java
index 23e3f9d88..23f368f54 100644
--- a/java/com/android/dialer/searchfragment/cp2/SearchContactsCursorLoader.java
+++ b/java/com/android/dialer/searchfragment/cp2/SearchContactsCursorLoader.java
@@ -28,9 +28,9 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.android.contacts.common.preference.ContactsPreferences;
-import com.android.dialer.dialpadview.SmartDialCursorLoader;
import com.android.dialer.searchfragment.common.Projections;
import com.android.dialer.searchfragment.common.SearchCursor;
+import com.android.dialer.smartdial.SmartDialCursorLoader;
/** Cursor Loader for CP2 contacts. */
public final class SearchContactsCursorLoader extends CursorLoader {
diff --git a/java/com/android/dialer/shortcuts/PinnedShortcuts.java b/java/com/android/dialer/shortcuts/PinnedShortcuts.java
index bfcc3df81..6e23a5c21 100644
--- a/java/com/android/dialer/shortcuts/PinnedShortcuts.java
+++ b/java/com/android/dialer/shortcuts/PinnedShortcuts.java
@@ -46,7 +46,6 @@ import java.util.Map;
* <p>When refreshing pinned shortcuts, we check to make sure that pinned contact information is
* still up to date (e.g. photo and name). We also check to see if the contact has been deleted from
* the user's contacts, and if so, we disable the pinned shortcut.
- *
*/
@TargetApi(VERSION_CODES.N_MR1) // Shortcuts introduced in N MR1
final class PinnedShortcuts {
@@ -107,6 +106,14 @@ final class PinnedShortcuts {
// setRank is nonsensical for pinned shortcuts and therefore could not be calculated.
continue;
}
+ // Exclude shortcuts like the "Phone NUI" shortcut.
+ String action = null;
+ if (shortcutInfo.getIntent() != null) {
+ action = shortcutInfo.getIntent().getAction();
+ }
+ if (action == null || !action.equals("com.android.dialer.shortcuts.CALL_CONTACT")) {
+ continue;
+ }
String lookupKey = DialerShortcut.getLookupKeyFromShortcutInfo(shortcutInfo);
Uri lookupUri = DialerShortcut.getLookupUriFromShortcutInfo(shortcutInfo);
diff --git a/java/com/android/dialer/simulator/impl/SimulatorDialogFragment.java b/java/com/android/dialer/simulator/impl/SimulatorDialogFragment.java
index f8403c7fe..96ea62739 100644
--- a/java/com/android/dialer/simulator/impl/SimulatorDialogFragment.java
+++ b/java/com/android/dialer/simulator/impl/SimulatorDialogFragment.java
@@ -29,7 +29,7 @@ public final class SimulatorDialogFragment extends DialogFragment {
private final String[] callerIdPresentationItems = {
"ALLOWED", "PAYPHONE", "RESTRICTED", "UNKNOWN"
};
- private int callerIdPresentationChoice;
+ private int callerIdPresentationChoice = 1;
private DialogCallback dialogCallback;
@@ -47,6 +47,7 @@ public final class SimulatorDialogFragment extends DialogFragment {
public Dialog onCreateDialog(Bundle bundle) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
final EditText input = new EditText(getActivity());
+ input.setHint("Please input phone number");
builder
.setTitle("Phone Number:")
.setView(input)
diff --git a/java/com/android/dialer/simulator/impl/SimulatorVoiceCall.java b/java/com/android/dialer/simulator/impl/SimulatorVoiceCall.java
index 89c5d2f14..ff00dd87e 100644
--- a/java/com/android/dialer/simulator/impl/SimulatorVoiceCall.java
+++ b/java/com/android/dialer/simulator/impl/SimulatorVoiceCall.java
@@ -120,7 +120,8 @@ final class SimulatorVoiceCall
private void addSpamIncomingCall() {
String callerId = "+1-661-778-3020"; /* Blacklisted custom spam number */
- SimulatorSimCallManager.addNewIncomingCall(context, callerId, false /* isVideo */);
+ connectionTag =
+ SimulatorSimCallManager.addNewIncomingCall(context, callerId, false /* isVideo */);
}
private void addNewEmergencyCallBack() {
diff --git a/java/com/android/dialer/smartdial/RussianSmartDialMap.java b/java/com/android/dialer/smartdial/RussianSmartDialMap.java
deleted file mode 100644
index ada9182e1..000000000
--- a/java/com/android/dialer/smartdial/RussianSmartDialMap.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.smartdial;
-
-import android.support.v4.util.SimpleArrayMap;
-import com.google.common.base.Optional;
-
-/** A {@link SmartDialMap} for the Russian alphabet. */
-@SuppressWarnings("Guava")
-final class RussianSmartDialMap extends SmartDialMap {
- private static final SimpleArrayMap<Character, Character> CHAR_TO_KEY_MAP =
- new SimpleArrayMap<>();
-
- // Reference: https://en.wikipedia.org/wiki/Russian_alphabet
- static {
- CHAR_TO_KEY_MAP.put('а', '2');
- CHAR_TO_KEY_MAP.put('б', '2');
- CHAR_TO_KEY_MAP.put('в', '2');
- CHAR_TO_KEY_MAP.put('г', '2');
-
- CHAR_TO_KEY_MAP.put('д', '3');
- CHAR_TO_KEY_MAP.put('е', '3');
- CHAR_TO_KEY_MAP.put('ё', '3');
- CHAR_TO_KEY_MAP.put('ж', '3');
- CHAR_TO_KEY_MAP.put('з', '3');
-
- CHAR_TO_KEY_MAP.put('и', '4');
- CHAR_TO_KEY_MAP.put('й', '4');
- CHAR_TO_KEY_MAP.put('к', '4');
- CHAR_TO_KEY_MAP.put('л', '4');
-
- CHAR_TO_KEY_MAP.put('м', '5');
- CHAR_TO_KEY_MAP.put('н', '5');
- CHAR_TO_KEY_MAP.put('о', '5');
- CHAR_TO_KEY_MAP.put('п', '5');
-
- CHAR_TO_KEY_MAP.put('р', '6');
- CHAR_TO_KEY_MAP.put('с', '6');
- CHAR_TO_KEY_MAP.put('т', '6');
- CHAR_TO_KEY_MAP.put('у', '6');
-
- CHAR_TO_KEY_MAP.put('ф', '7');
- CHAR_TO_KEY_MAP.put('х', '7');
- CHAR_TO_KEY_MAP.put('ц', '7');
- CHAR_TO_KEY_MAP.put('ч', '7');
-
- CHAR_TO_KEY_MAP.put('ш', '8');
- CHAR_TO_KEY_MAP.put('щ', '8');
- CHAR_TO_KEY_MAP.put('ъ', '8');
- CHAR_TO_KEY_MAP.put('ы', '8');
-
- CHAR_TO_KEY_MAP.put('ь', '9');
- CHAR_TO_KEY_MAP.put('э', '9');
- CHAR_TO_KEY_MAP.put('ю', '9');
- CHAR_TO_KEY_MAP.put('я', '9');
- }
-
- private static RussianSmartDialMap instance;
-
- static RussianSmartDialMap getInstance() {
- if (instance == null) {
- instance = new RussianSmartDialMap();
- }
-
- return instance;
- }
-
- private RussianSmartDialMap() {}
-
- @Override
- Optional<Character> normalizeCharacter(char ch) {
- ch = Character.toLowerCase(ch);
- return isValidDialpadAlphabeticChar(ch) ? Optional.of(ch) : Optional.absent();
- }
-
- @Override
- SimpleArrayMap<Character, Character> getCharToKeyMap() {
- return CHAR_TO_KEY_MAP;
- }
-}
diff --git a/java/com/android/dialer/dialpadview/SmartDialCursorLoader.java b/java/com/android/dialer/smartdial/SmartDialCursorLoader.java
index d085b55bd..f6bc9325a 100644
--- a/java/com/android/dialer/dialpadview/SmartDialCursorLoader.java
+++ b/java/com/android/dialer/smartdial/SmartDialCursorLoader.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.dialer.dialpadview;
+package com.android.dialer.smartdial;
import android.content.AsyncTaskLoader;
import android.content.Context;
@@ -25,7 +25,7 @@ import com.android.dialer.common.LogUtil;
import com.android.dialer.database.Database;
import com.android.dialer.database.DialerDatabaseHelper;
import com.android.dialer.database.DialerDatabaseHelper.ContactNumber;
-import com.android.dialer.smartdial.SmartDialNameMatcher;
+import com.android.dialer.smartdial.util.SmartDialNameMatcher;
import com.android.dialer.util.PermissionsUtil;
import java.util.ArrayList;
diff --git a/java/com/android/dialer/smartdial/map/BulgarianSmartDialMap.java b/java/com/android/dialer/smartdial/map/BulgarianSmartDialMap.java
new file mode 100644
index 000000000..5be9761a1
--- /dev/null
+++ b/java/com/android/dialer/smartdial/map/BulgarianSmartDialMap.java
@@ -0,0 +1,49 @@
+/*
+ * 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.smartdial.map;
+
+import android.support.v4.util.SimpleArrayMap;
+import com.android.dialer.dialpadview.DialpadCharMappings;
+import com.google.common.base.Optional;
+
+/** A {@link SmartDialMap} for the Bulgarian alphabet. */
+@SuppressWarnings("Guava")
+final class BulgarianSmartDialMap extends SmartDialMap {
+
+ private static BulgarianSmartDialMap instance;
+
+ static BulgarianSmartDialMap getInstance() {
+ if (instance == null) {
+ instance = new BulgarianSmartDialMap();
+ }
+
+ return instance;
+ }
+
+ private BulgarianSmartDialMap() {}
+
+ @Override
+ Optional<Character> normalizeCharacter(char ch) {
+ ch = Character.toLowerCase(ch);
+ return isValidDialpadAlphabeticChar(ch) ? Optional.of(ch) : Optional.absent();
+ }
+
+ @Override
+ SimpleArrayMap<Character, Character> getCharToKeyMap() {
+ return DialpadCharMappings.getCharToKeyMap("bul");
+ }
+}
diff --git a/java/com/android/dialer/smartdial/CompositeSmartDialMap.java b/java/com/android/dialer/smartdial/map/CompositeSmartDialMap.java
index d51e46f76..df32d4ce7 100644
--- a/java/com/android/dialer/smartdial/CompositeSmartDialMap.java
+++ b/java/com/android/dialer/smartdial/map/CompositeSmartDialMap.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.dialer.smartdial;
+package com.android.dialer.smartdial.map;
import android.content.Context;
import android.support.annotation.VisibleForTesting;
@@ -45,7 +45,9 @@ public class CompositeSmartDialMap {
private static final SimpleArrayMap<String, SmartDialMap> EXTRA_MAPS = new SimpleArrayMap<>();
static {
+ EXTRA_MAPS.put("bul", BulgarianSmartDialMap.getInstance());
EXTRA_MAPS.put("rus", RussianSmartDialMap.getInstance());
+ EXTRA_MAPS.put("ukr", UkrainianSmartDialMap.getInstance());
}
private CompositeSmartDialMap() {}
@@ -56,7 +58,7 @@ public class CompositeSmartDialMap {
* <p>The provided character is expected to be a normalized character. See {@link
* SmartDialMap#normalizeCharacter(char)} for details.
*/
- static boolean isValidDialpadCharacter(Context context, char ch) {
+ public static boolean isValidDialpadCharacter(Context context, char ch) {
if (DEFAULT_MAP.isValidDialpadCharacter(ch)) {
return true;
}
@@ -71,7 +73,7 @@ public class CompositeSmartDialMap {
* <p>The provided character is expected to be a normalized character. See {@link
* SmartDialMap#normalizeCharacter(char)} for details.
*/
- static boolean isValidDialpadAlphabeticChar(Context context, char ch) {
+ public static boolean isValidDialpadAlphabeticChar(Context context, char ch) {
if (DEFAULT_MAP.isValidDialpadAlphabeticChar(ch)) {
return true;
}
@@ -83,7 +85,7 @@ public class CompositeSmartDialMap {
/**
* Returns true if the provided character is a digit, and can be mapped to a key on the dialpad.
*/
- static boolean isValidDialpadNumericChar(Context context, char ch) {
+ public static boolean isValidDialpadNumericChar(Context context, char ch) {
if (DEFAULT_MAP.isValidDialpadNumericChar(ch)) {
return true;
}
@@ -100,7 +102,7 @@ public class CompositeSmartDialMap {
*
* <p>If the provided character can't be mapped to a key on the dialpad, return -1.
*/
- static byte getDialpadIndex(Context context, char ch) {
+ public static byte getDialpadIndex(Context context, char ch) {
Optional<Byte> dialpadIndex = DEFAULT_MAP.getDialpadIndex(ch);
if (dialpadIndex.isPresent()) {
return dialpadIndex.get();
@@ -122,7 +124,7 @@ public class CompositeSmartDialMap {
*
* <p>If the provided character can't be mapped to a key on the dialpad, return the character.
*/
- static char getDialpadNumericCharacter(Context context, char ch) {
+ public static char getDialpadNumericCharacter(Context context, char ch) {
Optional<Character> dialpadNumericChar = DEFAULT_MAP.getDialpadNumericCharacter(ch);
if (dialpadNumericChar.isPresent()) {
return dialpadNumericChar.get();
@@ -142,7 +144,7 @@ public class CompositeSmartDialMap {
*
* <p>If the provided character can't be mapped to a key on the dialpad, return the character.
*/
- static char normalizeCharacter(Context context, char ch) {
+ public static char normalizeCharacter(Context context, char ch) {
Optional<Character> normalizedChar = DEFAULT_MAP.normalizeCharacter(ch);
if (normalizedChar.isPresent()) {
return normalizedChar.get();
diff --git a/java/com/android/dialer/smartdial/LatinSmartDialMap.java b/java/com/android/dialer/smartdial/map/LatinSmartDialMap.java
index b67901bbe..b8ef951c5 100644
--- a/java/com/android/dialer/smartdial/LatinSmartDialMap.java
+++ b/java/com/android/dialer/smartdial/map/LatinSmartDialMap.java
@@ -14,52 +14,15 @@
* limitations under the License.
*/
-package com.android.dialer.smartdial;
+package com.android.dialer.smartdial.map;
import android.support.v4.util.SimpleArrayMap;
+import com.android.dialer.dialpadview.DialpadCharMappings;
import com.google.common.base.Optional;
/** A {@link SmartDialMap} for the Latin alphabet, which is for T9 dialpad searching. */
@SuppressWarnings("Guava")
final class LatinSmartDialMap extends SmartDialMap {
- private static final SimpleArrayMap<Character, Character> CHAR_TO_KEY_MAP =
- new SimpleArrayMap<>();
-
- static {
- CHAR_TO_KEY_MAP.put('a', '2');
- CHAR_TO_KEY_MAP.put('b', '2');
- CHAR_TO_KEY_MAP.put('c', '2');
-
- CHAR_TO_KEY_MAP.put('d', '3');
- CHAR_TO_KEY_MAP.put('e', '3');
- CHAR_TO_KEY_MAP.put('f', '3');
-
- CHAR_TO_KEY_MAP.put('g', '4');
- CHAR_TO_KEY_MAP.put('h', '4');
- CHAR_TO_KEY_MAP.put('i', '4');
-
- CHAR_TO_KEY_MAP.put('j', '5');
- CHAR_TO_KEY_MAP.put('k', '5');
- CHAR_TO_KEY_MAP.put('l', '5');
-
- CHAR_TO_KEY_MAP.put('m', '6');
- CHAR_TO_KEY_MAP.put('n', '6');
- CHAR_TO_KEY_MAP.put('o', '6');
-
- CHAR_TO_KEY_MAP.put('p', '7');
- CHAR_TO_KEY_MAP.put('q', '7');
- CHAR_TO_KEY_MAP.put('r', '7');
- CHAR_TO_KEY_MAP.put('s', '7');
-
- CHAR_TO_KEY_MAP.put('t', '8');
- CHAR_TO_KEY_MAP.put('u', '8');
- CHAR_TO_KEY_MAP.put('v', '8');
-
- CHAR_TO_KEY_MAP.put('w', '9');
- CHAR_TO_KEY_MAP.put('x', '9');
- CHAR_TO_KEY_MAP.put('y', '9');
- CHAR_TO_KEY_MAP.put('z', '9');
- }
private static LatinSmartDialMap instance;
@@ -780,6 +743,6 @@ final class LatinSmartDialMap extends SmartDialMap {
@Override
SimpleArrayMap<Character, Character> getCharToKeyMap() {
- return CHAR_TO_KEY_MAP;
+ return DialpadCharMappings.getDefaultCharToKeyMap();
}
}
diff --git a/java/com/android/dialer/smartdial/map/RussianSmartDialMap.java b/java/com/android/dialer/smartdial/map/RussianSmartDialMap.java
new file mode 100644
index 000000000..c10bbb0ce
--- /dev/null
+++ b/java/com/android/dialer/smartdial/map/RussianSmartDialMap.java
@@ -0,0 +1,49 @@
+/*
+ * 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.smartdial.map;
+
+import android.support.v4.util.SimpleArrayMap;
+import com.android.dialer.dialpadview.DialpadCharMappings;
+import com.google.common.base.Optional;
+
+/** A {@link SmartDialMap} for the Russian alphabet. */
+@SuppressWarnings("Guava")
+final class RussianSmartDialMap extends SmartDialMap {
+
+ private static RussianSmartDialMap instance;
+
+ static RussianSmartDialMap getInstance() {
+ if (instance == null) {
+ instance = new RussianSmartDialMap();
+ }
+
+ return instance;
+ }
+
+ private RussianSmartDialMap() {}
+
+ @Override
+ Optional<Character> normalizeCharacter(char ch) {
+ ch = Character.toLowerCase(ch);
+ return isValidDialpadAlphabeticChar(ch) ? Optional.of(ch) : Optional.absent();
+ }
+
+ @Override
+ SimpleArrayMap<Character, Character> getCharToKeyMap() {
+ return DialpadCharMappings.getCharToKeyMap("rus");
+ }
+}
diff --git a/java/com/android/dialer/smartdial/SmartDialMap.java b/java/com/android/dialer/smartdial/map/SmartDialMap.java
index bc5c9ea72..c74dd2893 100644
--- a/java/com/android/dialer/smartdial/SmartDialMap.java
+++ b/java/com/android/dialer/smartdial/map/SmartDialMap.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.dialer.smartdial;
+package com.android.dialer.smartdial.map;
import android.support.v4.util.SimpleArrayMap;
import com.google.common.base.Optional;
diff --git a/java/com/android/dialer/smartdial/map/UkrainianSmartDialMap.java b/java/com/android/dialer/smartdial/map/UkrainianSmartDialMap.java
new file mode 100644
index 000000000..844732c32
--- /dev/null
+++ b/java/com/android/dialer/smartdial/map/UkrainianSmartDialMap.java
@@ -0,0 +1,48 @@
+/*
+ * 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.smartdial.map;
+
+import android.support.v4.util.SimpleArrayMap;
+import com.android.dialer.dialpadview.DialpadCharMappings;
+import com.google.common.base.Optional;
+
+/** A {@link SmartDialMap} for the Ukrainian alphabet. */
+final class UkrainianSmartDialMap extends SmartDialMap {
+
+ private static UkrainianSmartDialMap instance;
+
+ static UkrainianSmartDialMap getInstance() {
+ if (instance == null) {
+ instance = new UkrainianSmartDialMap();
+ }
+
+ return instance;
+ }
+
+ private UkrainianSmartDialMap() {}
+
+ @Override
+ Optional<Character> normalizeCharacter(char ch) {
+ ch = Character.toLowerCase(ch);
+ return isValidDialpadAlphabeticChar(ch) ? Optional.of(ch) : Optional.absent();
+ }
+
+ @Override
+ SimpleArrayMap<Character, Character> getCharToKeyMap() {
+ return DialpadCharMappings.getCharToKeyMap("ukr");
+ }
+}
diff --git a/java/com/android/dialer/smartdial/SmartDialMatchPosition.java b/java/com/android/dialer/smartdial/util/SmartDialMatchPosition.java
index 8056ad723..db317ae6b 100644
--- a/java/com/android/dialer/smartdial/SmartDialMatchPosition.java
+++ b/java/com/android/dialer/smartdial/util/SmartDialMatchPosition.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.dialer.smartdial;
+package com.android.dialer.smartdial.util;
-import android.util.Log;
+import com.android.dialer.common.LogUtil;
import java.util.ArrayList;
/**
@@ -59,7 +59,7 @@ public class SmartDialMatchPosition {
public static void print(ArrayList<SmartDialMatchPosition> list) {
for (int i = 0; i < list.size(); i++) {
SmartDialMatchPosition m = list.get(i);
- Log.d(TAG, "[" + m.start + "," + m.end + "]");
+ LogUtil.d(TAG, "[" + m.start + "," + m.end + "]");
}
}
diff --git a/java/com/android/dialer/smartdial/SmartDialNameMatcher.java b/java/com/android/dialer/smartdial/util/SmartDialNameMatcher.java
index 4e3e0cc3f..725c88c57 100644
--- a/java/com/android/dialer/smartdial/SmartDialNameMatcher.java
+++ b/java/com/android/dialer/smartdial/util/SmartDialNameMatcher.java
@@ -14,12 +14,13 @@
* limitations under the License.
*/
-package com.android.dialer.smartdial;
+package com.android.dialer.smartdial.util;
import android.content.Context;
import android.support.annotation.Nullable;
import android.text.TextUtils;
-import com.android.dialer.smartdial.SmartDialPrefix.PhoneNumberTokens;
+import com.android.dialer.smartdial.map.CompositeSmartDialMap;
+import com.android.dialer.smartdial.util.SmartDialPrefix.PhoneNumberTokens;
import java.util.ArrayList;
/**
diff --git a/java/com/android/dialer/smartdial/SmartDialPrefix.java b/java/com/android/dialer/smartdial/util/SmartDialPrefix.java
index b9c1f8c11..9af411913 100644
--- a/java/com/android/dialer/smartdial/SmartDialPrefix.java
+++ b/java/com/android/dialer/smartdial/util/SmartDialPrefix.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.dialer.smartdial;
+package com.android.dialer.smartdial.util;
import android.content.Context;
import android.content.SharedPreferences;
@@ -22,6 +22,7 @@ import android.preference.PreferenceManager;
import android.support.annotation.VisibleForTesting;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
+import com.android.dialer.smartdial.map.CompositeSmartDialMap;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
diff --git a/java/com/android/dialer/telecom/TelecomUtil.java b/java/com/android/dialer/telecom/TelecomUtil.java
index 22f3727e6..c64a50231 100644
--- a/java/com/android/dialer/telecom/TelecomUtil.java
+++ b/java/com/android/dialer/telecom/TelecomUtil.java
@@ -178,6 +178,10 @@ public abstract class TelecomUtil {
* are not included.
*/
public static boolean isInManagedCall(Context context) {
+ return instance.isInManagedCall(context);
+ }
+
+ public static boolean isInCall(Context context) {
return instance.isInCall(context);
}
@@ -289,7 +293,7 @@ public abstract class TelecomUtil {
@VisibleForTesting()
public static class TelecomUtilImpl {
- public boolean isInCall(Context context) {
+ public boolean isInManagedCall(Context context) {
if (hasReadPhoneStatePermission(context)) {
// The TelecomManager#isInCall method returns true anytime the user is in a call.
// Starting in O, the APIs include support for self-managed ConnectionServices so that other
@@ -308,6 +312,10 @@ public abstract class TelecomUtil {
return false;
}
+ public boolean isInCall(Context context) {
+ return hasReadPhoneStatePermission(context) && getTelecomManager(context).isInCall();
+ }
+
public boolean hasPermission(Context context, String permission) {
return ContextCompat.checkSelfPermission(context, permission)
== PackageManager.PERMISSION_GRANTED;
diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java b/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java
index 315bf1cf0..93d5cda3e 100644
--- a/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java
+++ b/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java
@@ -67,9 +67,9 @@ final class NewVoicemailAdapter extends RecyclerView.Adapter<ViewHolder>
private final Clock clock;
/** {@link Integer#MAX_VALUE} when the "Today" header should not be displayed. */
- private final int todayHeaderPosition;
+ private int todayHeaderPosition = Integer.MAX_VALUE;
/** {@link Integer#MAX_VALUE} when the "Older" header should not be displayed. */
- private final int olderHeaderPosition;
+ private int olderHeaderPosition = Integer.MAX_VALUE;
private final FragmentManager fragmentManager;
/** A valid id for {@link VoicemailEntry} is greater than 0 */
@@ -107,7 +107,15 @@ final class NewVoicemailAdapter extends RecyclerView.Adapter<ViewHolder>
this.clock = clock;
this.fragmentManager = fragmentManager;
initializeMediaPlayerListeners();
+ updateHeaderPositions();
+ }
+ private void updateHeaderPositions() {
+ LogUtil.i(
+ "NewVoicemailAdapter.updateHeaderPositions",
+ "before updating todayPos:%d, olderPos:%d",
+ todayHeaderPosition,
+ olderHeaderPosition);
// Calculate header adapter positions by reading cursor.
long currentTimeMillis = clock.currentTimeMillis();
if (cursor.moveToNext()) {
@@ -134,6 +142,11 @@ final class NewVoicemailAdapter extends RecyclerView.Adapter<ViewHolder>
this.todayHeaderPosition = Integer.MAX_VALUE;
this.olderHeaderPosition = Integer.MAX_VALUE;
}
+ LogUtil.i(
+ "NewVoicemailAdapter.updateHeaderPositions",
+ "after updating todayPos:%d, olderPos:%d",
+ todayHeaderPosition,
+ olderHeaderPosition);
}
private void initializeMediaPlayerListeners() {
@@ -143,8 +156,10 @@ final class NewVoicemailAdapter extends RecyclerView.Adapter<ViewHolder>
}
public void updateCursor(Cursor updatedCursor) {
+ LogUtil.enterBlock("NewVoicemailAdapter.updateCursor");
deletedVoicemailPosition.clear();
this.cursor = updatedCursor;
+ updateHeaderPositions();
notifyDataSetChanged();
}
@@ -509,8 +524,6 @@ final class NewVoicemailAdapter extends RecyclerView.Adapter<ViewHolder>
Assert.checkArgument(expandedViewHolder.getViewHolderVoicemailUri().equals(voicemailUri));
- notifyItemRemoved(expandedViewHolder.getAdapterPosition());
-
Assert.checkArgument(currentlyExpandedViewHolderId == expandedViewHolder.getViewHolderId());
collapseExpandedViewHolder(expandedViewHolder);
@@ -524,6 +537,8 @@ final class NewVoicemailAdapter extends RecyclerView.Adapter<ViewHolder>
.onSuccess(deleteVoicemailCallBack)
.build()
.executeSerial(new Pair<>(context, voicemailUri));
+
+ notifyItemRemoved(expandedViewHolder.getAdapterPosition());
}
private void onVoicemailDeleted(Integer integer) {
diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java b/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java
index 24bed0f04..dac4ebafc 100644
--- a/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java
+++ b/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java
@@ -21,6 +21,7 @@ import static android.view.View.VISIBLE;
import android.app.FragmentManager;
import android.content.Context;
import android.database.Cursor;
+import android.graphics.Typeface;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
@@ -124,6 +125,9 @@ final class NewVoicemailViewHolder extends RecyclerView.ViewHolder implements On
transcriptionTextView.setText(voicemailTranscription);
}
+ // Bold if voicemail is unread
+ boldViewHolderIfUnread();
+
itemView.setOnClickListener(this);
menuButton.setOnClickListener(
NewVoicemailMenu.createOnClickListener(context, voicemailEntryOfViewHolder));
@@ -173,6 +177,20 @@ final class NewVoicemailViewHolder extends RecyclerView.ViewHolder implements On
mediaPlayerView.getVisibility() == VISIBLE);
}
+ private void boldViewHolderIfUnread() {
+ LogUtil.v(
+ "NewVoicemailViewHolder.boldViewHolderIfUnread",
+ "id:%d, isRead:%d",
+ voicemailEntryOfViewHolder.id(),
+ voicemailEntryOfViewHolder.isRead());
+
+ if (voicemailEntryOfViewHolder.isRead() == 0) {
+ primaryTextView.setTypeface(null, Typeface.BOLD);
+ secondaryTextView.setTypeface(null, Typeface.BOLD);
+ transcriptionTextView.setTypeface(null, Typeface.BOLD);
+ }
+ }
+
// TODO(uabdullah): Consider/Implement TYPE (e.g Spam, TYPE_VOICEMAIL)
private void setPhoto(VoicemailEntry voicemailEntry) {
ContactPhotoManager.getInstance(context)
@@ -214,6 +232,10 @@ final class NewVoicemailViewHolder extends RecyclerView.ViewHolder implements On
isViewHolderExpanded = false;
viewHolderVoicemailUri = null;
+ primaryTextView.setTypeface(null, Typeface.NORMAL);
+ secondaryTextView.setTypeface(null, Typeface.NORMAL);
+ transcriptionTextView.setTypeface(null, Typeface.NORMAL);
+
mediaPlayerView.reset();
LogUtil.i(
diff --git a/java/com/android/dialer/voicemail/listui/VoicemailCursorLoader.java b/java/com/android/dialer/voicemail/listui/VoicemailCursorLoader.java
index 6a55483a4..55d36b364 100644
--- a/java/com/android/dialer/voicemail/listui/VoicemailCursorLoader.java
+++ b/java/com/android/dialer/voicemail/listui/VoicemailCursorLoader.java
@@ -43,7 +43,8 @@ final class VoicemailCursorLoader extends CursorLoader {
AnnotatedCallLog.GEOCODED_LOCATION,
AnnotatedCallLog.CALL_TYPE,
AnnotatedCallLog.TRANSCRIPTION,
- AnnotatedCallLog.VOICEMAIL_URI
+ AnnotatedCallLog.VOICEMAIL_URI,
+ AnnotatedCallLog.IS_READ
};
// Indexes for VOICEMAIL_COLUMNS
@@ -60,6 +61,7 @@ final class VoicemailCursorLoader extends CursorLoader {
private static final int CALL_TYPE = 10;
private static final int TRANSCRIPTION = 11;
private static final int VOICEMAIL_URI = 12;
+ private static final int IS_READ = 13;
// TODO(zachh): Optimize indexes
VoicemailCursorLoader(Context context) {
@@ -95,6 +97,7 @@ final class VoicemailCursorLoader extends CursorLoader {
.setVoicemailUri(cursor.getString(VOICEMAIL_URI))
.setGeocodedLocation(cursor.getString(GEOCODED_LOCATION))
.setCallType(cursor.getInt(CALL_TYPE))
+ .setIsRead(cursor.getInt(IS_READ))
.build();
}
diff --git a/java/com/android/dialer/voicemail/model/VoicemailEntry.java b/java/com/android/dialer/voicemail/model/VoicemailEntry.java
index df30dee9c..702f52d17 100644
--- a/java/com/android/dialer/voicemail/model/VoicemailEntry.java
+++ b/java/com/android/dialer/voicemail/model/VoicemailEntry.java
@@ -32,7 +32,8 @@ public abstract class VoicemailEntry {
.setNumber(DialerPhoneNumber.getDefaultInstance())
.setPhotoId(0)
.setDuration(0)
- .setCallType(0);
+ .setCallType(0)
+ .setIsRead(0);
}
public abstract int id();
@@ -69,6 +70,8 @@ public abstract class VoicemailEntry {
public abstract int callType();
+ public abstract int isRead();
+
/** Builder for {@link VoicemailEntry}. */
@AutoValue.Builder
public abstract static class Builder {
@@ -99,6 +102,8 @@ public abstract class VoicemailEntry {
public abstract Builder setCallType(int callType);
+ public abstract Builder setIsRead(int isRead);
+
public abstract VoicemailEntry build();
}
}
diff --git a/java/com/android/incallui/AndroidManifest.xml b/java/com/android/incallui/AndroidManifest.xml
index b9d481b31..a98cc91d2 100644
--- a/java/com/android/incallui/AndroidManifest.xml
+++ b/java/com/android/incallui/AndroidManifest.xml
@@ -47,10 +47,13 @@
android:name="android.telephony.hide_voicemail_settings_menu"
android:value="true"/>
+ <!-- Go variants need hardware acceleration for IMS video calls even though it is disabled at
+ the application level -->
<activity
android:directBootAware="true"
android:excludeFromRecents="true"
android:exported="false"
+ android:hardwareAccelerated="true"
android:label="@string/phoneAppLabel"
android:launchMode="singleInstance"
android:name="com.android.incallui.InCallActivity"
diff --git a/java/com/android/incallui/NewReturnToCallController.java b/java/com/android/incallui/NewReturnToCallController.java
index ad49d6828..ca60a52c1 100644
--- a/java/com/android/incallui/NewReturnToCallController.java
+++ b/java/com/android/incallui/NewReturnToCallController.java
@@ -101,7 +101,7 @@ public class NewReturnToCallController implements InCallUiListener, Listener, Au
if (showing) {
hide();
} else {
- if (TelecomUtil.isInManagedCall(context)) {
+ if (getCall() != null) {
show();
}
}
@@ -157,22 +157,15 @@ public class NewReturnToCallController implements InCallUiListener, Listener, Au
@Override
public void onDisconnect(DialerCall call) {
- if (call.wasParentCall()) {
- // It's disconnected after the last child call is disconnected, and we already did everything
- // for the last child.
- LogUtil.i(
- "ReturnToCallController.onDisconnect", "being called for a parent call and do nothing");
- return;
- }
- if (bubble != null
- && bubble.isVisible()
- && (!TelecomUtil.isInManagedCall(context)
- || CallList.getInstance().getActiveOrBackgroundCall() != null)) {
- bubble.showText(context.getText(R.string.incall_call_ended));
- }
- // For conference call, we should hideAndReset for the last disconnected child call while the
- // parent call is still there.
- if (!CallList.getInstance().hasNonParentActiveOrBackgroundCall()) {
+ LogUtil.enterBlock("ReturnToCallController.onDisconnect");
+ if (bubble != null && bubble.isVisible() && (getCall() == null)) {
+ // Show "Call ended" and hide bubble when there is no outgoing, active or background call
+ LogUtil.i("ReturnToCallController.onDisconnect", "show call ended and hide bubble");
+ // Don't show text if it's Duo upgrade
+ // It doesn't work for Duo fallback upgrade since we're not considered in call
+ if (!TelecomUtil.isInCall(context) || CallList.getInstance().getIncomingCall() != null) {
+ bubble.showText(context.getText(R.string.incall_call_ended));
+ }
hideAndReset();
} else {
startContactInfoSearch();
@@ -197,19 +190,21 @@ public class NewReturnToCallController implements InCallUiListener, Listener, Au
}
private void startContactInfoSearch() {
- DialerCall dialerCall = CallList.getInstance().getIncomingCall();
- if (dialerCall == null) {
- dialerCall = CallList.getInstance().getOutgoingCall();
- }
- if (dialerCall == null) {
- dialerCall = CallList.getInstance().getActiveOrBackgroundCall();
- }
+ DialerCall dialerCall = getCall();
if (dialerCall != null) {
contactInfoCache.findInfo(
dialerCall, false /* isIncoming */, new ReturnToCallContactInfoCacheCallback(this));
}
}
+ private DialerCall getCall() {
+ DialerCall dialerCall = CallList.getInstance().getOutgoingCall();
+ if (dialerCall == null) {
+ dialerCall = CallList.getInstance().getActiveOrBackgroundCall();
+ }
+ return dialerCall;
+ }
+
private void onPhotoAvatarReceived(@NonNull Drawable photo) {
if (bubble != null) {
bubble.updatePhotoAvatar(photo);
diff --git a/java/com/android/incallui/call/DialerCall.java b/java/com/android/incallui/call/DialerCall.java
index 812024904..94c79e904 100644
--- a/java/com/android/incallui/call/DialerCall.java
+++ b/java/com/android/incallui/call/DialerCall.java
@@ -20,6 +20,7 @@ import android.Manifest.permission;
import android.content.Context;
import android.hardware.camera2.CameraCharacteristics;
import android.net.Uri;
+import android.os.Build;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
@@ -43,6 +44,7 @@ import android.telecom.VideoProfile;
import android.text.TextUtils;
import com.android.contacts.common.compat.CallCompat;
import com.android.contacts.common.compat.telecom.TelecomManagerCompat;
+import com.android.dialer.assisteddialing.ConcreteCreator;
import com.android.dialer.assisteddialing.TransformationInfo;
import com.android.dialer.callintent.CallInitiationType;
import com.android.dialer.callintent.CallIntentParser;
@@ -1073,19 +1075,50 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa
return mLogState.isIncoming;
}
+ /**
+ * Try and determine if the call used assisted dialing.
+ *
+ * <p>We will not be able to verify a call underwent assisted dialing until the Platform
+ * implmentation is complete in P+.
+ *
+ * @return a boolean indicating assisted dialing may have been performed
+ */
public boolean isAssistedDialed() {
if (getIntentExtras() != null) {
- return getIntentExtras().getBoolean(TelephonyManagerCompat.IS_ASSISTED_DIALED, false);
+ // O_MR1 and below uses the existence of USE_ASSISTED_DIALING to indicate assisted dialing
+ // was used. The Dialer client is responsible for performing assisted dialing before
+ // placing the outgoing call.
+ //
+ // The existence of the assisted dialing extras indicates that assisted dialing took place.
+ if (getIntentExtras().getBoolean(TelephonyManagerCompat.USE_ASSISTED_DIALING, false)
+ && getAssistedDialingExtras() != null
+ && Build.VERSION.SDK_INT <= ConcreteCreator.BUILD_CODE_CEILING) {
+ return true;
+ }
+ }
+
+ // Starting in P+ USE_ASSISTED_DIALING indicates that the client requested the platform
+ // perform assisted dialing. PROPERTY_ASSISTED_DIALING_USED indicates assisted dialing took
+ // place.
+ if (hasProperty(TelephonyManagerCompat.PROPERTY_ASSISTED_DIALING_USED)
+ && Build.VERSION.SDK_INT > ConcreteCreator.BUILD_CODE_CEILING) {
+ return true;
}
return false;
}
+ @Nullable
public TransformationInfo getAssistedDialingExtras() {
- if (isAssistedDialed()) {
- return TransformationInfo.newInstanceFromBundle(
- getIntentExtras().getBundle(TelephonyManagerCompat.ASSISTED_DIALING_EXTRAS));
+ if (getIntentExtras() == null) {
+ return null;
}
- return null;
+
+ if (getIntentExtras().getBundle(TelephonyManagerCompat.ASSISTED_DIALING_EXTRAS) == null) {
+ return null;
+ }
+
+ return TransformationInfo.newInstanceFromBundle(
+ getIntentExtras().getBundle(TelephonyManagerCompat.ASSISTED_DIALING_EXTRAS));
}
public LatencyReport getLatencyReport() {
diff --git a/java/com/android/incallui/contactgrid/TopRow.java b/java/com/android/incallui/contactgrid/TopRow.java
index f8a485519..556b11ba0 100644
--- a/java/com/android/incallui/contactgrid/TopRow.java
+++ b/java/com/android/incallui/contactgrid/TopRow.java
@@ -175,7 +175,7 @@ public class TopRow {
}
}
- if (state.isAssistedDialed) {
+ if (state.isAssistedDialed && state.assistedDialingExtras != null) {
LogUtil.i("TopRow.getLabelForDialing", "using assisted dialing label.");
String countryCode =
String.valueOf(state.assistedDialingExtras.transformedNumberCountryCallingCode());
diff --git a/java/com/android/incallui/spam/SpamCallListListener.java b/java/com/android/incallui/spam/SpamCallListListener.java
index fa3dd6e01..e7603f041 100644
--- a/java/com/android/incallui/spam/SpamCallListListener.java
+++ b/java/com/android/incallui/spam/SpamCallListListener.java
@@ -455,6 +455,6 @@ public class SpamCallListListener implements CallList.Listener {
}
static String getNotificationTagForCall(@NonNull DialerCall call) {
- return NOTIFICATION_TAG_PREFIX + call.getNumber();
+ return NOTIFICATION_TAG_PREFIX + call.getUniqueCallId();
}
}
diff --git a/java/com/android/newbubble/NewBubble.java b/java/com/android/newbubble/NewBubble.java
index 3378ad81a..469c15d71 100644
--- a/java/com/android/newbubble/NewBubble.java
+++ b/java/com/android/newbubble/NewBubble.java
@@ -39,6 +39,7 @@ import android.support.annotation.VisibleForTesting;
import android.support.v4.graphics.ColorUtils;
import android.support.v4.os.BuildCompat;
import android.support.v4.view.animation.LinearOutSlowInInterpolator;
+import android.text.TextUtils;
import android.transition.TransitionManager;
import android.transition.TransitionValues;
import android.view.ContextThemeWrapper;
@@ -70,6 +71,7 @@ import com.android.newbubble.NewBubbleInfo.Action;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
+import java.util.Locale;
/**
* Creates and manages a bubble window from information in a {@link NewBubbleInfo}. Before creating,
@@ -406,6 +408,8 @@ public class NewBubble {
hideAfterText = false;
+ boolean isRtl =
+ TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) == View.LAYOUT_DIRECTION_RTL;
if (windowParams == null) {
// Apps targeting O+ must use TYPE_APPLICATION_OVERLAY, which is not available prior to O.
@SuppressWarnings("deprecation")
@@ -423,7 +427,7 @@ public class NewBubble {
| LayoutParams.FLAG_NOT_FOCUSABLE
| LayoutParams.FLAG_LAYOUT_NO_LIMITS,
PixelFormat.TRANSLUCENT);
- windowParams.gravity = Gravity.TOP | Gravity.LEFT;
+ windowParams.gravity = Gravity.TOP | (isRtl ? Gravity.RIGHT : Gravity.LEFT);
windowParams.x = leftBoundary;
windowParams.y = currentInfo.getStartingYPosition();
windowParams.height = LayoutParams.WRAP_CONTENT;
@@ -441,6 +445,9 @@ public class NewBubble {
viewHolder.getPrimaryButton().setScaleY(0);
viewHolder.getPrimaryAvatar().setAlpha(0f);
viewHolder.getPrimaryIcon().setAlpha(0f);
+ if (isRtl) {
+ onLeftRightSwitch(true);
+ }
}
viewHolder.setChildClickable(true);
@@ -795,7 +802,13 @@ public class NewBubble {
}
private void configureButton(Action action, NewCheckableButton button) {
- button.setCompoundDrawablesWithIntrinsicBounds(action.getIconDrawable(), null, null, null);
+ boolean isRtl =
+ TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) == View.LAYOUT_DIRECTION_RTL;
+ if (isRtl) {
+ button.setCompoundDrawablesWithIntrinsicBounds(null, null, action.getIconDrawable(), null);
+ } else {
+ button.setCompoundDrawablesWithIntrinsicBounds(action.getIconDrawable(), null, null, null);
+ }
button.setChecked(action.isChecked());
button.setEnabled(action.isEnabled());
button.setText(action.getName());
diff --git a/java/com/android/newbubble/res/layout/new_bubble_base.xml b/java/com/android/newbubble/res/layout/new_bubble_base.xml
index f83b75395..f6ce26dd1 100644
--- a/java/com/android/newbubble/res/layout/new_bubble_base.xml
+++ b/java/com/android/newbubble/res/layout/new_bubble_base.xml
@@ -21,6 +21,7 @@
android:layout_height="wrap_content"
android:clipChildren="true"
android:clipToPadding="false"
+ android:layoutDirection="ltr"
tools:theme="@style/Theme.AppCompat">
<RelativeLayout
android:id="@+id/bubble_primary_container"