• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.app.voicemail.error.VoicemailErrorAlert;
32 import com.android.dialer.app.voicemail.error.VoicemailErrorMessageCreator;
33 import com.android.dialer.app.voicemail.error.VoicemailStatus;
34 import com.android.dialer.app.voicemail.error.VoicemailStatusReader;
35 import com.android.dialer.common.Assert;
36 import com.android.dialer.common.LogUtil;
37 import com.android.dialer.database.CallLogQueryHandler;
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()) {
90         statuses.add(status);
91         addServiceStateListener(status);
92       }
93     }
94     alertItem.updateStatus(statuses, this);
95     // TODO: b/30668323 support error from multiple sources.
96     return;
97   }
98 
99   @MainThread
addServiceStateListener(VoicemailStatus status)100   private void addServiceStateListener(VoicemailStatus status) {
101     Assert.isMainThread();
102     if (!VoicemailComponent.get(context).getVoicemailClient().isVoicemailModuleEnabled()) {
103       LogUtil.i("VoicemailErrorManager.addServiceStateListener", "VVM module not enabled");
104       return;
105     }
106     if (!status.sourcePackage.equals(context.getPackageName())) {
107       LogUtil.i("VoicemailErrorManager.addServiceStateListener", "non-dialer source");
108       return;
109     }
110     TelephonyManager telephonyManager =
111         context
112             .getSystemService(TelephonyManager.class)
113             .createForPhoneAccountHandle(status.getPhoneAccountHandle());
114     if (telephonyManager == null) {
115       LogUtil.e("VoicemailErrorManager.addServiceStateListener", "invalid PhoneAccountHandle");
116       return;
117     }
118     PhoneAccountHandle phoneAccountHandle = status.getPhoneAccountHandle();
119     if (listeners.containsKey(phoneAccountHandle)) {
120       return;
121     }
122     LogUtil.i(
123         "VoicemailErrorManager.addServiceStateListener",
124         "adding listener for " + phoneAccountHandle);
125     ServiceStateListener serviceStateListener = new ServiceStateListener();
126     telephonyManager.listen(serviceStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
127     listeners.put(phoneAccountHandle, serviceStateListener);
128   }
129 
130   @Override
onVoicemailUnreadCountFetched(Cursor cursor)131   public void onVoicemailUnreadCountFetched(Cursor cursor) {
132     // Do nothing
133   }
134 
135   @Override
onMissedCallsUnreadCountFetched(Cursor cursor)136   public void onMissedCallsUnreadCountFetched(Cursor cursor) {
137     // Do nothing
138   }
139 
140   @Override
onCallsFetched(Cursor combinedCursor)141   public boolean onCallsFetched(Cursor combinedCursor) {
142     // Do nothing
143     return false;
144   }
145 
onResume()146   public void onResume() {
147     isForeground = true;
148     if (statusInvalidated) {
149       fetchStatus();
150     }
151   }
152 
onPause()153   public void onPause() {
154     isForeground = false;
155     statusInvalidated = false;
156   }
157 
onDestroy()158   public void onDestroy() {
159     TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
160     for (ServiceStateListener listener : listeners.values()) {
161       telephonyManager.listen(listener, PhoneStateListener.LISTEN_NONE);
162     }
163   }
164 
165   @Override
refresh()166   public void refresh() {
167     fetchStatus();
168   }
169 
170   /**
171    * Fetch the status when the dialer is in foreground, or queue a fetch when the dialer resumes.
172    */
fetchStatus()173   private void fetchStatus() {
174     if (!isForeground) {
175       // Dialer is in the background, UI should not be updated. Reload the status when it resumes.
176       statusInvalidated = true;
177       return;
178     }
179     callLogQueryHandler.fetchVoicemailStatus();
180   }
181 
182   private class ServiceStateListener extends PhoneStateListener {
183 
184     @Override
onServiceStateChanged(ServiceState serviceState)185     public void onServiceStateChanged(ServiceState serviceState) {
186       fetchStatus();
187     }
188   }
189 }
190