blob: e0511c1acf361073e549a639c5b5cdc613718fd1 [file] [log] [blame]
/*
* 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");
}
}