blob: a211cd8a18ab4ce9e7df272ed610c7f0e8e2fbab [file] [log] [blame]
Kim Hansen086964d2013-12-10 11:33:28 +00001/*
2 * Copyright (C) 2013 Fairphone Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.fairphone.updater;
18
Jose Pascoalcf13fde2014-05-21 20:17:17 +010019import java.io.File;
20import java.io.IOException;
Filipe Gonçalvescd0f33d2014-12-15 15:05:15 +000021import java.io.UnsupportedEncodingException;
22import java.net.URLEncoder;
23import java.nio.charset.Charset;
24
Kim Hansen086964d2013-12-10 11:33:28 +000025import android.app.DownloadManager;
26import android.app.DownloadManager.Request;
27import android.app.Notification;
28import android.app.NotificationManager;
29import android.app.PendingIntent;
30import android.app.Service;
31import android.app.TaskStackBuilder;
32import android.content.BroadcastReceiver;
33import android.content.Context;
34import android.content.Intent;
35import android.content.IntentFilter;
36import android.content.SharedPreferences;
37import android.content.SharedPreferences.Editor;
38import android.content.res.Resources;
39import android.database.Cursor;
40import android.graphics.BitmapFactory;
41import android.net.ConnectivityManager;
42import android.net.Uri;
Jose Pascoalcf13fde2014-05-21 20:17:17 +010043import android.os.Build;
Kim Hansen086964d2013-12-10 11:33:28 +000044import android.os.Environment;
Filipe Gonçalvesb2536c02015-01-12 11:50:25 +000045import android.os.Handler;
Kim Hansen086964d2013-12-10 11:33:28 +000046import android.os.IBinder;
Filipe Gonçalvesb2536c02015-01-12 11:50:25 +000047import android.os.SystemClock;
Kim Hansen086964d2013-12-10 11:33:28 +000048import android.support.v4.app.NotificationCompat;
Tiago Costac14ea242014-04-24 10:14:41 +010049import android.util.Log;
Jose Pascoal0e966282014-08-12 18:49:05 +010050import android.widget.Toast;
Filipe Gonçalvescd0f33d2014-12-15 15:05:15 +000051
Filipe Gonçalves8f226b02014-12-12 11:21:58 +000052import java.util.concurrent.TimeoutException;
Kim Hansen086964d2013-12-10 11:33:28 +000053
Filipe Gonçalvesa75e1812015-03-19 12:12:07 +000054import com.fairphone.updater.data.UpdaterData;
Jose Pascoal7bf83a02014-10-13 18:30:18 +010055import com.fairphone.updater.data.Version;
56import com.fairphone.updater.data.VersionParserHelper;
Jose Pascoalac6a8462014-09-10 20:12:08 +010057import com.fairphone.updater.gappsinstaller.GappsInstallerHelper;
Filipe Gonçalves49ce23c2015-02-13 16:33:52 +000058import com.fairphone.updater.tools.PrivilegeChecker;
Jose Pascoal02b849e2014-06-26 17:07:51 +010059import com.fairphone.updater.tools.RSAUtils;
60import com.fairphone.updater.tools.Utils;
Jose Pascoalcf13fde2014-05-21 20:17:17 +010061import com.stericson.RootTools.execution.CommandCapture;
62import com.stericson.RootTools.execution.Shell;
Kim Hansen086964d2013-12-10 11:33:28 +000063
Filipe Gonçalvescd0f33d2014-12-15 15:05:15 +000064
Jose Pascoal810950b2014-10-09 17:16:08 +010065public class UpdaterService extends Service
66{
Kim Hansen086964d2013-12-10 11:33:28 +000067
Filipe Gonçalves6ce7b142015-01-22 14:39:29 +000068 public static final String LAST_CONFIG_DOWNLOAD_IN_MS = "LAST_CONFIG_DOWNLOAD_IN_MS";
Filipe Gonçalves8b263ad2015-01-12 12:30:11 +000069 private static final int CONFIG_FILE_DOWNLOAD_TIMEOUT_MILLIS = 23500;
Filipe Gonçalves8f226b02014-12-12 11:21:58 +000070 public static final String EXTRA_FORCE_CONFIG_FILE_DOWNLOAD = "FORCE_DOWNLOAD";
71
Jose Pascoal810950b2014-10-09 17:16:08 +010072 private static final String TAG = UpdaterService.class.getSimpleName();
73
Jose Pascoalc2545cc2014-12-18 16:51:52 +000074 public static final String PREFERENCE_LAST_CONFIG_DOWNLOAD_ID = "LastConfigDownloadId";
Tiago Costa87925fe2014-12-02 17:57:51 +000075 public static final String PREFERENCE_REINSTALL_GAPPS = "ReinstallGappsOmnStartUp";
Filipe Gonçalves80d4b152015-05-26 19:04:02 +010076 public static final String PREFERENCE_CONFIG_MD_5 = "CONFIG_MD5";
Jose Pascoal810950b2014-10-09 17:16:08 +010077 private DownloadManager mDownloadManager = null;
78 private DownloadBroadCastReceiver mDownloadBroadCastReceiver = null;
Kim Hansen086964d2013-12-10 11:33:28 +000079
Jose Pascoal1ee56e22014-05-21 16:58:20 +010080 private static final int MAX_DOWNLOAD_RETRIES = 3;
81 private int mDownloadRetries;
Jose Pascoal810950b2014-10-09 17:16:08 +010082 private long mLatestFileDownloadId;
Filipe Gonçalvesd28bd622014-11-05 11:40:12 +000083 private boolean mInternetConnectionAvailable;
Kim Hansen086964d2013-12-10 11:33:28 +000084
Filipe Gonçalvesb31d5862015-02-04 17:28:58 +000085 private SharedPreferences mSharedPreferences;
Jose Pascoal810950b2014-10-09 17:16:08 +010086
Jose Pascoalb03b55c2015-02-19 17:34:07 +000087 private final static long DOWNLOAD_GRACE_PERIOD_IN_MS = 24 /* hour */ * Utils.MINUTES_IN_HOUR /* minute */ * Utils.SECONDS_IN_MINUTE /* second */ * 1000 /* millisecond */;
Filipe Gonçalves40893132015-05-25 17:45:44 +010088 private BroadcastReceiver networkStateReceiver;
Jose Pascoal29ee1012014-09-12 17:25:36 +010089
Filipe Gonçalves40893132015-05-25 17:45:44 +010090 @Override
Jose Pascoal810950b2014-10-09 17:16:08 +010091 public int onStartCommand(Intent intent, int flags, int startId)
92 {
Jose Pascoal810950b2014-10-09 17:16:08 +010093 // remove the logs
94 clearDataLogs();
Jose Pascoalda00b382015-01-20 18:39:28 +000095
Filipe Gonçalvesb31d5862015-02-04 17:28:58 +000096 if(Utils.isDeviceUnsupported(getApplicationContext())){
Jose Pascoalda00b382015-01-20 18:39:28 +000097 stopSelf();
98 return START_NOT_STICKY;
99 }
Jose Pascoal29ee1012014-09-12 17:25:36 +0100100
Jose Pascoal7bf83a02014-10-13 18:30:18 +0100101 mSharedPreferences = getApplicationContext().getSharedPreferences(FairphoneUpdater.FAIRPHONE_UPDATER_PREFERENCES, MODE_PRIVATE);
Jose Pascoal29ee1012014-09-12 17:25:36 +0100102
Jose Pascoal810950b2014-10-09 17:16:08 +0100103 mLatestFileDownloadId = mSharedPreferences.getLong(PREFERENCE_LAST_CONFIG_DOWNLOAD_ID, 0);
Tiago Costa87925fe2014-12-02 17:57:51 +0000104
Jose Pascoalaa579a82014-11-05 22:17:16 +0000105 setupDownloadManager();
Tiago Costa87925fe2014-12-02 17:57:51 +0000106
Filipe Gonçalvesd28bd622014-11-05 11:40:12 +0000107 setupConnectivityMonitoring();
Jose Pascoal1ee56e22014-05-21 16:58:20 +0100108
Filipe Gonçalves40893132015-05-25 17:45:44 +0100109 if (Utils.isWiFiEnabled(getApplicationContext()))
Jose Pascoal810950b2014-10-09 17:16:08 +0100110 {
Filipe Gonçalves40893132015-05-25 17:45:44 +0100111 downloadConfigFile(intent != null && intent.getBooleanExtra(EXTRA_FORCE_CONFIG_FILE_DOWNLOAD, false));
Jose Pascoal810950b2014-10-09 17:16:08 +0100112 }
113
114 // setup the gapps installer
Jose Pascoal40916302015-02-06 18:43:47 +0000115 GappsInstallerHelper.checkGappsAreInstalled(getApplicationContext());
Jose Pascoal810950b2014-10-09 17:16:08 +0100116
Filipe Gonçalvesa75e1812015-03-19 12:12:07 +0000117 runInstallationDisclaimer(getApplicationContext());
Tiago Costa87925fe2014-12-02 17:57:51 +0000118
Jose Pascoal810950b2014-10-09 17:16:08 +0100119 return Service.START_STICKY;
120 }
121
Filipe Gonçalvesa75e1812015-03-19 12:12:07 +0000122 private static void runInstallationDisclaimer(Context context)
Tiago Costa87925fe2014-12-02 17:57:51 +0000123 {
Filipe Gonçalvesa75e1812015-03-19 12:12:07 +0000124 SharedPreferences sharedPreferences = context.getApplicationContext().getSharedPreferences(FairphoneUpdater.FAIRPHONE_UPDATER_PREFERENCES, MODE_PRIVATE);
125 if (sharedPreferences.getBoolean(PREFERENCE_REINSTALL_GAPPS, true) && !UpdaterData.getInstance().isAppStoreListEmpty())
Tiago Costa87925fe2014-12-02 17:57:51 +0000126 {
Tiago Costa87925fe2014-12-02 17:57:51 +0000127 if(!GappsInstallerHelper.areGappsInstalled()){
Filipe Gonçalvesa75e1812015-03-19 12:12:07 +0000128 showReinstallAlert(context);
Tiago Costa87925fe2014-12-02 17:57:51 +0000129 }
130
Filipe Gonçalvesa75e1812015-03-19 12:12:07 +0000131 Editor editor = sharedPreferences.edit();
Tiago Costa87925fe2014-12-02 17:57:51 +0000132 editor.putBoolean(PREFERENCE_REINSTALL_GAPPS, false);
133
Filipe Gonçalvesb31d5862015-02-04 17:28:58 +0000134 editor.apply();
Tiago Costa87925fe2014-12-02 17:57:51 +0000135 }
136 }
137
Filipe Gonçalvesa75e1812015-03-19 12:12:07 +0000138 private static void showReinstallAlert(Context context)
Tiago Costa87925fe2014-12-02 17:57:51 +0000139 {
Filipe Gonçalves825414a2015-01-26 14:52:48 +0000140 if ( FairphoneUpdater.BETA_MODE_ENABLED )
Jose Pascoal40916302015-02-06 18:43:47 +0000141 {
Filipe Gonçalves825414a2015-01-26 14:52:48 +0000142 return;
Jose Pascoal40916302015-02-06 18:43:47 +0000143 }
Filipe Gonçalvesb31d5862015-02-04 17:28:58 +0000144
145 NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Tiago Costa87925fe2014-12-02 17:57:51 +0000146
Tiago Costa73575aa2015-01-19 15:48:26 +0000147 //Intent notificationIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(context.getResources().getString(R.string.supportAppStoreUrl)));
Tiago Costa87925fe2014-12-02 17:57:51 +0000148
Tiago Costa73575aa2015-01-19 15:48:26 +0000149 Intent notificationIntent = new Intent(context, FairphoneUpdater.class);
150 notificationIntent.setAction(GappsInstallerHelper.EXTRA_START_GAPPS_INSTALL);
Tiago Costa87925fe2014-12-02 17:57:51 +0000151
Tiago Costa73575aa2015-01-19 15:48:26 +0000152 PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
Filipe Gonçalvesb31d5862015-02-04 17:28:58 +0000153
154 NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context).setSmallIcon(R.drawable.updater_tray_icon)
Filipe Gonçalvesa75e1812015-03-19 12:12:07 +0000155 .setContentTitle(context.getResources().getString(R.string.app_name))
Filipe Gonçalvesb31d5862015-02-04 17:28:58 +0000156 .setContentText(context.getResources().getString(R.string.appStoreReinstall))
157 .setAutoCancel(true)
158 .setDefaults(Notification.DEFAULT_SOUND)
159 .setContentIntent(contentIntent);
Tiago Costa87925fe2014-12-02 17:57:51 +0000160
161 mNotificationManager.notify(0, mBuilder.build());
162 }
163
Filipe Gonçalves8f226b02014-12-12 11:21:58 +0000164 private void downloadConfigFile(boolean forceDownload)
Jose Pascoal810950b2014-10-09 17:16:08 +0100165 {
Filipe Gonçalves8f226b02014-12-12 11:21:58 +0000166 long now = System.currentTimeMillis();
Filipe Gonçalves712d5482015-01-13 17:00:44 +0000167 long last_download = mSharedPreferences.getLong(LAST_CONFIG_DOWNLOAD_IN_MS, 0L);
Filipe Gonçalves8f226b02014-12-12 11:21:58 +0000168 if( forceDownload || now > (last_download + DOWNLOAD_GRACE_PERIOD_IN_MS) ) {
Filipe Gonçalves40893132015-05-25 17:45:44 +0100169 Log.i(TAG, "Downloading updater configuration file.");
Filipe Gonçalves8f226b02014-12-12 11:21:58 +0000170 // remove the old file if its still there for some reason
171 removeLatestFileDownload(getApplicationContext());
172
173 // start the download of the latest file
174 startDownloadLatest();
Jose Pascoal810950b2014-10-09 17:16:08 +0100175
Jose Pascoal0b48f8d2015-02-06 16:06:41 +0000176 mSharedPreferences.edit().putLong(LAST_CONFIG_DOWNLOAD_IN_MS, now).apply();
Filipe Gonçalves8f226b02014-12-12 11:21:58 +0000177 }
Jose Pascoal810950b2014-10-09 17:16:08 +0100178 }
179
Jose Pascoalcdd82042015-02-06 13:04:26 +0000180// --Commented out by Inspection START (06/02/2015 12:27):
181// public void updateGoogleAppsIntallerWidgets()
182// {
183// AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this);
184// int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(this, GoogleAppsInstallerWidget.class));
185// if (appWidgetIds.length > 0)
186// {
187// new GoogleAppsInstallerWidget().onUpdate(this, appWidgetManager, appWidgetIds);
188// }
189// }
190// --Commented out by Inspection STOP (06/02/2015 12:27)
Jose Pascoal810950b2014-10-09 17:16:08 +0100191
Jose Pascoalcfc2dd42015-02-09 18:00:05 +0000192 private static void clearDataLogs()
Jose Pascoal810950b2014-10-09 17:16:08 +0100193 {
Filipe Gonçalves49ce23c2015-02-13 16:33:52 +0000194 if (PrivilegeChecker.isPrivilegedApp()) {
195 clearDataLogsPrivileged();
196 } else {
197 clearDataLogsUnprivileged();
Tiago Costac14ea242014-04-24 10:14:41 +0100198 }
199 }
Kim Hansen086964d2013-12-10 11:33:28 +0000200
Filipe Gonçalves49ce23c2015-02-13 16:33:52 +0000201 private static void clearDataLogsPrivileged()
202 {
203 try
204 {
205 Log.d(TAG, "Clearing dump log data...");
206 Process p = Runtime.getRuntime().exec("rm /data/log_other_mode/*_log");
207 try
208 {
209 p.waitFor();
210 } catch (InterruptedException e)
211 {
212 e.printStackTrace();
213 }
214 } catch (IOException e)
215 {
216 Log.d(TAG, "Clearing dump log data failed: " + e.getLocalizedMessage());
217 }
218 }
219
220 private static void clearDataLogsUnprivileged()
221 {
222 try
223 {
224 Log.d(TAG, "Clearing dump log data...");
225 Shell.runCommand(new CommandCapture(0, "rm /data/log_other_mode/*_log"));
226 } catch (IOException | TimeoutException e)
227 {
228 Log.d(TAG, "Clearing dump log data failed: " + e.getLocalizedMessage());
229 }
230 }
231
232
Jose Pascoal810950b2014-10-09 17:16:08 +0100233 @Override
234 public IBinder onBind(Intent intent)
235 {
236 return null;
237 }
Kim Hansen086964d2013-12-10 11:33:28 +0000238
Filipe Gonçalvesb31d5862015-02-04 17:28:58 +0000239 void startDownloadLatest()
Jose Pascoal810950b2014-10-09 17:16:08 +0100240 {
Filipe Gonçalves5b65c012015-01-08 13:49:42 +0000241 Resources resources = getApplicationContext().getResources();
242 String downloadLink = getConfigDownloadLink(getApplicationContext());
243 // set the download for the latest version on the download manager
244 Request request = createDownloadRequest(downloadLink, resources.getString(R.string.configFilename) + resources.getString(R.string.config_zip));
Jose Pascoalfd3e43c2014-05-22 20:29:17 +0100245
Filipe Gonçalves5b65c012015-01-08 13:49:42 +0000246 if (request != null && mDownloadManager != null)
247 {
Jose Pascoal87758742015-01-28 20:00:22 +0000248 //Guarantee that only we have only one download
249 long oldDownloadId = mSharedPreferences.getLong(PREFERENCE_LAST_CONFIG_DOWNLOAD_ID, 0);
250 if(oldDownloadId != 0){
251 mDownloadManager.remove(oldDownloadId);
252 saveLatestDownloadId(0);
253 }
254
Filipe Gonçalves5b65c012015-01-08 13:49:42 +0000255 mLatestFileDownloadId = mDownloadManager.enqueue(request);
256 saveLatestDownloadId(mLatestFileDownloadId);
Filipe Gonçalvesb2536c02015-01-12 11:50:25 +0000257
258 final long currentId = mLatestFileDownloadId;
259 // Cancel download if it is stuck since DownloadManager doesn't seem able to do it.
260 new Handler().postAtTime(new Runnable() {
261 @Override
262 public void run() {
Jose Pascoal46fdb062015-02-05 18:59:32 +0000263 onDownloadStatus(currentId, new Runnable() {
Filipe Gonçalves712d5482015-01-13 17:00:44 +0000264 @Override
265 public void run() {
Filipe Gonçalvesb2536c02015-01-12 11:50:25 +0000266 Log.w(TAG, "Configuration file download timed out");
267 mDownloadManager.remove(currentId);
Jose Pascoal0b48f8d2015-02-06 16:06:41 +0000268 mSharedPreferences.edit().remove(LAST_CONFIG_DOWNLOAD_IN_MS).apply();
Filipe Gonçalvesb2536c02015-01-12 11:50:25 +0000269 }
Filipe Gonçalves712d5482015-01-13 17:00:44 +0000270 });
Filipe Gonçalvesb2536c02015-01-12 11:50:25 +0000271 }
Filipe Gonçalves8b263ad2015-01-12 12:30:11 +0000272 }, SystemClock.uptimeMillis() + CONFIG_FILE_DOWNLOAD_TIMEOUT_MILLIS);
Filipe Gonçalves5b65c012015-01-08 13:49:42 +0000273 }
274 else
275 {
276 Log.e(TAG, "Invalid request for link " + downloadLink);
277 Intent i = new Intent(FairphoneUpdater.FAIRPHONE_UPDATER_CONFIG_DOWNLOAD_FAILED);
278 i.putExtra(FairphoneUpdater.FAIRPHONE_UPDATER_CONFIG_DOWNLOAD_LINK, downloadLink);
279 sendBroadcast(i);
Jose Pascoal810950b2014-10-09 17:16:08 +0100280 }
281 }
282
Jose Pascoalc2545cc2014-12-18 16:51:52 +0000283 private void saveLatestDownloadId(long id)
284 {
285 mLatestFileDownloadId = id;
286 Editor editor = mSharedPreferences.edit();
287 editor.putLong(PREFERENCE_LAST_CONFIG_DOWNLOAD_ID, id);
288 editor.commit();
289 }
290
Jose Pascoal810950b2014-10-09 17:16:08 +0100291 private String getConfigDownloadLink(Context context)
292 {
293
294 Resources resources = context.getResources();
295
296 StringBuilder sb = new StringBuilder();
Filipe Gonçalvesafeac2c2015-01-27 17:49:53 +0000297 String download_url = mSharedPreferences.getString(FairphoneUpdater.PREFERENCE_OTA_DOWNLOAD_URL, getResources().getString(R.string.downloadUrl));
Filipe Gonçalvesb31d5862015-02-04 17:28:58 +0000298
299 sb.append(download_url);
Jose Pascoal810950b2014-10-09 17:16:08 +0100300 sb.append(Build.MODEL.replaceAll("\\s", ""));
Jose Pascoal0a5be012014-11-17 16:55:40 +0000301 sb.append(Utils.getPartitionDownloadPath(resources));
Jose Pascoal810950b2014-10-09 17:16:08 +0100302 sb.append("/");
303
304 sb.append(resources.getString(R.string.configFilename));
305
306 sb.append(resources.getString(R.string.config_zip));
307
308 addModelAndOS(context, sb);
309
310 String downloadLink = sb.toString();
311
312 Log.d(TAG, "Download link: " + downloadLink);
313
314 return downloadLink;
315 }
Jose Pascoalcf13fde2014-05-21 20:17:17 +0100316
Jose Pascoalcfc2dd42015-02-09 18:00:05 +0000317 private static void addModelAndOS(Context context, StringBuilder sb)
Tiago Costab24ef1c2014-07-25 12:02:34 +0100318 {
319 // attach the model and the os
Jose Pascoal810950b2014-10-09 17:16:08 +0100320 sb.append("?");
Filipe Gonçalvesb31d5862015-02-04 17:28:58 +0000321 sb.append("model=").append(Build.MODEL.replaceAll("\\s", ""));
Jose Pascoal810950b2014-10-09 17:16:08 +0100322 Version currentVersion = VersionParserHelper.getDeviceVersion(context.getApplicationContext());
323
324 if (currentVersion != null)
325 {
Filipe Gonçalvescd0f33d2014-12-15 15:05:15 +0000326 try {
327 final String defaultCharset = Charset.defaultCharset().displayName();
Filipe Gonçalvesb31d5862015-02-04 17:28:58 +0000328 sb.append("&os=").append(URLEncoder.encode(currentVersion.getAndroidVersion(), defaultCharset));
329 sb.append("&b_n=").append(URLEncoder.encode(currentVersion.getBuildNumber(), defaultCharset));
330 sb.append("&ota_v_n=").append(URLEncoder.encode(String.valueOf(currentVersion.getNumber()), defaultCharset));
331 sb.append("&d=").append(URLEncoder.encode(currentVersion.getReleaseDate(), defaultCharset));
332 sb.append("&beta=").append(URLEncoder.encode(currentVersion.getBetaStatus(), defaultCharset));
333 sb.append("&dev=").append(FairphoneUpdater.DEV_MODE_ENABLED ? "1" : "0");
Filipe Gonçalvescd0f33d2014-12-15 15:05:15 +0000334 } catch (UnsupportedEncodingException e) {
335 Log.e(TAG, "Failed to add extra info on update request: "+e.getLocalizedMessage());
336 }
Jose Pascoal810950b2014-10-09 17:16:08 +0100337 }
Tiago Costab24ef1c2014-07-25 12:02:34 +0100338 }
339
Jose Pascoal810950b2014-10-09 17:16:08 +0100340 private static void setNotification(Context currentContext)
341 {
Kim Hansen086964d2013-12-10 11:33:28 +0000342
Filipe Gonçalves825414a2015-01-26 14:52:48 +0000343 if ( FairphoneUpdater.BETA_MODE_ENABLED )
Jose Pascoal40916302015-02-06 18:43:47 +0000344 {
Filipe Gonçalves825414a2015-01-26 14:52:48 +0000345 return;
Jose Pascoal40916302015-02-06 18:43:47 +0000346 }
Filipe Gonçalves825414a2015-01-26 14:52:48 +0000347
Jose Pascoal810950b2014-10-09 17:16:08 +0100348 Context context = currentContext.getApplicationContext();
Kim Hansen086964d2013-12-10 11:33:28 +0000349
Jose Pascoal810950b2014-10-09 17:16:08 +0100350 NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Kim Hansen086964d2013-12-10 11:33:28 +0000351
Jose Pascoal810950b2014-10-09 17:16:08 +0100352 NotificationCompat.Builder builder =
Pedro Arelo259478b2014-10-10 12:10:37 +0100353 new NotificationCompat.Builder(context).setSmallIcon(R.drawable.updater_tray_icon_small)
354 .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.updater_tray_icon))
Jose Pascoal810950b2014-10-09 17:16:08 +0100355 .setContentTitle(context.getResources().getString(R.string.app_name))
Pedro Arelo773bd822014-10-10 11:57:34 +0100356 .setContentText(context.getResources().getString(R.string.fairphone_update_message));
Kim Hansen086964d2013-12-10 11:33:28 +0000357
Jose Pascoal7bf83a02014-10-13 18:30:18 +0100358 Intent resultIntent = new Intent(context, FairphoneUpdater.class);
Jose Pascoal810950b2014-10-09 17:16:08 +0100359 TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
Kim Hansen086964d2013-12-10 11:33:28 +0000360
Jose Pascoal7bf83a02014-10-13 18:30:18 +0100361 stackBuilder.addParentStack(FairphoneUpdater.class);
Kim Hansen086964d2013-12-10 11:33:28 +0000362
Jose Pascoal810950b2014-10-09 17:16:08 +0100363 stackBuilder.addNextIntent(resultIntent);
364 PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
Kim Hansen086964d2013-12-10 11:33:28 +0000365
Jose Pascoal810950b2014-10-09 17:16:08 +0100366 builder.setContentIntent(resultPendingIntent);
Kim Hansen086964d2013-12-10 11:33:28 +0000367
Jose Pascoal810950b2014-10-09 17:16:08 +0100368 Notification notificationWhileRunnig = builder.build();
Jose Pascoalfd3e43c2014-05-22 20:29:17 +0100369
Jose Pascoal810950b2014-10-09 17:16:08 +0100370 // Add notification
371 manager.notify(0, notificationWhileRunnig);
372 }
Kim Hansen086964d2013-12-10 11:33:28 +0000373
Jose Pascoal810950b2014-10-09 17:16:08 +0100374 private Request createDownloadRequest(String url, String fileName)
375 {
Kim Hansen086964d2013-12-10 11:33:28 +0000376
Jose Pascoal810950b2014-10-09 17:16:08 +0100377 Resources resources = getApplicationContext().getResources();
378 Request request;
Kim Hansen086964d2013-12-10 11:33:28 +0000379
Jose Pascoal810950b2014-10-09 17:16:08 +0100380 try
381 {
382 request = new Request(Uri.parse(url));
Filipe Gonçalvesb31d5862015-02-04 17:28:58 +0000383 final File externalStoragePublicDirectory = Environment.getExternalStoragePublicDirectory(Environment.getExternalStorageDirectory() + resources.getString(R.string.updaterFolder));
Jose Pascoal46fdb062015-02-05 18:59:32 +0000384 final boolean notMkDirs = !externalStoragePublicDirectory.mkdirs();
385 if(notMkDirs && !externalStoragePublicDirectory.exists()) {
Filipe Gonçalvesb31d5862015-02-04 17:28:58 +0000386 throw new Exception("Couldn't create updater dir structures.");
387 }
Kim Hansen086964d2013-12-10 11:33:28 +0000388
Filipe Gonçalvesb31d5862015-02-04 17:28:58 +0000389 request.setDestinationInExternalPublicDir(resources.getString(R.string.updaterFolder), fileName);
Jose Pascoal810950b2014-10-09 17:16:08 +0100390 request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
391 request.setAllowedOverRoaming(false);
Pedro Arelo773bd822014-10-10 11:57:34 +0100392 request.setTitle(resources.getString(R.string.fairphone_update_message_title));
Jose Pascoal810950b2014-10-09 17:16:08 +0100393 } catch (Exception e)
394 {
395 Log.e(TAG, "Error creating request: " + e.getMessage());
396 request = null;
397 }
Kim Hansen086964d2013-12-10 11:33:28 +0000398
Jose Pascoal810950b2014-10-09 17:16:08 +0100399 return request;
400 }
Kim Hansen086964d2013-12-10 11:33:28 +0000401
Filipe Gonçalvesd28bd622014-11-05 11:40:12 +0000402 private void setupConnectivityMonitoring()
403 {
404
Filipe Gonçalves40893132015-05-25 17:45:44 +0100405 if (networkStateReceiver == null) {
406 // Check current connectivity status
407 mInternetConnectionAvailable = Utils.isWiFiEnabled(getApplicationContext());
Filipe Gonçalvesd28bd622014-11-05 11:40:12 +0000408
Filipe Gonçalves40893132015-05-25 17:45:44 +0100409 // Setup monitoring for future connectivity status changes
410 networkStateReceiver = new BroadcastReceiver()
Tiago Costa87925fe2014-12-02 17:57:51 +0000411 {
Filipe Gonçalves40893132015-05-25 17:45:44 +0100412 @Override
413 public void onReceive(Context context, Intent intent)
Tiago Costa87925fe2014-12-02 17:57:51 +0000414 {
Filipe Gonçalves40893132015-05-25 17:45:44 +0100415 if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)) {
416 Log.i(TAG, "Lost network connectivity.");
417 mInternetConnectionAvailable = false;
418 if (mLatestFileDownloadId != 0 && mDownloadManager != null)
419 {
420 onDownloadStatus(mLatestFileDownloadId, new Runnable() {
421 @Override
422 public void run() {
423 Log.d(TAG, "Removing pending download.");
424 mDownloadManager.remove(mLatestFileDownloadId);
425 saveLatestDownloadId(0);
426 }
427 });
428 }
429 }
430 else
Tiago Costa87925fe2014-12-02 17:57:51 +0000431 {
Filipe Gonçalves40893132015-05-25 17:45:44 +0100432 int conn_type = intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_DUMMY);
433 if( conn_type == ConnectivityManager.TYPE_WIFI ) {
434 Log.i(TAG, "Network connectivity potentially available.");
435 if (!mInternetConnectionAvailable) {
436 downloadConfigFile(false);
Filipe Gonçalves712d5482015-01-13 17:00:44 +0000437 }
Filipe Gonçalves40893132015-05-25 17:45:44 +0100438 mInternetConnectionAvailable = true;
439 }
Tiago Costa87925fe2014-12-02 17:57:51 +0000440 }
441 }
Filipe Gonçalves40893132015-05-25 17:45:44 +0100442 };
Filipe Gonçalvesd28bd622014-11-05 11:40:12 +0000443
Filipe Gonçalves40893132015-05-25 17:45:44 +0100444 IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
445 registerReceiver(networkStateReceiver, filter);
Tiago Costa87925fe2014-12-02 17:57:51 +0000446
Filipe Gonçalves40893132015-05-25 17:45:44 +0100447 }
Jose Pascoal810950b2014-10-09 17:16:08 +0100448 }
449
450 private void setupDownloadManager()
451 {
452 if (mDownloadManager == null)
453 {
454 mDownloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
455 }
456
Filipe Gonçalvesd0dfe912014-11-04 16:24:25 +0000457 if (mDownloadBroadCastReceiver == null)
Jose Pascoal810950b2014-10-09 17:16:08 +0100458 {
459 mDownloadBroadCastReceiver = new DownloadBroadCastReceiver();
460
461 getApplicationContext().registerReceiver(mDownloadBroadCastReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
462 }
463 }
464
Jose Pascoal810950b2014-10-09 17:16:08 +0100465 private static void checkVersionValidation(Context context)
466 {
Jose Pascoal810950b2014-10-09 17:16:08 +0100467 Version latestVersion = VersionParserHelper.getLatestVersion(context.getApplicationContext());
468 Version currentVersion = VersionParserHelper.getDeviceVersion(context.getApplicationContext());
469
470 if (latestVersion != null)
471 {
472 if (latestVersion.isNewerVersionThan(currentVersion))
473 {
474 setNotification(context);
475 }
Jose Pascoal810950b2014-10-09 17:16:08 +0100476 }
Filipe Gonçalvesa75e1812015-03-19 12:12:07 +0000477 runInstallationDisclaimer(context);
Jose Pascoald5e4d4a2015-03-13 18:17:48 +0000478
479 // to update the activity
480 Intent updateIntent = new Intent(FairphoneUpdater.FAIRPHONE_UPDATER_NEW_VERSION_RECEIVED);
481 context.sendBroadcast(updateIntent);
Jose Pascoal810950b2014-10-09 17:16:08 +0100482 }
483
484 public static boolean readUpdaterData(Context context)
485 {
Jose Pascoal1ee56e22014-05-21 16:58:20 +0100486
487 boolean retVal = false;
488 Resources resources = context.getApplicationContext().getResources();
Jose Pascoal810950b2014-10-09 17:16:08 +0100489 String targetPath = Environment.getExternalStorageDirectory() + resources.getString(R.string.updaterFolder);
Jose Pascoal1ee56e22014-05-21 16:58:20 +0100490
Jose Pascoal810950b2014-10-09 17:16:08 +0100491 String filePath = targetPath + resources.getString(R.string.configFilename) + resources.getString(R.string.config_zip);
Jose Pascoal1ee56e22014-05-21 16:58:20 +0100492
493 File file = new File(filePath);
494
Jose Pascoal810950b2014-10-09 17:16:08 +0100495 if (file.exists())
496 {
Filipe Gonçalves80d4b152015-05-26 19:04:02 +0100497 String md5sum = Utils.calculateMD5(file);
498 SharedPreferences sp = context.getSharedPreferences(FairphoneUpdater.FAIRPHONE_UPDATER_PREFERENCES, MODE_PRIVATE);
499 if(sp.getString(PREFERENCE_CONFIG_MD_5, "").equals(md5sum)){
500 retVal = true;
501 } else if (RSAUtils.checkFileSignature(context, filePath, targetPath)) {
Jose Pascoal810950b2014-10-09 17:16:08 +0100502 checkVersionValidation(context);
503 retVal = true;
Filipe Gonçalves80d4b152015-05-26 19:04:02 +0100504 sp.edit().putString(PREFERENCE_CONFIG_MD_5, md5sum).apply();
505 } else {
Tiago Costa77019fc2014-12-03 15:42:08 +0000506 //Toast.makeText(context, resources.getString(R.string.invalid_signature_download_message), Toast.LENGTH_LONG).show();
Jose Pascoal46fdb062015-02-05 18:59:32 +0000507 final boolean notDeleted = !file.delete();
Filipe Gonçalves80d4b152015-05-26 19:04:02 +0100508 if(notDeleted) {
509 Log.d(TAG, "Unable to delete "+file.getAbsolutePath());
510 }
Filipe Gonçalvesb31d5862015-02-04 17:28:58 +0000511
Jose Pascoal810950b2014-10-09 17:16:08 +0100512 }
513 }
Jose Pascoal1ee56e22014-05-21 16:58:20 +0100514
515 return retVal;
516 }
Kim Hansen086964d2013-12-10 11:33:28 +0000517
Jose Pascoal810950b2014-10-09 17:16:08 +0100518 private void removeLatestFileDownload(Context context)
519 {
520 if (mLatestFileDownloadId != 0 && mDownloadManager != null)
521 {
522 mDownloadManager.remove(mLatestFileDownloadId);
Jose Pascoalc2545cc2014-12-18 16:51:52 +0000523 saveLatestDownloadId(0);
Kim Hansen086964d2013-12-10 11:33:28 +0000524 }
Jose Pascoalc2545cc2014-12-18 16:51:52 +0000525 VersionParserHelper.removeConfigFiles(context);
Kim Hansen086964d2013-12-10 11:33:28 +0000526 }
527
Jose Pascoal810950b2014-10-09 17:16:08 +0100528 private boolean retryDownload(Context context)
529 {
Filipe Gonçalves5b65c012015-01-08 13:49:42 +0000530 Log.d(TAG, "Retry "+mDownloadRetries+" of "+MAX_DOWNLOAD_RETRIES);
Jose Pascoal810950b2014-10-09 17:16:08 +0100531 // invalid file
532 boolean removeReceiver = true;
533 removeLatestFileDownload(context);
534 if (mDownloadRetries < MAX_DOWNLOAD_RETRIES)
535 {
536 startDownloadLatest();
537 mDownloadRetries++;
538 removeReceiver = false;
539 }
540 if (removeReceiver)
541 {
Pedro Arelo773bd822014-10-10 11:57:34 +0100542 Toast.makeText(getApplicationContext(), getResources().getString(R.string.config_file_download_error_message), Toast.LENGTH_LONG).show();
Jose Pascoal810950b2014-10-09 17:16:08 +0100543 }
544 return removeReceiver;
545 }
Jose Pascoal0e966282014-08-12 18:49:05 +0100546
Jose Pascoal46fdb062015-02-05 18:59:32 +0000547 private void onDownloadStatus(long id, Runnable ifRunning) {
Filipe Gonçalves712d5482015-01-13 17:00:44 +0000548 Cursor cursor = mDownloadManager != null ? mDownloadManager.query(new DownloadManager.Query().setFilterById(id)) : null;
549 if (cursor != null && cursor.moveToFirst())
550 {
551 int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
552 switch(status){
Filipe Gonçalves712d5482015-01-13 17:00:44 +0000553 case DownloadManager.STATUS_PAUSED:
554 if (ifRunning != null) {
555 ifRunning.run();
556 }
557 break;
558 case DownloadManager.STATUS_PENDING:
559 if (ifRunning != null) {
560 ifRunning.run();
561 }
562 break;
563 case DownloadManager.STATUS_RUNNING:
564 if (ifRunning != null) {
565 ifRunning.run();
566 }
567 break;
Jose Pascoal46fdb062015-02-05 18:59:32 +0000568 case DownloadManager.STATUS_FAILED:
Filipe Gonçalves712d5482015-01-13 17:00:44 +0000569 case DownloadManager.STATUS_SUCCESSFUL:
Filipe Gonçalves712d5482015-01-13 17:00:44 +0000570 default:
571 break;
572 }
573 }
574 if (cursor != null)
575 {
576 cursor.close();
577 }
578 }
579
Jose Pascoal810950b2014-10-09 17:16:08 +0100580 private class DownloadBroadCastReceiver extends BroadcastReceiver
581 {
Kim Hansen086964d2013-12-10 11:33:28 +0000582
Jose Pascoal1ee56e22014-05-21 16:58:20 +0100583 @Override
Jose Pascoal810950b2014-10-09 17:16:08 +0100584 public void onReceive(Context context, Intent intent)
585 {
Kim Hansen086964d2013-12-10 11:33:28 +0000586
Jose Pascoal810950b2014-10-09 17:16:08 +0100587 boolean removeReceiver = false;
Kim Hansen086964d2013-12-10 11:33:28 +0000588
Jose Pascoal810950b2014-10-09 17:16:08 +0100589 DownloadManager.Query query = new DownloadManager.Query();
590
591 query.setFilterById(mLatestFileDownloadId);
Jose Pascoal810950b2014-10-09 17:16:08 +0100592
Jose Pascoalaa579a82014-11-05 22:17:16 +0000593 Cursor cursor = mDownloadManager != null ? mDownloadManager.query(query) : null;
594
595 if (cursor != null && cursor.moveToFirst())
Jose Pascoal810950b2014-10-09 17:16:08 +0100596 {
597 int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
598 int status = cursor.getInt(columnIndex);
599 Resources resources = context.getApplicationContext().getResources();
600
601 switch (status)
602 {
603 case DownloadManager.STATUS_SUCCESSFUL:
604 {
Filipe Gonçalves5b65c012015-01-08 13:49:42 +0000605 Log.d(TAG, "Download successful.");
Jose Pascoal810950b2014-10-09 17:16:08 +0100606 String filePath = mDownloadManager.getUriForDownloadedFile(mLatestFileDownloadId).getPath();
607
608 String targetPath = Environment.getExternalStorageDirectory() + resources.getString(R.string.updaterFolder);
609
610 if (RSAUtils.checkFileSignature(context, filePath, targetPath))
611 {
612 checkVersionValidation(context);
613 }
614 else
615 {
Pedro Arelo773bd822014-10-10 11:57:34 +0100616 Toast.makeText(getApplicationContext(), resources.getString(R.string.invalid_signature_download_message), Toast.LENGTH_LONG).show();
Jose Pascoal810950b2014-10-09 17:16:08 +0100617 removeReceiver = retryDownload(context);
618 }
619 break;
620 }
621 case DownloadManager.STATUS_FAILED:
622 {
Filipe Gonçalves5b65c012015-01-08 13:49:42 +0000623 Log.d(TAG, "Download failed.");
Jose Pascoal810950b2014-10-09 17:16:08 +0100624 removeReceiver = retryDownload(context);
625 break;
626 }
Filipe Gonçalves42ffc322015-01-28 12:51:14 +0000627 default:
628 {
629 Log.d(TAG, "Status broadcast on mLatestFileDownloadId ("+mLatestFileDownloadId+"): "+ status);
630 }
Jose Pascoal810950b2014-10-09 17:16:08 +0100631 }
632 }
Tiago Costa87925fe2014-12-02 17:57:51 +0000633
Jose Pascoalaa579a82014-11-05 22:17:16 +0000634 if (cursor != null)
635 {
636 cursor.close();
637 }
Jose Pascoal810950b2014-10-09 17:16:08 +0100638
639 if (removeReceiver)
640 {
Filipe Gonçalves5b65c012015-01-08 13:49:42 +0000641 Log.d(TAG, "Configuration download failed. Clearing grace period.");
Jose Pascoal0b48f8d2015-02-06 16:06:41 +0000642 mSharedPreferences.edit().remove(LAST_CONFIG_DOWNLOAD_IN_MS).apply();
Jose Pascoal810950b2014-10-09 17:16:08 +0100643 }
644 }
645 }
Kim Hansen086964d2013-12-10 11:33:28 +0000646}