blob: 3447f03dfa1b954e8505de64e048fbaae3386e8f [file] [log] [blame]
/*
* Copyright (C) 2016 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.dialer.voicemail.listui.error;
import android.annotation.TargetApi;
import android.content.ComponentName;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.provider.VoicemailContract.Status;
import android.support.annotation.Nullable;
import android.support.v4.os.BuildCompat;
import android.telecom.PhoneAccountHandle;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import com.android.dialer.common.LogUtil;
import com.android.dialer.database.VoicemailStatusQuery;
/** Structured data from {@link android.provider.VoicemailContract.Status} */
public class VoicemailStatus {
public final String sourcePackage;
public final String type;
public final String phoneAccountComponentName;
public final String phoneAccountId;
@Nullable public final Uri settingsUri;
@Nullable public final Uri voicemailAccessUri;
public final int configurationState;
public final int dataChannelState;
public final int notificationChannelState;
public final int quotaOccupied;
public final int quotaTotal;
// System status
public final boolean isAirplaneMode;
/** Wraps the row currently pointed by <code>statusCursor</code> */
public VoicemailStatus(Context context, Cursor statusCursor) {
sourcePackage = getString(statusCursor, VoicemailStatusQuery.SOURCE_PACKAGE_INDEX, "");
settingsUri = getUri(statusCursor, VoicemailStatusQuery.SETTINGS_URI_INDEX);
voicemailAccessUri = getUri(statusCursor, VoicemailStatusQuery.VOICEMAIL_ACCESS_URI_INDEX);
if (VERSION.SDK_INT >= VERSION_CODES.N_MR1) {
type =
getString(
statusCursor, VoicemailStatusQuery.SOURCE_TYPE_INDEX, TelephonyManager.VVM_TYPE_OMTP);
phoneAccountComponentName =
getString(statusCursor, VoicemailStatusQuery.PHONE_ACCOUNT_COMPONENT_NAME, "");
phoneAccountId = getString(statusCursor, VoicemailStatusQuery.PHONE_ACCOUNT_ID, "");
} else {
type = TelephonyManager.VVM_TYPE_OMTP;
phoneAccountComponentName = "";
phoneAccountId = "";
}
configurationState =
getInt(
statusCursor,
VoicemailStatusQuery.CONFIGURATION_STATE_INDEX,
Status.CONFIGURATION_STATE_NOT_CONFIGURED);
dataChannelState =
getInt(
statusCursor,
VoicemailStatusQuery.DATA_CHANNEL_STATE_INDEX,
Status.DATA_CHANNEL_STATE_NO_CONNECTION);
/* Before O, the NOTIFICATION_CHANNEL_STATE in the voicemail status table for the system
* visual voicemail client always correspond to the service state (cellular signal availability)
* Tracking the state in the background is redundant because it will not be visible to the
* user. It is much simpler to poll the status on the UI side. The result is injected back to
* the status query result so the handling will be consistent with other voicemail clients.
*/
if (BuildCompat.isAtLeastO() && sourcePackage.equals(context.getPackageName())) {
notificationChannelState =
getNotificationChannelStateFormTelephony(context, getPhoneAccountHandle());
} else {
notificationChannelState =
getInt(
statusCursor,
VoicemailStatusQuery.NOTIFICATION_CHANNEL_STATE_INDEX,
Status.NOTIFICATION_CHANNEL_STATE_NO_CONNECTION);
}
isAirplaneMode =
Settings.System.getInt(context.getContentResolver(), Global.AIRPLANE_MODE_ON, 0) != 0;
if (VERSION.SDK_INT >= VERSION_CODES.N) {
quotaOccupied =
getInt(statusCursor, VoicemailStatusQuery.QUOTA_OCCUPIED_INDEX, Status.QUOTA_UNAVAILABLE);
quotaTotal =
getInt(statusCursor, VoicemailStatusQuery.QUOTA_TOTAL_INDEX, Status.QUOTA_UNAVAILABLE);
} else {
quotaOccupied = Status.QUOTA_UNAVAILABLE;
quotaTotal = Status.QUOTA_UNAVAILABLE;
}
}
private VoicemailStatus(Builder builder) {
sourcePackage = builder.sourcePackage;
phoneAccountComponentName = builder.phoneAccountComponentName;
phoneAccountId = builder.phoneAccountId;
type = builder.type;
settingsUri = builder.settingsUri;
voicemailAccessUri = builder.voicemailAccessUri;
configurationState = builder.configurationState;
dataChannelState = builder.dataChannelState;
notificationChannelState = builder.notificationChannelState;
quotaOccupied = builder.quotaOccupied;
quotaTotal = builder.quotaTotal;
isAirplaneMode = builder.isAirplaneMode;
}
@TargetApi(VERSION_CODES.O)
private static int getNotificationChannelStateFormTelephony(
Context context, PhoneAccountHandle phoneAccountHandle) {
TelephonyManager telephonyManager =
context
.getSystemService(TelephonyManager.class)
.createForPhoneAccountHandle(phoneAccountHandle);
if (telephonyManager == null) {
LogUtil.e("VoicemailStatus.constructor", "invalid PhoneAccountHandle");
return Status.NOTIFICATION_CHANNEL_STATE_NO_CONNECTION;
} else {
int state = telephonyManager.getServiceState().getState();
if (state == ServiceState.STATE_IN_SERVICE) {
return Status.NOTIFICATION_CHANNEL_STATE_OK;
} else {
return Status.NOTIFICATION_CHANNEL_STATE_NO_CONNECTION;
}
}
}
static class Builder {
private String sourcePackage = "";
private String type = TelephonyManager.VVM_TYPE_OMTP;
private String phoneAccountComponentName = "";
private String phoneAccountId = "";
@Nullable private Uri settingsUri;
@Nullable private Uri voicemailAccessUri;
private int configurationState = Status.CONFIGURATION_STATE_NOT_CONFIGURED;
private int dataChannelState = Status.DATA_CHANNEL_STATE_NO_CONNECTION;
private int notificationChannelState = Status.NOTIFICATION_CHANNEL_STATE_NO_CONNECTION;
private int quotaOccupied = Status.QUOTA_UNAVAILABLE;
private int quotaTotal = Status.QUOTA_UNAVAILABLE;
private boolean isAirplaneMode;
public VoicemailStatus build() {
return new VoicemailStatus(this);
}
public Builder setSourcePackage(String sourcePackage) {
this.sourcePackage = sourcePackage;
return this;
}
public Builder setType(String type) {
this.type = type;
return this;
}
public Builder setPhoneAccountComponentName(String name) {
this.phoneAccountComponentName = name;
return this;
}
public Builder setPhoneAccountId(String id) {
this.phoneAccountId = id;
return this;
}
public Builder setSettingsUri(Uri settingsUri) {
this.settingsUri = settingsUri;
return this;
}
public Builder setVoicemailAccessUri(Uri voicemailAccessUri) {
this.voicemailAccessUri = voicemailAccessUri;
return this;
}
public Builder setConfigurationState(int configurationState) {
this.configurationState = configurationState;
return this;
}
public Builder setDataChannelState(int dataChannelState) {
this.dataChannelState = dataChannelState;
return this;
}
public Builder setNotificationChannelState(int notificationChannelState) {
this.notificationChannelState = notificationChannelState;
return this;
}
public Builder setQuotaOccupied(int quotaOccupied) {
this.quotaOccupied = quotaOccupied;
return this;
}
public Builder setQuotaTotal(int quotaTotal) {
this.quotaTotal = quotaTotal;
return this;
}
public Builder setAirplaneMode(boolean isAirplaneMode) {
this.isAirplaneMode = isAirplaneMode;
return this;
}
}
public boolean isActive() {
switch (configurationState) {
case Status.CONFIGURATION_STATE_NOT_CONFIGURED:
case Status.CONFIGURATION_STATE_DISABLED:
return false;
default:
return true;
}
}
@Override
public String toString() {
return "VoicemailStatus["
+ "sourcePackage: "
+ sourcePackage
+ ", type:"
+ type
+ ", settingsUri: "
+ settingsUri
+ ", voicemailAccessUri: "
+ voicemailAccessUri
+ ", configurationState: "
+ configurationState
+ ", dataChannelState: "
+ dataChannelState
+ ", notificationChannelState: "
+ notificationChannelState
+ ", quotaOccupied: "
+ quotaOccupied
+ ", quotaTotal: "
+ quotaTotal
+ ", isAirplaneMode: "
+ isAirplaneMode
+ "]";
}
@Nullable
private static Uri getUri(Cursor cursor, int index) {
if (cursor.getString(index) != null) {
return Uri.parse(cursor.getString(index));
}
return null;
}
private static int getInt(Cursor cursor, int index, int defaultValue) {
if (cursor.isNull(index)) {
return defaultValue;
}
return cursor.getInt(index);
}
private static String getString(Cursor cursor, int index, String defaultValue) {
if (cursor.isNull(index)) {
return defaultValue;
}
return cursor.getString(index);
}
@Nullable
public PhoneAccountHandle getPhoneAccountHandle() {
if (TextUtils.isEmpty(phoneAccountComponentName) || TextUtils.isEmpty(phoneAccountId)) {
return null;
}
ComponentName componentName = ComponentName.unflattenFromString(phoneAccountComponentName);
if (componentName == null) {
return null;
}
return new PhoneAccountHandle(componentName, phoneAccountId);
}
}