ConditionManager.java revision db4ed191deefeda79af5644634415597c1c70217
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 */ 16package com.android.settings.dashboard.conditional; 17 18import android.content.Context; 19import android.os.PersistableBundle; 20import android.util.Log; 21import android.util.Xml; 22import org.xmlpull.v1.XmlPullParser; 23import org.xmlpull.v1.XmlPullParserException; 24import org.xmlpull.v1.XmlSerializer; 25 26import java.io.File; 27import java.io.FileReader; 28import java.io.FileWriter; 29import java.io.IOException; 30import java.lang.reflect.Constructor; 31import java.lang.reflect.InvocationTargetException; 32import java.util.ArrayList; 33import java.util.Collections; 34import java.util.Comparator; 35import java.util.List; 36 37public class ConditionManager { 38 39 private static final String TAG = "ConditionManager"; 40 41 private static final boolean DEBUG = true; 42 43 private static final String FILE_NAME = "condition_state.xml"; 44 private static final String TAG_CONDITIONS = "conditions"; 45 private static final String TAG_CONDITION = "condition"; 46 private static final String ATTR_CLASS = "class"; 47 48 private static ConditionManager sInstance; 49 50 private final Context mContext; 51 private final ArrayList<Condition> mConditions; 52 private final File mXmlFile; 53 54 private final ArrayList<ConditionListener> mListeners = new ArrayList<>(); 55 56 private ConditionManager(Context context) { 57 mContext = context; 58 mConditions = new ArrayList<Condition>(); 59 mXmlFile = new File(context.getFilesDir(), FILE_NAME); 60 if (mXmlFile.exists()) { 61 readFromXml(); 62 } 63 addMissingConditions(); 64 } 65 66 public void refreshAll() { 67 final int N = mConditions.size(); 68 for (int i = 0; i < N; i++) { 69 mConditions.get(i).refreshState(); 70 } 71 } 72 73 private void readFromXml() { 74 if (DEBUG) Log.d(TAG, "Reading from " + mXmlFile.toString()); 75 try { 76 XmlPullParser parser = Xml.newPullParser(); 77 FileReader in = new FileReader(mXmlFile); 78 parser.setInput(in); 79 int state = parser.getEventType(); 80 81 while (state != XmlPullParser.END_DOCUMENT) { 82 if (TAG_CONDITION.equals(parser.getName())) { 83 int depth = parser.getDepth(); 84 String clz = parser.getAttributeValue("", ATTR_CLASS); 85 Condition condition = createCondition(Class.forName(clz)); 86 PersistableBundle bundle = PersistableBundle.restoreFromXml(parser); 87 if (DEBUG) Log.d(TAG, "Reading " + clz + " -- " + bundle); 88 condition.restoreState(bundle); 89 mConditions.add(condition); 90 while (parser.getDepth() > depth) { 91 parser.next(); 92 } 93 } 94 state = parser.next(); 95 } 96 in.close(); 97 } catch (XmlPullParserException | IOException | ClassNotFoundException e) { 98 Log.w(TAG, "Problem reading " + FILE_NAME, e); 99 } 100 } 101 102 private void saveToXml() { 103 if (DEBUG) Log.d(TAG, "Writing to " + mXmlFile.toString()); 104 try { 105 XmlSerializer serializer = Xml.newSerializer(); 106 FileWriter writer = new FileWriter(mXmlFile); 107 serializer.setOutput(writer); 108 109 serializer.startDocument("UTF-8", true); 110 serializer.startTag("", TAG_CONDITIONS); 111 112 final int N = mConditions.size(); 113 for (int i = 0; i < N; i++) { 114 serializer.startTag("", TAG_CONDITION); 115 serializer.attribute("", ATTR_CLASS, mConditions.get(i).getClass().getName()); 116 PersistableBundle bundle = new PersistableBundle(); 117 mConditions.get(i).saveState(bundle); 118 bundle.saveToXml(serializer); 119 serializer.endTag("", TAG_CONDITION); 120 } 121 122 serializer.endTag("", TAG_CONDITIONS); 123 serializer.flush(); 124 writer.close(); 125 } catch (XmlPullParserException | IOException e) { 126 Log.w(TAG, "Problem writing " + FILE_NAME, e); 127 } 128 } 129 130 private void addMissingConditions() { 131 addIfMissing(AirplaneModeCondition.class); 132 addIfMissing(HotspotCondition.class); 133 } 134 135 private void addIfMissing(Class<? extends Condition> clz) { 136 if (getCondition(clz) == null) { 137 if (DEBUG) Log.d(TAG, "Adding missing " + clz.getName()); 138 mConditions.add(createCondition(clz)); 139 } 140 } 141 142 private Condition createCondition(Class<?> clz) { 143 if (AirplaneModeCondition.class == clz) { 144 return new AirplaneModeCondition(this); 145 } else if (HotspotCondition.class == clz) { 146 return new HotspotCondition(this); 147 } 148 try { 149 Constructor<?> constructor = clz.getConstructor(ConditionManager.class); 150 return (Condition) constructor.newInstance(this); 151 } catch (NoSuchMethodException | IllegalAccessException | InstantiationException 152 | InvocationTargetException e) { 153 } 154 return null; 155 } 156 157 Context getContext() { 158 return mContext; 159 } 160 161 public <T extends Condition> T getCondition(Class<T> clz) { 162 final int N = mConditions.size(); 163 for (int i = 0; i < N; i++) { 164 if (clz.equals(mConditions.get(i).getClass())) { 165 return (T) mConditions.get(i); 166 } 167 } 168 return null; 169 } 170 171 public List<Condition> getConditions() { 172 return mConditions; 173 } 174 175 public List<Condition> getVisibleConditions() { 176 List<Condition> conditions = new ArrayList<>(); 177 final int N = mConditions.size(); 178 for (int i = 0; i < N; i++) { 179 if (mConditions.get(i).shouldShow()) { 180 conditions.add(mConditions.get(i)); 181 } 182 } 183 Collections.sort(conditions, CONDITION_COMPARATOR); 184 return conditions; 185 } 186 187 public void notifyChanged(Condition condition) { 188 saveToXml(); 189 final int N = mListeners.size(); 190 for (int i = 0; i < N; i++) { 191 mListeners.get(i).onConditionsChanged(); 192 } 193 } 194 195 public void addListener(ConditionListener listener) { 196 mListeners.add(listener); 197 } 198 199 public void remListener(ConditionListener listener) { 200 mListeners.remove(listener); 201 } 202 203 public static ConditionManager get(Context context) { 204 if (sInstance == null) { 205 sInstance = new ConditionManager(context); 206 } 207 return sInstance; 208 } 209 210 public interface ConditionListener { 211 void onConditionsChanged(); 212 } 213 214 private static final Comparator<Condition> CONDITION_COMPARATOR = new Comparator<Condition>() { 215 @Override 216 public int compare(Condition lhs, Condition rhs) { 217 return Long.compare(lhs.getLastChange(), rhs.getLastChange()); 218 } 219 }; 220} 221