/* * Copyright 2014, 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.managedprovisioning; import android.accounts.Account; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.os.PersistableBundle; import android.util.Xml; import com.android.internal.util.FastXmlSerializer; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.Set; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; /** * This class is used to store an intent to an xml file, and then restore it. * Can only store: * - the action * - the component name * - extras of type string, Integer, Long, Boolean, ComponentName, PersistableBundle, Account */ public class IntentStore { private static final String TAG_INTENT_STORE = "intent-store"; private static final String TAG_ACTION = "action"; private static final String TAG_COMPONENT_NAME = "component-name"; private static final String TAG_EXTRAS = "extras"; private static final String TAG_STRING = "string"; private static final String TAG_INTEGER = "integer"; private static final String TAG_LONG = "long"; private static final String TAG_BOOLEAN = "boolean"; private static final String TAG_ACCOUNT = "account"; private static final String TAG_PERSISTABLE_BUNDLE = "persistable-bundle"; private static final String ATTR_VALUE = "value"; private static final String ATTR_NAME = "name"; private static final String ATTR_ACCOUNT_NAME = "account-name"; private static final String ATTR_ACCOUNT_TYPE = "account-type"; private final Context mContext; private final String mName; private static final Object STATIC_LOCK = new Object(); public IntentStore(Context context, String name) { mName = name; mContext = context; } public boolean save(Intent intent) { synchronized(STATIC_LOCK) { File file = getFile(); if (file.exists()) { ProvisionLogger.loge("Cannot save to the intent store because it already contains" + " an intent"); return false; } try (FileOutputStream stream = new FileOutputStream(file)){ XmlSerializer serializer = new FastXmlSerializer(); serializer.setOutput(stream, StandardCharsets.UTF_8.name()); serializer.startDocument(null, true); serializer.startTag(null, TAG_INTENT_STORE); writeIntent(intent, serializer); serializer.endTag(null, TAG_INTENT_STORE); serializer.endDocument(); return true; } catch (IOException | XmlPullParserException e) { ProvisionLogger.loge("Caught exception while trying to save an intent to the" + " intentStore", e); file.delete(); return false; } } } private void writeIntent(Intent intent, XmlSerializer serializer) throws IOException, XmlPullParserException { if (intent.getAction() != null) { writeTag(serializer, TAG_ACTION, intent.getAction()); } if (intent.getComponent() != null) { writeTag(serializer, TAG_COMPONENT_NAME, intent.getComponent().flattenToString()); } if (intent.getExtras() != null) { writeExtras(intent, serializer); } } private void writeExtras(Intent intent, XmlSerializer serializer) throws IOException, XmlPullParserException { serializer.startTag(null, TAG_EXTRAS); for (String key : intent.getExtras().keySet()) { Object o = intent.getExtra(key); if (o instanceof String) { writeTag(serializer, TAG_STRING, key, (String) o); } else if (o instanceof Integer) { writeTag(serializer, TAG_INTEGER, key, o.toString()); } else if (o instanceof Long) { writeTag(serializer, TAG_LONG, key, o.toString()); } else if (o instanceof Boolean) { writeTag(serializer, TAG_BOOLEAN, key, o.toString()); } else if (o instanceof ComponentName) { writeTag(serializer, TAG_COMPONENT_NAME, key, ((ComponentName) o).flattenToString()); } else if (o instanceof Account) { Account account = (Account) o; serializer.startTag(null, TAG_ACCOUNT); serializer.attribute(null, ATTR_NAME, key); serializer.attribute(null, ATTR_ACCOUNT_NAME, account.name); serializer.attribute(null, ATTR_ACCOUNT_TYPE, account.type); serializer.endTag(null, TAG_ACCOUNT); } else if (o instanceof PersistableBundle) { serializer.startTag(null, TAG_PERSISTABLE_BUNDLE); serializer.attribute(null, ATTR_NAME, key); ((PersistableBundle) o).saveToXml(serializer); serializer.endTag(null, TAG_PERSISTABLE_BUNDLE); } else if (o != null) { ProvisionLogger.loge("extra for key " + key + " cannot be save in the intent" + " store: " + o, new RuntimeException()); } } serializer.endTag(null, TAG_EXTRAS); } public Intent load() { File file = getFile(); if (!file.exists()) { return null; } synchronized(STATIC_LOCK) { try (FileInputStream stream = new FileInputStream(file)) { XmlPullParser parser = Xml.newPullParser(); parser.setInput(stream, null); Intent result = parseIntent(parser); return result; } catch (IOException | XmlPullParserException e) { ProvisionLogger.loge("Caught exception while trying to load an intent from the" + " IntentStore", e); return null; } } } private Intent parseIntent(XmlPullParser parser) throws XmlPullParserException, IOException { Intent intent = new Intent(); int outerDepth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } String tag = parser.getName(); if (tag.equals(TAG_ACTION)) { intent.setAction(parser.getAttributeValue(null, ATTR_VALUE)); } else if (tag.equals(TAG_COMPONENT_NAME)) { intent.setComponent(ComponentName.unflattenFromString( parser.getAttributeValue(null, ATTR_VALUE))); } else if (tag.equals(TAG_EXTRAS)) { parseExtras(intent, parser); } } return intent; } private void parseExtras(Intent intent, XmlPullParser parser) throws XmlPullParserException, IOException { int outerDepth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } String tag = parser.getName(); switch (tag) { case TAG_STRING: intent.putExtra(parser.getAttributeValue(null, ATTR_NAME), parser.getAttributeValue(null, ATTR_VALUE)); break; case TAG_INTEGER: intent.putExtra(parser.getAttributeValue(null, ATTR_NAME), Integer.parseInt(parser.getAttributeValue(null, ATTR_VALUE))); break; case TAG_LONG: intent.putExtra(parser.getAttributeValue(null, ATTR_NAME), Long.parseLong(parser.getAttributeValue(null, ATTR_VALUE))); break; case TAG_BOOLEAN: intent.putExtra(parser.getAttributeValue(null, ATTR_NAME), Boolean.parseBoolean( parser.getAttributeValue(null, ATTR_VALUE))); break; case TAG_COMPONENT_NAME: intent.putExtra(parser.getAttributeValue(null, ATTR_NAME), ComponentName.unflattenFromString( parser.getAttributeValue(null, ATTR_VALUE))); break; case TAG_ACCOUNT: Account a = new Account( parser.getAttributeValue(null, ATTR_ACCOUNT_NAME), parser.getAttributeValue(null, ATTR_ACCOUNT_TYPE)); intent.putExtra(parser.getAttributeValue(null, ATTR_NAME), a); break; case TAG_PERSISTABLE_BUNDLE: intent.putExtra(parser.getAttributeValue(null, ATTR_NAME), PersistableBundle.restoreFromXml(parser)); break; } } } public void clear() { getFile().delete(); } private void writeTag(XmlSerializer serializer, String tag, String value) throws IOException { serializer.startTag(null, tag); serializer.attribute(null, ATTR_VALUE, value); serializer.endTag(null, tag); } private void writeTag(XmlSerializer serializer, String tag, String name, String value) throws IOException { serializer.startTag(null, tag); serializer.attribute(null, ATTR_NAME, name); serializer.attribute(null, ATTR_VALUE, value); serializer.endTag(null, tag); } private File getFile() { return new File(mContext.getFilesDir(), "intent_store_" + mName + ".xml"); } }