1 /* 2 * Copyright (C) 2016 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.dialer.app.voicemail; 18 19 import android.content.Context; 20 import android.database.ContentObserver; 21 import android.database.Cursor; 22 import android.os.Handler; 23 import android.support.annotation.MainThread; 24 import android.telecom.PhoneAccountHandle; 25 import android.telephony.PhoneStateListener; 26 import android.telephony.ServiceState; 27 import android.telephony.TelephonyManager; 28 import android.util.ArrayMap; 29 import com.android.dialer.app.calllog.CallLogAlertManager; 30 import com.android.dialer.app.calllog.CallLogModalAlertManager; 31 import com.android.dialer.common.Assert; 32 import com.android.dialer.common.LogUtil; 33 import com.android.dialer.database.CallLogQueryHandler; 34 import com.android.dialer.voicemail.listui.error.VoicemailErrorAlert; 35 import com.android.dialer.voicemail.listui.error.VoicemailErrorMessageCreator; 36 import com.android.dialer.voicemail.listui.error.VoicemailStatus; 37 import com.android.dialer.voicemail.listui.error.VoicemailStatusReader; 38 import com.android.voicemail.VoicemailComponent; 39 import java.util.ArrayList; 40 import java.util.List; 41 import java.util.Map; 42 43 /** 44 * Fetches voicemail status and generate {@link VoicemailStatus} for {@link VoicemailErrorAlert} to 45 * show. 46 */ 47 public class VoicemailErrorManager implements CallLogQueryHandler.Listener, VoicemailStatusReader { 48 49 private final Context context; 50 private final CallLogQueryHandler callLogQueryHandler; 51 private final VoicemailErrorAlert alertItem; 52 53 private final Map<PhoneAccountHandle, ServiceStateListener> listeners = new ArrayMap<>(); 54 55 private final ContentObserver statusObserver = 56 new ContentObserver(new Handler()) { 57 @Override 58 public void onChange(boolean selfChange) { 59 super.onChange(selfChange); 60 fetchStatus(); 61 } 62 }; 63 64 private boolean isForeground; 65 private boolean statusInvalidated; 66 VoicemailErrorManager( Context context, CallLogAlertManager alertManager, CallLogModalAlertManager modalAlertManager)67 public VoicemailErrorManager( 68 Context context, 69 CallLogAlertManager alertManager, 70 CallLogModalAlertManager modalAlertManager) { 71 this.context = context; 72 alertItem = 73 new VoicemailErrorAlert( 74 context, alertManager, modalAlertManager, new VoicemailErrorMessageCreator()); 75 callLogQueryHandler = new CallLogQueryHandler(context, context.getContentResolver(), this); 76 fetchStatus(); 77 } 78 getContentObserver()79 public ContentObserver getContentObserver() { 80 return statusObserver; 81 } 82 83 @MainThread 84 @Override onVoicemailStatusFetched(Cursor statusCursor)85 public void onVoicemailStatusFetched(Cursor statusCursor) { 86 List<VoicemailStatus> statuses = new ArrayList<>(); 87 while (statusCursor.moveToNext()) { 88 VoicemailStatus status = new VoicemailStatus(context, statusCursor); 89 if (status.isActive(context)) { 90 statuses.add(status); 91 addServiceStateListener(status); 92 } else { 93 LogUtil.i("VisualVoicemailCallLogFragment.shouldAutoSync", "inactive source ignored"); 94 } 95 } 96 alertItem.updateStatus(statuses, this); 97 // TODO(twyen): a bug support error from multiple sources. 98 return; 99 } 100 101 @MainThread addServiceStateListener(VoicemailStatus status)102 private void addServiceStateListener(VoicemailStatus status) { 103 Assert.isMainThread(); 104 if (!VoicemailComponent.get(context).getVoicemailClient().isVoicemailModuleEnabled()) { 105 LogUtil.i("VoicemailErrorManager.addServiceStateListener", "VVM module not enabled"); 106 return; 107 } 108 if (!status.sourcePackage.equals(context.getPackageName())) { 109 LogUtil.i("VoicemailErrorManager.addServiceStateListener", "non-dialer source"); 110 return; 111 } 112 TelephonyManager telephonyManager = 113 context 114 .getSystemService(TelephonyManager.class) 115 .createForPhoneAccountHandle(status.getPhoneAccountHandle()); 116 if (telephonyManager == null) { 117 LogUtil.e("VoicemailErrorManager.addServiceStateListener", "invalid PhoneAccountHandle"); 118 return; 119 } 120 PhoneAccountHandle phoneAccountHandle = status.getPhoneAccountHandle(); 121 if (listeners.containsKey(phoneAccountHandle)) { 122 return; 123 } 124 LogUtil.i( 125 "VoicemailErrorManager.addServiceStateListener", 126 "adding listener for " + phoneAccountHandle); 127 ServiceStateListener serviceStateListener = new ServiceStateListener(); 128 telephonyManager.listen(serviceStateListener, PhoneStateListener.LISTEN_SERVICE_STATE); 129 listeners.put(phoneAccountHandle, serviceStateListener); 130 } 131 132 @Override onVoicemailUnreadCountFetched(Cursor cursor)133 public void onVoicemailUnreadCountFetched(Cursor cursor) { 134 // Do nothing 135 } 136 137 @Override onMissedCallsUnreadCountFetched(Cursor cursor)138 public void onMissedCallsUnreadCountFetched(Cursor cursor) { 139 // Do nothing 140 } 141 142 @Override onCallsFetched(Cursor combinedCursor)143 public boolean onCallsFetched(Cursor combinedCursor) { 144 // Do nothing 145 return false; 146 } 147 onResume()148 public void onResume() { 149 isForeground = true; 150 if (statusInvalidated) { 151 fetchStatus(); 152 } 153 } 154 onPause()155 public void onPause() { 156 isForeground = false; 157 statusInvalidated = false; 158 } 159 onDestroy()160 public void onDestroy() { 161 TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); 162 for (ServiceStateListener listener : listeners.values()) { 163 telephonyManager.listen(listener, PhoneStateListener.LISTEN_NONE); 164 } 165 } 166 167 @Override refresh()168 public void refresh() { 169 fetchStatus(); 170 } 171 172 /** 173 * Fetch the status when the dialer is in foreground, or queue a fetch when the dialer resumes. 174 */ fetchStatus()175 private void fetchStatus() { 176 if (!isForeground) { 177 // Dialer is in the background, UI should not be updated. Reload the status when it resumes. 178 statusInvalidated = true; 179 return; 180 } 181 callLogQueryHandler.fetchVoicemailStatus(); 182 } 183 184 private class ServiceStateListener extends PhoneStateListener { 185 186 @Override onServiceStateChanged(ServiceState serviceState)187 public void onServiceStateChanged(ServiceState serviceState) { 188 fetchStatus(); 189 } 190 } 191 } 192