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