1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.voicemail.impl; 18 19 import android.annotation.TargetApi; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.os.Build.VERSION_CODES; 23 import android.os.UserManager; 24 import android.preference.PreferenceManager; 25 import android.support.annotation.MainThread; 26 import android.support.annotation.NonNull; 27 import android.telecom.PhoneAccountHandle; 28 import android.telephony.VisualVoicemailService; 29 import android.telephony.VisualVoicemailSms; 30 import com.android.dialer.logging.DialerImpression; 31 import com.android.dialer.logging.Logger; 32 import com.android.voicemail.VoicemailComponent; 33 import com.android.voicemail.impl.settings.VisualVoicemailSettingsUtil; 34 import com.android.voicemail.impl.sms.LegacyModeSmsHandler; 35 import com.android.voicemail.impl.sync.VvmAccountManager; 36 37 /** Implements {@link VisualVoicemailService} to receive visual voicemail events */ 38 @TargetApi(VERSION_CODES.O) 39 public class OmtpService extends VisualVoicemailService { 40 41 private static final String TAG = "VvmOmtpService"; 42 43 public static final String ACTION_SMS_RECEIVED = "com.android.vociemailomtp.sms.sms_received"; 44 45 public static final String EXTRA_VOICEMAIL_SMS = "extra_voicemail_sms"; 46 47 private static final String IS_SHUTTING_DOWN = "com.android.voicemail.impl.is_shutting_down"; 48 49 @Override 50 public void onCellServiceConnected( 51 VisualVoicemailTask task, final PhoneAccountHandle phoneAccountHandle) { 52 VvmLog.i(TAG, "onCellServiceConnected"); 53 if (!isModuleEnabled()) { 54 VvmLog.e(TAG, "onCellServiceConnected received when module is disabled"); 55 task.finish(); 56 return; 57 } 58 59 if (!isUserUnlocked(this)) { 60 VvmLog.i(TAG, "onCellServiceConnected: user locked"); 61 task.finish(); 62 return; 63 } 64 65 if (!isServiceEnabled(phoneAccountHandle)) { 66 task.finish(); 67 return; 68 } 69 70 Logger.get(this).logImpression(DialerImpression.Type.VVM_UNBUNDLED_EVENT_RECEIVED); 71 ActivationTask.start(OmtpService.this, phoneAccountHandle, null); 72 task.finish(); 73 } 74 75 @Override 76 public void onSmsReceived(VisualVoicemailTask task, final VisualVoicemailSms sms) { 77 VvmLog.i(TAG, "onSmsReceived"); 78 if (!isModuleEnabled()) { 79 VvmLog.e(TAG, "onSmsReceived received when module is disabled"); 80 task.finish(); 81 return; 82 } 83 84 if (!isUserUnlocked(this)) { 85 LegacyModeSmsHandler.handle(this, sms); 86 return; 87 } 88 89 if (!isServiceEnabled(sms.getPhoneAccountHandle())) { 90 task.finish(); 91 return; 92 } 93 94 // isUserUnlocked() is not checked. OmtpMessageReceiver will handle the locked case. 95 96 Logger.get(this).logImpression(DialerImpression.Type.VVM_UNBUNDLED_EVENT_RECEIVED); 97 Intent intent = new Intent(ACTION_SMS_RECEIVED); 98 intent.setPackage(getPackageName()); 99 intent.putExtra(EXTRA_VOICEMAIL_SMS, sms); 100 sendBroadcast(intent); 101 task.finish(); 102 } 103 104 @Override 105 public void onSimRemoved( 106 final VisualVoicemailTask task, final PhoneAccountHandle phoneAccountHandle) { 107 VvmLog.i(TAG, "onSimRemoved"); 108 if (!isModuleEnabled()) { 109 VvmLog.e(TAG, "onSimRemoved called when module is disabled"); 110 task.finish(); 111 return; 112 } 113 114 if (!isUserUnlocked(this)) { 115 VvmLog.i(TAG, "onSimRemoved: user locked"); 116 task.finish(); 117 return; 118 } 119 120 if (isShuttingDown(this)) { 121 VvmLog.i(TAG, "onSimRemoved: system shutting down, ignoring"); 122 task.finish(); 123 return; 124 } 125 126 Logger.get(this).logImpression(DialerImpression.Type.VVM_UNBUNDLED_EVENT_RECEIVED); 127 VvmAccountManager.removeAccount(this, phoneAccountHandle); 128 task.finish(); 129 } 130 131 @Override 132 public void onStopped(VisualVoicemailTask task) { 133 VvmLog.i(TAG, "onStopped"); 134 if (!isModuleEnabled()) { 135 VvmLog.e(TAG, "onStopped called when module is disabled"); 136 task.finish(); 137 return; 138 } 139 if (!isUserUnlocked(this)) { 140 VvmLog.i(TAG, "onStopped: user locked"); 141 task.finish(); 142 return; 143 } 144 Logger.get(this).logImpression(DialerImpression.Type.VVM_UNBUNDLED_EVENT_RECEIVED); 145 } 146 147 @MainThread 148 static void onBoot(@NonNull Context context) { 149 VvmLog.i(TAG, "onBoot"); 150 Assert.isTrue(isUserUnlocked(context)); 151 Assert.isMainThread(); 152 setShuttingDown(context, false); 153 } 154 155 @MainThread 156 static void onShutdown(@NonNull Context context) { 157 VvmLog.i(TAG, "onShutdown"); 158 Assert.isTrue(isUserUnlocked(context)); 159 Assert.isMainThread(); 160 setShuttingDown(context, true); 161 } 162 163 private boolean isModuleEnabled() { 164 return VoicemailComponent.get(this).getVoicemailClient().isVoicemailModuleEnabled(); 165 } 166 167 private boolean isServiceEnabled(PhoneAccountHandle phoneAccountHandle) { 168 OmtpVvmCarrierConfigHelper config = new OmtpVvmCarrierConfigHelper(this, phoneAccountHandle); 169 if (!config.isValid()) { 170 VvmLog.i(TAG, "VVM not supported on " + phoneAccountHandle); 171 return false; 172 } 173 if (!VisualVoicemailSettingsUtil.isEnabled(this, phoneAccountHandle) 174 && !config.isLegacyModeEnabled()) { 175 VvmLog.i(TAG, "VVM is disabled"); 176 return false; 177 } 178 return true; 179 } 180 181 private static boolean isUserUnlocked(@NonNull Context context) { 182 UserManager userManager = context.getSystemService(UserManager.class); 183 return userManager.isUserUnlocked(); 184 } 185 186 private static void setShuttingDown(Context context, boolean value) { 187 PreferenceManager.getDefaultSharedPreferences(context) 188 .edit() 189 .putBoolean(IS_SHUTTING_DOWN, value) 190 .apply(); 191 } 192 193 private static boolean isShuttingDown(Context context) { 194 return PreferenceManager.getDefaultSharedPreferences(context) 195 .getBoolean(IS_SHUTTING_DOWN, false); 196 } 197 } 198