Merge changes I4bdadacc,Ie1f8da1a
am: add7d14341

Change-Id: I914a9786dc62d06393645130e63b94f85221ba97
diff --git a/java/com/android/dialer/calldetails/CallDetailsActivity.java b/java/com/android/dialer/calldetails/CallDetailsActivity.java
index bf978ec..26b38ed 100644
--- a/java/com/android/dialer/calldetails/CallDetailsActivity.java
+++ b/java/com/android/dialer/calldetails/CallDetailsActivity.java
@@ -40,7 +40,6 @@
 import android.view.View;
 import android.widget.Toast;
 import com.android.dialer.CoalescedIds;
-import com.android.dialer.DialerPhoneNumber;
 import com.android.dialer.assisteddialing.ui.AssistedDialingSettingActivity;
 import com.android.dialer.calldetails.CallDetailsEntries.CallDetailsEntry;
 import com.android.dialer.callintent.CallInitiationType;
@@ -65,13 +64,14 @@
 import com.android.dialer.logging.Logger;
 import com.android.dialer.logging.UiAction;
 import com.android.dialer.performancereport.PerformanceReport;
-import com.android.dialer.phonenumberproto.DialerPhoneNumberUtil;
 import com.android.dialer.postcall.PostCall;
 import com.android.dialer.precall.PreCall;
 import com.android.dialer.protos.ProtoParsers;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
+import com.google.i18n.phonenumbers.NumberParseException;
 import com.google.i18n.phonenumbers.PhoneNumberUtil;
+import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
 import java.lang.ref.WeakReference;
 import java.util.Collections;
 import java.util.List;
@@ -441,10 +441,17 @@
 
     @Override
     public Integer doInBackground(@NonNull String phoneNumber) {
-      DialerPhoneNumberUtil dialerPhoneNumberUtil =
-          new DialerPhoneNumberUtil(PhoneNumberUtil.getInstance());
-      DialerPhoneNumber parsedNumber = dialerPhoneNumberUtil.parse(phoneNumber, null);
-      return parsedNumber.getDialerInternalPhoneNumber().getCountryCode();
+      PhoneNumber parsedNumber = null;
+      try {
+        parsedNumber = PhoneNumberUtil.getInstance().parse(phoneNumber, null);
+      } catch (NumberParseException e) {
+        LogUtil.w(
+            "AssistedDialingNumberParseWorker.doInBackground",
+            "couldn't parse phone number: " + LogUtil.sanitizePii(phoneNumber),
+            e);
+        return 0;
+      }
+      return parsedNumber.getCountryCode();
     }
   }
 
diff --git a/java/com/android/dialer/calllog/ui/RealtimeRowProcessor.java b/java/com/android/dialer/calllog/ui/RealtimeRowProcessor.java
index 501dce4..f15c313 100644
--- a/java/com/android/dialer/calllog/ui/RealtimeRowProcessor.java
+++ b/java/com/android/dialer/calllog/ui/RealtimeRowProcessor.java
@@ -44,6 +44,7 @@
 import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.i18n.phonenumbers.PhoneNumberUtil;
 import java.util.ArrayList;
+import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.concurrent.TimeUnit;
@@ -77,7 +78,7 @@
   private final Map<DialerPhoneNumber, PhoneLookupInfo> cache = new ArrayMap<>();
 
   private final Map<DialerPhoneNumber, PhoneLookupInfo> queuedPhoneLookupHistoryWrites =
-      new ArrayMap<>();
+      new LinkedHashMap<>(); // Keep the order so the most recent looked up value always wins
   private final Runnable writePhoneLookupHistoryRunnable = this::writePhoneLookupHistory;
 
   @Inject
diff --git a/java/com/android/dialer/calllog/ui/menu/Modules.java b/java/com/android/dialer/calllog/ui/menu/Modules.java
index 96e5951..d591558 100644
--- a/java/com/android/dialer/calllog/ui/menu/Modules.java
+++ b/java/com/android/dialer/calllog/ui/menu/Modules.java
@@ -46,8 +46,7 @@
     // Conditionally add each module, which are items in the bottom sheet's menu.
     List<ContactActionModule> modules = new ArrayList<>();
 
-    // TODO(zach): Don't use raw input.
-    String normalizedNumber = row.number().getRawInput().getNumber();
+    String normalizedNumber = row.number().getNormalizedNumber();
     boolean canPlaceCalls =
         PhoneNumberHelper.canPlaceCallsTo(normalizedNumber, row.numberPresentation());
 
@@ -138,8 +137,7 @@
           .build();
     }
 
-    // TODO(zachh): Don't use raw input.
-    String normalizedNumber = row.number().getRawInput().getNumber();
+    String normalizedNumber = row.number().getNormalizedNumber();
     DialerContact.Builder dialerContactBuilder =
         DialerContact.newBuilder()
             .setNumber(normalizedNumber)
diff --git a/java/com/android/dialer/calllogutils/CallLogIntents.java b/java/com/android/dialer/calllogutils/CallLogIntents.java
index 227b15e..64fb33d 100644
--- a/java/com/android/dialer/calllogutils/CallLogIntents.java
+++ b/java/com/android/dialer/calllogutils/CallLogIntents.java
@@ -39,8 +39,7 @@
    */
   @Nullable
   public static Intent getCallBackIntent(Context context, CoalescedRow row) {
-    // TODO(zachh): Don't use raw input.
-    String normalizedNumber = row.number().getRawInput().getNumber();
+    String normalizedNumber = row.number().getNormalizedNumber();
     if (!PhoneNumberHelper.canPlaceCallsTo(normalizedNumber, row.numberPresentation())) {
       return null;
     }
diff --git a/java/com/android/dialer/contactactions/SharedModules.java b/java/com/android/dialer/contactactions/SharedModules.java
index 6c6f6b2..7e72863 100644
--- a/java/com/android/dialer/contactactions/SharedModules.java
+++ b/java/com/android/dialer/contactactions/SharedModules.java
@@ -48,14 +48,14 @@
     }
 
     // Skip showing the menu item if there is no number.
-    String originalNumber = number.getRawInput().getNumber();
-    if (TextUtils.isEmpty(originalNumber)) {
+    String normalizedNumber = number.getNormalizedNumber();
+    if (TextUtils.isEmpty(normalizedNumber)) {
       return;
     }
 
     Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
     intent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
-    intent.putExtra(ContactsContract.Intents.Insert.PHONE, originalNumber);
+    intent.putExtra(ContactsContract.Intents.Insert.PHONE, normalizedNumber);
 
     if (!TextUtils.isEmpty(name)) {
       intent.putExtra(ContactsContract.Intents.Insert.NAME, name);
diff --git a/java/com/android/dialer/main/impl/MainActivity.java b/java/com/android/dialer/main/impl/MainActivity.java
index 3edf6c6a..a7a9e6c 100644
--- a/java/com/android/dialer/main/impl/MainActivity.java
+++ b/java/com/android/dialer/main/impl/MainActivity.java
@@ -25,6 +25,7 @@
 import android.support.design.widget.FloatingActionButton;
 import android.support.v4.app.FragmentTransaction;
 import android.support.v7.app.AppCompatActivity;
+import android.view.View;
 import android.widget.ImageView;
 import com.android.dialer.calllog.ui.NewCallLogFragment;
 import com.android.dialer.common.LogUtil;
@@ -41,9 +42,11 @@
 import com.android.dialer.dialpadview.DialpadFragment.OnDialpadQueryChangedListener;
 import com.android.dialer.main.impl.BottomNavBar.OnBottomNavTabSelectedListener;
 import com.android.dialer.main.impl.toolbar.MainToolbar;
+import com.android.dialer.postcall.PostCall;
 import com.android.dialer.searchfragment.list.NewSearchFragment.SearchFragmentListener;
 import com.android.dialer.smartdial.util.SmartDialPrefix;
 import com.android.dialer.speeddial.SpeedDialFragment;
+import com.android.dialer.telecom.TelecomUtil;
 import com.android.dialer.voicemail.listui.NewVoicemailFragment;
 
 /** This is the main activity for dialer. It hosts favorites, call log, search, dialpad, etc... */
@@ -61,6 +64,8 @@
   /** Language the device was in last time {@link #onSaveInstanceState(Bundle)} was called. */
   private String savedLanguageCode;
 
+  private View snackbarContainer;
+
   /**
    * @param context Context of the application package implementing MainActivity class.
    * @return intent for MainActivity.class
@@ -81,6 +86,8 @@
   }
 
   private void initLayout(Bundle savedInstanceState) {
+    snackbarContainer = findViewById(R.id.coordinator_layout);
+
     FloatingActionButton fab = findViewById(R.id.fab);
     fab.setOnClickListener(v -> searchController.showDialpad(true));
 
@@ -110,6 +117,21 @@
     // language change.
     boolean forceUpdate = !CompatUtils.getLocale(this).getISO3Language().equals(savedLanguageCode);
     Database.get(this).getDatabaseHelper(this).startSmartDialUpdateThread(forceUpdate);
+    showPostCallPrompt();
+  }
+
+  private void showPostCallPrompt() {
+    if (TelecomUtil.isInManagedCall(this)) {
+      // No prompt to show if the user is in a call
+      return;
+    }
+
+    if (searchController.isInSearch()) {
+      // Don't show the prompt if we're in the search ui
+      return;
+    }
+
+    PostCall.promptUserForMessageIfNecessary(this, snackbarContainer);
   }
 
   @Override
diff --git a/java/com/android/dialer/main/impl/MainSearchController.java b/java/com/android/dialer/main/impl/MainSearchController.java
index b01f80d..1defdf5 100644
--- a/java/com/android/dialer/main/impl/MainSearchController.java
+++ b/java/com/android/dialer/main/impl/MainSearchController.java
@@ -40,7 +40,6 @@
 import com.android.dialer.main.impl.toolbar.SearchBarListener;
 import com.android.dialer.searchfragment.list.NewSearchFragment;
 import com.android.dialer.searchfragment.list.NewSearchFragment.SearchFragmentListener;
-import com.android.dialer.util.ViewUtil;
 import com.google.common.base.Optional;
 import java.util.ArrayList;
 
@@ -99,7 +98,7 @@
     // Show Search
     if (getSearchFragment() == null) {
       NewSearchFragment searchFragment = NewSearchFragment.newInstance(false);
-      transaction.add(R.id.search_fragment_container, searchFragment, SEARCH_FRAGMENT_TAG);
+      transaction.add(R.id.fragment_container, searchFragment, SEARCH_FRAGMENT_TAG);
     } else if (!isSearchVisible()) {
       transaction.show(getSearchFragment());
     }
@@ -153,17 +152,11 @@
   }
 
   private void hideBottomNav() {
-    bottomNav.setVisibility(View.INVISIBLE);
-    if (bottomNav.getHeight() == 0) {
-      ViewUtil.doOnGlobalLayout(bottomNav, v -> fab.setTranslationY(bottomNav.getHeight()));
-    } else {
-      fab.setTranslationY(bottomNav.getHeight());
-    }
+    bottomNav.setVisibility(View.GONE);
   }
 
   private void showBottomNav() {
     bottomNav.setVisibility(View.VISIBLE);
-    fab.setTranslationY(0);
   }
 
   /** Should be called when {@link DialpadListener#onDialpadShown()} is called. */
@@ -255,6 +248,11 @@
     return fragment != null && fragment.isAdded() && !fragment.isHidden();
   }
 
+  /** Returns true if the search UI is visible. */
+  public boolean isInSearch() {
+    return isSearchVisible();
+  }
+
   /**
    * Opens search in regular/search bar search mode.
    *
@@ -276,7 +274,7 @@
     // Show Search
     if (getSearchFragment() == null) {
       NewSearchFragment searchFragment = NewSearchFragment.newInstance(false);
-      transaction.add(R.id.search_fragment_container, searchFragment, SEARCH_FRAGMENT_TAG);
+      transaction.add(R.id.fragment_container, searchFragment, SEARCH_FRAGMENT_TAG);
     } else if (!isSearchVisible()) {
       transaction.show(getSearchFragment());
     }
diff --git a/java/com/android/dialer/main/impl/res/layout/main_activity.xml b/java/com/android/dialer/main/impl/res/layout/main_activity.xml
index eb0d45e..aaba8da 100644
--- a/java/com/android/dialer/main/impl/res/layout/main_activity.xml
+++ b/java/com/android/dialer/main/impl/res/layout/main_activity.xml
@@ -21,13 +21,31 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-  <!-- Holds SpeedDial, Call Log, Contacts and Voicemail fragments -->
-  <FrameLayout
-      android:id="@+id/fragment_container"
+  <android.support.design.widget.CoordinatorLayout
+      xmlns:android="http://schemas.android.com/apk/res/android"
+      xmlns:app="http://schemas.android.com/apk/res-auto"
+      android:id="@+id/coordinator_layout"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:layout_below="@+id/toolbar"
-      android:layout_above="@+id/bottom_nav_bar"/>
+      android:layout_above="@+id/bottom_nav_bar">
+
+    <!-- Holds SpeedDial, Call Log, Contacts, Voicemail and Search fragments -->
+    <FrameLayout
+        android:id="@+id/fragment_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_above="@+id/bottom_nav_bar"/>
+
+    <android.support.design.widget.FloatingActionButton
+        android:id="@+id/fab"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_margin="16dp"
+        android:layout_gravity="end|bottom"
+        android:src="@drawable/quantum_ic_dialpad_white_24"
+        app:backgroundTint="?android:attr/colorAccent"/>
+  </android.support.design.widget.CoordinatorLayout>
 
   <!-- BottomNavBar -->
   <include
@@ -37,13 +55,6 @@
       android:layout_height="wrap_content"
       android:layout_alignParentBottom="true"/>
 
-  <!-- Holds search fragment -->
-  <FrameLayout
-      android:id="@+id/search_fragment_container"
-      android:layout_width="match_parent"
-      android:layout_height="match_parent"
-      android:layout_below="@+id/toolbar"/>
-
   <!-- Holds Dialpad fragment -->
   <FrameLayout
       android:id="@+id/dialpad_fragment_container"
@@ -55,14 +66,4 @@
   <include
       android:id="@+id/toolbar"
       layout="@layout/toolbar_layout"/>
-
-  <android.support.design.widget.FloatingActionButton
-      android:id="@+id/fab"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:layout_above="@+id/bottom_nav_bar"
-      android:layout_alignParentEnd="true"
-      android:layout_margin="16dp"
-      android:src="@drawable/quantum_ic_dialpad_white_24"
-      app:backgroundTint="?android:attr/colorAccent"/>
 </RelativeLayout>
\ No newline at end of file
diff --git a/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java b/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java
index 622b4db..b77a86c 100644
--- a/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java
+++ b/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java
@@ -133,7 +133,7 @@
               if (subInfo == null) {
                 throw new IllegalStateException(
                     "A sublookup didn't return an info for number: "
-                        + LogUtil.sanitizePhoneNumber(dialerPhoneNumber.getRawInput().getNumber()));
+                        + LogUtil.sanitizePhoneNumber(dialerPhoneNumber.getNormalizedNumber()));
               }
               phoneLookups.get(i).setSubMessage(combinedInfo, subInfo);
             }
diff --git a/java/com/android/dialer/phonenumberproto/Converter.java b/java/com/android/dialer/phonenumberproto/Converter.java
deleted file mode 100644
index 453b988..0000000
--- a/java/com/android/dialer/phonenumberproto/Converter.java
+++ /dev/null
@@ -1,120 +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.phonenumberproto;
-
-import com.android.dialer.DialerInternalPhoneNumber;
-import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
-
-/**
- * Methods for converting from {@link PhoneNumber} POJOs to {@link DialerInternalPhoneNumber} protos
- * and back.
- */
-class Converter {
-
-  static DialerInternalPhoneNumber pojoToProto(PhoneNumber pojo) {
-    DialerInternalPhoneNumber.Builder proto = DialerInternalPhoneNumber.newBuilder();
-    if (pojo.hasCountryCode()) {
-      proto.setCountryCode(pojo.getCountryCode());
-    }
-    if (pojo.hasCountryCodeSource()) {
-      switch (pojo.getCountryCodeSource()) {
-        case FROM_NUMBER_WITH_PLUS_SIGN:
-          proto.setCountryCodeSource(
-              DialerInternalPhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN);
-          break;
-        case FROM_NUMBER_WITH_IDD:
-          proto.setCountryCodeSource(
-              DialerInternalPhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_IDD);
-          break;
-        case FROM_NUMBER_WITHOUT_PLUS_SIGN:
-          proto.setCountryCodeSource(
-              DialerInternalPhoneNumber.CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN);
-          break;
-        case FROM_DEFAULT_COUNTRY:
-          proto.setCountryCodeSource(
-              DialerInternalPhoneNumber.CountryCodeSource.FROM_DEFAULT_COUNTRY);
-          break;
-        default:
-          throw new IllegalArgumentException(
-              "unsupported country code source: " + pojo.getCountryCodeSource());
-      }
-    }
-    if (pojo.hasExtension()) {
-      proto.setExtension(pojo.getExtension());
-    }
-    if (pojo.hasItalianLeadingZero()) {
-      proto.setItalianLeadingZero(pojo.isItalianLeadingZero());
-    }
-    if (pojo.hasNationalNumber()) {
-      proto.setNationalNumber(pojo.getNationalNumber());
-    }
-    if (pojo.hasNumberOfLeadingZeros()) {
-      proto.setNumberOfLeadingZeros(pojo.getNumberOfLeadingZeros());
-    }
-    if (pojo.hasPreferredDomesticCarrierCode()) {
-      proto.setPreferredDomesticCarrierCode(pojo.getPreferredDomesticCarrierCode());
-    }
-    if (pojo.hasRawInput()) {
-      proto.setRawInput(pojo.getRawInput());
-    }
-    return proto.build();
-  }
-
-  static PhoneNumber protoToPojo(DialerInternalPhoneNumber proto) {
-    PhoneNumber pojo = new PhoneNumber();
-    if (proto.hasCountryCode()) {
-      pojo.setCountryCode(proto.getCountryCode());
-    }
-    if (proto.hasCountryCodeSource()) {
-      switch (proto.getCountryCodeSource()) {
-        case FROM_NUMBER_WITH_PLUS_SIGN:
-          pojo.setCountryCodeSource(PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN);
-          break;
-        case FROM_NUMBER_WITH_IDD:
-          pojo.setCountryCodeSource(PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_IDD);
-          break;
-        case FROM_NUMBER_WITHOUT_PLUS_SIGN:
-          pojo.setCountryCodeSource(PhoneNumber.CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN);
-          break;
-        case FROM_DEFAULT_COUNTRY:
-          pojo.setCountryCodeSource(PhoneNumber.CountryCodeSource.FROM_DEFAULT_COUNTRY);
-          break;
-        default:
-          throw new IllegalArgumentException(
-              "unsupported country code source: " + proto.getCountryCodeSource());
-      }
-    }
-    if (proto.hasExtension()) {
-      pojo.setExtension(proto.getExtension());
-    }
-    if (proto.hasItalianLeadingZero()) {
-      pojo.setItalianLeadingZero(proto.getItalianLeadingZero());
-    }
-    if (proto.hasNationalNumber()) {
-      pojo.setNationalNumber(proto.getNationalNumber());
-    }
-    if (proto.hasNumberOfLeadingZeros()) {
-      pojo.setNumberOfLeadingZeros(proto.getNumberOfLeadingZeros());
-    }
-    if (proto.hasPreferredDomesticCarrierCode()) {
-      pojo.setPreferredDomesticCarrierCode(proto.getPreferredDomesticCarrierCode());
-    }
-    if (proto.hasRawInput()) {
-      pojo.setRawInput(proto.getRawInput());
-    }
-    return pojo;
-  }
-}
diff --git a/java/com/android/dialer/phonenumberproto/DialerPhoneNumberUtil.java b/java/com/android/dialer/phonenumberproto/DialerPhoneNumberUtil.java
index 841524b..319467c 100644
--- a/java/com/android/dialer/phonenumberproto/DialerPhoneNumberUtil.java
+++ b/java/com/android/dialer/phonenumberproto/DialerPhoneNumberUtil.java
@@ -21,9 +21,8 @@
 import android.support.annotation.Nullable;
 import android.support.annotation.WorkerThread;
 import android.telephony.PhoneNumberUtils;
-import com.android.dialer.DialerInternalPhoneNumber;
+import android.text.TextUtils;
 import com.android.dialer.DialerPhoneNumber;
-import com.android.dialer.DialerPhoneNumber.RawInput;
 import com.android.dialer.common.Assert;
 import com.android.dialer.common.LogUtil;
 import com.google.common.base.Optional;
@@ -60,29 +59,12 @@
     Assert.isWorkerThread();
 
     DialerPhoneNumber.Builder dialerPhoneNumber = DialerPhoneNumber.newBuilder();
-    RawInput.Builder rawInput = RawInput.newBuilder();
     // Numbers can be null or empty for incoming "unknown" calls.
     if (numberToParse != null) {
-      rawInput.setNumber(numberToParse);
+      dialerPhoneNumber.setNormalizedNumber(normalizeNumber(numberToParse, defaultRegion));
     }
     if (defaultRegion != null) {
-      rawInput.setCountryIso(defaultRegion);
-    }
-    dialerPhoneNumber.setRawInput(rawInput.build());
-
-    // If the number is a service number, just store the raw input and don't bother trying to parse
-    // it. PhoneNumberUtil#parse ignores these characters which can lead to confusing behavior, such
-    // as the numbers "#123" and "123" being considered the same. The "#" can appear in the middle
-    // of a service number and the "*" can appear at the beginning (see a bug).
-    if (numberToParse != null && (numberToParse.contains("#") || numberToParse.startsWith("*"))) {
-      return dialerPhoneNumber.build();
-    }
-
-    try {
-      dialerPhoneNumber.setDialerInternalPhoneNumber(
-          Converter.pojoToProto(phoneNumberUtil.parse(numberToParse, defaultRegion)));
-    } catch (NumberParseException e) {
-      LogUtil.w("DialerPhoneNumberUtil.parse", "couldn't parse phone number", e);
+      dialerPhoneNumber.setCountryIso(defaultRegion);
     }
     return dialerPhoneNumber.build();
   }
@@ -103,6 +85,54 @@
   }
 
   /**
+   * Formats the provided number to E164 format or return a normalized version of the raw number if
+   * the number is not valid according to {@link PhoneNumberUtil#isValidNumber(PhoneNumber)}.
+   *
+   * @see #formatToValidE164(DialerPhoneNumber)
+   * @see PhoneNumberUtils#normalizeNumber(String)
+   */
+  public String normalizeNumber(DialerPhoneNumber number) {
+    // TODO(zachh): Inline this method.
+    // TODO(zachh): This loses country info when number is not valid.
+    return number.getNormalizedNumber();
+  }
+
+  @WorkerThread
+  private String normalizeNumber(@NonNull String rawNumber, @Nullable String defaultRegion) {
+    Assert.isWorkerThread();
+
+    // If the number is a service number, just store the raw number and don't bother trying to parse
+    // it. PhoneNumberUtil#parse ignores these characters which can lead to confusing behavior, such
+    // as the numbers "#123" and "123" being considered the same. The "#" can appear in the middle
+    // of a service number and the "*" can appear at the beginning (see a bug).
+    if (isServiceNumber(rawNumber)) {
+      return rawNumber;
+    }
+
+    String postDialPortion = PhoneNumberUtils.extractPostDialPortion(rawNumber);
+    String networkPortion = PhoneNumberUtils.extractNetworkPortion(rawNumber);
+
+    try {
+      PhoneNumber phoneNumber = phoneNumberUtil.parse(networkPortion, defaultRegion);
+      if (phoneNumberUtil.isValidNumber(phoneNumber)) {
+        String validNumber = phoneNumberUtil.format(phoneNumber, PhoneNumberFormat.E164);
+        if (TextUtils.isEmpty(validNumber)) {
+          throw new IllegalStateException(
+              "e164 number should not be empty: " + LogUtil.sanitizePii(rawNumber));
+        }
+        // The E164 representation doesn't contain post-dial digits, but we need to preserve them.
+        if (postDialPortion != null) {
+          validNumber += postDialPortion;
+        }
+        return validNumber;
+      }
+    } catch (NumberParseException e) {
+      // fall through
+    }
+    return networkPortion + postDialPortion;
+  }
+
+  /**
    * Returns true if the two numbers:
    *
    * <ul>
@@ -123,21 +153,46 @@
   public boolean isMatch(
       @NonNull DialerPhoneNumber firstNumberIn, @NonNull DialerPhoneNumber secondNumberIn) {
     Assert.isWorkerThread();
-    if (!Assert.isNotNull(firstNumberIn).hasDialerInternalPhoneNumber()
-        || !Assert.isNotNull(secondNumberIn).hasDialerInternalPhoneNumber()) {
-      // An empty number should not be combined with any other number.
-      if (firstNumberIn.getRawInput().getNumber().isEmpty()
-          || secondNumberIn.getRawInput().getNumber().isEmpty()) {
-        return false;
-      }
-      // Both the network and post-dial portions of the number should match.
-      return sameNetworkPortion(firstNumberIn, secondNumberIn)
-          && samePostDialPortion(firstNumberIn, secondNumberIn);
+
+    // An empty number should not be combined with any other number.
+    if (firstNumberIn.getNormalizedNumber().isEmpty()
+        || secondNumberIn.getNormalizedNumber().isEmpty()) {
+      return false;
     }
-    MatchType matchType =
-        isNumberMatch(
-            firstNumberIn.getDialerInternalPhoneNumber(),
-            secondNumberIn.getDialerInternalPhoneNumber());
+
+    // Two numbers with different countries should not match.
+    if (!firstNumberIn.getCountryIso().equals(secondNumberIn.getCountryIso())) {
+      return false;
+    }
+
+    PhoneNumber phoneNumber1 = null;
+    try {
+      phoneNumber1 =
+          phoneNumberUtil.parse(firstNumberIn.getNormalizedNumber(), firstNumberIn.getCountryIso());
+    } catch (NumberParseException e) {
+      // fall through
+    }
+
+    PhoneNumber phoneNumber2 = null;
+    try {
+      phoneNumber2 =
+          phoneNumberUtil.parse(
+              secondNumberIn.getNormalizedNumber(), secondNumberIn.getCountryIso());
+    } catch (NumberParseException e) {
+      // fall through
+    }
+
+    // If either number is a service number or either number can't be parsed by libphonenumber, just
+    // fallback to basic textual matching.
+    if (isServiceNumber(firstNumberIn.getNormalizedNumber())
+        || isServiceNumber(secondNumberIn.getNormalizedNumber())
+        || phoneNumber1 == null
+        || phoneNumber2 == null) {
+      return firstNumberIn.getNormalizedNumber().equals(secondNumberIn.getNormalizedNumber());
+    }
+
+    // Both numbers are parseable, use more sophisticated libphonenumber matching.
+    MatchType matchType = phoneNumberUtil.isNumberMatch(phoneNumber1, phoneNumber2);
 
     return (matchType == MatchType.SHORT_NSN_MATCH
             || matchType == MatchType.NSN_MATCH
@@ -145,45 +200,9 @@
         && samePostDialPortion(firstNumberIn, secondNumberIn);
   }
 
-  private static boolean sameNetworkPortion(DialerPhoneNumber number1, DialerPhoneNumber number2) {
-    return PhoneNumberUtils.extractNetworkPortion(number1.getRawInput().getNumber())
-        .equals(PhoneNumberUtils.extractNetworkPortion(number2.getRawInput().getNumber()));
-  }
-
   private static boolean samePostDialPortion(DialerPhoneNumber number1, DialerPhoneNumber number2) {
-    return PhoneNumberUtils.extractPostDialPortion(number1.getRawInput().getNumber())
-        .equals(PhoneNumberUtils.extractPostDialPortion(number2.getRawInput().getNumber()));
-  }
-
-  /**
-   * Compares the provided phone numbers.
-   *
-   * @see PhoneNumberUtil#isNumberMatch(com.google.i18n.phonenumbers.Phonenumber.PhoneNumber,
-   *     com.google.i18n.phonenumbers.Phonenumber.PhoneNumber)
-   */
-  @WorkerThread
-  private MatchType isNumberMatch(
-      @NonNull DialerInternalPhoneNumber firstNumberIn,
-      @NonNull DialerInternalPhoneNumber secondNumberIn) {
-    Assert.isWorkerThread();
-    return phoneNumberUtil.isNumberMatch(
-        Converter.protoToPojo(Assert.isNotNull(firstNumberIn)),
-        Converter.protoToPojo(Assert.isNotNull(secondNumberIn)));
-  }
-
-  /**
-   * Formats the provided number to E164 format or return a normalized version of the raw number if
-   * the number is not valid according to {@link PhoneNumberUtil#isValidNumber(PhoneNumber)}.
-   *
-   * @see #formatToValidE164(DialerPhoneNumber)
-   * @see PhoneNumberUtils#normalizeNumber(String)
-   */
-  @WorkerThread
-  public String normalizeNumber(DialerPhoneNumber number) {
-    Assert.isWorkerThread();
-    // TODO(zachh): This loses country info when number is not valid.
-    return formatToValidE164(number)
-        .or(PhoneNumberUtils.normalizeNumber(number.getRawInput().getNumber()));
+    return PhoneNumberUtils.extractPostDialPortion(number1.getNormalizedNumber())
+        .equals(PhoneNumberUtils.extractPostDialPortion(number2.getNormalizedNumber()));
   }
 
   /**
@@ -199,13 +218,21 @@
    */
   @WorkerThread
   public Optional<String> formatToValidE164(DialerPhoneNumber number) {
+    // TODO(zachh): We could do something like store a "valid" bit in DialerPhoneNumber?
     Assert.isWorkerThread();
-    if (number.hasDialerInternalPhoneNumber()) {
-      PhoneNumber phoneNumber = Converter.protoToPojo(number.getDialerInternalPhoneNumber());
-      if (phoneNumberUtil.isValidNumber(phoneNumber)) {
-        return Optional.fromNullable(phoneNumberUtil.format(phoneNumber, PhoneNumberFormat.E164));
-      }
+    PhoneNumber phoneNumber;
+    try {
+      phoneNumber = phoneNumberUtil.parse(number.getNormalizedNumber(), number.getCountryIso());
+    } catch (NumberParseException e) {
+      return Optional.absent();
+    }
+    if (phoneNumberUtil.isValidNumber(phoneNumber)) {
+      return Optional.fromNullable(phoneNumberUtil.format(phoneNumber, PhoneNumberFormat.E164));
     }
     return Optional.absent();
   }
+
+  private boolean isServiceNumber(@NonNull String rawNumber) {
+    return rawNumber.contains("#") || rawNumber.startsWith("*");
+  }
 }
diff --git a/java/com/android/dialer/phonenumberproto/PartitionedNumbers.java b/java/com/android/dialer/phonenumberproto/PartitionedNumbers.java
index 0a4aafa..dbf9936 100644
--- a/java/com/android/dialer/phonenumberproto/PartitionedNumbers.java
+++ b/java/com/android/dialer/phonenumberproto/PartitionedNumbers.java
@@ -70,7 +70,7 @@
         }
         currentNumbers.add(dialerPhoneNumber);
       } else {
-        String invalidNumber = dialerPhoneNumber.getRawInput().getNumber();
+        String invalidNumber = dialerPhoneNumber.getNormalizedNumber();
         Set<DialerPhoneNumber> currentNumbers = invalidMapBuilder.get(invalidNumber);
         if (currentNumbers == null) {
           currentNumbers = new ArraySet<>();
@@ -85,7 +85,7 @@
   }
 
   private boolean hasPostDialDigits(DialerPhoneNumber dialerPhoneNumber) {
-    return !PhoneNumberUtils.extractPostDialPortion(dialerPhoneNumber.getRawInput().getNumber())
+    return !PhoneNumberUtils.extractPostDialPortion(dialerPhoneNumber.getNormalizedNumber())
         .isEmpty();
   }
 
diff --git a/java/com/android/dialer/phonenumberproto/dialer_phone_number.proto b/java/com/android/dialer/phonenumberproto/dialer_phone_number.proto
index cd2ed50..941de04 100644
--- a/java/com/android/dialer/phonenumberproto/dialer_phone_number.proto
+++ b/java/com/android/dialer/phonenumberproto/dialer_phone_number.proto
@@ -21,152 +21,30 @@
 
 package com.android.dialer;
 
-// A phone number for use in the dialer application. It consists of a
-// DialerInternalPhoneNumber, which is a copy of libphonenumber's PhoneNumber
-// proto, and the raw input used to create it.
+// A phone number for use in the dialer application in the context of a call. It
+// consists of a normalized number string and a two-letter country code.
+// The country is retrieved from CallLog.Calls#COUNTRY: "The ISO 3166-1 two
+// letters country code of the country where the user received or made the
+// call."
 message DialerPhoneNumber {
-  // libphonenumber representation of the phone number. May be empty if the raw
-  // input failed to parse, in which case raw_input should be used.
-  optional DialerInternalPhoneNumber dialer_internal_phone_number = 1;
+  // A dialer-normalized version of the number. Here are some general rules:
+  //
+  // -Numbers containing "#" or starting with "*" are considered service numbers
+  // and are stored exactly as the user dialed them.
+  //
+  // -If a number is valid according to libphonenumber and can be parsed, this
+  //  is the E164 version of it, with post dial digits appended.
+  //
+  // -Otherwise, it is the network portion of the number as dialed with
+  //  non-digits removed, with post dial digits appended. An example invalid
+  //  number is a 7-digit US number (missing an area code) like "456-7890" which
+  //  would be stored as "4567890".
+  //
+  //  See DialerPhoneNumberUtil#parse.
+  optional string normalized_number = 1;
 
-  // The raw input which was used to create a DialerPhoneNumber.
-  message RawInput {
-    // The phone number as it was entered or received.
-    optional string number = 1;
-    // The ISO 3166-1 two letter country code of the country where the user made
-    // or received the call.
-    optional string country_iso = 2;
-  }
-  // Prefer to use dialer_internal_phone_number if present.
-  optional RawInput raw_input = 2;
+  // The country in which the call to the number occurred, retrieved from
+  // CallLog.Calls#COUNTRY: "The ISO 3166-1 two letters country code of the
+  // country where the user received or made the call."
+  optional string country_iso = 2;
 }
-
-// This is a copy of libphonenumber proto file for use in the dialer codebase.
-// We cannot depend on the real libphonenumber proto because it is not exposed
-// in any open source library. As such, this file could fall out of sync with
-// that proto over time.
-//
-// The only difference between this proto and the libphonenumber proto (as of
-// when this file was created) is the package name and proto name.
-//
-// If the libphonenumber proto becomes accessible some day, it may be possible
-// to remove this proto and use the real libphonenumber proto assuming this
-// proto is kept wire-compatible with it.
-message DialerInternalPhoneNumber {
-  // The country calling code for this number, as defined by the International
-  // Telecommunication Union (ITU). For example, this would be 1 for NANPA
-  // countries, and 33 for France.
-  required int32 country_code = 1;
-
-  // The National (significant) Number, as defined in International
-  // Telecommunication Union (ITU) Recommendation E.164, without any leading
-  // zero. The leading-zero is stored separately if required, since this is an
-  // uint64 and hence cannot store such information. Do not use this field
-  // directly: if you want the national significant number, call the
-  // getNationalSignificantNumber method of PhoneNumberUtil.
-  //
-  // For countries which have the concept of an "area code" or "national
-  // destination code", this is included in the National (significant) Number.
-  // Although the ITU says the maximum length should be 15, we have found longer
-  // numbers in some countries e.g. Germany.
-  // Note that the National (significant) Number does not contain the National
-  // (trunk) prefix. Obviously, as a uint64, it will never contain any
-  // formatting (hyphens, spaces, parentheses), nor any alphanumeric spellings.
-  required uint64 national_number = 2 [jstype = JS_NUMBER];
-
-  // Extension is not standardized in ITU recommendations, except for being
-  // defined as a series of numbers with a maximum length of 40 digits. It is
-  // defined as a string here to accommodate for the possible use of a leading
-  // zero in the extension (organizations have complete freedom to do so, as
-  // there is no standard defined). Other than digits, some other dialling
-  // characters such as "," (indicating a wait) may be stored here.
-  optional string extension = 3;
-
-  // In some countries, the national (significant) number starts with one or
-  // more "0"s without this being a national prefix or trunk code of some kind.
-  // For example, the leading zero in the national (significant) number of an
-  // Italian phone number indicates the number is a fixed-line number.  There
-  // have been plans to migrate fixed-line numbers to start with the digit two
-  // since December 2000, but it has not happened yet. See
-  // http://en.wikipedia.org/wiki/%2B39 for more details.
-  //
-  // These fields can be safely ignored (there is no need to set them) for most
-  // countries. Some limited number of countries behave like Italy - for these
-  // cases, if the leading zero(s) of a number would be retained even when
-  // dialling internationally, set this flag to true, and also set the number of
-  // leading zeros.
-  //
-  // Clients who use the parsing or conversion functionality of the i18n phone
-  // number libraries will have these fields set if necessary automatically.
-  optional bool italian_leading_zero = 4;
-  optional int32 number_of_leading_zeros = 8 [default = 1];
-
-  // The next few fields are non-essential fields for a phone number. They
-  // retain extra information about the form the phone number was in when it was
-  // provided to us to parse. They can be safely ignored by most clients. To
-  // populate them, call parseAndKeepRawInput on PhoneNumberUtil.
-
-  // This field is used to store the raw input string containing phone numbers
-  // before it was canonicalized by the library. For example, it could be used
-  // to store alphanumerical numbers such as "1-800-GOOG-411".
-  optional string raw_input = 5;
-
-  // The source from which the country_code is derived. This is not set in the
-  // general parsing method, but in the method that parses and keeps raw_input.
-  // New fields could be added upon request.
-  enum CountryCodeSource {
-    // The country_code is derived based on a phone number with a leading "+",
-    // e.g. the French number "+33 1 42 68 53 00".
-    FROM_NUMBER_WITH_PLUS_SIGN = 1;
-
-    // The country_code is derived based on a phone number with a leading IDD,
-    // e.g. the French number "011 33 1 42 68 53 00", as it is dialled from US.
-    FROM_NUMBER_WITH_IDD = 5;
-
-    // The country_code is derived based on a phone number without a leading
-    // "+", e.g. the French number "33 1 42 68 53 00" when defaultCountry is
-    // supplied as France.
-    FROM_NUMBER_WITHOUT_PLUS_SIGN = 10;
-
-    // The country_code is derived NOT based on the phone number itself, but
-    // from the defaultCountry parameter provided in the parsing function by the
-    // clients. This happens mostly for numbers written in the national format
-    // (without country code). For example, this would be set when parsing the
-    // French number "01 42 68 53 00", when defaultCountry is supplied as
-    // France.
-    FROM_DEFAULT_COUNTRY = 20;
-  }
-
-  // The source from which the country_code is derived.
-  optional CountryCodeSource country_code_source = 6;
-
-  // The carrier selection code that is preferred when calling this phone number
-  // domestically. This also includes codes that need to be dialed in some
-  // countries when calling from landlines to mobiles or vice versa. For
-  // example, in Columbia, a "3" needs to be dialed before the phone number
-  // itself when calling from a mobile phone to a domestic landline phone and
-  // vice versa.
-  //
-  // Note this is the "preferred" code, which means other codes may work as
-  // well.
-  optional string preferred_domestic_carrier_code = 7;
-}
-
-// Examples:
-//
-// Google MTV, +1 650-253-0000, (650) 253-0000
-// country_code: 1
-// national_number: 6502530000
-//
-// Google Paris, +33 (0)1 42 68 53 00, 01 42 68 53 00
-// country_code: 33
-// national_number: 142685300
-//
-// Google Beijing, +86-10-62503000, (010) 62503000
-// country_code: 86
-// national_number: 1062503000
-//
-// Google Italy, +39 02-36618 300, 02-36618 300
-// country_code: 39
-// national_number: 236618300
-// italian_leading_zero: true
diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailMediaPlayerView.java b/java/com/android/dialer/voicemail/listui/NewVoicemailMediaPlayerView.java
index dd59712..df47159 100644
--- a/java/com/android/dialer/voicemail/listui/NewVoicemailMediaPlayerView.java
+++ b/java/com/android/dialer/voicemail/listui/NewVoicemailMediaPlayerView.java
@@ -151,7 +151,7 @@
     Assert.isNotNull(voicemailEntryFromAdapter);
     Uri uri = Uri.parse(voicemailEntryFromAdapter.voicemailUri());
 
-    numberVoicemailFrom = voicemailEntryFromAdapter.number().getRawInput().getNumber();
+    numberVoicemailFrom = voicemailEntryFromAdapter.number().getNormalizedNumber();
 
     Assert.isNotNull(viewHolder);
     Assert.isNotNull(uri);
diff --git a/java/com/android/dialer/voicemail/listui/menu/Modules.java b/java/com/android/dialer/voicemail/listui/menu/Modules.java
index bd79932..665031a 100644
--- a/java/com/android/dialer/voicemail/listui/menu/Modules.java
+++ b/java/com/android/dialer/voicemail/listui/menu/Modules.java
@@ -43,8 +43,8 @@
         voicemailEntry.numberAttributes().getName(),
         voicemailEntry.numberAttributes().getLookupUri());
 
-    String originalNumber = voicemailEntry.number().getRawInput().getNumber();
-    SharedModules.maybeAddModuleForSendingTextMessage(context, modules, originalNumber);
+    String normalizedNumber = voicemailEntry.number().getNormalizedNumber();
+    SharedModules.maybeAddModuleForSendingTextMessage(context, modules, normalizedNumber);
 
     if (!modules.isEmpty()) {
       modules.add(new DividerModule());
@@ -52,7 +52,7 @@
 
     // TODO(zachh): Module for blocking/unblocking spam.
     // TODO(zachh): Module for CallComposer.
-    SharedModules.maybeAddModuleForCopyingNumber(context, modules, originalNumber);
+    SharedModules.maybeAddModuleForCopyingNumber(context, modules, normalizedNumber);
 
     return modules;
   }