1 /** 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * <p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * <p>http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * <p>Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 * express or implied. See the License for the specific language governing permissions and 12 * limitations under the License 13 */ 14 package com.android.voicemail.impl; 15 16 import android.annotation.TargetApi; 17 import android.content.Context; 18 import android.content.Intent; 19 import android.content.SharedPreferences; 20 import android.os.Build.VERSION_CODES; 21 import android.os.PersistableBundle; 22 import android.preference.PreferenceManager; 23 import android.provider.VoicemailContract.Status; 24 import android.provider.VoicemailContract.Voicemails; 25 import android.support.annotation.MainThread; 26 import android.support.annotation.NonNull; 27 import android.support.annotation.Nullable; 28 import android.support.v4.os.BuildCompat; 29 import android.telecom.PhoneAccountHandle; 30 import android.telephony.TelephonyManager; 31 import com.android.dialer.common.Assert; 32 import com.android.dialer.common.LogUtil; 33 import com.android.dialer.configprovider.ConfigProviderBindings; 34 import com.android.voicemail.PinChanger; 35 import com.android.voicemail.VisualVoicemailTypeExtensions; 36 import com.android.voicemail.VoicemailClient; 37 import com.android.voicemail.VoicemailVersionConstants; 38 import com.android.voicemail.impl.configui.VoicemailSecretCodeActivity; 39 import com.android.voicemail.impl.settings.VisualVoicemailSettingsUtil; 40 import com.android.voicemail.impl.sync.VvmAccountManager; 41 import com.android.voicemail.impl.transcribe.TranscriptionBackfillService; 42 import com.android.voicemail.impl.transcribe.TranscriptionConfigProvider; 43 import java.util.List; 44 import javax.inject.Inject; 45 46 /** 47 * {@link VoicemailClient} to be used when the voicemail module is activated. May only be used above 48 * O. 49 */ 50 public class VoicemailClientImpl implements VoicemailClient { 51 52 /** 53 * List of legacy OMTP voicemail packages that should be ignored. It could never be the active VVM 54 * package anymore. For example, voicemails in OC will no longer be handled by telephony, but 55 * legacy voicemails might still exist in the database due to upgrading from NYC. Dialer will 56 * fetch these voicemails again so it should be ignored. 57 */ 58 private static final String[] OMTP_VOICEMAIL_BLACKLIST = {"com.android.phone"}; 59 60 // Flag name used for configuration 61 private static final String ALLOW_VOICEMAIL_ARCHIVE = "allow_voicemail_archive"; 62 63 private static final String[] OMTP_VOICEMAIL_TYPE = { 64 TelephonyManager.VVM_TYPE_OMTP, 65 TelephonyManager.VVM_TYPE_CVVM, 66 VisualVoicemailTypeExtensions.VVM_TYPE_VVM3 67 }; 68 69 @Inject 70 public VoicemailClientImpl() { 71 Assert.checkArgument(BuildCompat.isAtLeastO()); 72 } 73 74 @Override 75 public boolean isVoicemailModuleEnabled() { 76 return true; 77 } 78 79 @Override 80 public boolean hasCarrierSupport(Context context, PhoneAccountHandle phoneAccountHandle) { 81 OmtpVvmCarrierConfigHelper config = new OmtpVvmCarrierConfigHelper(context, phoneAccountHandle); 82 return config.isValid() && !config.isCarrierAppInstalled(); 83 } 84 85 @Override 86 public boolean isVoicemailEnabled(Context context, PhoneAccountHandle phoneAccountHandle) { 87 return VisualVoicemailSettingsUtil.isEnabled(context, phoneAccountHandle); 88 } 89 90 @Override 91 public void setVoicemailEnabled( 92 Context context, PhoneAccountHandle phoneAccountHandle, boolean enabled) { 93 VisualVoicemailSettingsUtil.setEnabled(context, phoneAccountHandle, enabled); 94 } 95 96 @Override 97 public boolean isVoicemailArchiveEnabled(Context context, PhoneAccountHandle phoneAccountHandle) { 98 return VisualVoicemailSettingsUtil.isArchiveEnabled(context, phoneAccountHandle); 99 } 100 101 @Override 102 public boolean isVoicemailArchiveAvailable(Context context) { 103 if (!BuildCompat.isAtLeastO()) { 104 LogUtil.i("VoicemailClientImpl.isVoicemailArchiveAllowed", "not running on O or later"); 105 return false; 106 } 107 108 if (!ConfigProviderBindings.get(context).getBoolean(ALLOW_VOICEMAIL_ARCHIVE, false)) { 109 LogUtil.i( 110 "VoicemailClientImpl.isVoicemailArchiveAllowed", 111 "feature disabled by config: %s", 112 ALLOW_VOICEMAIL_ARCHIVE); 113 return false; 114 } 115 116 return true; 117 } 118 119 @Override 120 public void setVoicemailArchiveEnabled( 121 Context context, PhoneAccountHandle phoneAccountHandle, boolean value) { 122 VisualVoicemailSettingsUtil.setArchiveEnabled(context, phoneAccountHandle, value); 123 } 124 125 @Override 126 public boolean isVoicemailTranscriptionAvailable(Context context) { 127 if (!BuildCompat.isAtLeastO()) { 128 LogUtil.i( 129 "VoicemailClientImpl.isVoicemailTranscriptionAvailable", "not running on O or later"); 130 return false; 131 } 132 133 TranscriptionConfigProvider provider = new TranscriptionConfigProvider(context); 134 if (!provider.isVoicemailTranscriptionAvailable()) { 135 LogUtil.i( 136 "VoicemailClientImpl.isVoicemailTranscriptionAvailable", "feature disabled by config"); 137 return false; 138 } 139 140 return true; 141 } 142 143 @Override 144 public boolean isVoicemailDonationAvailable(Context context) { 145 if (!isVoicemailTranscriptionAvailable(context)) { 146 LogUtil.i("VoicemailClientImpl.isVoicemailDonationAvailable", "transcription not available"); 147 return false; 148 } 149 150 TranscriptionConfigProvider provider = new TranscriptionConfigProvider(context); 151 if (!provider.isVoicemailDonationAvailable()) { 152 LogUtil.i("VoicemailClientImpl.isVoicemailDonationAvailable", "feature disabled by config"); 153 return false; 154 } 155 156 return true; 157 } 158 159 @Override 160 public boolean isVoicemailDonationEnabled(Context context, PhoneAccountHandle account) { 161 return isVoicemailTranscriptionAvailable(context) 162 && VisualVoicemailSettingsUtil.isVoicemailDonationEnabled(context, account); 163 } 164 165 @Override 166 public void setVoicemailDonationEnabled( 167 Context context, PhoneAccountHandle phoneAccountHandle, boolean enabled) { 168 VisualVoicemailSettingsUtil.setVoicemailDonationEnabled(context, phoneAccountHandle, enabled); 169 } 170 171 @Override 172 public boolean isActivated(Context context, PhoneAccountHandle phoneAccountHandle) { 173 return VvmAccountManager.isAccountActivated(context, phoneAccountHandle); 174 } 175 176 @Override 177 public void showConfigUi(@NonNull Context context) { 178 Intent intent = new Intent(context, VoicemailSecretCodeActivity.class); 179 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 180 context.startActivity(intent); 181 } 182 183 @Override 184 public PersistableBundle getConfig(Context context, PhoneAccountHandle phoneAccountHandle) { 185 return new OmtpVvmCarrierConfigHelper(context, phoneAccountHandle).getConfig(); 186 } 187 188 @Override 189 @MainThread 190 public void onBoot(@NonNull Context context) { 191 OmtpService.onBoot(context); 192 StatusCheckJobService.schedule(context); 193 } 194 195 @Override 196 @MainThread 197 public void onShutdown(@NonNull Context context) { 198 OmtpService.onShutdown(context); 199 } 200 201 @Override 202 public void addActivationStateListener(ActivationStateListener listener) { 203 VvmAccountManager.addListener(listener); 204 } 205 206 @Override 207 public void removeActivationStateListener(ActivationStateListener listener) { 208 VvmAccountManager.removeListener(listener); 209 } 210 211 @Override 212 public PinChanger createPinChanger(Context context, PhoneAccountHandle phoneAccountHandle) { 213 return new PinChangerImpl(context, phoneAccountHandle); 214 } 215 216 @TargetApi(VERSION_CODES.O) 217 @Override 218 public void appendOmtpVoicemailSelectionClause( 219 Context context, StringBuilder where, List<String> selectionArgs) { 220 String omtpSource = 221 context.getSystemService(TelephonyManager.class).getVisualVoicemailPackageName(); 222 if (where.length() != 0) { 223 where.append(" AND "); 224 } 225 where.append("("); 226 { 227 where.append("("); 228 { 229 where.append(Voicemails.IS_OMTP_VOICEMAIL).append(" != 1"); 230 where.append(")"); 231 } 232 where.append(" OR "); 233 where.append("("); 234 { 235 where.append(Voicemails.SOURCE_PACKAGE).append(" = ?"); 236 selectionArgs.add(omtpSource); 237 where.append(")"); 238 } 239 where.append(")"); 240 } 241 242 for (String blacklistedPackage : OMTP_VOICEMAIL_BLACKLIST) { 243 where.append("AND (").append(Voicemails.SOURCE_PACKAGE).append("!= ?)"); 244 selectionArgs.add(blacklistedPackage); 245 } 246 } 247 248 @TargetApi(VERSION_CODES.O) 249 @Override 250 public void appendOmtpVoicemailStatusSelectionClause( 251 Context context, StringBuilder where, List<String> selectionArgs) { 252 String omtpSource = 253 context.getSystemService(TelephonyManager.class).getVisualVoicemailPackageName(); 254 if (where.length() != 0) { 255 where.append(" AND "); 256 } 257 where.append("("); 258 { 259 where.append("("); 260 { 261 where.append(Status.SOURCE_PACKAGE).append(" = ? "); 262 selectionArgs.add(omtpSource); 263 where.append(")"); 264 } 265 where.append(" OR NOT ("); 266 { 267 for (int i = 0; i < OMTP_VOICEMAIL_TYPE.length; i++) { 268 if (i != 0) { 269 where.append(" OR "); 270 } 271 where.append(" ("); 272 { 273 where.append(Status.SOURCE_TYPE).append(" IS ?"); 274 selectionArgs.add(OMTP_VOICEMAIL_TYPE[i]); 275 where.append(")"); 276 } 277 } 278 where.append(")"); 279 } 280 for (String blacklistedPackage : OMTP_VOICEMAIL_BLACKLIST) { 281 where.append("AND ("); 282 { 283 where.append(Voicemails.SOURCE_PACKAGE).append("!= ?"); 284 selectionArgs.add(blacklistedPackage); 285 where.append(")"); 286 } 287 } 288 where.append(")"); 289 } 290 } 291 292 @Override 293 public void onTosAccepted(Context context, PhoneAccountHandle account) { 294 LogUtil.i("VoicemailClientImpl.onTosAccepted", "try backfilling voicemail transcriptions"); 295 TranscriptionBackfillService.scheduleTask(context, account); 296 } 297 298 @Override 299 public boolean hasAcceptedTos(Context context, PhoneAccountHandle phoneAccountHandle) { 300 SharedPreferences preferences = 301 PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext()); 302 OmtpVvmCarrierConfigHelper helper = new OmtpVvmCarrierConfigHelper(context, phoneAccountHandle); 303 boolean isVvm3 = VisualVoicemailTypeExtensions.VVM_TYPE_VVM3.equals(helper.getVvmType()); 304 if (isVvm3) { 305 return preferences.getInt(VoicemailVersionConstants.PREF_VVM3_TOS_VERSION_ACCEPTED_KEY, 0) 306 >= VoicemailVersionConstants.CURRENT_VVM3_TOS_VERSION; 307 } else { 308 return preferences.getInt(VoicemailVersionConstants.PREF_DIALER_TOS_VERSION_ACCEPTED_KEY, 0) 309 >= VoicemailVersionConstants.CURRENT_DIALER_TOS_VERSION; 310 } 311 } 312 313 @Override 314 @Nullable 315 public String getCarrierConfigString(Context context, PhoneAccountHandle account, String key) { 316 OmtpVvmCarrierConfigHelper helper = new OmtpVvmCarrierConfigHelper(context, account); 317 return helper.isValid() ? helper.getString(key) : null; 318 } 319 } 320