1/* 2 * Copyright 2017 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 17package com.android.server.wifi; 18 19import android.util.ArraySet; 20import android.util.Log; 21 22import com.android.server.wifi.WifiConfigStore.StoreData; 23import com.android.server.wifi.util.XmlUtil; 24 25import org.xmlpull.v1.XmlPullParser; 26import org.xmlpull.v1.XmlPullParserException; 27import org.xmlpull.v1.XmlSerializer; 28 29import java.io.IOException; 30import java.util.Collections; 31import java.util.Set; 32 33/** 34 * Config store data for Wifi Wake. 35 */ 36public class WakeupConfigStoreData implements StoreData { 37 private static final String TAG = "WakeupConfigStoreData"; 38 39 private static final String XML_TAG_FEATURE_STATE_SECTION = "FeatureState"; 40 private static final String XML_TAG_IS_ACTIVE = "IsActive"; 41 private static final String XML_TAG_IS_ONBOARDED = "IsOnboarded"; 42 private static final String XML_TAG_NOTIFICATIONS_SHOWN = "NotificationsShown"; 43 private static final String XML_TAG_NETWORK_SECTION = "Network"; 44 private static final String XML_TAG_SSID = "SSID"; 45 private static final String XML_TAG_SECURITY = "Security"; 46 47 private final DataSource<Boolean> mIsActiveDataSource; 48 private final DataSource<Boolean> mIsOnboardedDataSource; 49 private final DataSource<Integer> mNotificationsDataSource; 50 private final DataSource<Set<ScanResultMatchInfo>> mNetworkDataSource; 51 private boolean mHasBeenRead = false; 52 53 /** 54 * Interface defining a data source for the store data. 55 * 56 * @param <T> Type of data source 57 */ 58 public interface DataSource<T> { 59 /** 60 * Returns the data from the data source. 61 */ 62 T getData(); 63 64 /** 65 * Updates the data in the data source. 66 * 67 * @param data Data retrieved from the store 68 */ 69 void setData(T data); 70 } 71 72 /** 73 * Creates the config store data with its data sources. 74 * 75 * @param isActiveDataSource Data source for isActive 76 * @param networkDataSource Data source for the locked network list 77 */ 78 public WakeupConfigStoreData( 79 DataSource<Boolean> isActiveDataSource, 80 DataSource<Boolean> isOnboardedDataSource, 81 DataSource<Integer> notificationsDataSource, 82 DataSource<Set<ScanResultMatchInfo>> networkDataSource) { 83 mIsActiveDataSource = isActiveDataSource; 84 mIsOnboardedDataSource = isOnboardedDataSource; 85 mNotificationsDataSource = notificationsDataSource; 86 mNetworkDataSource = networkDataSource; 87 } 88 89 /** 90 * Returns whether the user store has been read. 91 */ 92 public boolean hasBeenRead() { 93 return mHasBeenRead; 94 } 95 96 @Override 97 public void serializeData(XmlSerializer out, boolean shared) 98 throws XmlPullParserException, IOException { 99 if (shared) { 100 throw new XmlPullParserException("Share data not supported"); 101 } 102 103 writeFeatureState(out); 104 105 for (ScanResultMatchInfo scanResultMatchInfo : mNetworkDataSource.getData()) { 106 writeNetwork(out, scanResultMatchInfo); 107 } 108 } 109 110 /** 111 * Writes the current state of Wifi Wake to an XML output stream. 112 * 113 * @param out XML output stream 114 * @throws XmlPullParserException 115 * @throws IOException 116 */ 117 private void writeFeatureState(XmlSerializer out) 118 throws IOException, XmlPullParserException { 119 XmlUtil.writeNextSectionStart(out, XML_TAG_FEATURE_STATE_SECTION); 120 121 XmlUtil.writeNextValue(out, XML_TAG_IS_ACTIVE, mIsActiveDataSource.getData()); 122 XmlUtil.writeNextValue(out, XML_TAG_IS_ONBOARDED, mIsOnboardedDataSource.getData()); 123 XmlUtil.writeNextValue(out, XML_TAG_NOTIFICATIONS_SHOWN, 124 mNotificationsDataSource.getData()); 125 126 XmlUtil.writeNextSectionEnd(out, XML_TAG_FEATURE_STATE_SECTION); 127 } 128 129 /** 130 * Writes a {@link ScanResultMatchInfo} to an XML output stream. 131 * 132 * @param out XML output stream 133 * @param scanResultMatchInfo The ScanResultMatchInfo to serialize 134 * @throws XmlPullParserException 135 * @throws IOException 136 */ 137 private void writeNetwork(XmlSerializer out, ScanResultMatchInfo scanResultMatchInfo) 138 throws XmlPullParserException, IOException { 139 XmlUtil.writeNextSectionStart(out, XML_TAG_NETWORK_SECTION); 140 141 XmlUtil.writeNextValue(out, XML_TAG_SSID, scanResultMatchInfo.networkSsid); 142 XmlUtil.writeNextValue(out, XML_TAG_SECURITY, scanResultMatchInfo.networkType); 143 144 XmlUtil.writeNextSectionEnd(out, XML_TAG_NETWORK_SECTION); 145 } 146 147 @Override 148 public void deserializeData(XmlPullParser in, int outerTagDepth, boolean shared) 149 throws XmlPullParserException, IOException { 150 if (!shared) { 151 if (!mHasBeenRead) { 152 Log.d(TAG, "WifiWake user data has been read"); 153 mHasBeenRead = true; 154 } 155 } 156 157 // Ignore empty reads. 158 if (in == null) { 159 return; 160 } 161 if (shared) { 162 throw new XmlPullParserException("Shared data not supported"); 163 } 164 165 Set<ScanResultMatchInfo> networks = new ArraySet<>(); 166 167 String[] headerName = new String[1]; 168 while (XmlUtil.gotoNextSectionOrEnd(in, headerName, outerTagDepth)) { 169 switch (headerName[0]) { 170 case XML_TAG_FEATURE_STATE_SECTION: 171 parseFeatureState(in, outerTagDepth + 1); 172 break; 173 case XML_TAG_NETWORK_SECTION: 174 networks.add(parseNetwork(in, outerTagDepth + 1)); 175 break; 176 } 177 } 178 179 mNetworkDataSource.setData(networks); 180 } 181 182 /** 183 * Parses the state of Wifi Wake from an XML input stream and sets the respective data sources. 184 * 185 * @param in XML input stream 186 * @param outerTagDepth XML tag depth of the containing section 187 * @throws IOException 188 * @throws XmlPullParserException 189 */ 190 private void parseFeatureState(XmlPullParser in, int outerTagDepth) 191 throws IOException, XmlPullParserException { 192 boolean isActive = false; 193 boolean isOnboarded = false; 194 int notificationsShown = 0; 195 196 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 197 String[] valueName = new String[1]; 198 Object value = XmlUtil.readCurrentValue(in, valueName); 199 if (valueName[0] == null) { 200 throw new XmlPullParserException("Missing value name"); 201 } 202 switch (valueName[0]) { 203 case XML_TAG_IS_ACTIVE: 204 isActive = (Boolean) value; 205 break; 206 case XML_TAG_IS_ONBOARDED: 207 isOnboarded = (Boolean) value; 208 break; 209 case XML_TAG_NOTIFICATIONS_SHOWN: 210 notificationsShown = (Integer) value; 211 break; 212 default: 213 throw new XmlPullParserException("Unknown value found: " + valueName[0]); 214 } 215 } 216 217 mIsActiveDataSource.setData(isActive); 218 mIsOnboardedDataSource.setData(isOnboarded); 219 mNotificationsDataSource.setData(notificationsShown); 220 } 221 222 /** 223 * Parses a {@link ScanResultMatchInfo} from an XML input stream. 224 * 225 * @param in XML input stream 226 * @param outerTagDepth XML tag depth of the containing section 227 * @return The {@link ScanResultMatchInfo} 228 * @throws IOException 229 * @throws XmlPullParserException 230 */ 231 private ScanResultMatchInfo parseNetwork(XmlPullParser in, int outerTagDepth) 232 throws IOException, XmlPullParserException { 233 ScanResultMatchInfo scanResultMatchInfo = new ScanResultMatchInfo(); 234 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 235 String[] valueName = new String[1]; 236 Object value = XmlUtil.readCurrentValue(in, valueName); 237 if (valueName[0] == null) { 238 throw new XmlPullParserException("Missing value name"); 239 } 240 switch (valueName[0]) { 241 case XML_TAG_SSID: 242 scanResultMatchInfo.networkSsid = (String) value; 243 break; 244 case XML_TAG_SECURITY: 245 scanResultMatchInfo.networkType = (int) value; 246 break; 247 default: 248 throw new XmlPullParserException("Unknown tag under " + TAG + ": " 249 + valueName[0]); 250 } 251 } 252 253 return scanResultMatchInfo; 254 } 255 256 @Override 257 public void resetData(boolean shared) { 258 if (!shared) { 259 mNetworkDataSource.setData(Collections.emptySet()); 260 mIsActiveDataSource.setData(false); 261 mIsOnboardedDataSource.setData(false); 262 mNotificationsDataSource.setData(0); 263 } 264 } 265 266 @Override 267 public String getName() { 268 return TAG; 269 } 270 271 @Override 272 public boolean supportShareData() { 273 return false; 274 } 275} 276