1 /*
2  * Copyright (C) 2015 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 package com.android.systemui.statusbar.connectivity;
17 
18 import android.os.Handler;
19 import android.os.Looper;
20 import android.os.Message;
21 import android.telephony.SubscriptionInfo;
22 
23 import com.android.internal.annotations.VisibleForTesting;
24 import com.android.systemui.dagger.SysUISingleton;
25 import com.android.systemui.dagger.qualifiers.Main;
26 import com.android.systemui.statusbar.connectivity.NetworkController.EmergencyListener;
27 
28 import java.io.PrintWriter;
29 import java.text.SimpleDateFormat;
30 import java.util.ArrayList;
31 import java.util.List;
32 
33 import javax.inject.Inject;
34 
35 
36 /**
37  * Implements network listeners and forwards the calls along onto other listeners but on
38  * the current or specified Looper.
39  */
40 @SysUISingleton
41 public class CallbackHandler extends Handler implements EmergencyListener, SignalCallback {
42     private static final String TAG = "CallbackHandler";
43     private static final int MSG_EMERGENCE_CHANGED           = 0;
44     private static final int MSG_SUBS_CHANGED                = 1;
45     private static final int MSG_NO_SIM_VISIBLE_CHANGED      = 2;
46     private static final int MSG_ETHERNET_CHANGED            = 3;
47     private static final int MSG_AIRPLANE_MODE_CHANGED       = 4;
48     private static final int MSG_MOBILE_DATA_ENABLED_CHANGED = 5;
49     private static final int MSG_ADD_REMOVE_EMERGENCY        = 6;
50     private static final int MSG_ADD_REMOVE_SIGNAL           = 7;
51     private static final int HISTORY_SIZE = 64;
52     private static final SimpleDateFormat SSDF = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
53 
54     // All the callbacks.
55     private final ArrayList<EmergencyListener> mEmergencyListeners = new ArrayList<>();
56     private final ArrayList<SignalCallback> mSignalCallbacks = new ArrayList<>();
57 
58     // Save the previous HISTORY_SIZE states for logging.
59     private final String[] mHistory = new String[HISTORY_SIZE];
60     // Where to copy the next state into.
61     private int mHistoryIndex;
62     private String mLastCallback;
63 
64     @Inject
65     @VisibleForTesting
CallbackHandler(@ain Looper looper)66     CallbackHandler(@Main Looper looper) {
67         super(looper);
68     }
69 
70     @Override
71     @SuppressWarnings("unchecked")
handleMessage(Message msg)72     public void handleMessage(Message msg) {
73         switch (msg.what) {
74             case MSG_EMERGENCE_CHANGED:
75                 for (EmergencyListener listener : mEmergencyListeners) {
76                     listener.setEmergencyCallsOnly(msg.arg1 != 0);
77                 }
78                 break;
79             case MSG_SUBS_CHANGED:
80                 for (SignalCallback signalCluster : mSignalCallbacks) {
81                     signalCluster.setSubs((List<SubscriptionInfo>) msg.obj);
82                 }
83                 break;
84             case MSG_NO_SIM_VISIBLE_CHANGED:
85                 for (SignalCallback signalCluster : mSignalCallbacks) {
86                     signalCluster.setNoSims(msg.arg1 != 0, msg.arg2 != 0);
87                 }
88                 break;
89             case MSG_ETHERNET_CHANGED:
90                 for (SignalCallback signalCluster : mSignalCallbacks) {
91                     signalCluster.setEthernetIndicators((IconState) msg.obj);
92                 }
93                 break;
94             case MSG_AIRPLANE_MODE_CHANGED:
95                 for (SignalCallback signalCluster : mSignalCallbacks) {
96                     signalCluster.setIsAirplaneMode((IconState) msg.obj);
97                 }
98                 break;
99             case MSG_MOBILE_DATA_ENABLED_CHANGED:
100                 for (SignalCallback signalCluster : mSignalCallbacks) {
101                     signalCluster.setMobileDataEnabled(msg.arg1 != 0);
102                 }
103                 break;
104             case MSG_ADD_REMOVE_EMERGENCY:
105                 if (msg.arg1 != 0) {
106                     mEmergencyListeners.add((EmergencyListener) msg.obj);
107                 } else {
108                     mEmergencyListeners.remove((EmergencyListener) msg.obj);
109                 }
110                 break;
111             case MSG_ADD_REMOVE_SIGNAL:
112                 if (msg.arg1 != 0) {
113                     mSignalCallbacks.add((SignalCallback) msg.obj);
114                 } else {
115                     mSignalCallbacks.remove((SignalCallback) msg.obj);
116                 }
117                 break;
118         }
119     }
120 
121     @Override
setWifiIndicators(final WifiIndicators indicators)122     public void setWifiIndicators(final WifiIndicators indicators) {
123         String log = new StringBuilder()
124                 .append(SSDF.format(System.currentTimeMillis())).append(",")
125                 .append(indicators)
126                 .toString();
127         recordLastCallback(log);
128         post(() -> {
129             for (SignalCallback callback : mSignalCallbacks) {
130                 callback.setWifiIndicators(indicators);
131             }
132         });
133     }
134 
135     @Override
setMobileDataIndicators(final MobileDataIndicators indicators)136     public void setMobileDataIndicators(final MobileDataIndicators indicators) {
137         String log = new StringBuilder()
138                 .append(SSDF.format(System.currentTimeMillis())).append(",")
139                 .append(indicators)
140                 .toString();
141         recordLastCallback(log);
142         post(() -> {
143             for (SignalCallback signalCluster : mSignalCallbacks) {
144                 signalCluster.setMobileDataIndicators(indicators);
145             }
146         });
147     }
148 
149     @Override
setConnectivityStatus(boolean noDefaultNetwork, boolean noValidatedNetwork, boolean noNetworksAvailable)150     public void setConnectivityStatus(boolean noDefaultNetwork, boolean noValidatedNetwork,
151                 boolean noNetworksAvailable) {
152         String currentCallback = new StringBuilder()
153                 .append("setConnectivityStatus: ")
154                 .append("noDefaultNetwork=").append(noDefaultNetwork).append(",")
155                 .append("noValidatedNetwork=").append(noValidatedNetwork).append(",")
156                 .append("noNetworksAvailable=").append(noNetworksAvailable)
157                 .toString();
158         if (!currentCallback.equals(mLastCallback)) {
159             mLastCallback = currentCallback;
160             String log = new StringBuilder()
161                     .append(SSDF.format(System.currentTimeMillis())).append(",")
162                     .append(currentCallback).append(",")
163                     .toString();
164             recordLastCallback(log);
165         }
166         post(() -> {
167             for (SignalCallback signalCluster : mSignalCallbacks) {
168                 signalCluster.setConnectivityStatus(
169                         noDefaultNetwork, noValidatedNetwork, noNetworksAvailable);
170             }
171         });
172     }
173 
174     @Override
setCallIndicator(IconState statusIcon, int subId)175     public void setCallIndicator(IconState statusIcon, int subId) {
176         String currentCallback = new StringBuilder()
177                 .append("setCallIndicator: ")
178                 .append("statusIcon=").append(statusIcon).append(",")
179                 .append("subId=").append(subId)
180                 .toString();
181         if (!currentCallback.equals(mLastCallback)) {
182             mLastCallback = currentCallback;
183             String log = new StringBuilder()
184                     .append(SSDF.format(System.currentTimeMillis())).append(",")
185                     .append(currentCallback).append(",")
186                     .toString();
187             recordLastCallback(log);
188         }
189         post(() -> {
190             for (SignalCallback signalCluster : mSignalCallbacks) {
191                 signalCluster.setCallIndicator(statusIcon, subId);
192             }
193         });
194     }
195 
196     @Override
setSubs(List<SubscriptionInfo> subs)197     public void setSubs(List<SubscriptionInfo> subs) {
198         String currentCallback = new StringBuilder()
199                 .append("setSubs: ")
200                 .append("subs=").append(subs == null ? "" : subs.toString())
201                 .toString();
202         if (!currentCallback.equals(mLastCallback)) {
203             mLastCallback = currentCallback;
204             String log = new StringBuilder()
205                     .append(SSDF.format(System.currentTimeMillis())).append(",")
206                     .append(currentCallback).append(",")
207                     .toString();
208             recordLastCallback(log);
209         }
210         obtainMessage(MSG_SUBS_CHANGED, subs).sendToTarget();
211     }
212 
213     @Override
setNoSims(boolean show, boolean simDetected)214     public void setNoSims(boolean show, boolean simDetected) {
215         obtainMessage(MSG_NO_SIM_VISIBLE_CHANGED, show ? 1 : 0, simDetected ? 1 : 0).sendToTarget();
216     }
217 
218     @Override
setMobileDataEnabled(boolean enabled)219     public void setMobileDataEnabled(boolean enabled) {
220         obtainMessage(MSG_MOBILE_DATA_ENABLED_CHANGED, enabled ? 1 : 0, 0).sendToTarget();
221     }
222 
223     @Override
setEmergencyCallsOnly(boolean emergencyOnly)224     public void setEmergencyCallsOnly(boolean emergencyOnly) {
225         obtainMessage(MSG_EMERGENCE_CHANGED, emergencyOnly ? 1 : 0, 0).sendToTarget();
226     }
227 
228     @Override
setEthernetIndicators(IconState icon)229     public void setEthernetIndicators(IconState icon) {
230         String log = new StringBuilder()
231                 .append(SSDF.format(System.currentTimeMillis())).append(",")
232                 .append("setEthernetIndicators: ")
233                 .append("icon=").append(icon)
234                 .toString();
235         recordLastCallback(log);
236         obtainMessage(MSG_ETHERNET_CHANGED, icon).sendToTarget();
237     }
238 
239     @Override
setIsAirplaneMode(IconState icon)240     public void setIsAirplaneMode(IconState icon) {
241         String currentCallback = new StringBuilder()
242                 .append("setIsAirplaneMode: ")
243                 .append("icon=").append(icon)
244                 .toString();
245         if (!currentCallback.equals(mLastCallback)) {
246             mLastCallback = currentCallback;
247             String log = new StringBuilder()
248                     .append(SSDF.format(System.currentTimeMillis())).append(",")
249                     .append(currentCallback).append(",")
250                     .toString();
251             recordLastCallback(log);
252         }
253         obtainMessage(MSG_AIRPLANE_MODE_CHANGED, icon).sendToTarget();
254     }
255 
setListening(EmergencyListener listener, boolean listening)256     void setListening(EmergencyListener listener, boolean listening) {
257         obtainMessage(MSG_ADD_REMOVE_EMERGENCY, listening ? 1 : 0, 0, listener).sendToTarget();
258     }
259 
setListening(SignalCallback listener, boolean listening)260     void setListening(SignalCallback listener, boolean listening) {
261         obtainMessage(MSG_ADD_REMOVE_SIGNAL, listening ? 1 : 0, 0, listener).sendToTarget();
262     }
263 
recordLastCallback(String callback)264     protected void recordLastCallback(String callback) {
265         mHistory[mHistoryIndex] = callback;
266         mHistoryIndex = (mHistoryIndex + 1) % HISTORY_SIZE;
267     }
268 
269     /**
270      * Dump the Callback logs
271      */
dump(PrintWriter pw)272     public void dump(PrintWriter pw) {
273         pw.println("  - CallbackHandler -----");
274         int size = 0;
275         for (int i = 0; i < HISTORY_SIZE; i++) {
276             if (mHistory[i] != null) {
277                 size++;
278             }
279         }
280         // Print out the previous states in ordered number.
281         for (int i = mHistoryIndex + HISTORY_SIZE - 1;
282                 i >= mHistoryIndex + HISTORY_SIZE - size; i--) {
283             pw.println("  Previous Callback(" + (mHistoryIndex + HISTORY_SIZE - i) + "): "
284                     + mHistory[i & (HISTORY_SIZE - 1)]);
285         }
286     }
287 
288 }
289