/* Copyright 2012-2013, Polyvi Inc. (http://polyvi.github.io/openxface) This program is distributed under the terms of the GNU General Public License. This file is part of xFace. xFace is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. xFace is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with xFace. If not, see <http://www.gnu.org/licenses/>. */ package com.polyvi.xface.ams; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Iterator; import java.util.List; import android.content.Context; import android.content.SharedPreferences; import com.polyvi.xface.app.XAppInfo; import com.polyvi.xface.app.XApplication; import com.polyvi.xface.app.XApplicationCreator; import com.polyvi.xface.app.XIApplication; import com.polyvi.xface.configXml.XAbstractAppConfigParser; import com.polyvi.xface.configXml.XXmlOperatorFactory; import com.polyvi.xface.core.XConfiguration; import com.polyvi.xface.util.XConstant; import com.polyvi.xface.util.XLog; import com.polyvi.xface.util.XStringUtils; import com.polyvi.xface.view.XAppWebView; /** * XAppList的装饰者,负责把应用信息添加、删除、更新到SharedPreferences */ public class XPersistentAppList extends XAppList { private static final String CLASS_NAME = XPersistentAppList.class.getName(); /** 分隔符 */ private static final String DELIMITER = ",:,"; /** 所有应用的id,例如KEY:appsId VALUE:{app1,:,app2,:,app3} */ private static final String KEY_APPS_ID = "appsId"; /** 应用的源路径,例如KEY:app1 VALUE:{source_dirfile:///android_asset/data/app} */ private static final String TAG_SOURCE_DIR = "source_dir"; /** 保存应用信息的文件名称 */ private static final String APPS_FILE_NAME = "apps.pref"; private XAppList mAppList; private SharedPreferences mPreference; private XApplicationCreator mCreator; public XPersistentAppList(Context ctx, XApplicationCreator creator, XAppList appList) { mCreator = creator; mPreference = ctx.getSharedPreferences(APPS_FILE_NAME, Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE); mAppList = appList; // 读取所有的app到appList readApps(); } /** * 读取所有的app到appList */ private void readApps() { String appsId = mPreference.getString(KEY_APPS_ID, null); if (null == appsId) { XLog.i(CLASS_NAME, "No apps id in " + APPS_FILE_NAME); return; } String[] appId = appsId.split(DELIMITER); for (int index = 0; index < appId.length; index++) { try { XAppInfo appInfo = readAppInfo(appId, index); if (null == appInfo) { continue; } String appSourceDir = readSourceDir(appId[index]); if (null != appSourceDir) { appInfo.setSrcRoot(appSourceDir); } XIApplication app = mCreator.create(appInfo); add(app); } catch (FileNotFoundException e) { XLog.w(CLASS_NAME, "Can't locate app.xml of app: " + appId[index]); e.printStackTrace(); } catch (IOException e) { XLog.w(CLASS_NAME, "IOException in read app.xml of app: " + appId[index]); e.printStackTrace(); } } } /** * 读取app.xml文件,获取appInfo * @param appId * @param index * @return * @throws IOException, FileNotFoundException */ private XAppInfo readAppInfo(String[] appId, int index) throws FileNotFoundException, IOException { File appFile = new File(XConfiguration.getInstance() .getAppInstallDir(), appId[index] + File.separator + XConstant.APP_CONFIG_FILE_NAME); FileInputStream fis = new FileInputStream(appFile); XAbstractAppConfigParser appConfigParser = XXmlOperatorFactory .createAppConfigParser(); appConfigParser.setInput(fis); XAppInfo appInfo = appConfigParser.parseConfig(); fis.close(); return appInfo; } /** * 读取应用源码目录 * * @param appId * @return 应用源码目录 */ private String readSourceDir(String appId) { String appAttr = mPreference.getString(appId, null); if (null == appAttr) { XLog.e(CLASS_NAME, "Can't read " + appId + " in " + APPS_FILE_NAME); return null; } return appAttr.split(TAG_SOURCE_DIR)[1]; } @Override public void add(XIApplication app) { mAppList.add(app); String appsId = mPreference.getString(KEY_APPS_ID, null); String appId = app.getAppId(); if (null == appsId) { appsId = appId; } else { //如果有重复的appid则不增加 if(contains(appId)) { return; } appsId = appsId + DELIMITER + appId; } String appAttr = TAG_SOURCE_DIR + app.getAppInfo().getSrcRoot(); SharedPreferences.Editor editor = mPreference.edit(); editor.putString(KEY_APPS_ID, appsId); editor.putString(app.getAppId(), appAttr); editor.commit(); } @Override public XApplication getAppByViewId(int viewId) { return mAppList.getAppByViewId(viewId); } @Override public XIApplication getAppById(String appId) { return mAppList.getAppById(appId); } @Override public XAppWebView getAppViewById(int viewId) { return mAppList.getAppViewById(viewId); } @Override public String getAppIdByViewId(int viewId) { return mAppList.getAppIdByViewId(viewId); } @Override public int getTotalSize() { return mAppList.getTotalSize(); } @Override public XIApplication getAppByIndex(int index) { return mAppList.getAppByIndex(index); } @Override public void removeAppById(String appId) { mAppList.removeAppById(appId); String appsId = mPreference.getString(KEY_APPS_ID, null); if(null == appsId || !(contains(appId)) ) { XLog.i(CLASS_NAME, "No appsId found in apps.pref"); return; } try { String[] ids = appsId.split(DELIMITER); List<String> appIdList = XStringUtils.strArrayToList(ids); appIdList.remove(appId); appsId = XStringUtils.join(DELIMITER, appIdList); SharedPreferences.Editor editor = mPreference.edit(); editor.putString(KEY_APPS_ID, appsId); editor.remove(appId); editor.commit(); } catch(IllegalArgumentException e) { XLog.e(CLASS_NAME, "Remove App By Id Error!"); e.printStackTrace(); } } @Override public void updateApp(XAppInfo newAppInfo, XIApplication oldApp) { mAppList.updateApp(newAppInfo, oldApp); String appId = oldApp.getAppId(); String appsId = mPreference.getString(KEY_APPS_ID, null); if (null == appsId) { XLog.e(CLASS_NAME, "Update App Error: can't find KEY:" + KEY_APPS_ID + "in" + APPS_FILE_NAME); return; } if (contains(appId)) { String newSourceDir = newAppInfo.getSrcRoot(); String oldSourceDir = readSourceDir(appId); if (oldSourceDir == null && newSourceDir != null || (oldSourceDir != null && newSourceDir != null && !oldSourceDir .equals(newSourceDir))) { SharedPreferences.Editor editor = mPreference.edit(); editor.remove(appId); newSourceDir = TAG_SOURCE_DIR + newSourceDir; editor.putString(appId, newSourceDir); editor.commit(); } } else { XLog.e(CLASS_NAME, "Update App Error: can't find " + appId); } } /** * 判断传递的应用id是否在应用id列表中 * * @param appId * @return */ private boolean contains(String appId) { if (null == appId) { return false; } String appsId = mPreference.getString(KEY_APPS_ID, null); if (null == appsId) { return false; } String[] ids = appsId.split(DELIMITER); for (int index = 0; index < ids.length; index++) { if (ids[index].equals(appId)) { return true; } } return false; } @Override public Iterator<XIApplication> iterator() { return mAppList.iterator(); } }