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 */
14package com.android.voicemail.impl;
15
16import android.annotation.TargetApi;
17import android.content.Context;
18import android.content.Intent;
19import android.os.Build.VERSION_CODES;
20import android.os.Bundle;
21import android.telecom.PhoneAccountHandle;
22import android.telephony.ServiceState;
23import android.telephony.TelephonyManager;
24import com.android.dialer.logging.DialerImpression;
25import com.android.dialer.proguard.UsedByReflection;
26import com.android.voicemail.impl.scheduling.BaseTask;
27import com.android.voicemail.impl.sms.StatusMessage;
28import com.android.voicemail.impl.sms.StatusSmsFetcher;
29import com.android.voicemail.impl.sync.VvmAccountManager;
30import com.android.voicemail.impl.utils.LoggerUtils;
31import java.io.IOException;
32import java.util.concurrent.CancellationException;
33import java.util.concurrent.ExecutionException;
34import java.util.concurrent.TimeoutException;
35
36/**
37 * Task to verify the account status is still correct. This task is only for book keeping so any
38 * error is ignored and will not retry. If the provision status sent by the carrier is "ready" the
39 * access credentials will be updated (although it is not expected to change without the carrier
40 * actively sending out an STATUS SMS which will be handled by {@link
41 * com.android.voicemail.impl.sms.OmtpMessageReceiver}). If the provisioning status is not ready an
42 * {@link ActivationTask} will be launched to attempt to correct it.
43 */
44@TargetApi(VERSION_CODES.O)
45@UsedByReflection(value = "Tasks.java")
46public class StatusCheckTask extends BaseTask {
47
48  public StatusCheckTask() {
49    super(TASK_STATUS_CHECK);
50  }
51
52  public static void start(Context context, PhoneAccountHandle phoneAccountHandle) {
53    Intent intent = BaseTask.createIntent(context, StatusCheckTask.class, phoneAccountHandle);
54    context.sendBroadcast(intent);
55  }
56
57  @Override
58  public void onExecuteInBackgroundThread() {
59    TelephonyManager telephonyManager =
60        getContext()
61            .getSystemService(TelephonyManager.class)
62            .createForPhoneAccountHandle(getPhoneAccountHandle());
63
64    if (telephonyManager == null) {
65      VvmLog.w(
66          "StatusCheckTask.onExecuteInBackgroundThread",
67          getPhoneAccountHandle() + " no longer valid");
68      return;
69    }
70    if (telephonyManager.getServiceState().getState() != ServiceState.STATE_IN_SERVICE) {
71      VvmLog.i(
72          "StatusCheckTask.onExecuteInBackgroundThread",
73          getPhoneAccountHandle() + " not in service");
74      return;
75    }
76    OmtpVvmCarrierConfigHelper config =
77        new OmtpVvmCarrierConfigHelper(getContext(), getPhoneAccountHandle());
78    if (!config.isValid()) {
79      VvmLog.e(
80          "StatusCheckTask.onExecuteInBackgroundThread",
81          "config no longer valid for " + getPhoneAccountHandle());
82      VvmAccountManager.removeAccount(getContext(), getPhoneAccountHandle());
83      return;
84    }
85
86    Bundle data;
87    try (StatusSmsFetcher fetcher = new StatusSmsFetcher(getContext(), getPhoneAccountHandle())) {
88      config.getProtocol().requestStatus(config, fetcher.getSentIntent());
89      // Both the fetcher and OmtpMessageReceiver will be triggered, but
90      // OmtpMessageReceiver will just route the SMS back to ActivationTask, which will be
91      // rejected because the task is still running.
92      data = fetcher.get();
93    } catch (TimeoutException e) {
94      VvmLog.e("StatusCheckTask.onExecuteInBackgroundThread", "timeout requesting status");
95      return;
96    } catch (CancellationException e) {
97      VvmLog.e("StatusCheckTask.onExecuteInBackgroundThread", "Unable to send status request SMS");
98      return;
99    } catch (InterruptedException | ExecutionException | IOException e) {
100      VvmLog.e("StatusCheckTask.onExecuteInBackgroundThread", "can't get future STATUS SMS", e);
101      return;
102    }
103
104    StatusMessage message = new StatusMessage(data);
105    VvmLog.i(
106        "StatusCheckTask.onExecuteInBackgroundThread",
107        "STATUS SMS received: st="
108            + message.getProvisioningStatus()
109            + ", rc="
110            + message.getReturnCode());
111    if (message.getProvisioningStatus().equals(OmtpConstants.SUBSCRIBER_READY)) {
112      VvmLog.i(
113          "StatusCheckTask.onExecuteInBackgroundThread",
114          "subscriber ready, no activation required");
115      LoggerUtils.logImpressionOnMainThread(
116          getContext(), DialerImpression.Type.VVM_STATUS_CHECK_READY);
117      VvmAccountManager.addAccount(getContext(), getPhoneAccountHandle(), message);
118    } else {
119      VvmLog.i(
120          "StatusCheckTask.onExecuteInBackgroundThread",
121          "subscriber not ready, attempting reactivation");
122      VvmAccountManager.removeAccount(getContext(), getPhoneAccountHandle());
123      LoggerUtils.logImpressionOnMainThread(
124          getContext(), DialerImpression.Type.VVM_STATUS_CHECK_REACTIVATION);
125      ActivationTask.start(getContext(), getPhoneAccountHandle(), data);
126    }
127  }
128}
129