ZenModeConfig.java revision 99f963ea04d7a86219ece00c356f3f6bce33b6d6
1/** 2 * Copyright (c) 2014, 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 android.service.notification; 18 19import android.content.ComponentName; 20import android.net.Uri; 21import android.os.Parcel; 22import android.os.Parcelable; 23import android.text.TextUtils; 24 25import org.xmlpull.v1.XmlPullParser; 26import org.xmlpull.v1.XmlPullParserException; 27import org.xmlpull.v1.XmlSerializer; 28 29import java.io.IOException; 30import java.util.ArrayList; 31import java.util.Arrays; 32import java.util.Objects; 33 34/** 35 * Persisted configuration for zen mode. 36 * 37 * @hide 38 */ 39public class ZenModeConfig implements Parcelable { 40 41 public static final String SLEEP_MODE_NIGHTS = "nights"; 42 public static final String SLEEP_MODE_WEEKNIGHTS = "weeknights"; 43 44 public static final int SOURCE_ANYONE = 0; 45 public static final int SOURCE_CONTACT = 1; 46 public static final int SOURCE_STAR = 2; 47 public static final int MAX_SOURCE = SOURCE_STAR; 48 49 private static final int XML_VERSION = 1; 50 private static final String ZEN_TAG = "zen"; 51 private static final String ZEN_ATT_VERSION = "version"; 52 private static final String ALLOW_TAG = "allow"; 53 private static final String ALLOW_ATT_CALLS = "calls"; 54 private static final String ALLOW_ATT_MESSAGES = "messages"; 55 private static final String ALLOW_ATT_FROM = "from"; 56 private static final String SLEEP_TAG = "sleep"; 57 private static final String SLEEP_ATT_MODE = "mode"; 58 59 private static final String SLEEP_ATT_START_HR = "startHour"; 60 private static final String SLEEP_ATT_START_MIN = "startMin"; 61 private static final String SLEEP_ATT_END_HR = "endHour"; 62 private static final String SLEEP_ATT_END_MIN = "endMin"; 63 64 private static final String CONDITION_TAG = "condition"; 65 private static final String CONDITION_ATT_COMPONENT = "component"; 66 private static final String CONDITION_ATT_ID = "id"; 67 68 public boolean allowCalls; 69 public boolean allowMessages; 70 public int allowFrom = SOURCE_ANYONE; 71 72 public String sleepMode; 73 public int sleepStartHour; 74 public int sleepStartMinute; 75 public int sleepEndHour; 76 public int sleepEndMinute; 77 public ComponentName[] conditionComponents; 78 public Uri[] conditionIds; 79 80 public ZenModeConfig() { } 81 82 public ZenModeConfig(Parcel source) { 83 allowCalls = source.readInt() == 1; 84 allowMessages = source.readInt() == 1; 85 if (source.readInt() == 1) { 86 sleepMode = source.readString(); 87 } 88 sleepStartHour = source.readInt(); 89 sleepStartMinute = source.readInt(); 90 sleepEndHour = source.readInt(); 91 sleepEndMinute = source.readInt(); 92 int len = source.readInt(); 93 if (len > 0) { 94 conditionComponents = new ComponentName[len]; 95 source.readTypedArray(conditionComponents, ComponentName.CREATOR); 96 } 97 len = source.readInt(); 98 if (len > 0) { 99 conditionIds = new Uri[len]; 100 source.readTypedArray(conditionIds, Uri.CREATOR); 101 } 102 allowFrom = source.readInt(); 103 } 104 105 @Override 106 public void writeToParcel(Parcel dest, int flags) { 107 dest.writeInt(allowCalls ? 1 : 0); 108 dest.writeInt(allowMessages ? 1 : 0); 109 if (sleepMode != null) { 110 dest.writeInt(1); 111 dest.writeString(sleepMode); 112 } else { 113 dest.writeInt(0); 114 } 115 dest.writeInt(sleepStartHour); 116 dest.writeInt(sleepStartMinute); 117 dest.writeInt(sleepEndHour); 118 dest.writeInt(sleepEndMinute); 119 if (conditionComponents != null && conditionComponents.length > 0) { 120 dest.writeInt(conditionComponents.length); 121 dest.writeTypedArray(conditionComponents, 0); 122 } else { 123 dest.writeInt(0); 124 } 125 if (conditionIds != null && conditionIds.length > 0) { 126 dest.writeInt(conditionIds.length); 127 dest.writeTypedArray(conditionIds, 0); 128 } else { 129 dest.writeInt(0); 130 } 131 dest.writeInt(allowFrom); 132 } 133 134 @Override 135 public String toString() { 136 return new StringBuilder(ZenModeConfig.class.getSimpleName()).append('[') 137 .append("allowCalls=").append(allowCalls) 138 .append(",allowMessages=").append(allowMessages) 139 .append(",allowFrom=").append(sourceToString(allowFrom)) 140 .append(",sleepMode=").append(sleepMode) 141 .append(",sleepStart=").append(sleepStartHour).append('.').append(sleepStartMinute) 142 .append(",sleepEnd=").append(sleepEndHour).append('.').append(sleepEndMinute) 143 .append(",conditionComponents=") 144 .append(conditionComponents == null ? null : TextUtils.join(",", conditionComponents)) 145 .append(",conditionIds=") 146 .append(conditionIds == null ? null : TextUtils.join(",", conditionIds)) 147 .append(']').toString(); 148 } 149 150 public static String sourceToString(int source) { 151 switch (source) { 152 case SOURCE_ANYONE: 153 return "anyone"; 154 case SOURCE_CONTACT: 155 return "contacts"; 156 case SOURCE_STAR: 157 return "stars"; 158 default: 159 return "UNKNOWN"; 160 } 161 } 162 163 @Override 164 public boolean equals(Object o) { 165 if (!(o instanceof ZenModeConfig)) return false; 166 if (o == this) return true; 167 final ZenModeConfig other = (ZenModeConfig) o; 168 return other.allowCalls == allowCalls 169 && other.allowMessages == allowMessages 170 && other.allowFrom == allowFrom 171 && Objects.equals(other.sleepMode, sleepMode) 172 && other.sleepStartHour == sleepStartHour 173 && other.sleepStartMinute == sleepStartMinute 174 && other.sleepEndHour == sleepEndHour 175 && other.sleepEndMinute == sleepEndMinute 176 && Objects.deepEquals(other.conditionComponents, conditionComponents) 177 && Objects.deepEquals(other.conditionIds, conditionIds); 178 } 179 180 @Override 181 public int hashCode() { 182 return Objects.hash(allowCalls, allowMessages, allowFrom, sleepMode, 183 sleepStartHour, sleepStartMinute, sleepEndHour, sleepEndMinute, 184 Arrays.hashCode(conditionComponents), Arrays.hashCode(conditionIds)); 185 } 186 187 public boolean isValid() { 188 return isValidHour(sleepStartHour) && isValidMinute(sleepStartMinute) 189 && isValidHour(sleepEndHour) && isValidMinute(sleepEndMinute) 190 && (sleepMode == null || sleepMode.equals(SLEEP_MODE_NIGHTS) 191 || sleepMode.equals(SLEEP_MODE_WEEKNIGHTS)); 192 } 193 194 public static ZenModeConfig readXml(XmlPullParser parser) 195 throws XmlPullParserException, IOException { 196 int type = parser.getEventType(); 197 if (type != XmlPullParser.START_TAG) return null; 198 String tag = parser.getName(); 199 if (!ZEN_TAG.equals(tag)) return null; 200 final ZenModeConfig rt = new ZenModeConfig(); 201 final int version = Integer.parseInt(parser.getAttributeValue(null, ZEN_ATT_VERSION)); 202 final ArrayList<ComponentName> conditionComponents = new ArrayList<ComponentName>(); 203 final ArrayList<Uri> conditionIds = new ArrayList<Uri>(); 204 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { 205 tag = parser.getName(); 206 if (type == XmlPullParser.END_TAG && ZEN_TAG.equals(tag)) { 207 if (!conditionComponents.isEmpty()) { 208 rt.conditionComponents = conditionComponents 209 .toArray(new ComponentName[conditionComponents.size()]); 210 rt.conditionIds = conditionIds.toArray(new Uri[conditionIds.size()]); 211 } 212 return rt; 213 } 214 if (type == XmlPullParser.START_TAG) { 215 if (ALLOW_TAG.equals(tag)) { 216 rt.allowCalls = safeBoolean(parser, ALLOW_ATT_CALLS, false); 217 rt.allowMessages = safeBoolean(parser, ALLOW_ATT_MESSAGES, false); 218 rt.allowFrom = safeInt(parser, ALLOW_ATT_FROM, SOURCE_ANYONE); 219 if (rt.allowFrom < SOURCE_ANYONE || rt.allowFrom > MAX_SOURCE) { 220 throw new IndexOutOfBoundsException("bad source in config:" + rt.allowFrom); 221 } 222 } else if (SLEEP_TAG.equals(tag)) { 223 final String mode = parser.getAttributeValue(null, SLEEP_ATT_MODE); 224 rt.sleepMode = (SLEEP_MODE_NIGHTS.equals(mode) 225 || SLEEP_MODE_WEEKNIGHTS.equals(mode)) ? mode : null; 226 final int startHour = safeInt(parser, SLEEP_ATT_START_HR, 0); 227 final int startMinute = safeInt(parser, SLEEP_ATT_START_MIN, 0); 228 final int endHour = safeInt(parser, SLEEP_ATT_END_HR, 0); 229 final int endMinute = safeInt(parser, SLEEP_ATT_END_MIN, 0); 230 rt.sleepStartHour = isValidHour(startHour) ? startHour : 0; 231 rt.sleepStartMinute = isValidMinute(startMinute) ? startMinute : 0; 232 rt.sleepEndHour = isValidHour(endHour) ? endHour : 0; 233 rt.sleepEndMinute = isValidMinute(endMinute) ? endMinute : 0; 234 } else if (CONDITION_TAG.equals(tag)) { 235 final ComponentName component = 236 safeComponentName(parser, CONDITION_ATT_COMPONENT); 237 final Uri conditionId = safeUri(parser, CONDITION_ATT_ID); 238 if (component != null && conditionId != null) { 239 conditionComponents.add(component); 240 conditionIds.add(conditionId); 241 } 242 } 243 } 244 } 245 throw new IllegalStateException("Failed to reach END_DOCUMENT"); 246 } 247 248 public void writeXml(XmlSerializer out) throws IOException { 249 out.startTag(null, ZEN_TAG); 250 out.attribute(null, ZEN_ATT_VERSION, Integer.toString(XML_VERSION)); 251 252 out.startTag(null, ALLOW_TAG); 253 out.attribute(null, ALLOW_ATT_CALLS, Boolean.toString(allowCalls)); 254 out.attribute(null, ALLOW_ATT_MESSAGES, Boolean.toString(allowMessages)); 255 out.attribute(null, ALLOW_ATT_FROM, Integer.toString(allowFrom)); 256 out.endTag(null, ALLOW_TAG); 257 258 out.startTag(null, SLEEP_TAG); 259 if (sleepMode != null) { 260 out.attribute(null, SLEEP_ATT_MODE, sleepMode); 261 } 262 out.attribute(null, SLEEP_ATT_START_HR, Integer.toString(sleepStartHour)); 263 out.attribute(null, SLEEP_ATT_START_MIN, Integer.toString(sleepStartMinute)); 264 out.attribute(null, SLEEP_ATT_END_HR, Integer.toString(sleepEndHour)); 265 out.attribute(null, SLEEP_ATT_END_MIN, Integer.toString(sleepEndMinute)); 266 out.endTag(null, SLEEP_TAG); 267 268 if (conditionComponents != null && conditionIds != null 269 && conditionComponents.length == conditionIds.length) { 270 for (int i = 0; i < conditionComponents.length; i++) { 271 out.startTag(null, CONDITION_TAG); 272 out.attribute(null, CONDITION_ATT_COMPONENT, 273 conditionComponents[i].flattenToString()); 274 out.attribute(null, CONDITION_ATT_ID, conditionIds[i].toString()); 275 out.endTag(null, CONDITION_TAG); 276 } 277 } 278 out.endTag(null, ZEN_TAG); 279 } 280 281 public static boolean isValidHour(int val) { 282 return val >= 0 && val < 24; 283 } 284 285 public static boolean isValidMinute(int val) { 286 return val >= 0 && val < 60; 287 } 288 289 private static boolean safeBoolean(XmlPullParser parser, String att, boolean defValue) { 290 final String val = parser.getAttributeValue(null, att); 291 if (TextUtils.isEmpty(val)) return defValue; 292 return Boolean.valueOf(val); 293 } 294 295 private static int safeInt(XmlPullParser parser, String att, int defValue) { 296 final String val = parser.getAttributeValue(null, att); 297 if (TextUtils.isEmpty(val)) return defValue; 298 return Integer.valueOf(val); 299 } 300 301 private static ComponentName safeComponentName(XmlPullParser parser, String att) { 302 final String val = parser.getAttributeValue(null, att); 303 if (TextUtils.isEmpty(val)) return null; 304 return ComponentName.unflattenFromString(val); 305 } 306 307 private static Uri safeUri(XmlPullParser parser, String att) { 308 final String val = parser.getAttributeValue(null, att); 309 if (TextUtils.isEmpty(val)) return null; 310 return Uri.parse(val); 311 } 312 313 @Override 314 public int describeContents() { 315 return 0; 316 } 317 318 public ZenModeConfig copy() { 319 final Parcel parcel = Parcel.obtain(); 320 try { 321 writeToParcel(parcel, 0); 322 parcel.setDataPosition(0); 323 return new ZenModeConfig(parcel); 324 } finally { 325 parcel.recycle(); 326 } 327 } 328 329 public static final Parcelable.Creator<ZenModeConfig> CREATOR 330 = new Parcelable.Creator<ZenModeConfig>() { 331 @Override 332 public ZenModeConfig createFromParcel(Parcel source) { 333 return new ZenModeConfig(source); 334 } 335 336 @Override 337 public ZenModeConfig[] newArray(int size) { 338 return new ZenModeConfig[size]; 339 } 340 }; 341} 342