Fix UK numbers in international format with extra 0

See class comment on UkRegionPrefixInInternationalFormatHandler

Bug: 32501490
Test: Unit tests
PiperOrigin-RevId: 190296011
Change-Id: I6f01935f022fc288ad702735b38cb297fb9d2621
diff --git a/java/com/android/dialer/precall/impl/MalformedNumberRectifier.java b/java/com/android/dialer/precall/impl/MalformedNumberRectifier.java
new file mode 100644
index 0000000..2e41463
--- /dev/null
+++ b/java/com/android/dialer/precall/impl/MalformedNumberRectifier.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.precall.impl;
+
+import android.content.Context;
+import android.net.Uri;
+import android.support.annotation.MainThread;
+import android.telecom.PhoneAccount;
+import com.android.dialer.callintent.CallIntentBuilder;
+import com.android.dialer.precall.PreCallAction;
+import com.android.dialer.precall.PreCallCoordinator;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Fix common malformed number before it is dialed. Rewrite the number to the first handler that can
+ * handle it
+ */
+public class MalformedNumberRectifier implements PreCallAction {
+
+  /** Handler for individual rules. */
+  public interface MalformedNumberHandler {
+
+    /** @return the number to be corrected to. */
+    @MainThread
+    Optional<String> handle(Context context, String number);
+  }
+
+  private final ImmutableList<MalformedNumberHandler> handlers;
+
+  MalformedNumberRectifier(ImmutableList<MalformedNumberHandler> handlers) {
+    this.handlers = handlers;
+  }
+
+  @Override
+  public boolean requiresUi(Context context, CallIntentBuilder builder) {
+    return false;
+  }
+
+  @Override
+  public void runWithoutUi(Context context, CallIntentBuilder builder) {
+    if (!PhoneAccount.SCHEME_TEL.equals(builder.getUri().getScheme())) {
+      return;
+    }
+    String number = builder.getUri().getSchemeSpecificPart();
+
+    for (MalformedNumberHandler handler : handlers) {
+      Optional<String> result = handler.handle(context, number);
+      if (result.isPresent()) {
+        builder.setUri(Uri.fromParts(PhoneAccount.SCHEME_TEL, result.get(), null));
+        return;
+      }
+    }
+  }
+
+  @Override
+  public void runWithUi(PreCallCoordinator coordinator) {
+    runWithoutUi(coordinator.getActivity(), coordinator.getBuilder());
+  }
+
+  @Override
+  public void onDiscard() {}
+}
diff --git a/java/com/android/dialer/precall/impl/PreCallImpl.java b/java/com/android/dialer/precall/impl/PreCallImpl.java
index f75c8d9..bd23f9e 100644
--- a/java/com/android/dialer/precall/impl/PreCallImpl.java
+++ b/java/com/android/dialer/precall/impl/PreCallImpl.java
@@ -39,7 +39,11 @@
   @Override
   public ImmutableList<PreCallAction> getActions() {
     return ImmutableList.of(
-        new PermissionCheckAction(), new CallingAccountSelector(), new AssistedDialAction());
+        new PermissionCheckAction(),
+        new MalformedNumberRectifier(
+            ImmutableList.of(new UkRegionPrefixInInternationalFormatHandler())),
+        new CallingAccountSelector(),
+        new AssistedDialAction());
   }
 
   @NonNull
diff --git a/java/com/android/dialer/precall/impl/UkRegionPrefixInInternationalFormatHandler.java b/java/com/android/dialer/precall/impl/UkRegionPrefixInInternationalFormatHandler.java
new file mode 100644
index 0000000..b8f54d8
--- /dev/null
+++ b/java/com/android/dialer/precall/impl/UkRegionPrefixInInternationalFormatHandler.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.precall.impl;
+
+import android.content.Context;
+import android.telephony.PhoneNumberUtils;
+import com.android.dialer.common.LogUtil;
+import com.android.dialer.configprovider.ConfigProviderBindings;
+import com.android.dialer.precall.impl.MalformedNumberRectifier.MalformedNumberHandler;
+import com.google.common.base.Optional;
+
+/**
+ * It is customary in UK to present numbers as "+44 (0) xx xxxx xxxx". This is actually a amalgam of
+ * international (+44 xx xxxx xxxx) and regional (0xx xxxx xxxx) format, and is in fact invalid. It
+ * might be rejected depending on the carrier.
+ *
+ * <p>This class removes the "0" region code prefix if the first dialable digits are "+440". UK
+ * short codes and region codes in international format will never start with a 0.
+ */
+class UkRegionPrefixInInternationalFormatHandler implements MalformedNumberHandler {
+
+  private static final String MALFORMED_PREFIX = "+440";
+
+  @Override
+  public Optional<String> handle(Context context, String number) {
+    if (!ConfigProviderBindings.get(context)
+        .getBoolean("uk_region_prefix_in_international_format_fix_enabled", true)) {
+      return Optional.absent();
+    }
+    if (!PhoneNumberUtils.normalizeNumber(number).startsWith(MALFORMED_PREFIX)) {
+      return Optional.absent();
+    }
+    LogUtil.i("UkRegionPrefixInInternationalFormatHandler.handle", "removing (0) in UK numbers");
+
+    // libPhoneNumber is not used because we want to keep post dial digits, and this is on the main
+    // thread.
+    String convertedNumber = PhoneNumberUtils.convertKeypadLettersToDigits(number);
+    StringBuilder result = new StringBuilder();
+    int prefixPosition = 0;
+    for (int i = 0; i < convertedNumber.length(); i++) {
+      char c = convertedNumber.charAt(i);
+      if (c != MALFORMED_PREFIX.charAt(prefixPosition)) {
+        result.append(c);
+        continue;
+      }
+      prefixPosition++;
+      if (prefixPosition == MALFORMED_PREFIX.length()) {
+        result.append(convertedNumber.substring(i + 1));
+        break;
+      }
+      result.append(c);
+    }
+    return Optional.of(result.toString());
+  }
+}