/*
DevicePluginXmlUtil.java
Copyright (c) 2014 NTT DOCOMO,INC.
Released under the MIT license
http://opensource.org/licenses/mit-license.php
*/
package org.deviceconnect.android.localoauth;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.XmlResourceParser;
import org.deviceconnect.android.BuildConfig;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* デバイスプラグインxml関連ユーティリティ.
* @author NTT DOCOMO, INC.
*/
public final class DevicePluginXmlUtil {
/** デバイスプラグインに格納されるメタタグ名. */
private static final String PLUGIN_META_DATA = "org.deviceconnect.android.deviceplugin";
/**
* コンストラクタ.
*/
private DevicePluginXmlUtil() {
}
/**
* デバイスプラグインのxmlファイルを参照し、スコープに対応する有効期限設定値があれば返す.
*
* @param context コンテキスト
* @param packageName デバイスプラグインのパッケージ名
* @return not null: xmlで定義されているスコープ名と有効期限[msec]が対応付けされたMap / null:
* 有効期限設定値無し
*/
public static Map<String, DevicePluginXmlProfile> getSupportProfiles(final Context context,
final String packageName) {
Map<String, DevicePluginXmlProfile> supportProfiles = null;
ActivityInfo receiverInfo = getActivityInfo(context, packageName);
if (receiverInfo != null) {
if (receiverInfo.metaData != null) {
PackageManager pkgMgr = context.getPackageManager();
XmlResourceParser xrp = receiverInfo.loadXmlMetaData(pkgMgr, PLUGIN_META_DATA);
try {
supportProfiles = parseDevicePluginXML(xrp);
} catch (XmlPullParserException e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
} catch (IOException e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
}
}
}
return supportProfiles;
}
/**
* コンポーネントのActivityInfoを取得する.
*
* @param context コンテキスト
* @param packageName package name
* @return コンポーネントのActivityInfo
*/
private static ActivityInfo getActivityInfo(final Context context, final String packageName) {
try {
PackageManager pkgMgr = context.getPackageManager();
PackageInfo pkg = pkgMgr.getPackageInfo(packageName, PackageManager.GET_RECEIVERS);
if (pkg != null) {
ActivityInfo[] receivers = pkg.receivers;
if (receivers != null) {
for (int i = 0; i < receivers.length; i++) {
String pkgName = receivers[i].packageName;
String className = receivers[i].name;
ComponentName component = new ComponentName(pkgName, className);
ActivityInfo receiverInfo = pkgMgr.getReceiverInfo(component, PackageManager.GET_META_DATA);
if (receiverInfo.metaData != null) {
Object value = receiverInfo.metaData.get(PLUGIN_META_DATA);
if (value != null) {
return receiverInfo;
}
}
}
}
}
return null;
} catch (NameNotFoundException e) {
return null;
}
}
/**
* xml/deviceplugin.xmlの解析を行う.
*
* @param xrp xmlパーサ
* @throws XmlPullParserException xmlの解析に失敗した場合に発生
* @throws IOException xmlの読み込みに失敗した場合
* @return プロファイル名とプロファイル情報の一覧
*/
private static Map<String, DevicePluginXmlProfile> parseDevicePluginXML(final XmlResourceParser xrp)
throws XmlPullParserException, IOException {
Map<String, DevicePluginXmlProfile> list = new HashMap<String, DevicePluginXmlProfile>();
final String tagKeyLang = "lang";
final String tagKeyName = "name";
final String tagKeyDescription = "description";
DevicePluginXmlProfile profile = null;
String nameLang = null;
String nameText = null;
String descriptionLang = null;
String descriptionText = null;
String specPath = null;
int eventType = xrp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
final String tagName = xrp.getName();
if ("deviceplugin-provider".equals(tagName)) {
if (eventType == XmlPullParser.START_TAG) {
specPath = xrp.getAttributeValue(null, "spec-path");
}
} else if ("profile".equals(tagName)) {
if (eventType == XmlPullParser.START_TAG) {
String profileName = xrp.getAttributeValue(null, "name");
String strExpirePeriod = xrp.getAttributeValue(null, "expireperiod");
long expirePeriod = LocalOAuth2Settings.DEFAULT_TOKEN_EXPIRE_PERIOD; /* 秒単位 */
if (strExpirePeriod != null) { /* expireperiodが設定されている */
try {
/* 分単位 */
expirePeriod = Long.parseLong(strExpirePeriod);
/* 秒単位に変換 */
expirePeriod *= LocalOAuth2Settings.MINUTE;
} catch (NumberFormatException e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
}
}
/* profileデータ初期化してプロファイル名と有効期限を設定 */
profile = new DevicePluginXmlProfile(profileName, expirePeriod);
} else if (eventType == XmlPullParser.END_TAG) {
/* 有効期限がマイナス値なら格納しない */
if (profile != null && profile.getExpirePeriod() >= 0) {
list.put(profile.getProfile(), profile);
profile = null;
}
}
} else if (tagKeyName.equals(tagName) || nameLang != null) {
if (tagKeyName.equals(tagName) ) {
if (eventType == XmlPullParser.START_TAG) {
nameLang = xrp.getAttributeValue(null, tagKeyLang);
} else if (eventType == XmlPullParser.END_TAG) {
if (profile != null) {
profile.putName(nameLang, nameText);
nameLang = null;
nameText = null;
}
}
} else if (nameLang != null && eventType == XmlPullParser.TEXT) {
nameText = xrp.getText();
}
} else if (tagKeyDescription.equals(tagName) || descriptionLang != null) {
if (tagKeyDescription.equals(tagName)) {
if (eventType == XmlPullParser.START_TAG) {
descriptionLang = xrp.getAttributeValue(null, tagKeyLang);
} else if (eventType == XmlPullParser.END_TAG) {
if (profile != null) {
profile.putDescription(descriptionLang, descriptionText);
descriptionLang = null;
descriptionText = null;
}
}
} else if (descriptionLang != null && eventType == XmlPullParser.TEXT) {
descriptionText = xrp.getText();
}
}
eventType = xrp.next();
}
for (DevicePluginXmlProfile xmlProfile : list.values()) {
xmlProfile.setSpecPath(specPath);
}
return list;
}
}