diff options
Diffstat (limited to 'java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java')
-rw-r--r-- | java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java | 444 |
1 files changed, 444 insertions, 0 deletions
diff --git a/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java b/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java new file mode 100644 index 000000000..0296d208d --- /dev/null +++ b/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java @@ -0,0 +1,444 @@ +/* + * Copyright (C) 2015 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.voicemail.impl; + +import android.app.PendingIntent; +import android.content.Context; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Bundle; +import android.os.PersistableBundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; +import android.telecom.PhoneAccountHandle; +import android.telephony.CarrierConfigManager; +import android.telephony.TelephonyManager; +import android.telephony.VisualVoicemailService; +import android.telephony.VisualVoicemailSmsFilterSettings; +import android.text.TextUtils; +import android.util.ArraySet; +import com.android.dialer.common.Assert; +import com.android.voicemail.impl.protocol.VisualVoicemailProtocol; +import com.android.voicemail.impl.protocol.VisualVoicemailProtocolFactory; +import com.android.voicemail.impl.sms.StatusMessage; +import com.android.voicemail.impl.sync.VvmAccountManager; +import java.util.Collections; +import java.util.Set; + +/** + * Manages carrier dependent visual voicemail configuration values. The primary source is the value + * retrieved from CarrierConfigManager. If CarrierConfigManager does not provide the config + * (KEY_VVM_TYPE_STRING is empty, or "hidden" configs), then the value hardcoded in telephony will + * be used (in res/xml/vvm_config.xml) + * + * <p>Hidden configs are new configs that are planned for future APIs, or miscellaneous settings + * that may clutter CarrierConfigManager too much. + * + * <p>The current hidden configs are: {@link #getSslPort()} {@link #getDisabledCapabilities()} + */ +public class OmtpVvmCarrierConfigHelper { + + private static final String TAG = "OmtpVvmCarrierCfgHlpr"; + + static final String KEY_VVM_TYPE_STRING = CarrierConfigManager.KEY_VVM_TYPE_STRING; + static final String KEY_VVM_DESTINATION_NUMBER_STRING = + CarrierConfigManager.KEY_VVM_DESTINATION_NUMBER_STRING; + static final String KEY_VVM_PORT_NUMBER_INT = CarrierConfigManager.KEY_VVM_PORT_NUMBER_INT; + static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = + CarrierConfigManager.KEY_CARRIER_VVM_PACKAGE_NAME_STRING; + static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY = + "carrier_vvm_package_name_string_array"; + static final String KEY_VVM_PREFETCH_BOOL = CarrierConfigManager.KEY_VVM_PREFETCH_BOOL; + static final String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL = + CarrierConfigManager.KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL; + + /** @see #getSslPort() */ + static final String KEY_VVM_SSL_PORT_NUMBER_INT = "vvm_ssl_port_number_int"; + + /** @see #isLegacyModeEnabled() */ + static final String KEY_VVM_LEGACY_MODE_ENABLED_BOOL = "vvm_legacy_mode_enabled_bool"; + + /** + * Ban a capability reported by the server from being used. The array of string should be a subset + * of the capabilities returned IMAP CAPABILITY command. + * + * @see #getDisabledCapabilities() + */ + static final String KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY = + "vvm_disabled_capabilities_string_array"; + + static final String KEY_VVM_CLIENT_PREFIX_STRING = "vvm_client_prefix_string"; + + private final Context mContext; + private final PersistableBundle mCarrierConfig; + private final String mVvmType; + private final VisualVoicemailProtocol mProtocol; + private final PersistableBundle mTelephonyConfig; + + private PhoneAccountHandle mPhoneAccountHandle; + + public OmtpVvmCarrierConfigHelper(Context context, PhoneAccountHandle handle) { + mContext = context; + mPhoneAccountHandle = handle; + TelephonyManager telephonyManager = + context + .getSystemService(TelephonyManager.class) + .createForPhoneAccountHandle(mPhoneAccountHandle); + if (telephonyManager == null) { + VvmLog.e(TAG, "PhoneAccountHandle is invalid"); + mCarrierConfig = null; + mTelephonyConfig = null; + mVvmType = null; + mProtocol = null; + return; + } + + mCarrierConfig = getCarrierConfig(telephonyManager); + mTelephonyConfig = + new TelephonyVvmConfigManager(context.getResources()) + .getConfig(telephonyManager.getSimOperator()); + + mVvmType = getVvmType(); + mProtocol = VisualVoicemailProtocolFactory.create(mContext.getResources(), mVvmType); + } + + @VisibleForTesting + OmtpVvmCarrierConfigHelper( + Context context, PersistableBundle carrierConfig, PersistableBundle telephonyConfig) { + mContext = context; + mCarrierConfig = carrierConfig; + mTelephonyConfig = telephonyConfig; + mVvmType = getVvmType(); + mProtocol = VisualVoicemailProtocolFactory.create(mContext.getResources(), mVvmType); + } + + public Context getContext() { + return mContext; + } + + @Nullable + public PhoneAccountHandle getPhoneAccountHandle() { + return mPhoneAccountHandle; + } + + /** + * return whether the carrier's visual voicemail is supported, with KEY_VVM_TYPE_STRING set as a + * known protocol. + */ + public boolean isValid() { + return mProtocol != null; + } + + @Nullable + public String getVvmType() { + return (String) getValue(KEY_VVM_TYPE_STRING); + } + + @Nullable + public VisualVoicemailProtocol getProtocol() { + return mProtocol; + } + + /** @returns arbitrary String stored in the config file. Used for protocol specific values. */ + @Nullable + public String getString(String key) { + Assert.checkArgument(isValid()); + return (String) getValue(key); + } + + @Nullable + public Set<String> getCarrierVvmPackageNames() { + Assert.checkArgument(isValid()); + Set<String> names = getCarrierVvmPackageNames(mCarrierConfig); + if (names != null) { + return names; + } + return getCarrierVvmPackageNames(mTelephonyConfig); + } + + private static Set<String> getCarrierVvmPackageNames(@Nullable PersistableBundle bundle) { + if (bundle == null) { + return null; + } + Set<String> names = new ArraySet<>(); + if (bundle.containsKey(KEY_CARRIER_VVM_PACKAGE_NAME_STRING)) { + names.add(bundle.getString(KEY_CARRIER_VVM_PACKAGE_NAME_STRING)); + } + if (bundle.containsKey(KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY)) { + String[] vvmPackages = bundle.getStringArray(KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY); + if (vvmPackages != null && vvmPackages.length > 0) { + Collections.addAll(names, vvmPackages); + } + } + if (names.isEmpty()) { + return null; + } + return names; + } + + /** + * For checking upon sim insertion whether visual voicemail should be enabled. This method does so + * by checking if the carrier's voicemail app is installed. + */ + public boolean isEnabledByDefault() { + if (!isValid()) { + return false; + } + + Set<String> carrierPackages = getCarrierVvmPackageNames(); + if (carrierPackages == null) { + return true; + } + for (String packageName : carrierPackages) { + try { + mContext.getPackageManager().getPackageInfo(packageName, 0); + return false; + } catch (NameNotFoundException e) { + // Do nothing. + } + } + return true; + } + + public boolean isCellularDataRequired() { + Assert.checkArgument(isValid()); + return (boolean) getValue(KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL, false); + } + + public boolean isPrefetchEnabled() { + Assert.checkArgument(isValid()); + return (boolean) getValue(KEY_VVM_PREFETCH_BOOL, true); + } + + public int getApplicationPort() { + Assert.checkArgument(isValid()); + return (int) getValue(KEY_VVM_PORT_NUMBER_INT, 0); + } + + @Nullable + public String getDestinationNumber() { + Assert.checkArgument(isValid()); + return (String) getValue(KEY_VVM_DESTINATION_NUMBER_STRING); + } + + /** + * @return Port to start a SSL IMAP connection directly. + */ + public int getSslPort() { + Assert.checkArgument(isValid()); + return (int) getValue(KEY_VVM_SSL_PORT_NUMBER_INT, 0); + } + + /** + * Hidden Config. + * + * <p>Sometimes the server states it supports a certain feature but we found they have bug on the + * server side. For example, in b/28717550 the server reported AUTH=DIGEST-MD5 capability but + * using it to login will cause subsequent response to be erroneous. + * + * @return A set of capabilities that is reported by the IMAP CAPABILITY command, but determined + * to have issues and should not be used. + */ + @Nullable + public Set<String> getDisabledCapabilities() { + Assert.checkArgument(isValid()); + Set<String> disabledCapabilities = getDisabledCapabilities(mCarrierConfig); + if (disabledCapabilities != null) { + return disabledCapabilities; + } + return getDisabledCapabilities(mTelephonyConfig); + } + + @Nullable + private static Set<String> getDisabledCapabilities(@Nullable PersistableBundle bundle) { + if (bundle == null) { + return null; + } + if (!bundle.containsKey(KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY)) { + return null; + } + String[] disabledCapabilities = + bundle.getStringArray(KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY); + if (disabledCapabilities != null && disabledCapabilities.length > 0) { + ArraySet<String> result = new ArraySet<>(); + Collections.addAll(result, disabledCapabilities); + return result; + } + return null; + } + + public String getClientPrefix() { + Assert.checkArgument(isValid()); + String prefix = (String) getValue(KEY_VVM_CLIENT_PREFIX_STRING); + if (prefix != null) { + return prefix; + } + return "//VVM"; + } + + /** + * Should legacy mode be used when the OMTP VVM client is disabled? + * + * <p>Legacy mode is a mode that on the carrier side visual voicemail is still activated, but on + * the client side all network operations are disabled. SMSs are still monitored so a new message + * SYNC SMS will be translated to show a message waiting indicator, like traditional voicemails. + * + * <p>This is for carriers that does not support VVM deactivation so voicemail can continue to + * function without the data cost. + */ + public boolean isLegacyModeEnabled() { + Assert.checkArgument(isValid()); + return (boolean) getValue(KEY_VVM_LEGACY_MODE_ENABLED_BOOL, false); + } + + public void startActivation() { + Assert.checkArgument(isValid()); + PhoneAccountHandle phoneAccountHandle = getPhoneAccountHandle(); + if (phoneAccountHandle == null) { + // This should never happen + // Error logged in getPhoneAccountHandle(). + return; + } + + if (mVvmType == null || mVvmType.isEmpty()) { + // The VVM type is invalid; we should never have gotten here in the first place since + // this is loaded initially in the constructor, and callers should check isValid() + // before trying to start activation anyways. + VvmLog.e(TAG, "startActivation : vvmType is null or empty for account " + phoneAccountHandle); + return; + } + + if (mProtocol != null) { + ActivationTask.start(mContext, mPhoneAccountHandle, null); + } + } + + public void activateSmsFilter() { + Assert.checkArgument(isValid()); + VisualVoicemailService.setSmsFilterSettings( + mContext, + getPhoneAccountHandle(), + new VisualVoicemailSmsFilterSettings.Builder().setClientPrefix(getClientPrefix()).build()); + } + + public void startDeactivation() { + Assert.checkArgument(isValid()); + if (!isLegacyModeEnabled()) { + // SMS should still be filtered in legacy mode + VisualVoicemailService.setSmsFilterSettings(mContext, getPhoneAccountHandle(), null); + } + if (mProtocol != null) { + mProtocol.startDeactivation(this); + } + VvmAccountManager.removeAccount(mContext, getPhoneAccountHandle()); + } + + public boolean supportsProvisioning() { + Assert.checkArgument(isValid()); + return mProtocol.supportsProvisioning(); + } + + public void startProvisioning( + ActivationTask task, + PhoneAccountHandle phone, + VoicemailStatus.Editor status, + StatusMessage message, + Bundle data) { + Assert.checkArgument(isValid()); + mProtocol.startProvisioning(task, phone, this, status, message, data); + } + + public void requestStatus(@Nullable PendingIntent sentIntent) { + Assert.checkArgument(isValid()); + mProtocol.requestStatus(this, sentIntent); + } + + public void handleEvent(VoicemailStatus.Editor status, OmtpEvents event) { + Assert.checkArgument(isValid()); + VvmLog.i(TAG, "OmtpEvent:" + event); + mProtocol.handleEvent(mContext, this, status, event); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder("OmtpVvmCarrierConfigHelper ["); + builder + .append("phoneAccountHandle: ") + .append(mPhoneAccountHandle) + .append(", carrierConfig: ") + .append(mCarrierConfig != null) + .append(", telephonyConfig: ") + .append(mTelephonyConfig != null) + .append(", type: ") + .append(getVvmType()) + .append(", destinationNumber: ") + .append(getDestinationNumber()) + .append(", applicationPort: ") + .append(getApplicationPort()) + .append(", sslPort: ") + .append(getSslPort()) + .append(", isEnabledByDefault: ") + .append(isEnabledByDefault()) + .append(", isCellularDataRequired: ") + .append(isCellularDataRequired()) + .append(", isPrefetchEnabled: ") + .append(isPrefetchEnabled()) + .append(", isLegacyModeEnabled: ") + .append(isLegacyModeEnabled()) + .append("]"); + return builder.toString(); + } + + @Nullable + private PersistableBundle getCarrierConfig(@NonNull TelephonyManager telephonyManager) { + CarrierConfigManager carrierConfigManager = + (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); + if (carrierConfigManager == null) { + VvmLog.w(TAG, "No carrier config service found."); + return null; + } + + PersistableBundle config = telephonyManager.getCarrierConfig(); + + if (TextUtils.isEmpty(config.getString(CarrierConfigManager.KEY_VVM_TYPE_STRING))) { + return null; + } + return config; + } + + @Nullable + private Object getValue(String key) { + return getValue(key, null); + } + + @Nullable + private Object getValue(String key, Object defaultValue) { + Object result; + if (mCarrierConfig != null) { + result = mCarrierConfig.get(key); + if (result != null) { + return result; + } + } + if (mTelephonyConfig != null) { + result = mTelephonyConfig.get(key); + if (result != null) { + return result; + } + } + return defaultValue; + } +} |