| /* |
| * Copyright (C) 2015 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.android.settings.dashboard.conditional; |
| |
| import android.content.Context; |
| import android.os.AsyncTask; |
| import android.os.PersistableBundle; |
| import android.util.Log; |
| import android.util.Xml; |
| |
| import org.xmlpull.v1.XmlPullParser; |
| import org.xmlpull.v1.XmlPullParserException; |
| import org.xmlpull.v1.XmlSerializer; |
| |
| import java.io.File; |
| import java.io.FileReader; |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.List; |
| |
| public class ConditionManager { |
| |
| private static final String TAG = "ConditionManager"; |
| |
| private static final boolean DEBUG = false; |
| |
| private static final String PKG = "com.android.settings.dashboard.conditional."; |
| |
| private static final String FILE_NAME = "condition_state.xml"; |
| private static final String TAG_CONDITIONS = "cs"; |
| private static final String TAG_CONDITION = "c"; |
| private static final String ATTR_CLASS = "cls"; |
| |
| private static ConditionManager sInstance; |
| |
| private final Context mContext; |
| private final ArrayList<Condition> mConditions; |
| private File mXmlFile; |
| |
| private final ArrayList<ConditionListener> mListeners = new ArrayList<>(); |
| |
| private ConditionManager(Context context, boolean loadConditionsNow) { |
| mContext = context; |
| mConditions = new ArrayList<>(); |
| if (loadConditionsNow) { |
| ConditionLoader loader = new ConditionLoader(); |
| loader.onPostExecute(loader.doInBackground()); |
| } else { |
| new ConditionLoader().execute(); |
| } |
| } |
| |
| public void refreshAll() { |
| final int N = mConditions.size(); |
| for (int i = 0; i < N; i++) { |
| mConditions.get(i).refreshState(); |
| } |
| } |
| |
| private void readFromXml(File xmlFile, ArrayList<Condition> conditions) { |
| if (DEBUG) Log.d(TAG, "Reading from " + xmlFile.toString()); |
| try { |
| XmlPullParser parser = Xml.newPullParser(); |
| FileReader in = new FileReader(xmlFile); |
| parser.setInput(in); |
| int state = parser.getEventType(); |
| |
| while (state != XmlPullParser.END_DOCUMENT) { |
| if (TAG_CONDITION.equals(parser.getName())) { |
| int depth = parser.getDepth(); |
| String clz = parser.getAttributeValue("", ATTR_CLASS); |
| if (!clz.startsWith(PKG)) { |
| clz = PKG + clz; |
| } |
| Condition condition = createCondition(Class.forName(clz)); |
| PersistableBundle bundle = PersistableBundle.restoreFromXml(parser); |
| if (DEBUG) Log.d(TAG, "Reading " + clz + " -- " + bundle); |
| if (condition != null) { |
| condition.restoreState(bundle); |
| conditions.add(condition); |
| } else { |
| Log.e(TAG, "failed to add condition: " + clz); |
| } |
| while (parser.getDepth() > depth) { |
| parser.next(); |
| } |
| } |
| state = parser.next(); |
| } |
| in.close(); |
| } catch (XmlPullParserException | IOException | ClassNotFoundException e) { |
| Log.w(TAG, "Problem reading " + FILE_NAME, e); |
| } |
| } |
| |
| private void saveToXml() { |
| if (DEBUG) Log.d(TAG, "Writing to " + mXmlFile.toString()); |
| try { |
| XmlSerializer serializer = Xml.newSerializer(); |
| FileWriter writer = new FileWriter(mXmlFile); |
| serializer.setOutput(writer); |
| |
| serializer.startDocument("UTF-8", true); |
| serializer.startTag("", TAG_CONDITIONS); |
| |
| final int N = mConditions.size(); |
| for (int i = 0; i < N; i++) { |
| PersistableBundle bundle = new PersistableBundle(); |
| if (mConditions.get(i).saveState(bundle)) { |
| serializer.startTag("", TAG_CONDITION); |
| final String clz = mConditions.get(i).getClass().getSimpleName(); |
| serializer.attribute("", ATTR_CLASS, clz); |
| bundle.saveToXml(serializer); |
| serializer.endTag("", TAG_CONDITION); |
| } |
| } |
| |
| serializer.endTag("", TAG_CONDITIONS); |
| serializer.flush(); |
| writer.close(); |
| } catch (XmlPullParserException | IOException e) { |
| Log.w(TAG, "Problem writing " + FILE_NAME, e); |
| } |
| } |
| |
| private void addMissingConditions(ArrayList<Condition> conditions) { |
| addIfMissing(AirplaneModeCondition.class, conditions); |
| addIfMissing(HotspotCondition.class, conditions); |
| addIfMissing(DndCondition.class, conditions); |
| addIfMissing(BatterySaverCondition.class, conditions); |
| addIfMissing(CellularDataCondition.class, conditions); |
| addIfMissing(BackgroundDataCondition.class, conditions); |
| addIfMissing(WorkModeCondition.class, conditions); |
| addIfMissing(NightDisplayCondition.class, conditions); |
| Collections.sort(conditions, CONDITION_COMPARATOR); |
| } |
| |
| private void addIfMissing(Class<? extends Condition> clz, ArrayList<Condition> conditions) { |
| if (getCondition(clz, conditions) == null) { |
| if (DEBUG) Log.d(TAG, "Adding missing " + clz.getName()); |
| Condition condition = createCondition(clz); |
| if (condition != null) { |
| conditions.add(condition); |
| } |
| } |
| } |
| |
| private Condition createCondition(Class<?> clz) { |
| if (AirplaneModeCondition.class == clz) { |
| return new AirplaneModeCondition(this); |
| } else if (HotspotCondition.class == clz) { |
| return new HotspotCondition(this); |
| } else if (DndCondition.class == clz) { |
| return new DndCondition(this); |
| } else if (BatterySaverCondition.class == clz) { |
| return new BatterySaverCondition(this); |
| } else if (CellularDataCondition.class == clz) { |
| return new CellularDataCondition(this); |
| } else if (BackgroundDataCondition.class == clz) { |
| return new BackgroundDataCondition(this); |
| } else if (WorkModeCondition.class == clz) { |
| return new WorkModeCondition(this); |
| } else if (NightDisplayCondition.class == clz) { |
| return new NightDisplayCondition(this); |
| } |
| Log.e(TAG, "unknown condition class: " + clz.getSimpleName()); |
| return null; |
| } |
| |
| Context getContext() { |
| return mContext; |
| } |
| |
| public <T extends Condition> T getCondition(Class<T> clz) { |
| return getCondition(clz, mConditions); |
| } |
| |
| private <T extends Condition> T getCondition(Class<T> clz, List<Condition> conditions) { |
| final int N = conditions.size(); |
| for (int i = 0; i < N; i++) { |
| if (clz.equals(conditions.get(i).getClass())) { |
| return (T) conditions.get(i); |
| } |
| } |
| return null; |
| } |
| |
| public List<Condition> getConditions() { |
| return mConditions; |
| } |
| |
| public List<Condition> getVisibleConditions() { |
| List<Condition> conditions = new ArrayList<>(); |
| final int N = mConditions.size(); |
| for (int i = 0; i < N; i++) { |
| if (mConditions.get(i).shouldShow()) { |
| conditions.add(mConditions.get(i)); |
| } |
| } |
| return conditions; |
| } |
| |
| public void notifyChanged(Condition condition) { |
| saveToXml(); |
| Collections.sort(mConditions, CONDITION_COMPARATOR); |
| final int N = mListeners.size(); |
| for (int i = 0; i < N; i++) { |
| mListeners.get(i).onConditionsChanged(); |
| } |
| } |
| |
| public void addListener(ConditionListener listener) { |
| mListeners.add(listener); |
| listener.onConditionsChanged(); |
| } |
| |
| public void remListener(ConditionListener listener) { |
| mListeners.remove(listener); |
| } |
| |
| private class ConditionLoader extends AsyncTask<Void, Void, ArrayList<Condition>> { |
| @Override |
| protected ArrayList<Condition> doInBackground(Void... params) { |
| ArrayList<Condition> conditions = new ArrayList<>(); |
| mXmlFile = new File(mContext.getFilesDir(), FILE_NAME); |
| if (mXmlFile.exists()) { |
| readFromXml(mXmlFile, conditions); |
| } |
| addMissingConditions(conditions); |
| return conditions; |
| } |
| |
| @Override |
| protected void onPostExecute(ArrayList<Condition> conditions) { |
| mConditions.clear(); |
| mConditions.addAll(conditions); |
| refreshAll(); |
| } |
| } |
| |
| public static ConditionManager get(Context context) { |
| return get(context, true); |
| } |
| |
| public static ConditionManager get(Context context, boolean loadConditionsNow) { |
| if (sInstance == null) { |
| sInstance = new ConditionManager(context.getApplicationContext(), loadConditionsNow); |
| } |
| return sInstance; |
| } |
| |
| public interface ConditionListener { |
| void onConditionsChanged(); |
| } |
| |
| private static final Comparator<Condition> CONDITION_COMPARATOR = new Comparator<Condition>() { |
| @Override |
| public int compare(Condition lhs, Condition rhs) { |
| return Long.compare(lhs.getLastChange(), rhs.getLastChange()); |
| } |
| }; |
| } |