Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 package org.mozilla.gecko.webapp;
8 import java.io.Closeable;
9 import java.io.File;
10 import java.io.FileOutputStream;
11 import java.io.IOException;
12 import java.io.InputStream;
13 import java.io.OutputStream;
15 import org.json.JSONException;
16 import org.json.JSONObject;
17 import org.mozilla.gecko.GeckoAppShell;
18 import org.mozilla.gecko.GeckoEvent;
19 import org.mozilla.gecko.GeckoProfile;
20 import org.mozilla.gecko.gfx.BitmapUtils;
21 import org.mozilla.gecko.util.GeckoEventListener;
22 import org.mozilla.gecko.util.ThreadUtils;
24 import android.content.Context;
25 import android.graphics.Bitmap;
26 import android.net.Uri;
27 import android.util.Log;
29 public class InstallHelper implements GeckoEventListener {
30 private static final String LOGTAG = "GeckoWebappInstallHelper";
31 private static final String[] INSTALL_EVENT_NAMES = new String[] {"Webapps:Postinstall"};
32 private final Context mContext;
33 private final InstallCallback mCallback;
34 private final ApkResources mApkResources;
36 public static interface InstallCallback {
37 // on the GeckoThread
38 void installCompleted(InstallHelper installHelper, String event, JSONObject message);
40 // on the GeckoBackgroundThread
41 void installErrored(InstallHelper installHelper, Exception exception);
42 }
44 public InstallHelper(Context context, ApkResources apkResources, InstallCallback cb) {
45 mContext = context;
46 mCallback = cb;
47 mApkResources = apkResources;
48 }
50 public void startInstall(String profileName) throws IOException {
51 startInstall(profileName, null);
52 }
54 public void startInstall(final String profileName, final JSONObject message) throws IOException {
55 ThreadUtils.postToBackgroundThread(new Runnable() {
56 @Override
57 public void run() {
58 try {
59 install(profileName, message);
60 } catch (IOException e) {
61 handleException(e);
62 }
63 }
64 });
65 }
67 protected void handleException(Exception e) {
68 if (mCallback != null) {
69 mCallback.installErrored(this, e);
70 } else {
71 Log.e(LOGTAG, "mozApps.install failed", e);
72 }
73 }
75 private void install(String profileName, JSONObject message) throws IOException {
76 if (message == null) {
77 message = new JSONObject();
78 }
80 // we can change the profile to be in the app's area here
81 GeckoProfile profile = GeckoProfile.get(mContext, profileName);
83 try {
84 message.put("apkPackageName", mApkResources.getPackageName());
85 message.put("manifestURL", mApkResources.getManifestUrl());
86 message.put("title", mApkResources.getAppName());
87 message.put("manifest", new JSONObject(mApkResources.getManifest(mContext)));
89 String appType = mApkResources.getWebappType();
90 message.putOpt("type", appType);
91 if ("packaged".equals(appType)) {
92 message.putOpt("updateManifest", new JSONObject(mApkResources.getMiniManifest(mContext)));
93 }
95 message.putOpt("profilePath", profile.getDir());
97 if (mApkResources.isPackaged()) {
98 File zipFile = copyApplicationZipFile();
99 message.putOpt("zipFilePath", Uri.fromFile(zipFile).toString());
100 }
101 } catch (JSONException e) {
102 handleException(e);
103 return;
104 }
106 registerGeckoListener();
108 GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Webapps:AutoInstall", message.toString()));
109 calculateColor();
110 }
112 public File copyApplicationZipFile() throws IOException {
113 if (!mApkResources.isPackaged()) {
114 return null;
115 }
117 Uri uri = mApkResources.getZipFileUri();
119 InputStream in = null;
120 OutputStream out = null;
121 File destPath = new File(mApkResources.getFileDirectory(), "application.zip");
122 try {
123 in = mContext.getContentResolver().openInputStream(uri);
124 out = new FileOutputStream(destPath);
125 byte[] buffer = new byte[1024];
126 int read = 0;
127 while ((read = in.read(buffer)) != -1) {
128 out.write(buffer, 0, read);
129 }
130 out.flush();
131 } catch (IOException e) {
132 throw e;
133 } finally {
134 close(in);
135 close(out);
136 }
137 return destPath;
138 }
140 private static void close(Closeable close) {
141 if (close == null) {
142 return;
143 }
144 try {
145 close.close();
146 } catch (IOException e) {
147 // NOP
148 }
149 }
151 public void registerGeckoListener() {
152 for (String eventName : INSTALL_EVENT_NAMES) {
153 GeckoAppShell.registerEventListener(eventName, this);
154 }
155 }
157 private void calculateColor() {
158 ThreadUtils.assertOnBackgroundThread();
159 Allocator slots = Allocator.getInstance(mContext);
160 int index = slots.getIndexForApp(mApkResources.getPackageName());
161 Bitmap bitmap = BitmapUtils.getBitmapFromDrawable(mApkResources.getAppIcon());
162 slots.updateColor(index, BitmapUtils.getDominantColor(bitmap));
163 }
165 @Override
166 public void handleMessage(String event, JSONObject message) {
167 for (String eventName : INSTALL_EVENT_NAMES) {
168 GeckoAppShell.unregisterEventListener(eventName, this);
169 }
171 if (mCallback != null) {
172 mCallback.installCompleted(this, event, message);
173 }
174 }
175 }