Merge changes I66342431,I5e579f11,I927711aa,Idd4cc115,If8cdbdfa, ...
* changes:
Automated rollback of changelist 179615699
Automated rollback of changelist 179847039
Differentiate read/unread voicemails in the NUI Voicemail by bolding.
Use CHAR_TO_KEY_MAPS in DialpadCharMappings in SmartDialMaps.
Reorganize classes related to smart dial.
Use the orientation obtained in onFinishInflate as the truth in DialpadView.
Added context menu for favorite contacts in new speed dial.
Update assisted dialing extras in preparation for platform implementation.
Quick fix for bugs on simulator voice call.
Fixed crash in UiListener when launching activity with screen off.
Handle contacts which have been disassociated with a number in Cp2PhoneLookup.
Fixed crash in PinnedShortcuts.
Bug: 70402588
Added copySubMessage method to PhoneLookup interface.
Bubble v2 changes.
Always have hardware acceration enabled for InCallActivity
Include inserted calls for consideration in PhoneLookupDataSource.
Don't use phone number in spam call notifications
Register content observer when voicemail table changes.
Add SmartDialMaps for the Bulgarian alphabet and the Ukrainian alphabet.
Remove voicemail from UI only after delete request.
Bubble v2 RTL language fixes.
Implemented SpeedDialEntry Room Database.
diff --git a/java/com/android/bubble/res/values-car/values.xml b/java/com/android/bubble/res/values-car/values.xml
index cf8839a..47f20a1 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 eb95a4e..bbb4594 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.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 5b48ccf..1d2cda3 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.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 e97a16c..1a7f195 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.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 fbb5831..042ff30 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 @@
* <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 @@
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 @@
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 @@
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 0ed1859..95fbf9d 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.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 @@
}
// 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 @@
@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 c10b521..719878c 100644
--- a/java/com/android/dialer/calllog/ui/NewCallLogFragment.java
+++ b/java/com/android/dialer/calllog/ui/NewCallLogFragment.java
@@ -58,10 +58,10 @@
}
@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 9541dbc..df79130 100644
--- a/java/com/android/dialer/common/concurrent/UiListener.java
+++ b/java/com/android/dialer/common/concurrent/UiListener.java
@@ -71,7 +71,10 @@
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 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 6bed818..b01689d 100644
--- a/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java
+++ b/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java
@@ -57,22 +57,16 @@
*
* <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 b0bd62a..3fb8730 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.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 03bc2e7..0bb28ae 100644
--- a/java/com/android/dialer/dialpadview/DialpadCharMappings.java
+++ b/java/com/android/dialer/dialpadview/DialpadCharMappings.java
@@ -147,6 +147,23 @@
: 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 2f494e4..7b95ba7 100644
--- a/java/com/android/dialer/dialpadview/DialpadView.java
+++ b/java/com/android/dialer/dialpadview/DialpadView.java
@@ -87,6 +87,7 @@
private ViewGroup mRateContainer;
private TextView mIldCountry;
private TextView mIldRate;
+ private boolean mIsLandscapeMode;
public DialpadView(Context context) {
this(context, null);
@@ -125,6 +126,12 @@
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 @@
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 @@
* @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 @@
* @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 @@
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 @@
}
private boolean shouldAdjustKeySizes() {
- return isLandscapeMode() ? shouldAdjustKeyWidths() : shouldAdjustDigitKeyHeights();
+ return mIsLandscapeMode ? shouldAdjustKeyWidths() : shouldAdjustDigitKeyHeights();
}
/**
@@ -533,7 +536,7 @@
* 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 @@
* 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 @@
}
private void adjustKeySizes() {
- if (isLandscapeMode()) {
+ if (mIsLandscapeMode) {
adjustKeyWidths();
} else {
adjustDigitKeyHeights();
@@ -594,7 +597,7 @@
* LinearLayout#setLayoutParams(ViewGroup.LayoutParams)}.
*/
private void adjustDigitKeyHeights() {
- Assert.checkState(!isLandscapeMode());
+ Assert.checkState(!mIsLandscapeMode);
int maxHeight = 0;
@@ -638,7 +641,7 @@
* 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 0000000..5005221
--- /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 2d224f6..d294640 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.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.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 eeab4da..bb14c1f 100644
--- a/java/com/android/dialer/phonelookup/PhoneLookup.java
+++ b/java/com/android/dialer/phonelookup/PhoneLookup.java
@@ -62,6 +62,12 @@
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 ee22446..bb7856f 100644
--- a/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java
+++ b/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java
@@ -112,14 +112,15 @@
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 @@
}
@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 b31d0e7..a477e03 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.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.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 @@
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 @@
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 @@
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 @@
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 @@
() -> 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 @@
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 @@
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 c4f61d2..dc25109 100644
--- a/java/com/android/dialer/precall/impl/AssistedDialAction.java
+++ b/java/com/android/dialer/precall/impl/AssistedDialAction.java
@@ -51,10 +51,12 @@
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 @@
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 23e3f9d..23f368f 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.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 bfcc3df..6e23a5c 100644
--- a/java/com/android/dialer/shortcuts/PinnedShortcuts.java
+++ b/java/com/android/dialer/shortcuts/PinnedShortcuts.java
@@ -46,7 +46,6 @@
* <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 @@
// 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 f8403c7..96ea627 100644
--- a/java/com/android/dialer/simulator/impl/SimulatorDialogFragment.java
+++ b/java/com/android/dialer/simulator/impl/SimulatorDialogFragment.java
@@ -29,7 +29,7 @@
private final String[] callerIdPresentationItems = {
"ALLOWED", "PAYPHONE", "RESTRICTED", "UNKNOWN"
};
- private int callerIdPresentationChoice;
+ private int callerIdPresentationChoice = 1;
private DialogCallback dialogCallback;
@@ -47,6 +47,7 @@
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 89c5d2f..ff00dd8 100644
--- a/java/com/android/dialer/simulator/impl/SimulatorVoiceCall.java
+++ b/java/com/android/dialer/simulator/impl/SimulatorVoiceCall.java
@@ -120,7 +120,8 @@
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 ada9182..0000000
--- 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
similarity index 97%
rename from java/com/android/dialer/dialpadview/SmartDialCursorLoader.java
rename to java/com/android/dialer/smartdial/SmartDialCursorLoader.java
index d085b55..f6bc932 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.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 0000000..5be9761
--- /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
similarity index 90%
rename from java/com/android/dialer/smartdial/CompositeSmartDialMap.java
rename to java/com/android/dialer/smartdial/map/CompositeSmartDialMap.java
index d51e46f..df32d4c 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 @@
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 @@
* <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 @@
* <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 @@
/**
* 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 @@
*
* <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 @@
*
* <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 @@
*
* <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
similarity index 94%
rename from java/com/android/dialer/smartdial/LatinSmartDialMap.java
rename to java/com/android/dialer/smartdial/map/LatinSmartDialMap.java
index b67901b..b8ef951 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 @@
@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 0000000..c10bbb0
--- /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
similarity index 98%
rename from java/com/android/dialer/smartdial/SmartDialMap.java
rename to java/com/android/dialer/smartdial/map/SmartDialMap.java
index bc5c9ea..c74dd28 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 0000000..844732c
--- /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
similarity index 93%
rename from java/com/android/dialer/smartdial/SmartDialMatchPosition.java
rename to java/com/android/dialer/smartdial/util/SmartDialMatchPosition.java
index 8056ad7..db317ae 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 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
similarity index 98%
rename from java/com/android/dialer/smartdial/SmartDialNameMatcher.java
rename to java/com/android/dialer/smartdial/util/SmartDialNameMatcher.java
index 4e3e0cc..725c88c 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
similarity index 99%
rename from java/com/android/dialer/smartdial/SmartDialPrefix.java
rename to java/com/android/dialer/smartdial/util/SmartDialPrefix.java
index b9c1f8c..9af4119 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.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 22f3727..c64a502 100644
--- a/java/com/android/dialer/telecom/TelecomUtil.java
+++ b/java/com/android/dialer/telecom/TelecomUtil.java
@@ -178,6 +178,10 @@
* 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 @@
@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 @@
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 315bf1c..93d5cda 100644
--- a/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java
+++ b/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java
@@ -67,9 +67,9 @@
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 @@
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 @@
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 @@
}
public void updateCursor(Cursor updatedCursor) {
+ LogUtil.enterBlock("NewVoicemailAdapter.updateCursor");
deletedVoicemailPosition.clear();
this.cursor = updatedCursor;
+ updateHeaderPositions();
notifyDataSetChanged();
}
@@ -509,8 +524,6 @@
Assert.checkArgument(expandedViewHolder.getViewHolderVoicemailUri().equals(voicemailUri));
- notifyItemRemoved(expandedViewHolder.getAdapterPosition());
-
Assert.checkArgument(currentlyExpandedViewHolderId == expandedViewHolder.getViewHolderId());
collapseExpandedViewHolder(expandedViewHolder);
@@ -524,6 +537,8 @@
.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 24bed0f..dac4eba 100644
--- a/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java
+++ b/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java
@@ -21,6 +21,7 @@
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 @@
transcriptionTextView.setText(voicemailTranscription);
}
+ // Bold if voicemail is unread
+ boldViewHolderIfUnread();
+
itemView.setOnClickListener(this);
menuButton.setOnClickListener(
NewVoicemailMenu.createOnClickListener(context, voicemailEntryOfViewHolder));
@@ -173,6 +177,20 @@
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 @@
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 6a55483..55d36b3 100644
--- a/java/com/android/dialer/voicemail/listui/VoicemailCursorLoader.java
+++ b/java/com/android/dialer/voicemail/listui/VoicemailCursorLoader.java
@@ -43,7 +43,8 @@
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 @@
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 @@
.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 df30dee..702f52d 100644
--- a/java/com/android/dialer/voicemail/model/VoicemailEntry.java
+++ b/java/com/android/dialer/voicemail/model/VoicemailEntry.java
@@ -32,7 +32,8 @@
.setNumber(DialerPhoneNumber.getDefaultInstance())
.setPhotoId(0)
.setDuration(0)
- .setCallType(0);
+ .setCallType(0)
+ .setIsRead(0);
}
public abstract int id();
@@ -69,6 +70,8 @@
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 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 b9d481b..a98cc91 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 ad49d68..ca60a52 100644
--- a/java/com/android/incallui/NewReturnToCallController.java
+++ b/java/com/android/incallui/NewReturnToCallController.java
@@ -101,7 +101,7 @@
if (showing) {
hide();
} else {
- if (TelecomUtil.isInManagedCall(context)) {
+ if (getCall() != null) {
show();
}
}
@@ -157,22 +157,15 @@
@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 @@
}
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 8120249..94c79e9 100644
--- a/java/com/android/incallui/call/DialerCall.java
+++ b/java/com/android/incallui/call/DialerCall.java
@@ -20,6 +20,7 @@
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.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 @@
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 f8a4855..556b11b 100644
--- a/java/com/android/incallui/contactgrid/TopRow.java
+++ b/java/com/android/incallui/contactgrid/TopRow.java
@@ -175,7 +175,7 @@
}
}
- 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 fa3dd6e..e7603f0 100644
--- a/java/com/android/incallui/spam/SpamCallListListener.java
+++ b/java/com/android/incallui/spam/SpamCallListListener.java
@@ -455,6 +455,6 @@
}
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 3378ad8..469c15d 100644
--- a/java/com/android/newbubble/NewBubble.java
+++ b/java/com/android/newbubble/NewBubble.java
@@ -39,6 +39,7 @@
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 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 @@
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 @@
| 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 @@
viewHolder.getPrimaryButton().setScaleY(0);
viewHolder.getPrimaryAvatar().setAlpha(0f);
viewHolder.getPrimaryIcon().setAlpha(0f);
+ if (isRtl) {
+ onLeftRightSwitch(true);
+ }
}
viewHolder.setChildClickable(true);
@@ -795,7 +802,13 @@
}
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 f83b753..f6ce26d 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"