michael@0: /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: package org.mozilla.gecko.webapp; michael@0: michael@0: import java.io.Closeable; michael@0: import java.io.File; michael@0: import java.io.FileOutputStream; michael@0: import java.io.IOException; michael@0: import java.io.InputStream; michael@0: import java.io.OutputStream; michael@0: michael@0: import org.json.JSONException; michael@0: import org.json.JSONObject; michael@0: import org.mozilla.gecko.GeckoAppShell; michael@0: import org.mozilla.gecko.GeckoEvent; michael@0: import org.mozilla.gecko.GeckoProfile; michael@0: import org.mozilla.gecko.gfx.BitmapUtils; michael@0: import org.mozilla.gecko.util.GeckoEventListener; michael@0: import org.mozilla.gecko.util.ThreadUtils; michael@0: michael@0: import android.content.Context; michael@0: import android.graphics.Bitmap; michael@0: import android.net.Uri; michael@0: import android.util.Log; michael@0: michael@0: public class InstallHelper implements GeckoEventListener { michael@0: private static final String LOGTAG = "GeckoWebappInstallHelper"; michael@0: private static final String[] INSTALL_EVENT_NAMES = new String[] {"Webapps:Postinstall"}; michael@0: private final Context mContext; michael@0: private final InstallCallback mCallback; michael@0: private final ApkResources mApkResources; michael@0: michael@0: public static interface InstallCallback { michael@0: // on the GeckoThread michael@0: void installCompleted(InstallHelper installHelper, String event, JSONObject message); michael@0: michael@0: // on the GeckoBackgroundThread michael@0: void installErrored(InstallHelper installHelper, Exception exception); michael@0: } michael@0: michael@0: public InstallHelper(Context context, ApkResources apkResources, InstallCallback cb) { michael@0: mContext = context; michael@0: mCallback = cb; michael@0: mApkResources = apkResources; michael@0: } michael@0: michael@0: public void startInstall(String profileName) throws IOException { michael@0: startInstall(profileName, null); michael@0: } michael@0: michael@0: public void startInstall(final String profileName, final JSONObject message) throws IOException { michael@0: ThreadUtils.postToBackgroundThread(new Runnable() { michael@0: @Override michael@0: public void run() { michael@0: try { michael@0: install(profileName, message); michael@0: } catch (IOException e) { michael@0: handleException(e); michael@0: } michael@0: } michael@0: }); michael@0: } michael@0: michael@0: protected void handleException(Exception e) { michael@0: if (mCallback != null) { michael@0: mCallback.installErrored(this, e); michael@0: } else { michael@0: Log.e(LOGTAG, "mozApps.install failed", e); michael@0: } michael@0: } michael@0: michael@0: private void install(String profileName, JSONObject message) throws IOException { michael@0: if (message == null) { michael@0: message = new JSONObject(); michael@0: } michael@0: michael@0: // we can change the profile to be in the app's area here michael@0: GeckoProfile profile = GeckoProfile.get(mContext, profileName); michael@0: michael@0: try { michael@0: message.put("apkPackageName", mApkResources.getPackageName()); michael@0: message.put("manifestURL", mApkResources.getManifestUrl()); michael@0: message.put("title", mApkResources.getAppName()); michael@0: message.put("manifest", new JSONObject(mApkResources.getManifest(mContext))); michael@0: michael@0: String appType = mApkResources.getWebappType(); michael@0: message.putOpt("type", appType); michael@0: if ("packaged".equals(appType)) { michael@0: message.putOpt("updateManifest", new JSONObject(mApkResources.getMiniManifest(mContext))); michael@0: } michael@0: michael@0: message.putOpt("profilePath", profile.getDir()); michael@0: michael@0: if (mApkResources.isPackaged()) { michael@0: File zipFile = copyApplicationZipFile(); michael@0: message.putOpt("zipFilePath", Uri.fromFile(zipFile).toString()); michael@0: } michael@0: } catch (JSONException e) { michael@0: handleException(e); michael@0: return; michael@0: } michael@0: michael@0: registerGeckoListener(); michael@0: michael@0: GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Webapps:AutoInstall", message.toString())); michael@0: calculateColor(); michael@0: } michael@0: michael@0: public File copyApplicationZipFile() throws IOException { michael@0: if (!mApkResources.isPackaged()) { michael@0: return null; michael@0: } michael@0: michael@0: Uri uri = mApkResources.getZipFileUri(); michael@0: michael@0: InputStream in = null; michael@0: OutputStream out = null; michael@0: File destPath = new File(mApkResources.getFileDirectory(), "application.zip"); michael@0: try { michael@0: in = mContext.getContentResolver().openInputStream(uri); michael@0: out = new FileOutputStream(destPath); michael@0: byte[] buffer = new byte[1024]; michael@0: int read = 0; michael@0: while ((read = in.read(buffer)) != -1) { michael@0: out.write(buffer, 0, read); michael@0: } michael@0: out.flush(); michael@0: } catch (IOException e) { michael@0: throw e; michael@0: } finally { michael@0: close(in); michael@0: close(out); michael@0: } michael@0: return destPath; michael@0: } michael@0: michael@0: private static void close(Closeable close) { michael@0: if (close == null) { michael@0: return; michael@0: } michael@0: try { michael@0: close.close(); michael@0: } catch (IOException e) { michael@0: // NOP michael@0: } michael@0: } michael@0: michael@0: public void registerGeckoListener() { michael@0: for (String eventName : INSTALL_EVENT_NAMES) { michael@0: GeckoAppShell.registerEventListener(eventName, this); michael@0: } michael@0: } michael@0: michael@0: private void calculateColor() { michael@0: ThreadUtils.assertOnBackgroundThread(); michael@0: Allocator slots = Allocator.getInstance(mContext); michael@0: int index = slots.getIndexForApp(mApkResources.getPackageName()); michael@0: Bitmap bitmap = BitmapUtils.getBitmapFromDrawable(mApkResources.getAppIcon()); michael@0: slots.updateColor(index, BitmapUtils.getDominantColor(bitmap)); michael@0: } michael@0: michael@0: @Override michael@0: public void handleMessage(String event, JSONObject message) { michael@0: for (String eventName : INSTALL_EVENT_NAMES) { michael@0: GeckoAppShell.unregisterEventListener(eventName, this); michael@0: } michael@0: michael@0: if (mCallback != null) { michael@0: mCallback.installCompleted(this, event, message); michael@0: } michael@0: } michael@0: }