/* 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.FilenameFilter; import java.util.Iterator; import java.util.Stack; import com.polyvi.xface.XStartParams; import com.polyvi.xface.ams.XAMSError.AMS_ERROR; import com.polyvi.xface.app.XApplication; import com.polyvi.xface.app.XApplicationCreator; import com.polyvi.xface.app.XIApplication; import com.polyvi.xface.app.XNativeApplication; import com.polyvi.xface.core.XISystemContext; import com.polyvi.xface.util.XConstant; import com.polyvi.xface.util.XLog; import com.polyvi.xface.util.XStringUtils; import com.polyvi.xface.view.XAppWebView; /** * 负责应用的安装、卸载、运行和更新 */ public class XAppManagement { private static final String CLASS_NAME = XAppManagement.class .getSimpleName(); /** app安装器 */ private XAppInstaller mAppInstaller; /** 该栈用于管理已添加的app */ private Stack<XIApplication> mAppStack; /** 本地应用installer的托管 */ private XNativeAppInstallDelegate mNativeAppInstallDelegate; private XApplicationCreator mAppCreator; /** 空的安装器事件监听器,在不需要监听安装/更新/卸载事件时使用 */ private static final XInstallListener EMPTRY_INSTALL_LISTENER = new XInstallListener() { @Override public void onProgressUpdated(AMS_OPERATION_TYPE type, InstallStatus progressState) { } @Override public void onError(AMS_OPERATION_TYPE type, String appId, AMS_ERROR errorState) { } @Override public void onSuccess(AMS_OPERATION_TYPE type, String appId) { } }; public XAppManagement(XApplicationCreator appCreator) { this.mAppCreator = appCreator; } /** * ams模块的初始化工作 */ public void init(XISystemContext systemContext) { initAppInstaller(systemContext); // 其他的初始化放在这里 mAppStack = new Stack<XIApplication>(); } /** * 初始化AppInstaller */ private void initAppInstaller(XISystemContext context) { if (null == this.mAppInstaller) { this.mAppInstaller = new XAppInstaller(context, mAppCreator); mNativeAppInstallDelegate = new XNativeAppInstallDelegate(context); } } /** * 初始化AppList, 将系统已经安装的app初始化到appList中 */ public final XAppList getAppList() { return mAppInstaller.getInstalledAppList(); } /** * 启动一个app * * @param appId * 应用id * @param params * 启动参数 * @param startListener * 启动app监听器 * @return 启动应用是否成功 */ public boolean startApp(String appId, XStartParams params, XAppStartListener startListener) { XIApplication app = getAppList().getAppById(appId); if (null == app) { XLog.w(CLASS_NAME, "Start app failed, can't find app by id: " + appId); startListener.onError(appId, AMS_ERROR.APP_NOT_FOUND); return false; } String startData = null; if (null != params) { startData = params.data; } if (isNativeApp(app)) { String entry = app.getAppInfo().getEntry(); if (XStringUtils.isEmptyString(entry)) { startListener.onError(appId, AMS_ERROR.APP_ENTRY_ERR); return false; } if (!mNativeAppInstallDelegate.isAppInstalled(entry)) { String apkPath = XNativeAppInstallDelegate .getApkPathFromInstallDir(appId); if (XStringUtils.isEmptyString(apkPath) || !new File(apkPath).exists()) { startListener.onError(appId, AMS_ERROR.APP_NOT_FOUND); return false; } mNativeAppInstallDelegate.installApp(apkPath, EMPTRY_INSTALL_LISTENER); return true; } if (!app.start(params)) { startListener.onError(appId, AMS_ERROR.START_NATIVE_APP_ERR); return false; } else { startListener.onSuccess(appId); return true; } } else { // 如果app处于活动状态即已经被启动,不能再次被启动 XApplication webApp = XApplicationCreator.toWebApp(app); if (webApp.isActive()) { startListener.onError(appId, AMS_ERROR.APP_ALREADY_RUNNING); return false; } mAppStack.push(webApp); String pageEntry = null; if (null != params) { pageEntry = params.pageEntry; } if (!XStringUtils.isEmptyString(pageEntry)) { webApp.getAppInfo().setEntry(pageEntry); } if (!XStringUtils.isEmptyString(startData)) { webApp.setData(XConstant.TAG_APP_START_PARAMS, startData); } webApp.start(params); startListener.onSuccess(appId); return true; } } /** * 根据app类型得到相应的安装listener * * @param path * app的路径 * @return 监听 */ private XInstallListener wrapInstallerListener(XInstallListener listener, String path) { if (isNativePackage(path)) { XNativeAppInstallerListener nativeListener = new XNativeAppInstallerListener( listener, mNativeAppInstallDelegate); return nativeListener; } else { return listener; } } /** * 根据app的类型得到相应的卸载listener * * @param id * app的id * @return 监听 */ private XInstallListener wrapUninstallerListener(XInstallListener listener, String id) { if (isNativeApp(id)) { XNativeAppInstallerListener nativeListener = new XNativeAppInstallerListener( listener, mNativeAppInstallDelegate, getAppList() .getAppById(id)); return nativeListener; } return listener; } /** * 安装一个应用 * * @param path * 应用安装包的绝对路径 * @param listener * 安装监听器 */ public String installApp(String path, XInstallListener listener) { return mAppInstaller.install(path, wrapInstallerListener(listener, path)); } /** * 安装一个应用 * * @param path * 应用安装包的绝对路径 * @param appId * 应用的appId * @param listener * 安装监听器 */ public String installApp(String path, String appId, XInstallListener listener) { return mAppInstaller.install(path, appId, listener); } /** * 更新一个应用 * * @param path * 安装包路径 * @param listener * 更新监听器 */ public void updateApp(String path, XInstallListener listener) { mAppInstaller.update(path, wrapInstallerListener(listener, path)); } /** * 卸载应用 * * @param appId * @param listener * 卸载监听器 */ public void uninstallApp(String appId, XInstallListener listener) { mAppInstaller .uninstall(appId, wrapUninstallerListener(listener, appId)); } /** * 安装一个应用 * * @param path * 应用安装包的绝对路径 */ public String installApp(String path) { return installApp(path, wrapInstallerListener(EMPTRY_INSTALL_LISTENER, path)); } public String installApp(String path, String appid) { if (XStringUtils.isEmptyString(appid)) { return installApp(path); } return installApp(path, appid, wrapInstallerListener(EMPTRY_INSTALL_LISTENER, path)); } /** * 更新一个应用 * * @param path * 安装包路径 */ public void updateApp(String path) { updateApp(path, wrapInstallerListener(EMPTRY_INSTALL_LISTENER, path)); } /** * 关闭应用 * * @param viewId * 需要关闭应用对应的viewId */ public void closeApp(int viewId) { XAppList appList = getAppList(); String appId = appList.getAppIdByViewId(viewId); assert appId != null; closeApp(appId); } /** * 关闭应用 * * @param appId */ public void closeApp(String appId) { XApplication app = XApplicationCreator.toWebApp(getAppList() .getAppById(appId)); if (null == app) { XLog.e(CLASS_NAME, "Close app failed, can't find app by id: " + appId); return; } if (mAppStack.empty()) { XLog.d(CLASS_NAME, "The app stack is empty when closing app!"); return; } mAppStack.remove(app); app.close(); } /** * 得到当前活动的app * */ public XIApplication getCurrActiveApp() { if (mAppStack.empty()) { XLog.d(CLASS_NAME, "The app stack is empty when getting current Active App!"); return null; } return mAppStack.peek(); } /** * 处理app的通讯消息 * * @param view * @param data */ public void handleAppMessage(XApplication startApp, XAppWebView view, String msgData) { XAppList list = getAppList(); XApplication app = list.getAppByViewId(view.getViewId()); String jsScript = "try{cordova.require('com.polyvi.xface.extension.ams.app').fireAppEvent('message'," + msgData + ");}catch(e){console.log('exception in fireAppEvent:' + e);}"; if (null != app) { startApp.loadJavascript(jsScript); } else { Iterator<XIApplication> apps = mAppStack.iterator(); while (apps.hasNext()) { XApplication xapp = XApplicationCreator.toWebApp(apps.next()); if (null == xapp) { continue; } xapp.loadJavascript(jsScript); } } } /** * 获取预置包 * * @return 返回预置包数组,每一项是预置包名 * */ public String[] getPresetAppPackages(String startAppWorkSpace) { assert null != startAppWorkSpace; File presetPackageDir = new File(startAppWorkSpace, XConstant.PRE_SET_APP_PACKAGE_DIR_NAME); if (!presetPackageDir.exists()) { return null; } return presetPackageDir.list(new FilenameFilter() { @Override public boolean accept(File file, String name) { File presetFile = new File(file.getAbsolutePath(), name); if (presetFile.isFile()) { return name.endsWith(XConstant.APP_PACKAGE_SUFFIX) || name.endsWith(XConstant.APP_PACKAGE_SUFFIX_XPA) || name.endsWith(XConstant.APP_PACKAGE_SUFFIX_XSPA); } return false; } }); } /** * 在xFace退出的时候要关闭所有app * */ public void closeAllApp() { while (null != mAppStack && !mAppStack.empty()) { XIApplication app = mAppStack.peek(); closeApp(app.getAppId()); } } /** * 判断是否是native app的类型 * * @param app * 被判断的app类型 * @return 是native类型,不是native类型 */ boolean isNativeApp(XIApplication app) { return app instanceof XNativeApplication; } /** * 判断是否是native app的类型 * * @param app * 被判断的app的id * @return true:是native类型,false:不是native类型 */ boolean isNativeApp(String appId) { XIApplication app = getAppList().getAppById(appId); return isNativeApp(app); } /** * 判断压缩包是否为NativeApp的压缩包 * * @param path * 压缩包的路径 * @return true:是native压缩包,false不是native压缩包 */ boolean isNativePackage(String path) { return path.endsWith(XConstant.NATIVE_APP_SUFFIX_NPA); } /** * 获得app的创建工厂 */ public XApplicationCreator getAppCreator() { return mAppCreator; } }