Merge "Set "has no children" capability on IMS conferences." into mnc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 1ba8ee0..c01cdb4 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -536,7 +536,7 @@
android:theme="@android:style/Theme.NoDisplay"
android:excludeFromRecents="true">
<intent-filter>
- <action android:name="android.telecom.action.CONNECTION_SERVICE_CONFIGURE" />
+ <action android:name="android.telecom.action.CONFIGURE_PHONE_ACCOUNT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 91f4806..075680c 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -370,7 +370,7 @@
<string name="fdn_failed" msgid="540018079008319747">"פעולת FDN נכשלה."</string>
<string name="simContacts_emptyLoading" msgid="2203331234764498011">"קורא מכרטיס SIM…"</string>
<string name="simContacts_empty" msgid="5270660846489561932">"אין אנשי קשר בכרטיס ה-SIM."</string>
- <string name="simContacts_title" msgid="1861472842524839921">"בחר אנשי קשר ליבוא"</string>
+ <string name="simContacts_title" msgid="1861472842524839921">"בחר אנשי קשר לייבוא"</string>
<string name="simContacts_airplaneMode" msgid="5254946758982621072">"בטל את מצב טיסה כדי לייבא אנשי קשר מכרטיס ה-SIM."</string>
<string name="enable_pin" msgid="5422767284133234860">"הפוך לפעיל/השבת PIN של SIM"</string>
<string name="change_pin" msgid="9174186126330785343">"שנה PIN של SIM"</string>
diff --git a/src/com/android/phone/CallFeaturesSetting.java b/src/com/android/phone/CallFeaturesSetting.java
index 11f81ff..00c9170 100644
--- a/src/com/android/phone/CallFeaturesSetting.java
+++ b/src/com/android/phone/CallFeaturesSetting.java
@@ -52,6 +52,7 @@
import com.android.internal.telephony.PhoneConstants;
import com.android.phone.common.util.SettingsUtil;
import com.android.phone.settings.AccountSelectionPreference;
+import com.android.phone.settings.PhoneAccountSettingsFragment;
import com.android.phone.settings.VoicemailSettingsActivity;
import com.android.phone.settings.fdn.FdnSetting;
import com.android.services.telephony.sip.SipUtil;
@@ -274,8 +275,8 @@
}
if (ImsManager.isVolteEnabledByPlatform(this) &&
- !mPhone.getContext().getResources().getBoolean(
- com.android.internal.R.bool.config_carrier_volte_tty_supported)) {
+ !carrierConfig.getBoolean(
+ CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL)) {
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
/* tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); */
}
@@ -284,20 +285,10 @@
getResources().getString(R.string.wifi_calling_settings_key));
final PhoneAccountHandle simCallManager = mTelecomManager.getSimCallManager();
- String simCallManagerPackage = simCallManager != null
- && simCallManager.getComponentName() != null
- ? simCallManager.getComponentName().getPackageName()
- : null;
-
- if (!TextUtils.isEmpty(simCallManagerPackage)) {
- final Intent intent = new Intent(TelecomManager.ACTION_CONNECTION_SERVICE_CONFIGURE)
- .addCategory(Intent.CATEGORY_DEFAULT)
- .setPackage(simCallManagerPackage);
-
- // Check whether the configuration intent is supported.
- PackageManager pm = getPackageManager();
- List<ResolveInfo> resolutions = pm.queryIntentActivities(intent, 0);
- if (resolutions.size() > 0) {
+ if (simCallManager != null) {
+ Intent intent = PhoneAccountSettingsFragment.buildPhoneAccountConfigureIntent(
+ this, simCallManager);
+ if (intent != null) {
wifiCallingSettings.setTitle(R.string.wifi_calling);
wifiCallingSettings.setSummary(null);
wifiCallingSettings.setIntent(intent);
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index 303a384..780f76b 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -200,10 +200,13 @@
mDialButton = findViewById(R.id.floating_action_button);
- CarrierConfigLoader configLoader = CarrierConfigLoader.init(this);
// Check whether we should show the onscreen "Dial" button and co.
+ // Read carrier config through the public API because PhoneGlobals is not available when we
+ // run as a secondary user.
+ CarrierConfigManager configMgr =
+ (CarrierConfigManager) getSystemService(Context.CARRIER_CONFIG_SERVICE);
PersistableBundle carrierConfig =
- configLoader.getConfigForSubId(SubscriptionManager.getDefaultVoiceSubId());
+ configMgr.getConfigForSubId(SubscriptionManager.getDefaultVoiceSubId());
if (carrierConfig.getBoolean(CarrierConfigManager.KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL)) {
mDialButton.setOnClickListener(this);
} else {
diff --git a/src/com/android/phone/MobileNetworkSettings.java b/src/com/android/phone/MobileNetworkSettings.java
index 96d00ae..bcb627e 100644
--- a/src/com/android/phone/MobileNetworkSettings.java
+++ b/src/com/android/phone/MobileNetworkSettings.java
@@ -470,6 +470,12 @@
}
@Override
+ protected void onDestroy() {
+ super.onDestroy();
+ unregisterReceiver(mPhoneChangeReceiver);
+ }
+
+ @Override
protected void onResume() {
super.onResume();
if (DBG) log("onResume:+");
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index e8b6e05..0e82b99 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -2393,7 +2393,8 @@
@Override
public String getLine1NumberForDisplay(int subId, String callingPackage) {
- if (!canReadPhoneState(callingPackage, "getLine1NumberForDisplay")) {
+ // This is open to apps with WRITE_SMS.
+ if (!canReadPhoneNumber(callingPackage, "getLine1NumberForDisplay")) {
return null;
}
@@ -2651,8 +2652,16 @@
}
private boolean canReadPhoneState(String callingPackage, String message) {
- mApp.enforceCallingOrSelfPermission(
- android.Manifest.permission.READ_PHONE_STATE, message);
+ try {
+ mApp.enforceCallingOrSelfPermission(
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, message);
+
+ // SKIP checking for run-time permission since self or obtained PRIVILEDGED
+ return true;
+ } catch (SecurityException e) {
+ mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE,
+ message);
+ }
if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
callingPackage) != AppOpsManager.MODE_ALLOWED) {
@@ -2662,6 +2671,16 @@
return true;
}
+ /**
+ * Besides READ_PHONE_STATE, WRITE_SMS also allows apps to get phone numbers.
+ */
+ private boolean canReadPhoneNumber(String callingPackage, String message) {
+ // Note canReadPhoneState() may throw, so we need to do the appops check first.
+ return (mAppOps.noteOp(AppOpsManager.OP_WRITE_SMS,
+ Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED)
+ || canReadPhoneState(callingPackage, message);
+ }
+
@Override
public void factoryReset(int subId) {
enforceConnectivityInternalPermission();
@@ -2719,21 +2738,36 @@
// Try and fetch the locale from the carrier properties or from the SIM language
// preferences (EF-PL and EF-LI)...
+ final int mcc = info.getMcc();
+ final Locale mccLocale = MccTable.getLocaleFromMcc(mPhone.getContext(), mcc);
final Phone defaultPhone = getPhone(info.getSubscriptionId());
if (defaultPhone != null) {
final Locale localeFromDefaultSim = defaultPhone.getLocaleFromSimAndCarrierPrefs();
if (localeFromDefaultSim != null) {
- return localeFromDefaultSim.toLanguageTag();
+ // The SIM language preferences only store a language (e.g. fr = French), not an
+ // exact locale (e.g. fr_FR = French/France). So, if the locale returned from
+ // the SIM and carrier preferences does not include a country we add the country
+ // determined from the SIM MCC to provide an exact locale.
+ // Note this can result in unusual locale combinatons (e.g. en_DE) being returned.
+ if ((localeFromDefaultSim.getCountry().isEmpty()) && (mccLocale != null)) {
+ final Locale combinedLocale = new Locale (localeFromDefaultSim.getLanguage(),
+ mccLocale.getCountry());
+ if (DBG) log("Using SIM language and mcc country:" + combinedLocale);
+ return combinedLocale.toLanguageTag();
+ } else {
+ if (DBG) log("Using locale from default SIM:" + localeFromDefaultSim);
+ return localeFromDefaultSim.toLanguageTag();
+ }
}
}
// .. if that doesn't work, try and guess the language from the sim MCC.
- final int mcc = info.getMcc();
- final Locale locale = MccTable.getLocaleFromMcc(mPhone.getContext(), mcc);
- if (locale != null) {
- return locale.toLanguageTag();
+ if (mccLocale != null) {
+ if (DBG) log("No locale from default SIM, using mcc locale:" + mccLocale);
+ return mccLocale.toLanguageTag();
}
+ if (DBG) log("No locale found - returning null");
return null;
}
diff --git a/src/com/android/phone/settings/AccessibilitySettingsFragment.java b/src/com/android/phone/settings/AccessibilitySettingsFragment.java
index fdb0cd5..d5a613b 100644
--- a/src/com/android/phone/settings/AccessibilitySettingsFragment.java
+++ b/src/com/android/phone/settings/AccessibilitySettingsFragment.java
@@ -25,6 +25,7 @@
import android.preference.PreferenceScreen;
import android.provider.Settings;
import android.telecom.TelecomManager;
+import android.telephony.CarrierConfigManager;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
@@ -98,9 +99,7 @@
public void onResume() {
super.onResume();
- if (ImsManager.isVolteEnabledByPlatform(mContext) &&
- !mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_carrier_volte_tty_supported)) {
+ if (ImsManager.isVolteEnabledByPlatform(mContext) && !getVolteTtySupported()) {
TelephonyManager tm =
(TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
@@ -111,9 +110,7 @@
public void onPause() {
super.onPause();
- if (ImsManager.isVolteEnabledByPlatform(mContext) &&
- !mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_carrier_volte_tty_supported)) {
+ if (ImsManager.isVolteEnabledByPlatform(mContext) && !getVolteTtySupported()) {
TelephonyManager tm =
(TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
@@ -138,4 +135,11 @@
}
return false;
}
+
+ private boolean getVolteTtySupported() {
+ CarrierConfigManager configManager =
+ (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ return configManager.getConfig().getBoolean(
+ CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL);
+ }
}
diff --git a/src/com/android/phone/settings/PhoneAccountSettingsFragment.java b/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
index dd9c050..c08b32a 100644
--- a/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
+++ b/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
@@ -18,6 +18,8 @@
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
import com.android.internal.telephony.Phone;
import com.android.phone.PhoneUtils;
@@ -48,6 +50,9 @@
private static final String USE_SIP_PREF_KEY = "use_sip_calling_options_key";
private static final String SIP_RECEIVE_CALLS_PREF_KEY = "sip_receive_calls_key";
+ private static final String LEGACY_ACTION_CONFIGURE_PHONE_ACCOUNT =
+ "android.telecom.action.CONNECTION_SERVICE_CONFIGURE";
+
/**
* Value to start ordering of phone accounts relative to other preferences. By setting this
* value on the phone account listings, we ensure that anything that is ordered before
@@ -56,7 +61,7 @@
*/
private static final int ACCOUNT_ORDERING_START_VALUE = 100;
- private String LOG_TAG = PhoneAccountSettingsFragment.class.getSimpleName();
+ private static final String LOG_TAG = PhoneAccountSettingsFragment.class.getSimpleName();
private TelecomManager mTelecomManager;
private TelephonyManager mTelephonyManager;
@@ -346,18 +351,7 @@
}
}
} else {
- // Build the settings intent.
- intent = new Intent(TelecomManager.ACTION_CONNECTION_SERVICE_CONFIGURE);
- intent.setPackage(handle.getComponentName().getPackageName());
- intent.addCategory(Intent.CATEGORY_DEFAULT);
- intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, handle);
-
- // Check to see that the phone account package can handle the setting intent.
- PackageManager pm = getActivity().getPackageManager();
- List<ResolveInfo> resolutions = pm.queryIntentActivities(intent, 0);
- if (resolutions.size() == 0) {
- intent = null; // set no intent if the package cannot handle it.
- }
+ intent = buildPhoneAccountConfigureIntent(getActivity(), handle);
}
// Create the preference & add the label
@@ -417,4 +411,43 @@
return PhoneUtils.makePstnPhoneAccountHandleWithPrefix(
(Phone) null, "" /* prefix */, true /* isEmergency */);
}
+
+ public static Intent buildPhoneAccountConfigureIntent(
+ Context context, PhoneAccountHandle accountHandle) {
+ Intent intent = buildConfigureIntent(
+ context, accountHandle, TelecomManager.ACTION_CONFIGURE_PHONE_ACCOUNT);
+
+ if (intent == null) {
+ // If the new configuration didn't work, try the old configuration intent.
+ intent = buildConfigureIntent(
+ context, accountHandle, LEGACY_ACTION_CONFIGURE_PHONE_ACCOUNT);
+ if (intent != null) {
+ Log.w(LOG_TAG, "Phone account using old configuration intent: " + accountHandle);
+ }
+ }
+ return intent;
+ }
+
+ private static Intent buildConfigureIntent(
+ Context context, PhoneAccountHandle accountHandle, String actionStr) {
+ if (accountHandle == null || accountHandle.getComponentName() == null ||
+ TextUtils.isEmpty(accountHandle.getComponentName().getPackageName())) {
+ return null;
+ }
+
+ // Build the settings intent.
+ Intent intent = new Intent(actionStr);
+ intent.setPackage(accountHandle.getComponentName().getPackageName());
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle);
+
+ // Check to see that the phone account package can handle the setting intent.
+ PackageManager pm = context.getPackageManager();
+ List<ResolveInfo> resolutions = pm.queryIntentActivities(intent, 0);
+ if (resolutions.size() == 0) {
+ intent = null; // set no intent if the package cannot handle it.
+ }
+
+ return intent;
+ }
}
diff --git a/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java b/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java
index d2e797b..45ad1cb 100644
--- a/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java
+++ b/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java
@@ -40,6 +40,12 @@
// however, the user can override this setting.
private static final String IS_USER_SET = "is_user_set";
+ // Setting for how often retries should be done.
+ private static final String SYNC_RETRY_INTERVAL = "sync_retry_interval";
+ private static final long MAX_SYNC_RETRY_INTERVAL_MS = 86400000; // 24 hours
+ private static final long DEFAULT_SYNC_RETRY_INTERVAL_MS = 900000; // 15 minutes
+
+
public static void setVisualVoicemailEnabled(Phone phone, boolean isEnabled,
boolean isUserSet) {
setVisualVoicemailEnabled(phone.getContext(), PhoneUtils.makePstnPhoneAccountHandle(phone),
@@ -73,12 +79,6 @@
PhoneUtils.makePstnPhoneAccountHandle(phone));
}
- public static boolean isEnabledByUserOverride(Context context,
- PhoneAccountHandle phoneAccount) {
- return isVisualVoicemailUserSet(context, phoneAccount) &&
- isVisualVoicemailEnabled(context, phoneAccount);
- }
-
/**
* Differentiate user-enabled/disabled to know whether to ignore automatic enabling and
* disabling by the system. This is relevant when a carrier vvm app is installed and the user
@@ -121,6 +121,27 @@
return prefs.getString(getVisualVoicemailSharedPrefsKey(key, phoneAccount), null);
}
+ public static long getVisualVoicemailRetryInterval(Context context,
+ PhoneAccountHandle phoneAccount) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ return prefs.getLong(getVisualVoicemailSharedPrefsKey(SYNC_RETRY_INTERVAL, phoneAccount),
+ DEFAULT_SYNC_RETRY_INTERVAL_MS);
+ }
+
+ public static void resetVisualVoicemailRetryInterval(Context context,
+ PhoneAccountHandle phoneAccount) {
+ setVisualVoicemailRetryInterval(context, phoneAccount, DEFAULT_SYNC_RETRY_INTERVAL_MS);
+ }
+
+ public static void setVisualVoicemailRetryInterval(Context context,
+ PhoneAccountHandle phoneAccount, long interval) {
+ SharedPreferences.Editor editor =
+ PreferenceManager.getDefaultSharedPreferences(context).edit();
+ editor.putLong(getVisualVoicemailSharedPrefsKey(SYNC_RETRY_INTERVAL, phoneAccount),
+ Math.min(interval, MAX_SYNC_RETRY_INTERVAL_MS));
+ editor.commit();
+ }
+
private static String getVisualVoicemailSharedPrefsKey(String key,
PhoneAccountHandle phoneAccount) {
return VISUAL_VOICEMAIL_SHARED_PREFS_KEY_PREFIX + key + "_" + phoneAccount.getId();
diff --git a/src/com/android/phone/vvm/omtp/SimChangeReceiver.java b/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
index 0823552..5ffc9ea 100644
--- a/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
+++ b/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
@@ -21,7 +21,6 @@
import android.telecom.PhoneAccountHandle;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
import android.util.Log;
import com.android.internal.telephony.IccCardConstants;
@@ -68,20 +67,30 @@
PhoneAccountHandle phoneAccount = PhoneUtils.makePstnPhoneAccountHandle(
SubscriptionManager.getPhoneId(subId));
- if (carrierConfigHelper.isEnabledByDefault()) {
- VisualVoicemailSettingsUtil.setVisualVoicemailEnabled(
- context, phoneAccount, true, false);
+ boolean isUserSet = VisualVoicemailSettingsUtil.isVisualVoicemailUserSet(
+ context, phoneAccount);
+ boolean isEnabledInSettings =
+ VisualVoicemailSettingsUtil.isVisualVoicemailEnabled(context,
+ phoneAccount);
+ boolean isEnabled = isUserSet ? isEnabledInSettings :
+ carrierConfigHelper.isEnabledByDefault();
+
+ if (!isUserSet) {
+ // Preserve the previous setting for "isVisualVoicemailEnabled" if it is
+ // set by the user, otherwise, set this value for the first time.
+ VisualVoicemailSettingsUtil.setVisualVoicemailEnabled(context, phoneAccount,
+ isEnabled, /** isUserSet */ false);
}
- if (carrierConfigHelper.isEnabledByDefault() ||
- VisualVoicemailSettingsUtil.isEnabledByUserOverride(
- context, phoneAccount)) {
+ if (isEnabled) {
+ // Add a phone state listener so that changes to the communication channels
+ // can be recorded.
+ OmtpVvmSourceManager.getInstance(context).addPhoneStateListener(
+ phoneAccount);
carrierConfigHelper.startActivation();
} else {
// It may be that the source was not registered to begin with but we want
// to run through the steps to remove the source just in case.
- VisualVoicemailSettingsUtil.setVisualVoicemailEnabled(
- context, phoneAccount, false, false);
OmtpVvmSourceManager.getInstance(context).removeSource(phoneAccount);
carrierConfigHelper.startDeactivation();
}
diff --git a/src/com/android/phone/vvm/omtp/VvmPackageInstallReceiver.java b/src/com/android/phone/vvm/omtp/VvmPackageInstallReceiver.java
index 5559feb..0c4eb62 100644
--- a/src/com/android/phone/vvm/omtp/VvmPackageInstallReceiver.java
+++ b/src/com/android/phone/vvm/omtp/VvmPackageInstallReceiver.java
@@ -45,8 +45,8 @@
OmtpVvmSourceManager vvmSourceManager = OmtpVvmSourceManager.getInstance(context);
Set<PhoneAccountHandle> phoneAccounts = vvmSourceManager.getOmtpVvmSources();
for (PhoneAccountHandle phoneAccount : phoneAccounts) {
- if (VisualVoicemailSettingsUtil.isEnabledByUserOverride(context, phoneAccount)) {
- // Skip the check if this voicemail source is enabled by the user.
+ if (VisualVoicemailSettingsUtil.isVisualVoicemailUserSet(context, phoneAccount)) {
+ // Skip the check if this voicemail source's setting is overridden by the user.
continue;
}
diff --git a/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java b/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
index de2ccf5..43724e4 100644
--- a/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
+++ b/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
@@ -53,6 +53,9 @@
// Timeout used to call ConnectivityManager.requestNetwork
private static final int NETWORK_REQUEST_TIMEOUT_MILLIS = 60 * 1000;
+ // Number of retries
+ private static final int NETWORK_RETRY_COUNT = 3;
+
private ContentResolver mContentResolver;
private Uri mUri;
private NetworkRequest mNetworkRequest;
@@ -61,6 +64,7 @@
private String mUid;
private ConnectivityManager mConnectivityManager;
private PhoneAccountHandle mPhoneAccount;
+ private int mRetryCount = NETWORK_RETRY_COUNT;
@Override
public void onReceive(final Context context, Intent intent) {
@@ -107,15 +111,14 @@
}
int subId = PhoneUtils.getSubIdForPhoneAccountHandle(mPhoneAccount);
-
mNetworkRequest = new NetworkRequest.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
- .setNetworkSpecifier(Integer.toString(subId))
- .build();
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .setNetworkSpecifier(Integer.toString(subId))
+ .build();
+
mNetworkCallback = new OmtpVvmNetworkRequestCallback();
- getConnectivityManager().requestNetwork(
- mNetworkRequest, mNetworkCallback, NETWORK_REQUEST_TIMEOUT_MILLIS);
+ requestNetwork();
}
} finally {
cursor.close();
@@ -130,9 +133,23 @@
executor.execute(new Runnable() {
@Override
public void run() {
- new ImapHelper(mContext, mPhoneAccount, network).fetchVoicemailPayload(
- new VoicemailFetchedCallback(mContext, mUri), mUid);
- releaseNetwork();
+ while (mRetryCount > 0) {
+ ImapHelper imapHelper = new ImapHelper(mContext, mPhoneAccount, network);
+ if (!imapHelper.isSuccessfullyInitialized()) {
+ Log.w(TAG, "Can't retrieve Imap credentials.");
+ releaseNetwork();
+ return;
+ }
+
+ boolean success = imapHelper.fetchVoicemailPayload(
+ new VoicemailFetchedCallback(mContext, mUri), mUid);
+ if (!success && mRetryCount > 0) {
+ mRetryCount--;
+ } else {
+ releaseNetwork();
+ return;
+ }
+ }
}
});
}
@@ -140,14 +157,29 @@
@Override
public void onLost(Network network) {
releaseNetwork();
+
+ if (mRetryCount > 0) {
+ mRetryCount--;
+ requestNetwork();
+ }
}
@Override
public void onUnavailable() {
releaseNetwork();
+
+ if (mRetryCount > 0) {
+ mRetryCount--;
+ requestNetwork();
+ }
}
}
+ private void requestNetwork() {
+ getConnectivityManager().requestNetwork(
+ mNetworkRequest, mNetworkCallback, NETWORK_REQUEST_TIMEOUT_MILLIS);
+ }
+
private void releaseNetwork() {
getConnectivityManager().unregisterNetworkCallback(mNetworkCallback);
}
diff --git a/src/com/android/phone/vvm/omtp/imap/ImapHelper.java b/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
index e23dd41..1d20dbd 100644
--- a/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
+++ b/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
@@ -79,10 +79,19 @@
mImapStore = new ImapStore(
context, username, password, port, serverName, ImapStore.FLAG_NONE, network);
} catch (NumberFormatException e) {
- LogUtils.e(TAG, e, "Could not parse port number");
+ LogUtils.w(TAG, "Could not parse port number");
}
}
+ /**
+ * If mImapStore is null, this means that there was a missing or badly formatted port number,
+ * which means there aren't sufficient credentials for login. If mImapStore is succcessfully
+ * initialized, then ImapHelper is ready to go.
+ */
+ public boolean isSuccessfullyInitialized() {
+ return mImapStore != null;
+ }
+
/** The caller thread will block until the method returns. */
public boolean markMessagesAsRead(List<Voicemail> voicemails) {
return setFlags(voicemails, Flag.SEEN);
@@ -175,21 +184,23 @@
}
- public void fetchVoicemailPayload(VoicemailFetchedCallback callback, final String uid) {
+ public boolean fetchVoicemailPayload(VoicemailFetchedCallback callback, final String uid) {
Message message;
try {
mFolder = openImapFolder(ImapFolder.MODE_READ_WRITE);
if (mFolder == null) {
// This means we were unable to successfully open the folder.
- return;
+ return false;
}
message = mFolder.getMessage(uid);
VoicemailPayload voicemailPayload = fetchVoicemailPayload(message);
callback.setVoicemailContent(voicemailPayload);
+ return true;
} catch (MessagingException e) {
} finally {
closeImapFolder();
}
+ return false;
}
/**
diff --git a/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java b/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
index 1467e41..d768e17 100644
--- a/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
+++ b/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
@@ -104,9 +104,9 @@
queryHelper.insertIfUnique(voicemail);
break;
case OmtpConstants.MAILBOX_UPDATE:
- Intent serviceIntent = new Intent(mContext, OmtpVvmSyncService.class);
- serviceIntent.setAction(OmtpVvmSyncService.SYNC_DOWNLOAD_ONLY);
- serviceIntent.putExtra(OmtpVvmSyncService.EXTRA_PHONE_ACCOUNT, mPhoneAccount);
+ Intent serviceIntent = OmtpVvmSyncService.getSyncIntent(
+ mContext, OmtpVvmSyncService.SYNC_DOWNLOAD_ONLY, mPhoneAccount,
+ true /* firstAttempt */);
mContext.startService(serviceIntent);
break;
case OmtpConstants.GREETINGS_UPDATE:
@@ -121,23 +121,32 @@
private void updateSource(StatusMessage message) {
OmtpVvmSourceManager vvmSourceManager =
OmtpVvmSourceManager.getInstance(mContext);
- VoicemailContract.Status.setStatus(mContext, mPhoneAccount,
- VoicemailContract.Status.CONFIGURATION_STATE_OK,
- VoicemailContract.Status.DATA_CHANNEL_STATE_OK,
- VoicemailContract.Status.NOTIFICATION_CHANNEL_STATE_OK);
- // Save the IMAP credentials in preferences so they are persistent and can be retrieved.
- VisualVoicemailSettingsUtil.setVisualVoicemailCredentialsFromStatusMessage(
- mContext,
- mPhoneAccount,
- message);
+ if (OmtpConstants.SUCCESS.equals(message.getReturnCode())) {
+ VoicemailContract.Status.setStatus(mContext, mPhoneAccount,
+ VoicemailContract.Status.CONFIGURATION_STATE_OK,
+ VoicemailContract.Status.DATA_CHANNEL_STATE_OK,
+ VoicemailContract.Status.NOTIFICATION_CHANNEL_STATE_OK);
- // Add a phone state listener so that changes to the communication channels can be recorded.
- vvmSourceManager.addPhoneStateListener(mPhoneAccount);
+ // Save the IMAP credentials in preferences so they are persistent and can be retrieved.
+ VisualVoicemailSettingsUtil.setVisualVoicemailCredentialsFromStatusMessage(
+ mContext,
+ mPhoneAccount,
+ message);
- Intent serviceIntent = new Intent(mContext, OmtpVvmSyncService.class);
- serviceIntent.setAction(OmtpVvmSyncService.SYNC_FULL_SYNC);
- serviceIntent.putExtra(OmtpVvmSyncService.EXTRA_PHONE_ACCOUNT, mPhoneAccount);
- mContext.startService(serviceIntent);
+ // Add the source to indicate that it is active.
+ vvmSourceManager.addSource(mPhoneAccount);
+
+ Intent serviceIntent = OmtpVvmSyncService.getSyncIntent(
+ mContext, OmtpVvmSyncService.SYNC_FULL_SYNC, mPhoneAccount,
+ true /* firstAttempt */);
+ mContext.startService(serviceIntent);
+ } else {
+ Log.w(TAG, "Visual voicemail not available for subscriber.");
+ // Override default isEnabled setting to false since visual voicemail is unable to
+ // be accessed for some reason.
+ VisualVoicemailSettingsUtil.setVisualVoicemailEnabled(mContext, mPhoneAccount,
+ /* isEnabled */ false, /* isUserSet */ true);
+ }
}
}
\ No newline at end of file
diff --git a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSourceManager.java b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSourceManager.java
index 37fb5e4..63e9fee 100644
--- a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSourceManager.java
+++ b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSourceManager.java
@@ -24,9 +24,9 @@
import com.android.internal.telephony.Phone;
import com.android.phone.PhoneUtils;
-import com.android.phone.settings.VisualVoicemailSettingsUtil;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@@ -45,6 +45,7 @@
private TelephonyManager mTelephonyManager;
// Each phone account is associated with a phone state listener for updates to whether the
// device is able to sync.
+ private Set<PhoneAccountHandle> mActiveVvmSources;
private Map<PhoneAccountHandle, PhoneStateListener> mPhoneStateListenerMap;
/**
@@ -67,18 +68,22 @@
mSubscriptionManager = SubscriptionManager.from(context);
mTelephonyManager = (TelephonyManager)
mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ mActiveVvmSources = new HashSet<PhoneAccountHandle>();
mPhoneStateListenerMap = new HashMap<PhoneAccountHandle, PhoneStateListener>();
}
}
+ public void addSource(PhoneAccountHandle phoneAccount) {
+ mActiveVvmSources.add(phoneAccount);
+ }
+
/**
* When a voicemail source is removed, we don't always know which one was removed. Check the
* list of registered phone accounts against the active subscriptions list and remove the
* inactive sources.
*/
public void removeInactiveSources() {
- Set<PhoneAccountHandle> phoneAccounts = getOmtpVvmSources();
- for (PhoneAccountHandle phoneAccount : phoneAccounts) {
+ for (PhoneAccountHandle phoneAccount : mActiveVvmSources) {
if (!PhoneUtils.isPhoneAccountActive(mSubscriptionManager, phoneAccount)) {
removeSource(phoneAccount);
}
@@ -95,6 +100,8 @@
VoicemailContract.Status.DATA_CHANNEL_STATE_NO_CONNECTION,
VoicemailContract.Status.NOTIFICATION_CHANNEL_STATE_NO_CONNECTION);
removePhoneStateListener(phoneAccount);
+ mActiveVvmSources.remove(phoneAccount);
+ OmtpVvmSyncService.cancelAllRetries(mContext, phoneAccount);
}
public void addPhoneStateListener(PhoneAccountHandle phoneAccount) {
@@ -113,27 +120,21 @@
}
public Set<PhoneAccountHandle> getOmtpVvmSources() {
- return mPhoneStateListenerMap.keySet();
+ return mActiveVvmSources;
}
/**
* Check if a certain account is registered.
*
* @param phoneAccount The account to look for.
- * @return {@code true} if the account is in the list of registered OMTP voicemail sync
- * accounts. {@code false} otherwise.
+ * @return {@code true} if the account is in the list of registered OMTP voicemail sources.
+ * {@code false} otherwise.
*/
public boolean isVvmSourceRegistered(PhoneAccountHandle phoneAccount) {
if (phoneAccount == null) {
return false;
}
- Set<PhoneAccountHandle> sources = getOmtpVvmSources();
- for (PhoneAccountHandle source : sources) {
- if (phoneAccount.equals(source)) {
- return true;
- }
- }
- return false;
+ return mActiveVvmSources.contains(phoneAccount);
}
}
\ No newline at end of file
diff --git a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
index 5af912c..d0c6231 100644
--- a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
+++ b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
@@ -15,7 +15,9 @@
*/
package com.android.phone.vvm.omtp.sync;
+import android.app.AlarmManager;
import android.app.IntentService;
+import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
@@ -55,14 +57,73 @@
// Timeout used to call ConnectivityManager.requestNetwork
private static final int NETWORK_REQUEST_TIMEOUT_MILLIS = 60 * 1000;
- private VoicemailsQueryHelper mQueryHelper;
+ // Number of retries
+ private static final int NETWORK_RETRY_COUNT = 6;
+ private VoicemailsQueryHelper mQueryHelper;
private ConnectivityManager mConnectivityManager;
+ private Map<NetworkCallback, NetworkRequest> mNetworkRequestMap;
public OmtpVvmSyncService() {
super("OmtpVvmSyncService");
}
+ public static Intent getSyncIntent(Context context, String action,
+ PhoneAccountHandle phoneAccount, boolean firstAttempt) {
+ if (firstAttempt) {
+ if (phoneAccount != null) {
+ VisualVoicemailSettingsUtil.resetVisualVoicemailRetryInterval(context,
+ phoneAccount);
+ } else {
+ OmtpVvmSourceManager vvmSourceManager =
+ OmtpVvmSourceManager.getInstance(context);
+ Set<PhoneAccountHandle> sources = vvmSourceManager.getOmtpVvmSources();
+ for (PhoneAccountHandle source : sources) {
+ VisualVoicemailSettingsUtil.resetVisualVoicemailRetryInterval(context, source);
+ }
+ }
+ }
+
+ Intent serviceIntent = new Intent(context, OmtpVvmSyncService.class);
+ serviceIntent.setAction(action);
+ if (phoneAccount != null) {
+ serviceIntent.putExtra(EXTRA_PHONE_ACCOUNT, phoneAccount);
+ }
+
+ cancelRetriesForIntent(context, serviceIntent);
+ return serviceIntent;
+ }
+
+ /**
+ * Cancel all retry syncs for an account.
+ * @param context The context the service runs in.
+ * @param phoneAccount The phone account for which to cancel syncs.
+ */
+ public static void cancelAllRetries(Context context, PhoneAccountHandle phoneAccount) {
+ cancelRetriesForIntent(context, getSyncIntent(context, SYNC_FULL_SYNC, phoneAccount,
+ false));
+ }
+
+ /**
+ * A helper method to cancel all pending alarms for intents that would be identical to the given
+ * intent.
+ * @param context The context the service runs in.
+ * @param intent The intent to search and cancel.
+ */
+ private static void cancelRetriesForIntent(Context context, Intent intent) {
+ AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ alarmManager.cancel(PendingIntent.getService(context, 0, intent, 0));
+
+ Intent copyIntent = new Intent(intent);
+ if (SYNC_FULL_SYNC.equals(copyIntent.getAction())) {
+ // A full sync action should also cancel both of the other types of syncs
+ copyIntent.setAction(SYNC_DOWNLOAD_ONLY);
+ alarmManager.cancel(PendingIntent.getService(context, 0, copyIntent, 0));
+ copyIntent.setAction(SYNC_UPLOAD_ONLY);
+ alarmManager.cancel(PendingIntent.getService(context, 0, copyIntent, 0));
+ }
+ }
+
@Override
public void onCreate() {
super.onCreate();
@@ -76,80 +137,151 @@
return;
}
+ mNetworkRequestMap = new HashMap<NetworkCallback, NetworkRequest>();
+
String action = intent.getAction();
PhoneAccountHandle phoneAccount = intent.getParcelableExtra(EXTRA_PHONE_ACCOUNT);
if (phoneAccount != null) {
Log.v(TAG, "Sync requested: " + action + " - for account: " + phoneAccount);
- doSync(phoneAccount, action);
+ setupAndSendNetworkRequest(phoneAccount, action);
} else {
Log.v(TAG, "Sync requested: " + action + " - for all accounts");
OmtpVvmSourceManager vvmSourceManager =
OmtpVvmSourceManager.getInstance(this);
Set<PhoneAccountHandle> sources = vvmSourceManager.getOmtpVvmSources();
for (PhoneAccountHandle source : sources) {
- doSync(source, action);
+ setupAndSendNetworkRequest(source, action);
}
}
}
- private void doSync(PhoneAccountHandle phoneAccount, String action) {
+ private void setupAndSendNetworkRequest(PhoneAccountHandle phoneAccount, String action) {
if (!VisualVoicemailSettingsUtil.isVisualVoicemailEnabled(this, phoneAccount)) {
Log.v(TAG, "Sync requested for disabled account");
return;
}
- int subId = PhoneUtils.getSubIdForPhoneAccountHandle(phoneAccount);
-
NetworkRequest networkRequest = new NetworkRequest.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
- .setNetworkSpecifier(Integer.toString(subId))
- .build();
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .setNetworkSpecifier(
+ Integer.toString(PhoneUtils.getSubIdForPhoneAccountHandle(phoneAccount)))
+ .build();
+
NetworkCallback networkCallback = new OmtpVvmNetworkRequestCallback(this, phoneAccount,
action);
- getConnectivityManager().requestNetwork(
- networkRequest, networkCallback, NETWORK_REQUEST_TIMEOUT_MILLIS);
+
+ mNetworkRequestMap.put(networkCallback, networkRequest);
+
+ requestNetwork(networkCallback);
}
private class OmtpVvmNetworkRequestCallback extends ConnectivityManager.NetworkCallback {
Context mContext;
PhoneAccountHandle mPhoneAccount;
String mAction;
+ int mRetryCount;
public OmtpVvmNetworkRequestCallback(Context context, PhoneAccountHandle phoneAccount,
String action) {
mContext = context;
mPhoneAccount = phoneAccount;
mAction = action;
+ mRetryCount = NETWORK_RETRY_COUNT;
}
@Override
public void onAvailable(final Network network) {
- ImapHelper imapHelper = new ImapHelper(mContext, mPhoneAccount, network);
- if (SYNC_FULL_SYNC.equals(mAction) || SYNC_UPLOAD_ONLY.equals(mAction)) {
- upload(imapHelper);
+ boolean uploadSuccess;
+ boolean downloadSuccess;
+
+ while (mRetryCount > 0) {
+ uploadSuccess = true;
+ downloadSuccess = true;
+
+ ImapHelper imapHelper = new ImapHelper(mContext, mPhoneAccount, network);
+
+ if (!imapHelper.isSuccessfullyInitialized()) {
+ Log.w(TAG, "Can't retrieve Imap credentials.");
+ releaseNetwork(this);
+ VisualVoicemailSettingsUtil.resetVisualVoicemailRetryInterval(mContext,
+ mPhoneAccount);
+ return;
+ }
+
+ if (SYNC_FULL_SYNC.equals(mAction) || SYNC_UPLOAD_ONLY.equals(mAction)) {
+ uploadSuccess = upload(imapHelper);
+ }
+ if (SYNC_FULL_SYNC.equals(mAction) || SYNC_DOWNLOAD_ONLY.equals(mAction)) {
+ downloadSuccess = download(imapHelper);
+ }
+
+ Log.v(TAG, "upload succeeded: ["+ String.valueOf(uploadSuccess)
+ + "] download succeeded: [" + String.valueOf(downloadSuccess) + "]");
+
+ // Need to check again for whether visual voicemail is enabled because it could have
+ // been disabled while waiting for the response from the network.
+ if (VisualVoicemailSettingsUtil.isVisualVoicemailEnabled(mContext, mPhoneAccount) &&
+ (!uploadSuccess || !downloadSuccess)) {
+ mRetryCount--;
+ // Re-adjust so that only the unsuccessful action needs to be retried.
+ // No need to re-adjust if both are unsuccessful. It means the full sync
+ // failed so the action remains unchanged.
+ if (uploadSuccess) {
+ mAction = SYNC_DOWNLOAD_ONLY;
+ } else if (downloadSuccess) {
+ mAction = SYNC_UPLOAD_ONLY;
+ }
+
+ Log.v(TAG, "Retrying " + mAction);
+ } else {
+ // Nothing more to do here, just exit.
+ releaseNetwork(this);
+ VisualVoicemailSettingsUtil.resetVisualVoicemailRetryInterval(mContext,
+ mPhoneAccount);
+ return;
+ }
}
- if (SYNC_FULL_SYNC.equals(mAction) || SYNC_DOWNLOAD_ONLY.equals(mAction)) {
- download(imapHelper);
- }
- releaseNetwork();
+
+ releaseNetwork(this);
+ setRetryAlarm(mPhoneAccount, mAction);
}
@Override
public void onLost(Network network) {
- releaseNetwork();
+ releaseNetwork(this);
+
+ if (mRetryCount > 0) {
+ mRetryCount--;
+ requestNetwork(this);
+ } else {
+ setRetryAlarm(mPhoneAccount, mAction);
+ }
}
@Override
public void onUnavailable() {
- releaseNetwork();
- }
+ releaseNetwork(this);
- private void releaseNetwork() {
- getConnectivityManager().unregisterNetworkCallback(this);
+ if (mRetryCount> 0) {
+ mRetryCount--;
+ requestNetwork(this);
+ } else {
+ setRetryAlarm(mPhoneAccount, mAction);
+ }
}
}
+ private void requestNetwork(NetworkCallback networkCallback) {
+ NetworkRequest networkRequest = mNetworkRequestMap.get(networkCallback);
+ getConnectivityManager().requestNetwork(
+ networkRequest, networkCallback, NETWORK_REQUEST_TIMEOUT_MILLIS);
+ }
+
+ private void releaseNetwork(NetworkCallback networkCallback) {
+ getConnectivityManager().unregisterNetworkCallback(networkCallback);
+ }
+
private ConnectivityManager getConnectivityManager() {
if (mConnectivityManager == null) {
mConnectivityManager = (ConnectivityManager) this.getSystemService(
@@ -158,36 +290,58 @@
return mConnectivityManager;
}
- private void upload(ImapHelper imapHelper) {
+ private void setRetryAlarm(PhoneAccountHandle phoneAccount, String action) {
+ Intent serviceIntent = new Intent(this, OmtpVvmSyncService.class);
+ serviceIntent.setAction(action);
+ serviceIntent.putExtra(OmtpVvmSyncService.EXTRA_PHONE_ACCOUNT, phoneAccount);
+ PendingIntent pendingIntent = PendingIntent.getService(this, 0, serviceIntent, 0);
+ long retryInterval = VisualVoicemailSettingsUtil.getVisualVoicemailRetryInterval(this,
+ phoneAccount);
+
+ Log.v(TAG, "Retrying "+ action + " in " + retryInterval + "ms");
+
+ AlarmManager alarmManager = (AlarmManager)
+ this.getSystemService(Context.ALARM_SERVICE);
+ alarmManager.set(AlarmManager.ELAPSED_REALTIME, retryInterval, pendingIntent);
+
+ VisualVoicemailSettingsUtil.setVisualVoicemailRetryInterval(this, phoneAccount,
+ retryInterval * 2);
+ }
+
+ private boolean upload(ImapHelper imapHelper) {
List<Voicemail> readVoicemails = mQueryHelper.getReadVoicemails();
List<Voicemail> deletedVoicemails = mQueryHelper.getDeletedVoicemails();
- if (deletedVoicemails != null) {
+ boolean success = true;
+
+ if (deletedVoicemails.size() > 0) {
if (imapHelper.markMessagesAsDeleted(deletedVoicemails)) {
// We want to delete selectively instead of all the voicemails for this provider
// in case the state changed since the IMAP query was completed.
mQueryHelper.deleteFromDatabase(deletedVoicemails);
} else {
- mQueryHelper.markUndeletedInDatabase(deletedVoicemails);
+ success = false;
}
}
- if (readVoicemails != null) {
+ if (readVoicemails.size() > 0) {
if (imapHelper.markMessagesAsRead(readVoicemails)) {
mQueryHelper.markReadInDatabase(readVoicemails);
} else {
- mQueryHelper.markUnreadInDatabase(readVoicemails);
+ success = false;
}
}
+
+ return success;
}
- private void download(ImapHelper imapHelper) {
+ private boolean download(ImapHelper imapHelper) {
List<Voicemail> serverVoicemails = imapHelper.fetchAllVoicemails();
List<Voicemail> localVoicemails = mQueryHelper.getAllVoicemails();
if (localVoicemails == null || serverVoicemails == null) {
// Null value means the query failed.
- return;
+ return false;
}
Map<String, Voicemail> remoteMap = buildMap(serverVoicemails);
@@ -213,6 +367,8 @@
for (Voicemail remoteVoicemail : remoteMap.values()) {
VoicemailContract.Voicemails.insert(this, remoteVoicemail);
}
+
+ return true;
}
/**
diff --git a/src/com/android/phone/vvm/omtp/sync/VoicemailProviderChangeReceiver.java b/src/com/android/phone/vvm/omtp/sync/VoicemailProviderChangeReceiver.java
index 0885d65..c2e6178 100644
--- a/src/com/android/phone/vvm/omtp/sync/VoicemailProviderChangeReceiver.java
+++ b/src/com/android/phone/vvm/omtp/sync/VoicemailProviderChangeReceiver.java
@@ -30,8 +30,8 @@
OmtpVvmSourceManager vvmSourceManager =
OmtpVvmSourceManager.getInstance(context);
if (vvmSourceManager.getOmtpVvmSources().size() > 0 && !isSelfChanged) {
- Intent serviceIntent = new Intent(context, OmtpVvmSyncService.class);
- serviceIntent.setAction(OmtpVvmSyncService.SYNC_UPLOAD_ONLY);
+ Intent serviceIntent = OmtpVvmSyncService.getSyncIntent(
+ context, OmtpVvmSyncService.SYNC_UPLOAD_ONLY, null, true /* firstAttempt */);
context.startService(serviceIntent);
}
}
diff --git a/src/com/android/phone/vvm/omtp/sync/VoicemailStatusQueryHelper.java b/src/com/android/phone/vvm/omtp/sync/VoicemailStatusQueryHelper.java
index fa87a59..66f3e9d 100644
--- a/src/com/android/phone/vvm/omtp/sync/VoicemailStatusQueryHelper.java
+++ b/src/com/android/phone/vvm/omtp/sync/VoicemailStatusQueryHelper.java
@@ -22,23 +22,23 @@
import android.provider.VoicemailContract;
import android.provider.VoicemailContract.Status;
import android.telecom.PhoneAccountHandle;
-import android.util.Log;
/**
* Construct queries to interact with the voicemail status table.
*/
public class VoicemailStatusQueryHelper {
- private static final String TAG = "VoicemailStatusQueryHelper";
final static String[] PROJECTION = new String[] {
Status._ID, // 0
- Status.NOTIFICATION_CHANNEL_STATE, // 1
- Status.SOURCE_PACKAGE // 2
+ Status.CONFIGURATION_STATE, // 1
+ Status.NOTIFICATION_CHANNEL_STATE, // 2
+ Status.SOURCE_PACKAGE // 3
};
public static final int _ID = 0;
- public static final int NOTIFICATION_CHANNEL_STATE = 1;
- public static final int SOURCE_PACKAGE = 2;
+ public static final int CONFIGURATION_STATE = 1;
+ public static final int NOTIFICATION_CHANNEL_STATE = 2;
+ public static final int SOURCE_PACKAGE = 3;
private Context mContext;
private ContentResolver mContentResolver;
@@ -51,12 +51,38 @@
}
/**
+ * Check if the configuration state for the voicemail source is "ok", meaning that the
+ * source is set up.
+ *
+ * @param phoneAccount The phone account for the voicemail source to check.
+ * @return {@code true} if the voicemail source is configured, {@code} false otherwise,
+ * including if the voicemail source is not registered in the table.
+ */
+ public boolean isVoicemailSourceConfigured(PhoneAccountHandle phoneAccount) {
+ return isFieldEqualTo(phoneAccount, CONFIGURATION_STATE, Status.CONFIGURATION_STATE_OK);
+ }
+
+ /**
* Check if the notifications channel of a voicemail source is active. That is, when a new
* voicemail is available, if the server able to notify the device.
*
* @return {@code true} if notifications channel is active, {@code false} otherwise.
*/
public boolean isNotificationsChannelActive(PhoneAccountHandle phoneAccount) {
+ return isFieldEqualTo(phoneAccount, NOTIFICATION_CHANNEL_STATE,
+ Status.NOTIFICATION_CHANNEL_STATE_OK);
+ }
+
+ /**
+ * Check if a field for an entry in the status table is equal to a specific value.
+ *
+ * @param phoneAccount The phone account of the voicemail source to query for.
+ * @param columnIndex The column index of the field in the returned query.
+ * @param value The value to compare against.
+ * @return {@code true} if the stored value is equal to the provided value. {@code false}
+ * otherwise.
+ */
+ private boolean isFieldEqualTo(PhoneAccountHandle phoneAccount, int columnIndex, int value) {
Cursor cursor = null;
if (phoneAccount != null) {
String phoneAccountComponentName = phoneAccount.getComponentName().flattenToString();
@@ -73,8 +99,7 @@
cursor = mContentResolver.query(
mSourceUri, PROJECTION, whereClause, whereArgs, null);
if (cursor != null && cursor.moveToFirst()) {
- return cursor.getInt(NOTIFICATION_CHANNEL_STATE) ==
- Status.NOTIFICATION_CHANNEL_STATE_OK;
+ return cursor.getInt(columnIndex) == value;
}
}
finally {
diff --git a/src/com/android/phone/vvm/omtp/sync/VoicemailsQueryHelper.java b/src/com/android/phone/vvm/omtp/sync/VoicemailsQueryHelper.java
index 2a30216..b86351c 100644
--- a/src/com/android/phone/vvm/omtp/sync/VoicemailsQueryHelper.java
+++ b/src/com/android/phone/vvm/omtp/sync/VoicemailsQueryHelper.java
@@ -104,7 +104,10 @@
while (cursor.moveToNext()) {
final long id = cursor.getLong(_ID);
final String sourceData = cursor.getString(SOURCE_DATA);
- Voicemail voicemail = Voicemail.createForUpdate(id, sourceData).build();
+ final boolean isRead = cursor.getInt(IS_READ) == 1;
+ Voicemail voicemail = Voicemail
+ .createForUpdate(id, sourceData)
+ .setIsRead(isRead).build();
voicemails.add(voicemail);
}
return voicemails;
@@ -166,36 +169,9 @@
* Utility method to mark single message as read.
*/
public void markReadInDatabase(Voicemail voicemail) {
- updateInDatabase(voicemail, Voicemails.IS_READ, "1");
- }
-
- /**
- * Undelete in database. This will be called if sync to server fails.
- */
- public void markUndeletedInDatabase(List<Voicemail> voicemails) {
- int count = voicemails.size();
- for (int i = 0; i < count; i++) {
- updateInDatabase(voicemails.get(i), Voicemails.DELETED, "0");
- }
- }
-
- /**
- * Unread in database. This will be called if sync to server fails.
- */
- public void markUnreadInDatabase(List<Voicemail> voicemails) {
- int count = voicemails.size();
- for (int i = 0; i < count; i++) {
- updateInDatabase(voicemails.get(i), Voicemails.IS_READ, "0");
- }
- }
-
- /**
- * Make an update of the requested field in the database.
- */
- private void updateInDatabase(Voicemail voicemail, String field, String value) {
Uri uri = ContentUris.withAppendedId(mSourceUri, voicemail.getId());
ContentValues contentValues = new ContentValues();
- contentValues.put(field, value);
+ contentValues.put(Voicemails.IS_READ, "1");
mContentResolver.update(uri, contentValues, null, null);
}
diff --git a/src/com/android/phone/vvm/omtp/sync/VvmPhoneStateListener.java b/src/com/android/phone/vvm/omtp/sync/VvmPhoneStateListener.java
index f51a2f0..84449d7 100644
--- a/src/com/android/phone/vvm/omtp/sync/VvmPhoneStateListener.java
+++ b/src/com/android/phone/vvm/omtp/sync/VvmPhoneStateListener.java
@@ -23,11 +23,13 @@
import android.telephony.ServiceState;
import com.android.phone.PhoneUtils;
+import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
/**
* Check if service is lost and indicate this in the voicemail status.
*/
public class VvmPhoneStateListener extends PhoneStateListener {
+
private PhoneAccountHandle mPhoneAccount;
private Context mContext;
public VvmPhoneStateListener(Context context, PhoneAccountHandle accountHandle) {
@@ -41,17 +43,24 @@
if (serviceState.getState() == ServiceState.STATE_IN_SERVICE) {
VoicemailStatusQueryHelper voicemailStatusQueryHelper =
new VoicemailStatusQueryHelper(mContext);
- if (!voicemailStatusQueryHelper.isNotificationsChannelActive(mPhoneAccount)) {
- VoicemailContract.Status.setStatus(mContext, mPhoneAccount,
- VoicemailContract.Status.CONFIGURATION_STATE_OK,
- VoicemailContract.Status.DATA_CHANNEL_STATE_OK,
- VoicemailContract.Status.NOTIFICATION_CHANNEL_STATE_OK);
+ if (voicemailStatusQueryHelper.isVoicemailSourceConfigured(mPhoneAccount)) {
+ if (!voicemailStatusQueryHelper.isNotificationsChannelActive(mPhoneAccount)) {
+ VoicemailContract.Status.setStatus(mContext, mPhoneAccount,
+ VoicemailContract.Status.CONFIGURATION_STATE_OK,
+ VoicemailContract.Status.DATA_CHANNEL_STATE_OK,
+ VoicemailContract.Status.NOTIFICATION_CHANNEL_STATE_OK);
+ // Run a full sync in case something was missed while signal was down.
+ Intent serviceIntent = OmtpVvmSyncService.getSyncIntent(
+ mContext, OmtpVvmSyncService.SYNC_FULL_SYNC, mPhoneAccount,
+ true /* firstAttempt */);
+ mContext.startService(serviceIntent);
+ }
+ }
- // Run a full sync in case something was missed while signal was down.
- Intent serviceIntent = new Intent(mContext, OmtpVvmSyncService.class);
- serviceIntent.setAction(OmtpVvmSyncService.SYNC_FULL_SYNC);
- serviceIntent.putExtra(OmtpVvmSyncService.EXTRA_PHONE_ACCOUNT, mPhoneAccount);
- mContext.startService(serviceIntent);
+ if (!OmtpVvmSourceManager.getInstance(mContext).isVvmSourceRegistered(mPhoneAccount)) {
+ OmtpVvmCarrierConfigHelper carrierConfigHelper = new OmtpVvmCarrierConfigHelper(
+ mContext, PhoneUtils.getSubIdForPhoneAccountHandle(mPhoneAccount));
+ carrierConfigHelper.startActivation();
}
} else {
VoicemailContract.Status.setStatus(mContext, mPhoneAccount,
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index a1729b7..72c9b07 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -27,6 +27,7 @@
import android.telecom.ConnectionService;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
+import android.telephony.CarrierConfigManager;
import android.telephony.PhoneNumberUtils;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
@@ -152,44 +153,20 @@
// Obtain the configuration for the outgoing phone's SIM. If the outgoing number
// matches the *228 regex pattern, fail the call. This number is used for OTASP, and
// when dialed could lock LTE SIMs to 3G if not prohibited..
- SubscriptionManager subManager = SubscriptionManager.from(phone.getContext());
- SubscriptionInfo subInfo = subManager.getActiveSubscriptionInfo(phone.getSubId());
- if (subInfo != null) {
- Configuration config = new Configuration();
- config.mcc = subInfo.getMcc();
- config.mnc = subInfo.getMnc();
- Context subContext = phone.getContext().createConfigurationContext(config);
+ boolean disableActivation = false;
+ CarrierConfigManager cfgManager = (CarrierConfigManager)
+ phone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ if (cfgManager != null) {
+ disableActivation = cfgManager.getConfigForSubId(phone.getSubId())
+ .getBoolean(CarrierConfigManager.KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL);
+ }
- // Get the resources specific to the subscription in question.
- Resources res = subContext.getResources();
- if (res != null) {
- boolean disableActivation = false;
- String configValue =
- res.getString(R.string.config_disable_cdma_activation_code);
-
- // Set disableActivation based on the configuration value.
- if (!TextUtils.isEmpty(configValue)) {
- String [] valueArray = configValue.split(";");
-
- if (valueArray.length == 1) {
- // If the configuration says just "true" disable it.
- disableActivation = valueArray[0].equalsIgnoreCase("true");
- } else if (valueArray.length == 2) {
- // If the configuration is split by a semicolon, make sure the
- // second half is equal to the group ID for the phone.
- disableActivation = valueArray[0].equalsIgnoreCase("true") &&
- valueArray[1].equalsIgnoreCase(phone.getGroupIdLevel1());
- }
- }
-
- if (disableActivation) {
- return Connection.createFailedConnection(
- DisconnectCauseUtil.toTelecomDisconnectCause(
- android.telephony.DisconnectCause
- .CDMA_ALREADY_ACTIVATED,
- "Tried to dial *228"));
- }
- }
+ if (disableActivation) {
+ return Connection.createFailedConnection(
+ DisconnectCauseUtil.toTelecomDisconnectCause(
+ android.telephony.DisconnectCause
+ .CDMA_ALREADY_ACTIVATED,
+ "Tried to dial *228"));
}
}
}
@@ -569,6 +546,8 @@
Log.d(this, "Adding CDMA connection to conference controller: " + connection);
mCdmaConferenceController.add((CdmaConnection)connection);
}
+ Log.d(this, "Removing connection from IMS conference controller: " + connection);
+ mImsConferenceController.remove(connection);
}
}
}