blob: 5ecb6613708a5e5b1aba322dded5dd11cc332326 [file] [log] [blame]
Vivek Sekharb53a5952015-07-17 14:14:38 -07001/*
2 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*/
29
30package com.android.browser;
31
32import android.app.IntentService;
33import android.app.Notification;
34import android.app.NotificationManager;
35import android.app.PendingIntent;
36import android.app.TaskStackBuilder;
37import android.content.Intent;
38import android.content.Context;
39import android.content.SharedPreferences;
40import android.content.pm.ApplicationInfo;
41import android.content.pm.PackageInfo;
42import android.content.pm.PackageManager;
43import android.net.Uri;
44import android.support.v4.app.NotificationCompat;
Vivek Sekharb53a5952015-07-17 14:14:38 -070045
46
47import org.codeaurora.swe.BrowserCommandLine;
48import org.codeaurora.swe.Engine;
Vivek Sekhar1f4cd1a2015-08-07 15:23:31 -070049import org.codeaurora.swe.utils.Logger;
Vivek Sekharb53a5952015-07-17 14:14:38 -070050import org.json.JSONObject;
51import org.json.JSONTokener;
52
53import java.io.BufferedReader;
Vivek Sekharb53a5952015-07-17 14:14:38 -070054import java.io.InputStream;
55import java.io.InputStreamReader;
56import java.net.URL;
57import java.net.URLConnection;
58
59public class UpdateNotificationService extends IntentService {
60 private static final String LOGTAG = "UpdateNotificationService";
61 private static final String ACTION_CHECK_UPDATES = BrowserConfig.AUTHORITY +
62 ".action.check.update";
Vivek Sekhar1f4cd1a2015-08-07 15:23:31 -070063 public static final int DEFAULT_UPDATE_INTERVAL = 172800000; // two days
Vivek Sekharb53a5952015-07-17 14:14:38 -070064 public static final String UPDATE_SERVICE_PREF = "browser_update_service";
65 public static final String UPDATE_JSON_VERSION_CODE = "versioncode";
66 public static final String UPDATE_JSON_VERSION_STRING = "versionstring";
67 public static final String UPDATE_JSON_MIN_INTERVAL = "interval";
68 public static final String UPDATE_INTERVAL = "update_interval";
69 public static final String UPDATE_VERSION_CODE = "version_code";
70 public static final String UPDATE_VERSION = "update_version";
71 public static final String UPDATE_URL = "update_url";
72 public static final String UPDATE_TIMESTAMP = "update_timestamp";
73 private static int NOTIFICATION_ID = 1000;
74 private static boolean sIntentServiceInitialized = false;
75 private static boolean sNotifyAlways = false;
76
77 @Override
78 public void onCreate() {
79 super.onCreate();
80 initEngine(this);
81 }
82
83 @Override
84 public void onDestroy() {
85 super.onDestroy();
86 if (sIntentServiceInitialized)
87 Engine.pauseTracing(this);
88 }
89
90 private static void initEngine(Context context) {
91 if (!EngineInitializer.isInitialized()) {
92 sIntentServiceInitialized = true;
93 EngineInitializer.initializeSync((Context) context);
94 }
95 }
96
97 public static void startActionUpdateNotificationService(Context context) {
98 Intent intent = new Intent(context, UpdateNotificationService.class);
99 intent.setAction(ACTION_CHECK_UPDATES);
100 context.startService(intent);
101 }
102
103 public static String getFlavor(Context ctx) {
104 String flavor = "";
105 try {
106 ApplicationInfo ai = ctx.getPackageManager().getApplicationInfo(
107 ctx.getPackageName(),PackageManager.GET_META_DATA);
108 String compiler = (String) ai.metaData.get("Compiler");
109 String arch = (String) ai.metaData.get("Architecture");
110 flavor = "url-" + compiler + "-" + arch;
111 } catch (Exception e) {
Vivek Sekhar1f4cd1a2015-08-07 15:23:31 -0700112 Logger.e(LOGTAG, "getFlavor Exception : " + e.toString());
Vivek Sekharb53a5952015-07-17 14:14:38 -0700113 }
114 return flavor;
115 }
116
117 public static void updateCheck(Context context) {
118 initEngine(context.getApplicationContext());
119 if (!BrowserCommandLine.hasSwitch(BrowserSwitches.AUTO_UPDATE_SERVER_CMD)) {
Vivek Sekhar1f4cd1a2015-08-07 15:23:31 -0700120 Logger.v(LOGTAG, "skip no command line: ");
Vivek Sekharb53a5952015-07-17 14:14:38 -0700121 return;
122 }
123 long interval = getInterval(context);
124 Long last_update_time = getLastUpdateTimestamp(context);
125 if ((last_update_time + interval) < System.currentTimeMillis()) {
Vivek Sekhar1f4cd1a2015-08-07 15:23:31 -0700126 Logger.v(LOGTAG, "check for update now: ");
Vivek Sekharb53a5952015-07-17 14:14:38 -0700127 startActionUpdateNotificationService(context);
128 }
129 }
130
131 public static int getLatestVersionCode(Context ctx) {
132 SharedPreferences sharedPref = ctx.getSharedPreferences(
133 UPDATE_SERVICE_PREF, Context.MODE_PRIVATE);
134 return sharedPref.getInt(UPDATE_VERSION_CODE, 0);
135 }
136
137 public static String getLatestDownloadUrl(Context ctx) {
138 SharedPreferences sharedPref = ctx.getSharedPreferences(
139 UPDATE_SERVICE_PREF, Context.MODE_PRIVATE);
140 return sharedPref.getString(UPDATE_URL,"");
141 }
142
143 public static String getLatestVersion(Context ctx) {
144 SharedPreferences sharedPref = ctx.getSharedPreferences(
145 UPDATE_SERVICE_PREF, Context.MODE_PRIVATE);
146 return sharedPref.getString(UPDATE_VERSION, "");
147 }
148
149 private static long getLastUpdateTimestamp(Context ctx) {
150 SharedPreferences sharedPref = ctx.getSharedPreferences(
151 UPDATE_SERVICE_PREF, Context.MODE_PRIVATE);
152 return sharedPref.getLong(UPDATE_TIMESTAMP, 0);
153 }
154
155 private static int getInterval(Context ctx) {
156 SharedPreferences sharedPref = ctx.getSharedPreferences(
157 UPDATE_SERVICE_PREF, Context.MODE_PRIVATE);
158 return sharedPref.getInt(UPDATE_INTERVAL, DEFAULT_UPDATE_INTERVAL);
159 }
160
161 public UpdateNotificationService() {
162 super("UpdateNotificationService");
163 }
164
165 @Override
166 protected void onHandleIntent(Intent intent) {
167 if (intent != null) {
168 final String action = intent.getAction();
169 if (ACTION_CHECK_UPDATES.equals(action)) {
170 handleUpdateCheck();
171 }
172 }
173 }
174
175 private void updateTimeStamp() {
176 SharedPreferences sharedPref = getSharedPreferences(
177 UPDATE_SERVICE_PREF, Context.MODE_PRIVATE);
178 SharedPreferences.Editor editor = sharedPref.edit();
179 editor.putLong(UPDATE_TIMESTAMP, System.currentTimeMillis());
180 editor.commit();
181 }
182
183 private void persist(int versionCode, String url, String version, int interval) {
184 SharedPreferences sharedPref = getSharedPreferences(
185 UPDATE_SERVICE_PREF, Context.MODE_PRIVATE);
186 SharedPreferences.Editor editor = sharedPref.edit();
187 editor.putInt(UPDATE_VERSION_CODE, versionCode);
188 editor.putInt(UPDATE_INTERVAL, interval);
189 editor.putString(UPDATE_VERSION, version);
190 editor.putString(UPDATE_URL, url);
Vivek Sekhar1f4cd1a2015-08-07 15:23:31 -0700191 Logger.v(LOGTAG, "persist version code : " + versionCode);
192 Logger.v(LOGTAG, "persist version : " + version);
193 Logger.v(LOGTAG, "persist download url : " + url);
Vivek Sekharb53a5952015-07-17 14:14:38 -0700194 editor.commit();
195 }
196
197 private void handleUpdateCheck() {
198 String server_url = BrowserCommandLine.getSwitchValue(
Vivek Sekhar1f4cd1a2015-08-07 15:23:31 -0700199 BrowserSwitches.AUTO_UPDATE_SERVER_CMD);
Vivek Sekharb53a5952015-07-17 14:14:38 -0700200 int interval = DEFAULT_UPDATE_INTERVAL;
201 InputStream stream = null;
202 if (server_url != null && !server_url.isEmpty()) {
203 try {
204 URLConnection connection = new URL(server_url).openConnection();
205 stream = connection.getInputStream();
206 String result = readContents(stream);
Vivek Sekhar1f4cd1a2015-08-07 15:23:31 -0700207 Logger.v(LOGTAG, "handleUpdateCheck result : " + result);
Vivek Sekharb53a5952015-07-17 14:14:38 -0700208 JSONObject jsonResult = (JSONObject) new JSONTokener(result).nextValue();
209 int versionCode = Integer.parseInt((String) jsonResult.get(UPDATE_JSON_VERSION_CODE));
210 String url = (String) jsonResult.get(getFlavor(this));
211 String version = (String) jsonResult.get(UPDATE_JSON_VERSION_STRING);
212 if (jsonResult.has(UPDATE_JSON_MIN_INTERVAL))
213 interval = Integer.parseInt((String) jsonResult.get(UPDATE_JSON_MIN_INTERVAL));
214 if (getCurrentVersionCode(this) < versionCode &&
215 (sNotifyAlways || getLatestVersionCode(this) != versionCode)) {
216 persist(versionCode, url, version, interval);
217 // notify only once per version change
218 showNotification(this, url, version);
219 }
220 stream.close();
Vivek Sekhard4887292015-07-31 16:52:00 -0700221 } catch (Exception e) {
Vivek Sekhar1f4cd1a2015-08-07 15:23:31 -0700222 Logger.e(LOGTAG, "handleUpdateCheck Exception : " + e.toString());
Vivek Sekharb53a5952015-07-17 14:14:38 -0700223 } finally {
224 // always update the timestamp
225 updateTimeStamp();
226 }
227 }
228 }
229
230 public static int getCurrentVersionCode(Context ctx) {
231 PackageInfo pInfo = null;
232 try {
233 pInfo = ctx.getPackageManager().getPackageInfo(ctx.getPackageName(), 0);
234 } catch (PackageManager.NameNotFoundException e) {
Vivek Sekhar1f4cd1a2015-08-07 15:23:31 -0700235 Logger.e(LOGTAG, "getCurrentVersionCode Exception : " + e.toString());
Vivek Sekharb53a5952015-07-17 14:14:38 -0700236 }
237 return pInfo.versionCode;
238 }
239
240 private static void showNotification(Context ctx, String url, String version) {
241 NotificationCompat.Builder builder =
242 new NotificationCompat.Builder(ctx)
243 .setSmallIcon(R.drawable.img_notify_update_white)
244 .setContentTitle(ctx.getString(R.string.update))
245 .setContentText(ctx.getString(R.string.update_msg) + version);
246 Intent resultIntent = new Intent(ctx, BrowserActivity.class);
247 resultIntent.setAction(Intent.ACTION_VIEW);
248 resultIntent.setData(Uri.parse(url));
249 TaskStackBuilder stackBuilder = TaskStackBuilder.create(ctx);
250 stackBuilder.addParentStack(BrowserActivity.class);
251 stackBuilder.addNextIntent(resultIntent);
252 PendingIntent resultPendingIntent =
253 stackBuilder.getPendingIntent(
254 0,
255 PendingIntent.FLAG_UPDATE_CURRENT
256 );
257 builder.setContentIntent(resultPendingIntent);
258 NotificationManager mNotificationManager =
259 (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
260 Notification notification = builder.build();
261 notification.flags = Notification.DEFAULT_LIGHTS | Notification.FLAG_AUTO_CANCEL;
262 mNotificationManager.notify(NOTIFICATION_ID, notification);
263 }
264
265 private static void removeNotification(Context ctx) {
266 NotificationManager mNotificationManager =
267 (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
268 mNotificationManager.cancel(NOTIFICATION_ID);
269 }
270
271 private static String readContents(InputStream is) {
272 String line = null;
273 BufferedReader reader = new BufferedReader(new InputStreamReader(is));
274 StringBuilder sb = new StringBuilder();
275 try {
276 line = reader.readLine();
277 while (line != null) {
278 line = line.replaceFirst("channel = ","");
279 sb.append(line + "\n");
280 line = reader.readLine();
281 }
282 } catch (Exception e) {
Vivek Sekhar1f4cd1a2015-08-07 15:23:31 -0700283 Logger.e(LOGTAG, "convertStreamToString Exception : " + e.toString());
Vivek Sekharb53a5952015-07-17 14:14:38 -0700284 } finally {
285 try {
286 is.close();
287 } catch (Exception e) {
Vivek Sekhar1f4cd1a2015-08-07 15:23:31 -0700288 Logger.e(LOGTAG, "convertStreamToString Exception : " + e.toString());
Vivek Sekharb53a5952015-07-17 14:14:38 -0700289 }
290 }
291 return sb.toString();
292 }
293
294}