/* 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.core; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Set; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.os.Build; import android.os.Looper; import com.polyvi.xface.XStartParams; import com.polyvi.xface.configXml.XPreInstallPackageItem; import com.polyvi.xface.configXml.XSysConfigInfo; import com.polyvi.xface.configXml.XSysConfigParser; import com.polyvi.xface.configXml.XTagNotFoundException; import com.polyvi.xface.extension.XExtensionContext; import com.polyvi.xface.extension.XExtensionEntry; import com.polyvi.xface.util.XConstant; import com.polyvi.xface.util.XFileUtils; import com.polyvi.xface.util.XLog; import com.polyvi.xface.util.XStrings; /** * 负责所有配置的管理,单例 */ public class XConfiguration { private static final String CLASS_NAME = XConfiguration.class .getSimpleName(); private static final String APPS_FOLDER_NAME = "applications"; /** 系统数据路径 */ public static final String SYS_DATA_DIR_NAME = "sys_data"; private static final int TAG_SYSTEM_EXIT_CODE = 1; private boolean mWorkDirectoryChanged = false; // 解析config.xml得到的configInfo对象 protected XSysConfigInfo mSysConfigInfo; private static HashMap<String, XExtensionEntry> mExtensionsCache; // 表示工作目录的三种配置方式 private enum WorkDirConfig { TAG_MAIN_MEMORY_ONLY, // 仅手机内存 TAG_EXTERNAL_MEMORY_CARD_ONLY, // 仅外部存储(FlashROM及SD/TF扩展卡) TAG_EXTERNAL_MEMORY_CARD_FIRST// 外部存储优先 }; // 表示最终工作目录配置的配置 目前有两种表示方式 static public enum WorkDirStrategy { MEMORY, SDCARD }; /** singleton */ protected static XConfiguration instance = null; /** 工作目录路径 */ private String mWorkDir; /** 是否支持点击view上的数字触发联系人添加操作 */ private boolean mTelLinkEnabled = true; protected XConfiguration() { } public static XConfiguration getInstance() { if (instance == null) { instance = new XConfiguration(); } return instance; } /** * 从配置文件读取系统配置数据 * * @param configStream * 配置文件输入流 * @throws XTagNotFoundException */ public void readConfig(InputStream configStream) throws XTagNotFoundException { XSysConfigParser sysConfigParser = new XSysConfigParser(); sysConfigParser.setInput(configStream); mSysConfigInfo = sysConfigParser.parseConfig(); } /** * 设置程序的工作空间 * * @param workDir * 工作空间绝对路径 */ public void setWorkDirectory(String workDir) { this.mWorkDir = workDir; } /** * 获取所有的application安装目录 * * @return 所有application安装目录绝对路径 */ public String getAppInstallDir() { return this.mWorkDir + APPS_FOLDER_NAME + File.separator; } /** * 获取sys_data目录 * * @return sys_data目录绝对路径 */ public String getSysDataDir() { return this.getAppInstallDir() + SYS_DATA_DIR_NAME + File.separator; } /** * 获取程序的工作空间 * * @return 工作空间绝对路径 */ public String getWorkDirectory() { return this.mWorkDir; } /** * 获取预安装的应用包列表,每一项代表一个应用的包名 */ public List<XPreInstallPackageItem> getPreinstallPackages() { return (null == mSysConfigInfo) ? null : mSysConfigInfo .getPreinstallPackages(); } /** * 获取startapp的id * * @param sysCtx * 系统上下文环境 * @return startAppId */ public String getStartAppId(XISystemContext sysCtx) { XStartParams params = sysCtx.getStartParams(); if (null != params && null != params.appId) { // 如果系统指定了启动的app则从启动参数中读取appid,packagename // 并新建一个XPreInstallPackageItem return params.appId; } return (null == mSysConfigInfo) ? null : mSysConfigInfo.getStartAppId(); } /** * 获取系统允许执行的扩展列表,每一项代表一个扩展的名称 */ public HashMap<String, XExtensionEntry> getSysExtensions() { return (null == mSysConfigInfo) ? null : mSysConfigInfo .getSysExtensions(); } /** * 从config.xml配置文件中读取要加载的扩展 */ public HashMap<String, XExtensionEntry> readLoadingExtensions( XExtensionContext extensionContext) { if (null != mExtensionsCache) { return mExtensionsCache; } mExtensionsCache = getSysExtensions(); return mExtensionsCache; } /** * 从config.xml配置文件中读取LOG输出等级 */ public String readLogLevel() { return (null == mSysConfigInfo) ? null : mSysConfigInfo.getLogLevel(); } /** * 从config.xml配置文件中读取是否需要显示splash图片 * * @return */ public boolean readShowSplash() { return (null == mSysConfigInfo) ? false : mSysConfigInfo .getShowSplash(); } /** * 从config.xml配置文件中读取是否需要自动隐藏splash图片 * * @return */ public boolean readAutoHideSplash() { return (null == mSysConfigInfo) ? true : mSysConfigInfo .getAutoHideSplash(); } /** * 从config.xml配置文件中读取是否需要全屏显示 * * @return */ public boolean readFullscreen() { return (null == mSysConfigInfo) ? false : mSysConfigInfo .getFullscreen(); } /** * 从config.xml配置文件中读取是否需要检测更新的服务器地址 * * @return */ public boolean readUpdateCheck() { return (null == mSysConfigInfo) ? false : mSysConfigInfo .getUpdateCheck(); } /** * 从config.xml配置文件中读取需要检测更新的服务器地址 * * @return */ public String readUpdateAddress() { return (null == mSysConfigInfo) ? null : mSysConfigInfo .getUpdateAddress(); } /** * 从config.xml配置文件中读取splash显示的时间 * * @return */ public String readSplashDelay() { return (null == mSysConfigInfo) ? null : mSysConfigInfo .getSplashDelay(); } /** * 从config.xml配置文件中读取引擎版本 * * @return */ public String readEngineVersion() { return (null == mSysConfigInfo) ? null : mSysConfigInfo .getEngineVersion(); } /** * 从config.xml配置文件中读取build号 * * @return */ public String readEngineBuild() { return (null == mSysConfigInfo) ? null : mSysConfigInfo .getEngineBuild(); } /** * 从config.xml配置文件中读取加载应用时等待xface.js是否加载完成的时间 * * @return */ public String readLoadUrlTimeout() { return (null == mSysConfigInfo) ? null : mSysConfigInfo .getLoadUrlTimeout(); } /** * 从config.xml配置文件中读取插件配置信息 * * @return */ public HashMap<String, String> readPluginsConfig() { return (null == mSysConfigInfo) ? null : mSysConfigInfo .getPluginsConfig(); } /** * 从config.xml配置文件中读取插件描述信息 * * @return */ public Set<String> readPluginDescriptions() { return (null == mSysConfigInfo) ? null : mSysConfigInfo .getPluginDesciptions(); } /** 因为只加载config.xml配置文件中xFace标签中的内容,该方法用于判断是否到了配置文件结尾或者遇到xFace结束标签 */ /** * 配置系统的工作目录 * * @param context * android程序对应的Context对象 * @param workDirName * 工作目录名称 */ public void configWorkDirectory(Context context, String workDirName) { if (null == workDirName) { alerExitMessage( XStrings.getInstance().getString( XStrings.EXIT_MESSAGE_TITLE), XStrings.getInstance().getString( XStrings.EXIT_MESSAGE_CONTENT), context); } else { // 设置系统的工作目录到config中 setWorkDirectory(workDirName); } } /** * 获取程序的工作空间目录,'/'结尾 * * @param context * android程序对应的Context对象 * @param workDirName * 工作目录名称 */ public String getWorkDirectory(Context context, String workDirName) { String dirType = mSysConfigInfo.getWorkDir(); String baseDir = null; int work_dir_config; WorkDirConfig configType; try {// 捕获用户所有可能的错误配置输入 work_dir_config = Integer.parseInt(dirType); configType = WorkDirConfig.values()[--work_dir_config]; } catch (Exception e) { return null; } // FIXME:如果android版本是3.2则直接安装在系统内存中 if (Build.VERSION.SDK_INT == 13) { configType = WorkDirConfig.TAG_MAIN_MEMORY_ONLY; } switch (configType) { case TAG_MAIN_MEMORY_ONLY: try { baseDir = context.getFilesDir().getCanonicalPath(); setWorkDirStrategy(context, WorkDirStrategy.MEMORY); } catch (IOException e) { XLog.e(CLASS_NAME, "error when get work directory:" + e.getMessage()); e.printStackTrace(); } break; case TAG_EXTERNAL_MEMORY_CARD_ONLY: {// 如果外部存储卡不可用,则报错,并退出程序。 if (null == (baseDir = XFileUtils.getSdcardPath())) {// 外存卡不可用 return null; } workDirName = XConstant.ANDROID_DIR + File.separator + XConstant.APP_DATA_DIR_NAME + File.separator + workDirName; setWorkDirStrategy(context, WorkDirStrategy.SDCARD); } break; case TAG_EXTERNAL_MEMORY_CARD_FIRST: { if (null == (baseDir = XFileUtils.getSdcardPath())) {// 外存卡不可用 try { baseDir = context.getFilesDir().getCanonicalPath(); setWorkDirStrategy(context, WorkDirStrategy.MEMORY); } catch (IOException e) { XLog.e(CLASS_NAME, "error when getWorkDirectory:" + e.getMessage()); e.printStackTrace(); } } else { workDirName = XConstant.ANDROID_DIR + File.separator + XConstant.APP_DATA_DIR_NAME + File.separator + workDirName; setWorkDirStrategy(context, WorkDirStrategy.SDCARD); } } break; } StringBuffer sb = new StringBuffer(); sb.append(baseDir); if (!baseDir.endsWith(File.separator)) { sb.append(File.separatorChar); } sb.append(workDirName); sb.append(File.separatorChar); File workDir = new File(sb.toString()); if (!workDir.exists()) { workDir.mkdirs(); // 修改文件夹的权限为其它用户可执行 XFileUtils.setPermissionUntilDir( XFileUtils.EXECUTABLE_BY_OTHER, workDir.getAbsolutePath(), "/"); } return sb.toString(); } /** * 设置工作目录配置策略 * * @param ctx * @param wds */ private void setWorkDirStrategy(Context ctx, WorkDirStrategy wds) { if (getWorkDirStrategy(ctx) != wds.ordinal()) { mWorkDirectoryChanged = true; } SharedPreferences pref = ctx.getSharedPreferences( XConstant.PREF_SETTING_FILE_NAME, Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE); SharedPreferences.Editor editor = pref.edit(); editor.putInt(XConstant.TAG_WD_STRATEGY, wds.ordinal()); editor.commit(); } /** * 工作目录是否变化的标志 * * @return */ public boolean isWorkDirectoryChanged() { return mWorkDirectoryChanged; } /** * 获得工作目录最终的配置策略 * * @return */ private int getWorkDirStrategy(Context ctx) { SharedPreferences pref = ctx.getSharedPreferences( XConstant.PREF_SETTING_FILE_NAME, Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE); int ret = pref.getInt(XConstant.TAG_WD_STRATEGY, -1); return ret; } /** * 弹出错误消息,用户点击后程序退出 * * @param title * 弹出框标题 * @param exitMessage * 弹出框的错误信息 * @return */ private void alerExitMessage(String title, String exitMessage, Context context) { AlertDialog.Builder builder = new Builder(context); builder.setTitle(title); builder.setPositiveButton( XStrings.getInstance().getString(XStrings.CONFIRM), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { System.exit(TAG_SYSTEM_EXIT_CODE); } }); builder.setIcon(android.R.drawable.ic_dialog_info); builder.setMessage(exitMessage); builder.show(); // 将对话框变成阻塞式对话框 Looper.loop(); } /** 设置该应用是否支持点击view上的数字触发联系人添加操作 */ public void setTelLinkEnabled(boolean telLinkEnabled) { this.mTelLinkEnabled = telLinkEnabled; } /** 返回该应用是否支持点击view上的数字触发联系人添加操作 */ public boolean isTelLinkEnabled() { return mTelLinkEnabled; } /** * 加载平台的string常量 * * @param context */ public void loadPlatformStrings(Context context) { XStrings.getInstance().loadPlatformStrings(context); } }