summaryrefslogtreecommitdiff
path: root/java/com/android/dialer/oem
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/android/dialer/oem')
-rw-r--r--java/com/android/dialer/oem/AndroidManifest.xml21
-rw-r--r--java/com/android/dialer/oem/CequintCallerIdManager.java317
-rw-r--r--java/com/android/dialer/oem/MotorolaHiddenMenuKeySequence.java154
-rw-r--r--java/com/android/dialer/oem/MotorolaUtils.java118
-rw-r--r--java/com/android/dialer/oem/res/values-mcc310-mnc000/motorola_config.xml6
-rw-r--r--java/com/android/dialer/oem/res/values-mcc310-mnc120/motorola_config.xml5
-rw-r--r--java/com/android/dialer/oem/res/values-mcc311-mnc490/motorola_config.xml5
-rw-r--r--java/com/android/dialer/oem/res/values-mcc311-mnc870/motorola_config.xml5
-rw-r--r--java/com/android/dialer/oem/res/values-mcc312-mnc530/motorola_config.xml5
-rw-r--r--java/com/android/dialer/oem/res/values-mcc316-mnc010/motorola_config.xml5
-rw-r--r--java/com/android/dialer/oem/res/values/motorola_config.xml64
11 files changed, 705 insertions, 0 deletions
diff --git a/java/com/android/dialer/oem/AndroidManifest.xml b/java/com/android/dialer/oem/AndroidManifest.xml
new file mode 100644
index 000000000..9e0373ab4
--- /dev/null
+++ b/java/com/android/dialer/oem/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.dialer.oem">
+ <!-- This is used for querying Cequint caller id. -->
+ <uses-permission android:name="com.cequint.ecid.CALLER_ID_LOOKUP"/>
+
+</manifest> \ No newline at end of file
diff --git a/java/com/android/dialer/oem/CequintCallerIdManager.java b/java/com/android/dialer/oem/CequintCallerIdManager.java
new file mode 100644
index 000000000..095ee4e66
--- /dev/null
+++ b/java/com/android/dialer/oem/CequintCallerIdManager.java
@@ -0,0 +1,317 @@
+/*
+ * 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.oem;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Build.VERSION_CODES;
+import android.support.annotation.AnyThread;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
+import android.telephony.PhoneNumberUtils;
+import android.text.TextUtils;
+import com.android.dialer.common.Assert;
+import com.android.dialer.common.ConfigProviderBindings;
+import com.android.dialer.common.LogUtil;
+import com.android.dialer.util.PermissionsUtil;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Cequint Caller ID manager to provide caller information.
+ *
+ * <p>This is only enabled on Motorola devices for Sprint.
+ *
+ * <p>If it's enabled, this class will be called by call log and incall to get caller info from
+ * Cequint Caller ID. It also caches any information fetched in static map, which lives through
+ * whole application lifecycle.
+ */
+@TargetApi(VERSION_CODES.M)
+public class CequintCallerIdManager {
+
+ private static final String CONFIG_CALLER_ID_ENABLED = "config_caller_id_enabled";
+
+ private static final String PROVIDER_NAME = "com.cequint.ecid";
+
+ private static final Uri CONTENT_URI = Uri.parse("content://" + PROVIDER_NAME + "/lookup");
+
+ private static final int CALLER_ID_LOOKUP_USER_PROVIDED_CID = 0x0001;
+ private static final int CALLER_ID_LOOKUP_SYSTEM_PROVIDED_CID = 0x0002;
+ private static final int CALLER_ID_LOOKUP_INCOMING_CALL = 0x0020;
+
+ private static final Uri CONTENT_URI_FOR_INCALL =
+ Uri.parse("content://" + PROVIDER_NAME + "/incalllookup");
+
+ private static final String[] EMPTY_PROJECTION = new String[] {};
+
+ // Column names in Cequint provider.
+ private static final String CITY_NAME = "cid_pCityName";
+ private static final String STATE_NAME = "cid_pStateName";
+ private static final String STATE_ABBR = "cid_pStateAbbr";
+ private static final String COUNTRY_NAME = "cid_pCountryName";
+ private static final String COMPANY = "cid_pCompany";
+ private static final String NAME = "cid_pName";
+ private static final String FIRST_NAME = "cid_pFirstName";
+ private static final String LAST_NAME = "cid_pLastName";
+ private static final String IMAGE = "cid_pLogo";
+ private static final String DISPLAY_NAME = "cid_pDisplayName";
+
+ // TODO: Revisit it and maybe remove it if it's not necessary.
+ private static final ConcurrentHashMap<String, CequintCallerIdContact> callLogCache =
+ new ConcurrentHashMap<>();
+ private static final ConcurrentHashMap<String, CequintCallerIdContact> incallIncomingCallCache =
+ new ConcurrentHashMap<>();
+ private static final ConcurrentHashMap<String, CequintCallerIdContact> incallOutgoingCallCache =
+ new ConcurrentHashMap<>();
+ private static boolean hasRegisteredContentObserver;
+ private static boolean hasAlreadyCheckedCequintCallerIdPackage;
+ private static boolean isCequintCallerIdEnabled;
+
+ /** Cequint caller id contact information. */
+ public static class CequintCallerIdContact {
+ public final String name;
+ public final String geoDescription;
+ public final String imageUrl;
+
+ private CequintCallerIdContact(String name, String geoDescription, String imageUrl) {
+ this.name = name;
+ this.geoDescription = geoDescription;
+ this.imageUrl = imageUrl;
+ }
+ }
+
+ /** Check whether Cequint Caller Id provider package is available and enabled. */
+ @AnyThread
+ public static synchronized boolean isCequintCallerIdEnabled(@NonNull Context context) {
+ if (!ConfigProviderBindings.get(context).getBoolean(CONFIG_CALLER_ID_ENABLED, true)) {
+ return false;
+ }
+ if (!hasAlreadyCheckedCequintCallerIdPackage) {
+ hasAlreadyCheckedCequintCallerIdPackage = true;
+ isCequintCallerIdEnabled = false;
+
+ try {
+ context.getPackageManager().getPackageInfo(PROVIDER_NAME, 0);
+ isCequintCallerIdEnabled = true;
+ } catch (PackageManager.NameNotFoundException e) {
+ isCequintCallerIdEnabled = false;
+ }
+ }
+ return isCequintCallerIdEnabled;
+ }
+
+ @WorkerThread
+ @Nullable
+ public static CequintCallerIdContact getCequintCallerIdContact(Context context, String number) {
+ Assert.isWorkerThread();
+ LogUtil.d(
+ "CequintCallerIdManager.getCequintCallerIdContact",
+ "number: %s",
+ LogUtil.sanitizePhoneNumber(number));
+ if (callLogCache.containsKey(number)) {
+ return callLogCache.get(number);
+ }
+ CequintCallerIdContact cequintCallerIdContact =
+ lookup(
+ context,
+ CONTENT_URI,
+ PhoneNumberUtils.stripSeparators(number),
+ new String[] {"system"});
+ if (cequintCallerIdContact != null) {
+ callLogCache.put(number, cequintCallerIdContact);
+ }
+ return cequintCallerIdContact;
+ }
+
+ @WorkerThread
+ @Nullable
+ public static CequintCallerIdContact getCequintCallerIdContactForInCall(
+ Context context, String number, String cnapName, boolean isIncoming) {
+ Assert.isWorkerThread();
+ LogUtil.d(
+ "CequintCallerIdManager.getCequintCallerIdContactForInCall",
+ "number: %s, cnapName: %s, isIncoming: %b",
+ LogUtil.sanitizePhoneNumber(number),
+ LogUtil.sanitizePii(cnapName),
+ isIncoming);
+ registerContentObserver(context);
+ if (isIncoming && incallIncomingCallCache.containsKey(number)) {
+ return incallIncomingCallCache.get(number);
+ } else if (!isIncoming && incallOutgoingCallCache.containsKey(number)) {
+ return incallOutgoingCallCache.get(number);
+ }
+ int flag = 0;
+ if (isIncoming) {
+ flag |= CALLER_ID_LOOKUP_INCOMING_CALL;
+ flag |= CALLER_ID_LOOKUP_SYSTEM_PROVIDED_CID;
+ } else {
+ flag |= CALLER_ID_LOOKUP_USER_PROVIDED_CID;
+ }
+ String[] flags = {cnapName, String.valueOf(flag)};
+ CequintCallerIdContact cequintCallerIdContact =
+ lookup(context, CONTENT_URI_FOR_INCALL, number, flags);
+ if (cequintCallerIdContact != null) {
+ if (isIncoming) {
+ incallIncomingCallCache.put(number, cequintCallerIdContact);
+ } else {
+ incallOutgoingCallCache.put(number, cequintCallerIdContact);
+ }
+ }
+ return cequintCallerIdContact;
+ }
+
+ @WorkerThread
+ @Nullable
+ private static CequintCallerIdContact lookup(
+ Context context, Uri uri, @NonNull String number, String[] flags) {
+ Assert.isWorkerThread();
+ Assert.isNotNull(number);
+
+ // Cequint is using custom arguments for content provider. See more details in b/35766080.
+ try (Cursor cursor =
+ context.getContentResolver().query(uri, EMPTY_PROJECTION, number, flags, null)) {
+ if (cursor != null && cursor.moveToFirst()) {
+ String city = getString(cursor, cursor.getColumnIndex(CITY_NAME));
+ String state = getString(cursor, cursor.getColumnIndex(STATE_NAME));
+ String stateAbbr = getString(cursor, cursor.getColumnIndex(STATE_ABBR));
+ String country = getString(cursor, cursor.getColumnIndex(COUNTRY_NAME));
+ String company = getString(cursor, cursor.getColumnIndex(COMPANY));
+ String name = getString(cursor, cursor.getColumnIndex(NAME));
+ String firstName = getString(cursor, cursor.getColumnIndex(FIRST_NAME));
+ String lastName = getString(cursor, cursor.getColumnIndex(LAST_NAME));
+ String imageUrl = getString(cursor, cursor.getColumnIndex(IMAGE));
+ String displayName = getString(cursor, cursor.getColumnIndex(DISPLAY_NAME));
+
+ String contactName =
+ TextUtils.isEmpty(displayName)
+ ? generateDisplayName(firstName, lastName, company, name)
+ : displayName;
+ String geoDescription = getGeoDescription(city, state, stateAbbr, country);
+ LogUtil.d(
+ "CequintCallerIdManager.lookup",
+ "number: %s, contact name: %s, geo: %s, photo url: %s",
+ LogUtil.sanitizePhoneNumber(number),
+ LogUtil.sanitizePii(contactName),
+ LogUtil.sanitizePii(geoDescription),
+ imageUrl);
+ return new CequintCallerIdContact(contactName, geoDescription, imageUrl);
+ } else {
+ LogUtil.d("CequintCallerIdManager.lookup", "No CequintCallerIdContact found");
+ return null;
+ }
+ } catch (Exception e) {
+ LogUtil.e("CequintCallerIdManager.lookup", "exception on query", e);
+ return null;
+ }
+ }
+
+ private static String getString(Cursor cursor, int columnIndex) {
+ if (!cursor.isNull(columnIndex)) {
+ String string = cursor.getString(columnIndex);
+ if (!TextUtils.isEmpty(string)) {
+ return string;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns generated name from other names, e.g. first name, last name etc. Returns null if there
+ * is no other names.
+ */
+ @Nullable
+ private static String generateDisplayName(
+ String firstName, String lastName, String company, String name) {
+ boolean hasFirstName = !TextUtils.isEmpty(firstName);
+ boolean hasLastName = !TextUtils.isEmpty(lastName);
+ boolean hasCompanyName = !TextUtils.isEmpty(company);
+ boolean hasName = !TextUtils.isEmpty(name);
+
+ StringBuilder stringBuilder = new StringBuilder();
+
+ if (hasFirstName || hasLastName) {
+ if (hasFirstName) {
+ stringBuilder.append(firstName);
+ if (hasLastName) {
+ stringBuilder.append(" ");
+ }
+ }
+ if (hasLastName) {
+ stringBuilder.append(lastName);
+ }
+ } else if (hasCompanyName) {
+ stringBuilder.append(company);
+ } else if (hasName) {
+ stringBuilder.append(name);
+ } else {
+ return null;
+ }
+
+ if (stringBuilder.length() > 0) {
+ return stringBuilder.toString();
+ }
+ return null;
+ }
+
+ /** Returns geo location information. e.g. Mountain View, CA. */
+ private static String getGeoDescription(
+ String city, String state, String stateAbbr, String country) {
+ String geoDescription = null;
+
+ if (TextUtils.isEmpty(city) && !TextUtils.isEmpty(state)) {
+ geoDescription = state;
+ } else if (!TextUtils.isEmpty(city) && !TextUtils.isEmpty(stateAbbr)) {
+ geoDescription = city + ", " + stateAbbr;
+ } else if (!TextUtils.isEmpty(country)) {
+ geoDescription = country;
+ }
+ return geoDescription;
+ }
+
+ private static synchronized void registerContentObserver(Context context) {
+ if (!PermissionsUtil.hasCequintPermissions(context)) {
+ LogUtil.i("CequintCallerIdManager.registerContentObserver", "no cequint permissions");
+ return;
+ }
+
+ if (hasRegisteredContentObserver) {
+ return;
+ }
+ ContentObserver contentObserver =
+ new ContentObserver(null) {
+ @Override
+ public void onChange(boolean selfChange) {
+ invalidateCache();
+ }
+ };
+
+ context
+ .getContentResolver()
+ .registerContentObserver(CONTENT_URI_FOR_INCALL, true, contentObserver);
+ hasRegisteredContentObserver = true;
+ }
+
+ private static void invalidateCache() {
+ incallIncomingCallCache.clear();
+ incallOutgoingCallCache.clear();
+ }
+
+ private CequintCallerIdManager() {}
+}
diff --git a/java/com/android/dialer/oem/MotorolaHiddenMenuKeySequence.java b/java/com/android/dialer/oem/MotorolaHiddenMenuKeySequence.java
new file mode 100644
index 000000000..9cf145b7a
--- /dev/null
+++ b/java/com/android/dialer/oem/MotorolaHiddenMenuKeySequence.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * This file is derived in part from code issued under the following license.
+ *
+ * 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.oem;
+
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import com.android.dialer.common.LogUtil;
+import java.util.regex.Pattern;
+
+/**
+ * Util class to handle special char sequence and launch corresponding intent based the sequence.
+ */
+public class MotorolaHiddenMenuKeySequence {
+ private static final String EXTRA_HIDDEN_MENU_CODE = "HiddenMenuCode";
+ private static MotorolaHiddenMenuKeySequence instance = null;
+
+ private static String[] hiddenKeySequenceArray = null;
+ private static String[] hiddenKeySequenceIntentArray = null;
+ private static String[] hiddenKeyPatternArray = null;
+ private static String[] hiddenKeyPatternIntentArray = null;
+ private static boolean featureHiddenMenuEnabled = false;
+
+ /**
+ * Handle input char sequence.
+ *
+ * @param context context
+ * @param input input sequence
+ * @return true if the input matches any pattern
+ */
+ static boolean handleCharSequence(Context context, String input) {
+ getInstance(context);
+ if (!featureHiddenMenuEnabled) {
+ return false;
+ }
+ return handleKeySequence(context, input) || handleKeyPattern(context, input);
+ }
+
+ /**
+ * Public interface to return the Singleton instance
+ *
+ * @param context the Context
+ * @return the MotorolaHiddenMenuKeySequence singleton instance
+ */
+ private static synchronized MotorolaHiddenMenuKeySequence getInstance(Context context) {
+ if (null == instance) {
+ instance = new MotorolaHiddenMenuKeySequence(context);
+ }
+ return instance;
+ }
+
+ private MotorolaHiddenMenuKeySequence(Context context) {
+ featureHiddenMenuEnabled =
+ MotorolaUtils.isSpnMatched(context)
+ && context.getResources().getBoolean(R.bool.motorola_feature_hidden_menu);
+ // In case we do have a SPN from resource we need to match from service; otherwise we are
+ // free to go
+ if (featureHiddenMenuEnabled) {
+
+ hiddenKeySequenceArray =
+ context.getResources().getStringArray(R.array.motorola_hidden_menu_key_sequence);
+ hiddenKeySequenceIntentArray =
+ context.getResources().getStringArray(R.array.motorola_hidden_menu_key_sequence_intents);
+ hiddenKeyPatternArray =
+ context.getResources().getStringArray(R.array.motorola_hidden_menu_key_pattern);
+ hiddenKeyPatternIntentArray =
+ context.getResources().getStringArray(R.array.motorola_hidden_menu_key_pattern_intents);
+
+ if (hiddenKeySequenceArray.length != hiddenKeySequenceIntentArray.length
+ || hiddenKeyPatternArray.length != hiddenKeyPatternIntentArray.length
+ || (hiddenKeySequenceArray.length == 0 && hiddenKeyPatternArray.length == 0)) {
+ LogUtil.e(
+ "MotorolaHiddenMenuKeySequence",
+ "the key sequence array is not matching, turn off feature."
+ + "key sequence: %d != %d, key pattern %d != %d",
+ hiddenKeySequenceArray.length,
+ hiddenKeySequenceIntentArray.length,
+ hiddenKeyPatternArray.length,
+ hiddenKeyPatternIntentArray.length);
+ featureHiddenMenuEnabled = false;
+ }
+ }
+ }
+
+ private static boolean handleKeyPattern(Context context, String input) {
+ int len = input.length();
+ if (len <= 3 || hiddenKeyPatternArray == null || hiddenKeyPatternIntentArray == null) {
+ return false;
+ }
+
+ for (int i = 0; i < hiddenKeyPatternArray.length; i++) {
+ if ((Pattern.compile(hiddenKeyPatternArray[i])).matcher(input).matches()) {
+ return sendIntent(context, input, hiddenKeyPatternIntentArray[i]);
+ }
+ }
+ return false;
+ }
+
+ private static boolean handleKeySequence(Context context, String input) {
+ int len = input.length();
+ if (len <= 3 || hiddenKeySequenceArray == null || hiddenKeySequenceIntentArray == null) {
+ return false;
+ }
+
+ for (int i = 0; i < hiddenKeySequenceArray.length; i++) {
+ if (hiddenKeySequenceArray[i].equals(input)) {
+ return sendIntent(context, input, hiddenKeySequenceIntentArray[i]);
+ }
+ }
+ return false;
+ }
+
+ private static boolean sendIntent(
+ final Context context, final String input, final String action) {
+ LogUtil.d("MotorolaHiddenMenuKeySequence.sendIntent", "input: %s", input);
+ try {
+ Intent intent = new Intent(action);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(EXTRA_HIDDEN_MENU_CODE, input);
+
+ ResolveInfo resolveInfo = context.getPackageManager().resolveActivity(intent, 0);
+
+ if (resolveInfo != null
+ && resolveInfo.activityInfo != null
+ && resolveInfo.activityInfo.enabled) {
+ context.startActivity(intent);
+ return true;
+ } else {
+ LogUtil.w("MotorolaHiddenMenuKeySequence.sendIntent", "not able to resolve the intent");
+ }
+ } catch (ActivityNotFoundException e) {
+ LogUtil.e(
+ "MotorolaHiddenMenuKeySequence.sendIntent", "handleHiddenMenu Key Pattern Exception", e);
+ }
+ return false;
+ }
+}
diff --git a/java/com/android/dialer/oem/MotorolaUtils.java b/java/com/android/dialer/oem/MotorolaUtils.java
new file mode 100644
index 000000000..db2b8909a
--- /dev/null
+++ b/java/com/android/dialer/oem/MotorolaUtils.java
@@ -0,0 +1,118 @@
+/*
+ * 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.oem;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.telephony.TelephonyManager;
+import com.android.dialer.common.ConfigProviderBindings;
+import com.android.dialer.common.PackageUtils;
+
+/** Util class for Motorola OEM devices. */
+public class MotorolaUtils {
+
+ private static final String CONFIG_HD_CODEC_BLINKING_ICON_WHEN_CONNECTING_CALL_ENABLED =
+ "hd_codec_blinking_icon_when_connecting_enabled";
+ private static final String CONFIG_HD_CODEC_SHOW_ICON_IN_NOTIFICATION_ENABLED =
+ "hd_codec_show_icon_in_notification_enabled";
+ private static final String CONFIG_HD_CODEC_SHOW_ICON_IN_CALL_LOG_ENABLED =
+ "hd_codec_show_icon_in_call_log_enabled";
+ private static final String CONFIG_WIFI_CALL_SHOW_ICON_IN_CALL_LOG_ENABLED =
+ "wifi_call_show_icon_in_call_log_enabled";
+
+ // This is used to check if a Motorola device supports HD voice call feature, which comes from
+ // system feature setting.
+ private static final String HD_CALL_FEATRURE = "com.motorola.software.sprint.hd_call";
+ // This is used to check if a Motorola device supports WiFi call feature, by checking if a certain
+ // package is enabled.
+ private static final String WIFI_CALL_PACKAGE_NAME = "com.motorola.sprintwfc";
+
+ // Feature flag indicates it's a HD call, currently this is only used by Motorola system build.
+ // TODO(b/35359461): Use reference to android.provider.CallLog once it's in new SDK.
+ private static final int FEATURES_HD_CALL = 0x4;
+ // Feature flag indicates it's a WiFi call, currently this is only used by Motorola system build.
+ private static final int FEATURES_WIFI = 0x8;
+
+ private static boolean hasCheckedSprintWifiCall;
+ private static boolean supportSprintWifiCall;
+
+ /**
+ * Returns true if SPN is specified and matched the current sim operator name. This is necessary
+ * since mcc310-mnc000 is not sufficient to identify Sprint network.
+ */
+ static boolean isSpnMatched(Context context) {
+ try {
+ String spnResource = context.getResources().getString(R.string.motorola_enabled_spn);
+ return spnResource.equalsIgnoreCase(
+ context.getSystemService(TelephonyManager.class).getSimOperatorName());
+ } catch (Resources.NotFoundException exception) {
+ // If SPN is not specified we consider as not necessary to enable/disable the feature.
+ return true;
+ }
+ }
+
+ public static boolean shouldBlinkHdIconWhenConnectingCall(Context context) {
+ return ConfigProviderBindings.get(context)
+ .getBoolean(CONFIG_HD_CODEC_BLINKING_ICON_WHEN_CONNECTING_CALL_ENABLED, true)
+ && isSupportingSprintHdCodec(context);
+ }
+
+ public static boolean shouldShowHdIconInNotification(Context context) {
+ return ConfigProviderBindings.get(context)
+ .getBoolean(CONFIG_HD_CODEC_SHOW_ICON_IN_NOTIFICATION_ENABLED, true)
+ && isSupportingSprintHdCodec(context);
+ }
+
+ public static boolean shouldShowHdIconInCallLog(Context context, int features) {
+ return ConfigProviderBindings.get(context)
+ .getBoolean(CONFIG_HD_CODEC_SHOW_ICON_IN_CALL_LOG_ENABLED, true)
+ && (features & FEATURES_HD_CALL) == FEATURES_HD_CALL
+ && isSupportingSprintHdCodec(context);
+ }
+
+ public static boolean shouldShowWifiIconInCallLog(Context context, int features) {
+ return ConfigProviderBindings.get(context)
+ .getBoolean(CONFIG_WIFI_CALL_SHOW_ICON_IN_CALL_LOG_ENABLED, true)
+ && (features & FEATURES_WIFI) == FEATURES_WIFI
+ && isSupportingSprintWifiCall(context);
+ }
+
+ /**
+ * Handle special char sequence entered in dialpad. This may launch special intent based on input.
+ *
+ * @param context context
+ * @param input input string
+ * @return true if the input is consumed and the intent is launched
+ */
+ public static boolean handleSpecialCharSequence(Context context, String input) {
+ // TODO(b/35395377): Add check for Motorola devices.
+ return MotorolaHiddenMenuKeySequence.handleCharSequence(context, input);
+ }
+
+ private static boolean isSupportingSprintHdCodec(Context context) {
+ return isSpnMatched(context)
+ && context.getResources().getBoolean(R.bool.motorola_sprint_hd_codec)
+ && context.getPackageManager().hasSystemFeature(HD_CALL_FEATRURE);
+ }
+
+ private static boolean isSupportingSprintWifiCall(Context context) {
+ if (!hasCheckedSprintWifiCall) {
+ supportSprintWifiCall = PackageUtils.isPackageEnabled(WIFI_CALL_PACKAGE_NAME, context);
+ hasCheckedSprintWifiCall = true;
+ }
+ return supportSprintWifiCall;
+ }
+}
diff --git a/java/com/android/dialer/oem/res/values-mcc310-mnc000/motorola_config.xml b/java/com/android/dialer/oem/res/values-mcc310-mnc000/motorola_config.xml
new file mode 100644
index 000000000..7f63bee75
--- /dev/null
+++ b/java/com/android/dialer/oem/res/values-mcc310-mnc000/motorola_config.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <bool name="motorola_sprint_hd_codec">true</bool>
+ <bool name="motorola_feature_hidden_menu">true</bool>
+ <string name="motorola_enabled_spn">Sprint</string>
+</resources> \ No newline at end of file
diff --git a/java/com/android/dialer/oem/res/values-mcc310-mnc120/motorola_config.xml b/java/com/android/dialer/oem/res/values-mcc310-mnc120/motorola_config.xml
new file mode 100644
index 000000000..39b72cdd1
--- /dev/null
+++ b/java/com/android/dialer/oem/res/values-mcc310-mnc120/motorola_config.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <bool name="motorola_sprint_hd_codec">true</bool>
+ <bool name="motorola_feature_hidden_menu">true</bool>
+</resources> \ No newline at end of file
diff --git a/java/com/android/dialer/oem/res/values-mcc311-mnc490/motorola_config.xml b/java/com/android/dialer/oem/res/values-mcc311-mnc490/motorola_config.xml
new file mode 100644
index 000000000..39b72cdd1
--- /dev/null
+++ b/java/com/android/dialer/oem/res/values-mcc311-mnc490/motorola_config.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <bool name="motorola_sprint_hd_codec">true</bool>
+ <bool name="motorola_feature_hidden_menu">true</bool>
+</resources> \ No newline at end of file
diff --git a/java/com/android/dialer/oem/res/values-mcc311-mnc870/motorola_config.xml b/java/com/android/dialer/oem/res/values-mcc311-mnc870/motorola_config.xml
new file mode 100644
index 000000000..39b72cdd1
--- /dev/null
+++ b/java/com/android/dialer/oem/res/values-mcc311-mnc870/motorola_config.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <bool name="motorola_sprint_hd_codec">true</bool>
+ <bool name="motorola_feature_hidden_menu">true</bool>
+</resources> \ No newline at end of file
diff --git a/java/com/android/dialer/oem/res/values-mcc312-mnc530/motorola_config.xml b/java/com/android/dialer/oem/res/values-mcc312-mnc530/motorola_config.xml
new file mode 100644
index 000000000..39b72cdd1
--- /dev/null
+++ b/java/com/android/dialer/oem/res/values-mcc312-mnc530/motorola_config.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <bool name="motorola_sprint_hd_codec">true</bool>
+ <bool name="motorola_feature_hidden_menu">true</bool>
+</resources> \ No newline at end of file
diff --git a/java/com/android/dialer/oem/res/values-mcc316-mnc010/motorola_config.xml b/java/com/android/dialer/oem/res/values-mcc316-mnc010/motorola_config.xml
new file mode 100644
index 000000000..39b72cdd1
--- /dev/null
+++ b/java/com/android/dialer/oem/res/values-mcc316-mnc010/motorola_config.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <bool name="motorola_sprint_hd_codec">true</bool>
+ <bool name="motorola_feature_hidden_menu">true</bool>
+</resources> \ No newline at end of file
diff --git a/java/com/android/dialer/oem/res/values/motorola_config.xml b/java/com/android/dialer/oem/res/values/motorola_config.xml
new file mode 100644
index 000000000..f875d573d
--- /dev/null
+++ b/java/com/android/dialer/oem/res/values/motorola_config.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- Flag to control if HD codec is supported by Sprint. -->
+ <bool name="motorola_sprint_hd_codec">false</bool>
+
+ <!-- Hidden menu configuration for Motorola. -->
+ <!-- Flag to control if the Hidden Menu sequence will be supported by Sprint. -->
+ <bool name="motorola_feature_hidden_menu">false</bool>
+
+ <!-- This defines the specific key seuquence that will be catched in the SpecialCharSequenceMgr
+ such as, ##OMADM# -->
+ <string-array name="motorola_hidden_menu_key_sequence">
+ <item>##66236#</item> <!--##OMADM#-->
+ <item>##2539#</item> <!--##AKEY#-->
+ <item>##786#</item> <!--##RTN#-->
+ <item>##72786#</item> <!--##SCRTN#-->
+ <item>##3282#</item> <!--##DATA#-->
+ <item>##33284#</item> <!--##DEBUG#-->
+ <item>##3424#</item> <!--##DIAG#-->
+ <item>##564#</item> <!--##LOG#-->
+ <item>##4567257#</item> <!--##GLMSCLR#-->
+ <item>##873283#</item> <!--##UPDATE#-->
+ <item>##6343#</item> <!--##MEID#-->
+ <item>##27263#</item> <!--##BRAND#-->
+ <item>##258#</item> <!--##BLV#-->
+ <item>##8422#</item> <!--##UICC#-->
+ <item>##4382#</item> <!--CMAS/WEA-->
+ </string-array>
+
+ <string name="motorola_hidden_menu_intent">com.motorola.intent.action.LAUNCH_HIDDEN_MENU</string>
+
+ <!-- This defines the intents that will be send out when the key quence is matched, this must be
+ in the same order with he KeySequence array. -->
+ <string-array name="motorola_hidden_menu_key_sequence_intents">
+ <item>@string/motorola_hidden_menu_intent</item>
+ <item>@string/motorola_hidden_menu_intent</item>
+ <item>@string/motorola_hidden_menu_intent</item>
+ <item>@string/motorola_hidden_menu_intent</item>
+ <item>@string/motorola_hidden_menu_intent</item>
+ <item>@string/motorola_hidden_menu_intent</item>
+ <item>@string/motorola_hidden_menu_intent</item>
+ <item>@string/motorola_hidden_menu_intent</item>
+ <item>@string/motorola_hidden_menu_intent</item>
+ <item>com.motorola.android.intent.action.omadm.sprint.hfa</item>
+ <item>@string/motorola_hidden_menu_intent</item>
+ <item>@string/motorola_hidden_menu_intent</item>
+ <item>@string/motorola_hidden_menu_intent</item>
+ <item>@string/motorola_hidden_menu_intent</item>
+ <item>@string/motorola_hidden_menu_intent</item>
+ </string-array>
+
+ <!-- This defines the specific key patterns that will be catched in the SpecialCharSequenceMgr
+ such as, ##[0-9]{3,7}# -->
+ <string-array name="motorola_hidden_menu_key_pattern">
+ <!--##MSL#, here MSL is 6 digits SPC code, ##OTKSL#, OTKSL is also digits code -->
+ <item>##[0-9]{6}#</item>
+ </string-array>
+
+ <!-- This defines the intents that will be send out when the key quence is matched, this must be
+ in the same order with he KeyPattern array. -->
+ <string-array name="motorola_hidden_menu_key_pattern_intents">
+ <item>@string/motorola_hidden_menu_intent</item>
+ </string-array>
+</resources> \ No newline at end of file