• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static com.android.systemui.statusbar.connectivity.NetworkControllerImpl.TAG;
19 
20 import android.annotation.NonNull;
21 import android.content.Context;
22 import android.util.Log;
23 
24 import com.android.settingslib.SignalIcon.IconGroup;
25 import com.android.systemui.dump.DumpsysTableLogger;
26 
27 import java.io.PrintWriter;
28 import java.util.ArrayList;
29 import java.util.BitSet;
30 import java.util.List;
31 
32 /**
33  * Common base class for handling signal for both wifi and mobile data.
34  *
35  * @param <T> State of the SysUI controller.
36  * @param <I> Icon groups of the SysUI controller for a given State.
37  *
38  * @deprecated "Use Recommended Architecture classes instead: MobileIconsInteractor, WifiInteractor,
39  * AirplaneModeInteractor, and EthernetInteractor
40  */
41 @Deprecated
42 public abstract class SignalController<T extends ConnectivityState, I extends IconGroup> {
43     // Save the previous SignalController.States of all SignalControllers for dumps.
44     static final boolean RECORD_HISTORY = true;
45     // If RECORD_HISTORY how many to save, must be a power of 2.
46     static final int HISTORY_SIZE = 64;
47 
48     protected static final boolean DEBUG = NetworkControllerImpl.DEBUG;
49     protected static final boolean CHATTY = NetworkControllerImpl.CHATTY;
50 
51     protected final String mTag;
52     protected final T mCurrentState;
53     protected final T mLastState;
54     protected final int mTransportType;
55     protected final Context mContext;
56     // The owner of the SignalController (i.e. NetworkController) will maintain the following
57     // lists and call notifyListeners whenever the list has changed to ensure everyone
58     // is aware of current state.
59     protected final NetworkControllerImpl mNetworkController;
60 
61     private final CallbackHandler mCallbackHandler;
62 
63     // Save the previous HISTORY_SIZE states for logging.
64     private final ConnectivityState[] mHistory;
65     // Where to copy the next state into.
66     private int mHistoryIndex;
67 
SignalController(String tag, Context context, int type, CallbackHandler callbackHandler, NetworkControllerImpl networkController)68     public SignalController(String tag, Context context, int type, CallbackHandler callbackHandler,
69             NetworkControllerImpl networkController) {
70         mTag = TAG + "." + tag;
71         mNetworkController = networkController;
72         mTransportType = type;
73         mContext = context;
74         mCallbackHandler = callbackHandler;
75         mCurrentState = cleanState();
76         mLastState = cleanState();
77         if (RECORD_HISTORY) {
78             mHistory = new ConnectivityState[HISTORY_SIZE];
79             for (int i = 0; i < HISTORY_SIZE; i++) {
80                 mHistory[i] = cleanState();
81             }
82         }
83     }
84 
getState()85     public T getState() {
86         return mCurrentState;
87     }
88 
updateConnectivity(BitSet connectedTransports, BitSet validatedTransports)89     void updateConnectivity(BitSet connectedTransports, BitSet validatedTransports) {
90         mCurrentState.inetCondition = validatedTransports.get(mTransportType) ? 1 : 0;
91         notifyListenersIfNecessary();
92     }
93 
94     /**
95      * Used at the end of demo mode to clear out any ugly state that it has created.
96      * Since we haven't had any callbacks, then isDirty will not have been triggered,
97      * so we can just take the last good state directly from there.
98      *
99      * Used for demo mode.
100      */
resetLastState()101     public void resetLastState() {
102         mCurrentState.copyFrom(mLastState);
103     }
104 
105     /**
106      * Determines if the state of this signal controller has changed and
107      * needs to trigger callbacks related to it.
108      */
isDirty()109     boolean isDirty() {
110         if (!mLastState.equals(mCurrentState)) {
111             if (DEBUG) {
112                 Log.d(mTag, "Change in state from: " + mLastState + "\n"
113                         + "\tto: " + mCurrentState);
114             }
115             return true;
116         }
117         return false;
118     }
119 
saveLastState()120     void saveLastState() {
121         if (RECORD_HISTORY) {
122             recordLastState();
123         }
124         // Updates the current time.
125         mCurrentState.time = System.currentTimeMillis();
126         mLastState.copyFrom(mCurrentState);
127     }
128 
129     /**
130      * Gets the signal icon for QS based on current state of connected, enabled, and level.
131      */
getQsCurrentIconId()132     public int getQsCurrentIconId() {
133         if (mCurrentState.connected) {
134             return getIcons().qsIcons[mCurrentState.inetCondition][mCurrentState.level];
135         } else if (mCurrentState.enabled) {
136             return getIcons().qsDiscState;
137         } else {
138             return getIcons().qsNullState;
139         }
140     }
141 
142     /**
143      * Gets the signal icon for SB based on current state of connected, enabled, and level.
144      */
getCurrentIconId()145     public int getCurrentIconId() {
146         if (mCurrentState.connected) {
147             return getIcons().sbIcons[mCurrentState.inetCondition][mCurrentState.level];
148         } else if (mCurrentState.enabled) {
149             return getIcons().sbDiscState;
150         } else {
151             return getIcons().sbNullState;
152         }
153     }
154 
155     /**
156      * Gets the content description id for the signal based on current state of connected and
157      * level.
158      */
getContentDescription()159     public int getContentDescription() {
160         if (mCurrentState.connected) {
161             return getIcons().contentDesc[mCurrentState.level];
162         } else {
163             return getIcons().discContentDesc;
164         }
165     }
166 
notifyListenersIfNecessary()167     void notifyListenersIfNecessary() {
168         if (isDirty()) {
169             saveLastState();
170             notifyListeners();
171         }
172     }
173 
174     /**
175      * Returns the resource if resId is not 0, and an empty string otherwise.
176      */
getTextIfExists(int resId)177     @NonNull CharSequence getTextIfExists(int resId) {
178         return resId != 0 ? mContext.getText(resId) : "";
179     }
180 
getIcons()181     protected I getIcons() {
182         return (I) mCurrentState.iconGroup;
183     }
184 
185     /**
186      * Saves the last state of any changes, so we can log the current
187      * and last value of any state data.
188      */
recordLastState()189     protected void recordLastState() {
190         mHistory[mHistoryIndex].copyFrom(mLastState);
191         mHistoryIndex = (mHistoryIndex + 1) % HISTORY_SIZE;
192     }
193 
dump(PrintWriter pw)194     void dump(PrintWriter pw) {
195         pw.println("  - " + mTag + " -----");
196         pw.println("  Current State: " + mCurrentState);
197         if (RECORD_HISTORY) {
198             List<ConnectivityState> history = getOrderedHistoryExcludingCurrentState();
199             for (int i = 0; i < history.size(); i++) {
200                 pw.println("  Previous State(" + (i + 1) + "): " + mHistory[i]);
201             }
202         }
203     }
204 
205     /**
206      * mHistory is a ring, so use this method to get the time-ordered (from youngest to oldest)
207      * list of historical states. Filters out any state whose `time` is `0`.
208      *
209      * For ease of compatibility, this list returns JUST the historical states, not the current
210      * state which has yet to be copied into the history
211      *
212      * @see #getOrderedHistory()
213      * @return historical states, ordered from newest to oldest
214      */
getOrderedHistoryExcludingCurrentState()215     List<ConnectivityState> getOrderedHistoryExcludingCurrentState() {
216         ArrayList<ConnectivityState> history = new ArrayList<>();
217 
218         // Count up the states that actually contain time stamps, and only display those.
219         int size = 0;
220         for (int i = 0; i < HISTORY_SIZE; i++) {
221             if (mHistory[i].time != 0) size++;
222         }
223         // Print out the previous states in ordered number.
224         for (int i = mHistoryIndex + HISTORY_SIZE - 1;
225                 i >= mHistoryIndex + HISTORY_SIZE - size; i--) {
226             history.add(mHistory[i & (HISTORY_SIZE - 1)]);
227         }
228 
229         return history;
230     }
231 
232     /**
233      * Get the ordered history states, including the current yet-to-be-copied state. Useful for
234      * logging
235      *
236      * @see #getOrderedHistoryExcludingCurrentState()
237      * @return [currentState, historicalState...] array
238      */
getOrderedHistory()239     List<ConnectivityState> getOrderedHistory() {
240         ArrayList<ConnectivityState> history = new ArrayList<>();
241         // Start with the current state
242         history.add(mCurrentState);
243         history.addAll(getOrderedHistoryExcludingCurrentState());
244         return history;
245     }
246 
dumpTableData(PrintWriter pw)247     void dumpTableData(PrintWriter pw) {
248         List<List<String>> tableData = new ArrayList<List<String>>();
249         List<ConnectivityState> history = getOrderedHistory();
250         for (int i = 0; i < history.size(); i++) {
251             tableData.add(history.get(i).tableData());
252         }
253 
254         DumpsysTableLogger logger =
255                 new DumpsysTableLogger(mTag, mCurrentState.tableColumns(), tableData);
256 
257         logger.printTableData(pw);
258     }
259 
notifyListeners()260     final void notifyListeners() {
261         notifyListeners(mCallbackHandler);
262     }
263 
264     /**
265      * Trigger callbacks based on current state.  The callbacks should be completely
266      * based on current state, and only need to be called in the scenario where
267      * mCurrentState != mLastState.
268      */
notifyListeners(SignalCallback callback)269     abstract void notifyListeners(SignalCallback callback);
270 
271     /**
272      * Generate a blank T.
273      */
cleanState()274     protected abstract T cleanState();
275 }
276