Jose Pascoal | 91aff13 | 2014-10-02 17:19:47 +0100 | [diff] [blame] | 1 | package com.fairphone.updater.fragments; |
| 2 | |
Filipe Gonçalves | b31d586 | 2015-02-04 17:28:58 +0000 | [diff] [blame] | 3 | import android.annotation.SuppressLint; |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 4 | import android.app.AlertDialog; |
| 5 | import android.app.DownloadManager; |
| 6 | import android.app.DownloadManager.Request; |
| 7 | import android.content.Context; |
| 8 | import android.content.DialogInterface; |
| 9 | import android.content.res.Resources; |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 10 | import android.net.Uri; |
Jose Pascoal | 91aff13 | 2014-10-02 17:19:47 +0100 | [diff] [blame] | 11 | import android.os.Bundle; |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 12 | import android.os.Environment; |
Tiago Costa | e29f4cd | 2014-10-10 18:30:59 +0100 | [diff] [blame] | 13 | import android.support.v4.app.FragmentManager; |
Filipe Gonçalves | bc616bc | 2014-12-31 14:39:22 +0000 | [diff] [blame] | 14 | import android.util.Log; |
Jose Pascoal | 91aff13 | 2014-10-02 17:19:47 +0100 | [diff] [blame] | 15 | import android.view.LayoutInflater; |
| 16 | import android.view.View; |
Jose Pascoal | e4c48e3 | 2014-10-03 19:55:39 +0100 | [diff] [blame] | 17 | import android.view.View.OnClickListener; |
Jose Pascoal | 91aff13 | 2014-10-02 17:19:47 +0100 | [diff] [blame] | 18 | import android.view.ViewGroup; |
Jose Pascoal | e4c48e3 | 2014-10-03 19:55:39 +0100 | [diff] [blame] | 19 | import android.widget.Button; |
Jose Pascoal | e4c48e3 | 2014-10-03 19:55:39 +0100 | [diff] [blame] | 20 | import android.widget.TextView; |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 21 | import android.widget.Toast; |
Jose Pascoal | 91aff13 | 2014-10-02 17:19:47 +0100 | [diff] [blame] | 22 | |
Jose Pascoal | cfc2dd4 | 2015-02-09 18:00:05 +0000 | [diff] [blame] | 23 | import com.fairphone.updater.FairphoneUpdater; |
Jose Pascoal | 7bf83a0 | 2014-10-13 18:30:18 +0100 | [diff] [blame] | 24 | import com.fairphone.updater.FairphoneUpdater.HeaderType; |
| 25 | import com.fairphone.updater.FairphoneUpdater.UpdaterState; |
Jose Pascoal | 91aff13 | 2014-10-02 17:19:47 +0100 | [diff] [blame] | 26 | import com.fairphone.updater.R; |
Jose Pascoal | 02d8624 | 2014-12-17 18:50:08 +0000 | [diff] [blame] | 27 | import com.fairphone.updater.data.DownloadableItem; |
Tiago Costa | 3add03e | 2014-12-16 12:05:23 +0000 | [diff] [blame] | 28 | import com.fairphone.updater.data.Store; |
Jose Pascoal | 7bf83a0 | 2014-10-13 18:30:18 +0100 | [diff] [blame] | 29 | import com.fairphone.updater.data.Version; |
Tiago Costa | e29f4cd | 2014-10-10 18:30:59 +0100 | [diff] [blame] | 30 | import com.fairphone.updater.fragments.ConfirmationPopupDialog.ConfirmationPopupDialogListener; |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 31 | import com.fairphone.updater.tools.Utils; |
Jose Pascoal | 91aff13 | 2014-10-02 17:19:47 +0100 | [diff] [blame] | 32 | |
Filipe Gonçalves | b31d586 | 2015-02-04 17:28:58 +0000 | [diff] [blame] | 33 | import java.io.File; |
| 34 | import java.net.MalformedURLException; |
| 35 | import java.net.URL; |
| 36 | import java.util.Locale; |
| 37 | |
| 38 | @SuppressLint("ValidFragment") |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 39 | public class VersionDetailFragment extends BaseFragment |
| 40 | { |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 41 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 42 | private static final String TAG = VersionDetailFragment.class.getSimpleName(); |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 43 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 44 | public static enum DetailLayoutType |
| 45 | { |
Maarten Derks | d270426 | 2016-03-17 15:34:51 +0100 | [diff] [blame] | 46 | UPDATE_FAIRPHONE, UPDATE_ANDROID, LATEST_FAIRPHONE, FAIRPHONE, ANDROID, APP_STORE |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 47 | } |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 48 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 49 | private HeaderType mHeaderType; |
| 50 | private String mHeaderText; |
| 51 | private TextView mVersion_details_title_text; |
| 52 | private TextView mVersion_release_notes_text; |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 53 | private Button mDownload_and_update_button; |
| 54 | private TextView mVersion_details_name_text; |
| 55 | private String mVersionDetailsTitle; |
| 56 | private Version mSelectedVersion; |
| 57 | private DownloadManager mDownloadManager; |
| 58 | private DetailLayoutType mDetailLayoutType; |
Jose Pascoal | dc29afe | 2014-10-10 13:43:47 +0100 | [diff] [blame] | 59 | private boolean mIsOSChange; |
Jose Pascoal | 391bd31 | 2014-10-13 18:16:27 +0100 | [diff] [blame] | 60 | private boolean mIsOlderVersion; |
Tiago Costa | 3add03e | 2014-12-16 12:05:23 +0000 | [diff] [blame] | 61 | private Store mSelectedStore; |
Filipe Gonçalves | b31d586 | 2015-02-04 17:28:58 +0000 | [diff] [blame] | 62 | private final boolean mIsVersion; |
Jose Pascoal | 02d8624 | 2014-12-17 18:50:08 +0000 | [diff] [blame] | 63 | |
| 64 | public VersionDetailFragment(boolean isVersion) |
| 65 | { |
| 66 | super(); |
| 67 | |
| 68 | mIsVersion = isVersion; |
| 69 | } |
Tiago Costa | 3add03e | 2014-12-16 12:05:23 +0000 | [diff] [blame] | 70 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 71 | @Override |
| 72 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) |
| 73 | { |
| 74 | // Inflate the layout for this fragment |
| 75 | View view = setLayoutType(inflater, container); |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 76 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 77 | setupLayout(view); |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 78 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 79 | return view; |
| 80 | } |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 81 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 82 | private View setLayoutType(LayoutInflater inflater, ViewGroup container) |
| 83 | { |
Filipe Gonçalves | b31d586 | 2015-02-04 17:28:58 +0000 | [diff] [blame] | 84 | View view; |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 85 | switch (mDetailLayoutType) |
| 86 | { |
Jose Pascoal | ee8a8eb | 2014-10-15 15:20:28 +0100 | [diff] [blame] | 87 | case UPDATE_ANDROID: |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 88 | case ANDROID: |
| 89 | view = inflater.inflate(R.layout.fragment_version_detail_android, container, false); |
| 90 | break; |
Tiago Costa | 3add03e | 2014-12-16 12:05:23 +0000 | [diff] [blame] | 91 | case APP_STORE: |
Tiago Costa | 198bf3d | 2014-12-16 15:23:18 +0000 | [diff] [blame] | 92 | view = inflater.inflate(R.layout.fragment_app_store_detail, container, false); |
Tiago Costa | 3add03e | 2014-12-16 12:05:23 +0000 | [diff] [blame] | 93 | break; |
Jose Pascoal | b01dd26 | 2014-10-17 17:21:19 +0100 | [diff] [blame] | 94 | case UPDATE_FAIRPHONE: |
Maarten Derks | d270426 | 2016-03-17 15:34:51 +0100 | [diff] [blame] | 95 | case LATEST_FAIRPHONE: |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 96 | case FAIRPHONE: |
| 97 | default: |
| 98 | view = inflater.inflate(R.layout.fragment_version_detail_fairphone, container, false); |
| 99 | break; |
| 100 | } |
| 101 | return view; |
| 102 | } |
Jose Pascoal | e4c48e3 | 2014-10-03 19:55:39 +0100 | [diff] [blame] | 103 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 104 | private void setupLayout(View view) |
| 105 | { |
| 106 | mVersion_details_title_text = (TextView) view.findViewById(R.id.version_details_title_text); |
| 107 | mVersion_details_name_text = (TextView) view.findViewById(R.id.version_details_name_text); |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 108 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 109 | mVersion_release_notes_text = (TextView) view.findViewById(R.id.version_release_notes_text); |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 110 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 111 | mDownload_and_update_button = (Button) view.findViewById(R.id.download_and_update_button); |
| 112 | } |
Jose Pascoal | e4c48e3 | 2014-10-03 19:55:39 +0100 | [diff] [blame] | 113 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 114 | private void setupDownloadAndUpdateButton() |
| 115 | { |
Jose Pascoal | d6c19a7 | 2014-10-17 16:52:36 +0100 | [diff] [blame] | 116 | setDownloadAndUpdateButtonText(); |
| 117 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 118 | mDownload_and_update_button.setOnClickListener(new OnClickListener() |
| 119 | { |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 120 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 121 | @Override |
| 122 | public void onClick(View v) |
| 123 | { |
Maarten Derks | e2f0ffc | 2016-04-26 11:58:36 +0200 | [diff] [blame] | 124 | boolean isWifiEnabled = Utils.isWiFiEnabled(mainActivity); |
| 125 | boolean isBatteryLevelOk = Utils.isBatteryLevelOk(mainActivity); |
| 126 | |
| 127 | if (isWifiEnabled && isBatteryLevelOk) |
| 128 | { |
| 129 | startDownload(); |
| 130 | } |
| 131 | else |
| 132 | { |
| 133 | if(!isWifiEnabled) { |
| 134 | AlertDialog.Builder wifiDialog = new AlertDialog.Builder(mainActivity); |
| 135 | wifiDialog.setIcon(R.drawable.ic_signal_wifi_4_bar_fpblue_24dp); |
| 136 | wifiDialog.setTitle(R.string.connect_to_wifi); |
| 137 | wifiDialog.setPositiveButton(R.string.got_it, new DialogInterface.OnClickListener() { |
| 138 | public void onClick(DialogInterface dialog, int id) { |
| 139 | // do nothing, since the state is still the same |
| 140 | } |
| 141 | }); |
| 142 | wifiDialog.create(); |
| 143 | wifiDialog.show(); |
| 144 | } |
| 145 | |
| 146 | if(!isBatteryLevelOk) { |
| 147 | AlertDialog.Builder batteryDialog = new AlertDialog.Builder(mainActivity); |
| 148 | batteryDialog.setIcon(R.drawable.ic_battery_std_fpblue_24dp); |
| 149 | batteryDialog.setTitle(R.string.charge_battery); |
| 150 | batteryDialog.setPositiveButton(R.string.got_it, new DialogInterface.OnClickListener() { |
| 151 | public void onClick(DialogInterface dialog, int id) { |
| 152 | // do nothing, since the state is still the same |
| 153 | } |
| 154 | }); |
| 155 | batteryDialog.create(); |
| 156 | batteryDialog.show(); |
| 157 | } |
| 158 | } |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 159 | } |
| 160 | }); |
| 161 | } |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 162 | |
Jose Pascoal | d6c19a7 | 2014-10-17 16:52:36 +0100 | [diff] [blame] | 163 | private void setDownloadAndUpdateButtonText() |
| 164 | { |
| 165 | switch (mDetailLayoutType) |
| 166 | { |
| 167 | case UPDATE_ANDROID: |
| 168 | case UPDATE_FAIRPHONE: |
| 169 | mDownload_and_update_button.setText(R.string.install_update); |
| 170 | break; |
Tiago Costa | 3add03e | 2014-12-16 12:05:23 +0000 | [diff] [blame] | 171 | case APP_STORE: |
Maarten Derks | d270426 | 2016-03-17 15:34:51 +0100 | [diff] [blame] | 172 | case LATEST_FAIRPHONE: |
Jose Pascoal | d6c19a7 | 2014-10-17 16:52:36 +0100 | [diff] [blame] | 173 | case FAIRPHONE: |
| 174 | case ANDROID: |
| 175 | default: |
| 176 | mDownload_and_update_button.setText(R.string.install); |
| 177 | break; |
| 178 | } |
| 179 | } |
| 180 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 181 | private void updateReleaseNotesText() |
| 182 | { |
Jose Pascoal | 02d8624 | 2014-12-17 18:50:08 +0000 | [diff] [blame] | 183 | DownloadableItem item = mIsVersion ? mSelectedVersion : mSelectedStore; |
| 184 | if (item != null) |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 185 | { |
Jose Pascoal | 02d8624 | 2014-12-17 18:50:08 +0000 | [diff] [blame] | 186 | mVersion_release_notes_text.setText(item.getReleaseNotes(Locale.getDefault().getLanguage())); |
Jose Pascoal | ad4ea57 | 2014-12-16 20:31:48 +0000 | [diff] [blame] | 187 | } |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 188 | } |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 189 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 190 | private void updateVersionName() |
| 191 | { |
Jose Pascoal | 02d8624 | 2014-12-17 18:50:08 +0000 | [diff] [blame] | 192 | DownloadableItem item = mIsVersion ? mSelectedVersion : mSelectedStore; |
| 193 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 194 | mVersion_details_title_text.setText(mVersionDetailsTitle); |
Jose Pascoal | 02d8624 | 2014-12-17 18:50:08 +0000 | [diff] [blame] | 195 | if (item != null) |
Jose Pascoal | ad4ea57 | 2014-12-16 20:31:48 +0000 | [diff] [blame] | 196 | { |
Jose Pascoal | 4091630 | 2015-02-06 18:43:47 +0000 | [diff] [blame] | 197 | mVersion_details_name_text.setText(mainActivity.getItemName(item, mIsVersion)); |
Jose Pascoal | ad4ea57 | 2014-12-16 20:31:48 +0000 | [diff] [blame] | 198 | } |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 199 | } |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 200 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 201 | public void setupFragment(Version selectedVersion, DetailLayoutType detailType) |
| 202 | { |
| 203 | mSelectedVersion = selectedVersion; |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 204 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 205 | mDetailLayoutType = detailType; |
Jose Pascoal | ad4ea57 | 2014-12-16 20:31:48 +0000 | [diff] [blame] | 206 | mSelectedStore = null; |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 207 | } |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 208 | |
Filipe Gonçalves | b31d586 | 2015-02-04 17:28:58 +0000 | [diff] [blame] | 209 | public void setupAppStoreFragment(Store selectedStore) |
Tiago Costa | 3add03e | 2014-12-16 12:05:23 +0000 | [diff] [blame] | 210 | { |
| 211 | mSelectedStore = selectedStore; |
| 212 | |
Filipe Gonçalves | b31d586 | 2015-02-04 17:28:58 +0000 | [diff] [blame] | 213 | mDetailLayoutType = DetailLayoutType.APP_STORE; |
Jose Pascoal | ad4ea57 | 2014-12-16 20:31:48 +0000 | [diff] [blame] | 214 | mSelectedVersion = null; |
Tiago Costa | 3add03e | 2014-12-16 12:05:23 +0000 | [diff] [blame] | 215 | } |
| 216 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 217 | private void setHeaderAndVersionDetailsTitles() |
| 218 | { |
Jose Pascoal | 436915f | 2014-10-08 15:37:26 +0100 | [diff] [blame] | 219 | |
Jose Pascoal | e866cef | 2014-10-09 19:46:21 +0100 | [diff] [blame] | 220 | Resources resources = mainActivity.getResources(); |
Jose Pascoal | ad4ea57 | 2014-12-16 20:31:48 +0000 | [diff] [blame] | 221 | Version deviceVersion = mainActivity.getDeviceVersion(); |
Jose Pascoal | 02d8624 | 2014-12-17 18:50:08 +0000 | [diff] [blame] | 222 | |
| 223 | if (mIsVersion && mSelectedVersion != null) |
Jose Pascoal | ad4ea57 | 2014-12-16 20:31:48 +0000 | [diff] [blame] | 224 | { |
Jose Pascoal | cfc2dd4 | 2015-02-09 18:00:05 +0000 | [diff] [blame] | 225 | mHeaderType = FairphoneUpdater.getHeaderTypeFromImageType(mSelectedVersion.getImageType()); |
Jose Pascoal | ad4ea57 | 2014-12-16 20:31:48 +0000 | [diff] [blame] | 226 | } |
| 227 | else if (mSelectedStore != null) |
| 228 | { |
| 229 | mHeaderType = HeaderType.APP_STORE; |
| 230 | } |
| 231 | else |
| 232 | { |
| 233 | mHeaderType = HeaderType.FAIRPHONE; |
| 234 | } |
Jose Pascoal | 436915f | 2014-10-08 15:37:26 +0100 | [diff] [blame] | 235 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 236 | switch (mDetailLayoutType) |
| 237 | { |
Jose Pascoal | ee8a8eb | 2014-10-15 15:20:28 +0100 | [diff] [blame] | 238 | case UPDATE_FAIRPHONE: |
| 239 | case UPDATE_ANDROID: |
Jose Pascoal | e866cef | 2014-10-09 19:46:21 +0100 | [diff] [blame] | 240 | mHeaderText = resources.getString(R.string.install_update); |
| 241 | mVersionDetailsTitle = resources.getString(R.string.update_version); |
Jose Pascoal | dc29afe | 2014-10-10 13:43:47 +0100 | [diff] [blame] | 242 | mIsOSChange = false; |
Jose Pascoal | 391bd31 | 2014-10-13 18:16:27 +0100 | [diff] [blame] | 243 | mIsOlderVersion = false; |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 244 | break; |
Tiago Costa | e29f4cd | 2014-10-10 18:30:59 +0100 | [diff] [blame] | 245 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 246 | case ANDROID: |
Maarten Derks | 4bb5789 | 2016-01-26 10:52:53 +0100 | [diff] [blame] | 247 | mHeaderText = mSelectedVersion.getHumanReadableName(); |
Jose Pascoal | e866cef | 2014-10-09 19:46:21 +0100 | [diff] [blame] | 248 | mVersionDetailsTitle = resources.getString(R.string.new_os); |
Jose Pascoal | ad4ea57 | 2014-12-16 20:31:48 +0000 | [diff] [blame] | 249 | mIsOSChange = deviceVersion.getImageType().equalsIgnoreCase(Version.IMAGE_TYPE_FAIRPHONE); |
Jose Pascoal | 391bd31 | 2014-10-13 18:16:27 +0100 | [diff] [blame] | 250 | mIsOlderVersion = |
Jose Pascoal | ad4ea57 | 2014-12-16 20:31:48 +0000 | [diff] [blame] | 251 | (deviceVersion.getImageType().equalsIgnoreCase(Version.IMAGE_TYPE_AOSP) && deviceVersion.isNewerVersionThan(mSelectedVersion)); |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 252 | break; |
Jose Pascoal | ad4ea57 | 2014-12-16 20:31:48 +0000 | [diff] [blame] | 253 | case APP_STORE: |
Jose Pascoal | cfc2dd4 | 2015-02-09 18:00:05 +0000 | [diff] [blame] | 254 | mHeaderText = FairphoneUpdater.getStoreName(mSelectedStore); |
Jose Pascoal | ad4ea57 | 2014-12-16 20:31:48 +0000 | [diff] [blame] | 255 | mVersionDetailsTitle = resources.getString(R.string.install); |
| 256 | mIsOSChange = false; |
| 257 | mIsOlderVersion = false; |
| 258 | break; |
Maarten Derks | d270426 | 2016-03-17 15:34:51 +0100 | [diff] [blame] | 259 | case LATEST_FAIRPHONE: |
| 260 | mHeaderText = mSelectedVersion.getHumanReadableName(); |
| 261 | mVersionDetailsTitle = resources.getString(R.string.latest_version); |
| 262 | mIsOSChange = deviceVersion.getImageType().equalsIgnoreCase(Version.IMAGE_TYPE_AOSP); |
Maarten Derks | 3eac39c | 2016-06-07 14:22:31 +0200 | [diff] [blame] | 263 | mIsOlderVersion = false; |
Maarten Derks | d270426 | 2016-03-17 15:34:51 +0100 | [diff] [blame] | 264 | break; |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 265 | case FAIRPHONE: |
| 266 | default: |
Maarten Derks | 4bb5789 | 2016-01-26 10:52:53 +0100 | [diff] [blame] | 267 | mHeaderText = mSelectedVersion.getHumanReadableName(); |
Jose Pascoal | e866cef | 2014-10-09 19:46:21 +0100 | [diff] [blame] | 268 | mVersionDetailsTitle = resources.getString(R.string.older_version); |
Jose Pascoal | ad4ea57 | 2014-12-16 20:31:48 +0000 | [diff] [blame] | 269 | mIsOSChange = deviceVersion.getImageType().equalsIgnoreCase(Version.IMAGE_TYPE_AOSP); |
Jose Pascoal | 391bd31 | 2014-10-13 18:16:27 +0100 | [diff] [blame] | 270 | mIsOlderVersion = |
Jose Pascoal | ad4ea57 | 2014-12-16 20:31:48 +0000 | [diff] [blame] | 271 | (deviceVersion.getImageType().equalsIgnoreCase(Version.IMAGE_TYPE_FAIRPHONE) && deviceVersion.isNewerVersionThan(mSelectedVersion)); |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 272 | break; |
| 273 | } |
| 274 | } |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 275 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 276 | private Request createDownloadRequest(String url, String fileName, String downloadTitle) |
| 277 | { |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 278 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 279 | Resources resources = getResources(); |
| 280 | Request request; |
| 281 | try |
| 282 | { |
| 283 | request = new Request(Uri.parse(url)); |
Filipe Gonçalves | b31d586 | 2015-02-04 17:28:58 +0000 | [diff] [blame] | 284 | final File externalStoragePublicDirectory = Environment.getExternalStoragePublicDirectory(Environment.getExternalStorageDirectory() + resources.getString(R.string.updaterFolder)); |
Jose Pascoal | 46fdb06 | 2015-02-05 18:59:32 +0000 | [diff] [blame] | 285 | final boolean notMkDirs = !externalStoragePublicDirectory.mkdirs(); |
| 286 | if(notMkDirs && !externalStoragePublicDirectory.exists()) { |
Filipe Gonçalves | b31d586 | 2015-02-04 17:28:58 +0000 | [diff] [blame] | 287 | throw new Exception("Couldn't create updater dir structures."); |
| 288 | } |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 289 | |
Filipe Gonçalves | b31d586 | 2015-02-04 17:28:58 +0000 | [diff] [blame] | 290 | request.setDestinationInExternalPublicDir(resources.getString(R.string.updaterFolder), fileName); |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 291 | request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI); |
| 292 | request.setAllowedOverRoaming(false); |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 293 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 294 | request.setTitle(downloadTitle); |
| 295 | } catch (Exception e) |
| 296 | { |
Jose Pascoal | cfc2dd4 | 2015-02-09 18:00:05 +0000 | [diff] [blame] | 297 | Log.w(TAG, "Error setting the download request: " + e.getLocalizedMessage()); |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 298 | request = null; |
| 299 | } |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 300 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 301 | return request; |
| 302 | } |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 303 | |
Filipe Gonçalves | b31d586 | 2015-02-04 17:28:58 +0000 | [diff] [blame] | 304 | void startUpdateDownload() |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 305 | { |
Jose Pascoal | 02d8624 | 2014-12-17 18:50:08 +0000 | [diff] [blame] | 306 | DownloadableItem item = mIsVersion ? mSelectedVersion : mSelectedStore; |
Maarten Derks | e2f0ffc | 2016-04-26 11:58:36 +0200 | [diff] [blame] | 307 | |
| 308 | boolean isWifiEnabled = Utils.isWiFiEnabled(mainActivity); |
| 309 | boolean isBatteryLevelOk = Utils.isBatteryLevelOk(mainActivity); |
| 310 | |
| 311 | if (isWifiEnabled && isBatteryLevelOk) |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 312 | { |
Jose Pascoal | 02d8624 | 2014-12-17 18:50:08 +0000 | [diff] [blame] | 313 | if (item != null) |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 314 | { |
Jose Pascoal | aa579a8 | 2014-11-05 22:17:16 +0000 | [diff] [blame] | 315 | // set the download for the latest version on the download |
| 316 | // manager |
Jose Pascoal | 4091630 | 2015-02-06 18:43:47 +0000 | [diff] [blame] | 317 | String fileName = Utils.getFilenameFromDownloadableItem(item, mIsVersion); |
| 318 | String downloadTitle = Utils.getDownloadTitleFromDownloadableItem(getResources(), item, mIsVersion); |
Filipe Gonçalves | bc616bc | 2014-12-31 14:39:22 +0000 | [diff] [blame] | 319 | String download_link = item.getDownloadLink(); |
| 320 | if (!(download_link.startsWith("http://") || download_link.startsWith("https://"))) |
| 321 | { |
| 322 | // If the download URL is a relative path, make it an absolute |
Jose Pascoal | 4fe7ba5 | 2015-03-13 16:54:31 +0000 | [diff] [blame] | 323 | download_link = mainActivity.getPreferenceOtaDownloadUrl() + "/" + download_link; |
Filipe Gonçalves | bc616bc | 2014-12-31 14:39:22 +0000 | [diff] [blame] | 324 | // Sanitize URL - e.g. turn http://a.b//c/./d/../e to http://a.b/c/e |
| 325 | download_link = download_link.replaceAll("([^:])//", "/"); |
| 326 | download_link = download_link.replaceAll("/([^/]+)/\\.\\./", "/"); |
| 327 | download_link = download_link.replaceAll("/\\./", "/"); |
| 328 | try { |
| 329 | download_link = new URL(download_link).toExternalForm(); |
| 330 | } catch (MalformedURLException e) { |
Jose Pascoal | cfc2dd4 | 2015-02-09 18:00:05 +0000 | [diff] [blame] | 331 | Log.w(TAG, "Potentially malformed download link " + download_link + ": " + e.getLocalizedMessage()); |
Filipe Gonçalves | bc616bc | 2014-12-31 14:39:22 +0000 | [diff] [blame] | 332 | } |
| 333 | } |
Maarten Derks | ab3a986 | 2016-04-19 11:38:41 +0200 | [diff] [blame] | 334 | Request request = createDownloadRequest(download_link, fileName, downloadTitle); |
Jose Pascoal | aa579a8 | 2014-11-05 22:17:16 +0000 | [diff] [blame] | 335 | if (request != null && mDownloadManager != null) |
| 336 | { |
Jose Pascoal | 8775874 | 2015-01-28 20:00:22 +0000 | [diff] [blame] | 337 | //Guarantee that only we have only one download |
| 338 | long oldDownloadId = mainActivity.getLatestUpdateDownloadIdFromSharedPreference(); |
| 339 | if(oldDownloadId != 0){ |
| 340 | mDownloadManager.remove(oldDownloadId); |
| 341 | mainActivity.saveLatestUpdateDownloadId(0); |
| 342 | } |
| 343 | |
Jose Pascoal | aa579a8 | 2014-11-05 22:17:16 +0000 | [diff] [blame] | 344 | long mLatestUpdateDownloadId = mDownloadManager.enqueue(request); |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 345 | |
Jose Pascoal | aa579a8 | 2014-11-05 22:17:16 +0000 | [diff] [blame] | 346 | // save it on the shared preferences |
| 347 | mainActivity.saveLatestUpdateDownloadId(mLatestUpdateDownloadId); |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 348 | |
Jose Pascoal | aa579a8 | 2014-11-05 22:17:16 +0000 | [diff] [blame] | 349 | // change state to download |
Filipe Gonçalves | b31d586 | 2015-02-04 17:28:58 +0000 | [diff] [blame] | 350 | mainActivity.updateStatePreference(UpdaterState.DOWNLOAD); |
| 351 | mainActivity.changeFragment(mainActivity.getFragmentFromState()); |
Jose Pascoal | aa579a8 | 2014-11-05 22:17:16 +0000 | [diff] [blame] | 352 | } |
| 353 | else |
| 354 | { |
| 355 | Toast.makeText(mainActivity, getResources().getString(R.string.error_downloading) + " " + downloadTitle, Toast.LENGTH_LONG).show(); |
| 356 | } |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 357 | } |
| 358 | } |
| 359 | else |
| 360 | { |
| 361 | Resources resources = this.getResources(); |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 362 | |
Maarten Derks | e2f0ffc | 2016-04-26 11:58:36 +0200 | [diff] [blame] | 363 | if(!isWifiEnabled) { |
| 364 | AlertDialog.Builder wifiDialog = new AlertDialog.Builder(mainActivity); |
| 365 | wifiDialog.setIcon(R.drawable.ic_signal_wifi_4_bar_fpblue_24dp); |
| 366 | wifiDialog.setTitle(resources.getString(R.string.connect_to_wifi)); |
| 367 | wifiDialog.setPositiveButton(resources.getString(R.string.got_it), new DialogInterface.OnClickListener() { |
| 368 | public void onClick(DialogInterface dialog, int id) { |
| 369 | // do nothing, since the state is still the same |
| 370 | } |
| 371 | }); |
| 372 | wifiDialog.create(); |
| 373 | wifiDialog.show(); |
| 374 | } |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 375 | |
Maarten Derks | e2f0ffc | 2016-04-26 11:58:36 +0200 | [diff] [blame] | 376 | if(!isBatteryLevelOk) { |
| 377 | AlertDialog.Builder batteryDialog = new AlertDialog.Builder(mainActivity); |
| 378 | batteryDialog.setIcon(R.drawable.ic_battery_std_fpblue_24dp); |
| 379 | batteryDialog.setTitle(resources.getString(R.string.charge_battery)); |
| 380 | batteryDialog.setPositiveButton(resources.getString(R.string.got_it), new DialogInterface.OnClickListener() { |
| 381 | public void onClick(DialogInterface dialog, int id) { |
| 382 | // do nothing, since the state is still the same |
| 383 | } |
| 384 | }); |
| 385 | batteryDialog.create(); |
| 386 | batteryDialog.show(); |
| 387 | } |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 388 | } |
| 389 | } |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 390 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 391 | @Override |
| 392 | public void onResume() |
| 393 | { |
| 394 | super.onResume(); |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 395 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 396 | mDownloadManager = (DownloadManager) mainActivity.getSystemService(Context.DOWNLOAD_SERVICE); |
Jose Pascoal | e866cef | 2014-10-09 19:46:21 +0100 | [diff] [blame] | 397 | |
| 398 | setHeaderAndVersionDetailsTitles(); |
Tiago Costa | 3855faa | 2014-11-14 17:55:05 +0000 | [diff] [blame] | 399 | mainActivity.updateHeader(mHeaderType, mHeaderText, false); |
Jose Pascoal | e866cef | 2014-10-09 19:46:21 +0100 | [diff] [blame] | 400 | updateVersionName(); |
| 401 | updateReleaseNotesText(); |
Jose Pascoal | e866cef | 2014-10-09 19:46:21 +0100 | [diff] [blame] | 402 | setupDownloadAndUpdateButton(); |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 403 | } |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 404 | |
Jose Pascoal | d6c19a7 | 2014-10-17 16:52:36 +0100 | [diff] [blame] | 405 | private void showPopupDialog(String version, boolean hasEraseAllDataWarning, ConfirmationPopupDialogListener listener) |
Tiago Costa | e29f4cd | 2014-10-10 18:30:59 +0100 | [diff] [blame] | 406 | { |
| 407 | FragmentManager fm = getActivity().getSupportFragmentManager(); |
Jose Pascoal | d6c19a7 | 2014-10-17 16:52:36 +0100 | [diff] [blame] | 408 | ConfirmationPopupDialog popupDialog = |
| 409 | new ConfirmationPopupDialog(version, mIsOSChange, mIsOlderVersion, hasEraseAllDataWarning, mDetailLayoutType, listener); |
Tiago Costa | e29f4cd | 2014-10-10 18:30:59 +0100 | [diff] [blame] | 410 | popupDialog.show(fm, version); |
| 411 | } |
| 412 | |
Filipe Gonçalves | b31d586 | 2015-02-04 17:28:58 +0000 | [diff] [blame] | 413 | void startDownload() |
Tiago Costa | 3add03e | 2014-12-16 12:05:23 +0000 | [diff] [blame] | 414 | { |
Jose Pascoal | 02d8624 | 2014-12-17 18:50:08 +0000 | [diff] [blame] | 415 | if (mIsVersion && mSelectedVersion != null) |
Tiago Costa | 3add03e | 2014-12-16 12:05:23 +0000 | [diff] [blame] | 416 | { |
Jose Pascoal | 02d8624 | 2014-12-17 18:50:08 +0000 | [diff] [blame] | 417 | if (mIsOSChange || mIsOlderVersion) |
Jose Pascoal | dc29afe | 2014-10-10 13:43:47 +0100 | [diff] [blame] | 418 | { |
Maarten Derks | 4bb5789 | 2016-01-26 10:52:53 +0100 | [diff] [blame] | 419 | showPopupDialog(mSelectedVersion.getHumanReadableName(), mSelectedVersion.hasEraseAllPartitionWarning(), |
Jose Pascoal | 02d8624 | 2014-12-17 18:50:08 +0000 | [diff] [blame] | 420 | new ConfirmationPopupDialogListener() |
| 421 | { |
| 422 | |
| 423 | @Override |
| 424 | public void onFinishPopUpDialog(boolean isOk) |
Jose Pascoal | aa579a8 | 2014-11-05 22:17:16 +0000 | [diff] [blame] | 425 | { |
Jose Pascoal | 02d8624 | 2014-12-17 18:50:08 +0000 | [diff] [blame] | 426 | if (isOk) |
Tiago Costa | 3add03e | 2014-12-16 12:05:23 +0000 | [diff] [blame] | 427 | { |
Jose Pascoal | 02d8624 | 2014-12-17 18:50:08 +0000 | [diff] [blame] | 428 | mainActivity.setSelectedVersion(mSelectedVersion); |
| 429 | showEraseAllDataWarning(true); |
Tiago Costa | 3add03e | 2014-12-16 12:05:23 +0000 | [diff] [blame] | 430 | } |
Jose Pascoal | 02d8624 | 2014-12-17 18:50:08 +0000 | [diff] [blame] | 431 | } |
| 432 | }); |
Tiago Costa | 3add03e | 2014-12-16 12:05:23 +0000 | [diff] [blame] | 433 | } |
| 434 | else |
| 435 | { |
Jose Pascoal | 02d8624 | 2014-12-17 18:50:08 +0000 | [diff] [blame] | 436 | mainActivity.setSelectedVersion(mSelectedVersion); |
| 437 | showEraseAllDataWarning(false); |
Tiago Costa | 3add03e | 2014-12-16 12:05:23 +0000 | [diff] [blame] | 438 | } |
| 439 | } |
Jose Pascoal | 02d8624 | 2014-12-17 18:50:08 +0000 | [diff] [blame] | 440 | else if (mSelectedStore != null) |
| 441 | { |
| 442 | mainActivity.setSelectedStore(mSelectedStore); |
| 443 | showStoreDisclaimer(); |
| 444 | } |
Tiago Costa | 3add03e | 2014-12-16 12:05:23 +0000 | [diff] [blame] | 445 | } |
Jose Pascoal | 02d8624 | 2014-12-17 18:50:08 +0000 | [diff] [blame] | 446 | |
Jose Pascoal | 7539216 | 2014-10-15 18:29:01 +0100 | [diff] [blame] | 447 | private void showEraseAllDataWarning(boolean bypassEraseAllWarning) |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 448 | { |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 449 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 450 | final UpdaterState currentState = mainActivity.getCurrentUpdaterState(); |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 451 | |
Jose Pascoal | aa579a8 | 2014-11-05 22:17:16 +0000 | [diff] [blame] | 452 | if (mSelectedVersion != null && mSelectedVersion.hasEraseAllPartitionWarning() && !bypassEraseAllWarning) |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 453 | { |
Pedro Arelo | 773bd82 | 2014-10-10 11:57:34 +0100 | [diff] [blame] | 454 | new AlertDialog.Builder(mainActivity).setTitle(android.R.string.dialog_alert_title).setMessage(R.string.erase_all_partitions_warning_message) |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 455 | .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() |
| 456 | { |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 457 | |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 458 | @Override |
| 459 | public void onClick(DialogInterface dialog, int which) |
| 460 | { |
| 461 | if (currentState == UpdaterState.NORMAL) |
| 462 | { |
| 463 | startUpdateDownload(); |
| 464 | } |
| 465 | } |
| 466 | }).setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() |
| 467 | { |
| 468 | public void onClick(DialogInterface dialog, int which) |
| 469 | { |
| 470 | mainActivity.setSelectedVersion(null); |
| 471 | } |
| 472 | }).show(); |
| 473 | } |
| 474 | else |
| 475 | { |
| 476 | if (currentState == UpdaterState.NORMAL) |
| 477 | { |
| 478 | startUpdateDownload(); |
| 479 | } |
| 480 | else |
| 481 | { |
| 482 | mainActivity.setSelectedVersion(null); |
| 483 | } |
| 484 | } |
| 485 | } |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 486 | |
Filipe Gonçalves | b31d586 | 2015-02-04 17:28:58 +0000 | [diff] [blame] | 487 | void showStoreDisclaimer() |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 488 | { |
Jose Pascoal | 02d8624 | 2014-12-17 18:50:08 +0000 | [diff] [blame] | 489 | final UpdaterState currentState = mainActivity.getCurrentUpdaterState(); |
Jose Pascoal | 54b3ae6 | 2014-10-07 20:29:58 +0100 | [diff] [blame] | 490 | |
Jose Pascoal | 02d8624 | 2014-12-17 18:50:08 +0000 | [diff] [blame] | 491 | if (mSelectedStore != null && mSelectedStore.showDisclaimer()) |
| 492 | { |
| 493 | new AlertDialog.Builder(mainActivity).setTitle(R.string.google_apps_disclaimer_title).setMessage(R.string.google_apps_disclaimer_description) |
| 494 | .setPositiveButton(R.string.google_apps_disclaimer_agree, new DialogInterface.OnClickListener() |
Pedro Arelo | 4b62623 | 2014-10-09 15:12:41 +0100 | [diff] [blame] | 495 | { |
Tiago Costa | 3add03e | 2014-12-16 12:05:23 +0000 | [diff] [blame] | 496 | |
Jose Pascoal | 02d8624 | 2014-12-17 18:50:08 +0000 | [diff] [blame] | 497 | @Override |
| 498 | public void onClick(DialogInterface dialog, int which) |
| 499 | { |
| 500 | if (currentState == UpdaterState.NORMAL) |
| 501 | { |
| 502 | startUpdateDownload(); |
| 503 | } |
| 504 | } |
| 505 | }).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() |
| 506 | { |
| 507 | public void onClick(DialogInterface dialog, int which) |
| 508 | { |
| 509 | mainActivity.setSelectedStore(null); |
| 510 | } |
| 511 | }).show(); |
| 512 | } |
| 513 | else |
| 514 | { |
| 515 | if (currentState == UpdaterState.NORMAL) |
| 516 | { |
| 517 | startUpdateDownload(); |
| 518 | } |
| 519 | else |
| 520 | { |
| 521 | mainActivity.setSelectedStore(null); |
| 522 | } |
| 523 | } |
| 524 | } |
Jose Pascoal | 91aff13 | 2014-10-02 17:19:47 +0100 | [diff] [blame] | 525 | } |