Initial commit for GitHub
diff --git a/FairphoneUpdater/.classpath b/FairphoneUpdater/.classpath
new file mode 100644
index 0000000..26bdfa6
--- /dev/null
+++ b/FairphoneUpdater/.classpath
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="gen"/>
+ <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
+ <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
+ <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
+ <classpathentry kind="output" path="bin/classes"/>
+</classpath>
diff --git a/FairphoneUpdater/.project b/FairphoneUpdater/.project
new file mode 100644
index 0000000..7630c9f
--- /dev/null
+++ b/FairphoneUpdater/.project
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>FairphoneUpdater</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.ApkBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>com.android.ide.eclipse.adt.AndroidNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/FairphoneUpdater/.settings/org.eclipse.jdt.core.prefs b/FairphoneUpdater/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..b080d2d
--- /dev/null
+++ b/FairphoneUpdater/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/FairphoneUpdater/Android.mk b/FairphoneUpdater/Android.mk
new file mode 100644
index 0000000..483a95d
--- /dev/null
+++ b/FairphoneUpdater/Android.mk
@@ -0,0 +1,33 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-common android-support-v4
+LOCAL_JAVA_LIBRARIES += mediatek-framework
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
+#LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := FairphoneUpdater
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/FairphoneUpdater/AndroidManifest.xml b/FairphoneUpdater/AndroidManifest.xml
new file mode 100644
index 0000000..3f62121
--- /dev/null
+++ b/FairphoneUpdater/AndroidManifest.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.fairphone.updater"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk
+ android:minSdkVersion="17"
+ android:targetSdkVersion="17" />
+
+ <uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.REBOOT" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+ <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+
+ <application
+ android:allowBackup="true"
+ android:icon="@drawable/fairphone_updater_app_icon"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme" >
+ <activity
+ android:name="com.fairphone.updater.FairphoneUpdater"
+ android:label="@string/app_name"
+ android:screenOrientation="portrait" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <service
+ android:name=".UpdaterService"
+ android:icon="@drawable/fairphone_updater_app_icon_small"
+ android:label="@string/updaterService" />
+
+ <receiver android:name="BootBroadcastReceiver" >
+ <intent-filter>
+ <action android:name="android.intent.action.BOOT_COMPLETED" />
+ </intent-filter>
+ </receiver>
+ </application>
+
+</manifest>
\ No newline at end of file
diff --git a/FairphoneUpdater/CleanSpec.mk b/FairphoneUpdater/CleanSpec.mk
new file mode 100644
index 0000000..a2b2866
--- /dev/null
+++ b/FairphoneUpdater/CleanSpec.mk
@@ -0,0 +1,56 @@
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/FairphoneUpdater_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/FairphoneUpdater_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/FairphoneUpdater_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/FairphoneUpdater_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/FairphoneUpdater_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/app/FairphoneUpdater.apk)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
diff --git a/FairphoneUpdater/bin/AndroidManifest.xml b/FairphoneUpdater/bin/AndroidManifest.xml
new file mode 100644
index 0000000..3f62121
--- /dev/null
+++ b/FairphoneUpdater/bin/AndroidManifest.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.fairphone.updater"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk
+ android:minSdkVersion="17"
+ android:targetSdkVersion="17" />
+
+ <uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.REBOOT" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+ <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+
+ <application
+ android:allowBackup="true"
+ android:icon="@drawable/fairphone_updater_app_icon"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme" >
+ <activity
+ android:name="com.fairphone.updater.FairphoneUpdater"
+ android:label="@string/app_name"
+ android:screenOrientation="portrait" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <service
+ android:name=".UpdaterService"
+ android:icon="@drawable/fairphone_updater_app_icon_small"
+ android:label="@string/updaterService" />
+
+ <receiver android:name="BootBroadcastReceiver" >
+ <intent-filter>
+ <action android:name="android.intent.action.BOOT_COMPLETED" />
+ </intent-filter>
+ </receiver>
+ </application>
+
+</manifest>
\ No newline at end of file
diff --git a/FairphoneUpdater/bin/classes/com/fairphone/updater/BootBroadcastReceiver.class b/FairphoneUpdater/bin/classes/com/fairphone/updater/BootBroadcastReceiver.class
new file mode 100644
index 0000000..59215d0
--- /dev/null
+++ b/FairphoneUpdater/bin/classes/com/fairphone/updater/BootBroadcastReceiver.class
Binary files differ
diff --git a/FairphoneUpdater/bin/classes/com/fairphone/updater/BuildConfig.class b/FairphoneUpdater/bin/classes/com/fairphone/updater/BuildConfig.class
new file mode 100644
index 0000000..a4b4e66
--- /dev/null
+++ b/FairphoneUpdater/bin/classes/com/fairphone/updater/BuildConfig.class
Binary files differ
diff --git a/FairphoneUpdater/bin/classes/com/fairphone/updater/FairphoneUpdater$1.class b/FairphoneUpdater/bin/classes/com/fairphone/updater/FairphoneUpdater$1.class
new file mode 100644
index 0000000..5eb8cc2
--- /dev/null
+++ b/FairphoneUpdater/bin/classes/com/fairphone/updater/FairphoneUpdater$1.class
Binary files differ
diff --git a/FairphoneUpdater/bin/classes/com/fairphone/updater/FairphoneUpdater$2.class b/FairphoneUpdater/bin/classes/com/fairphone/updater/FairphoneUpdater$2.class
new file mode 100644
index 0000000..7ff82e8
--- /dev/null
+++ b/FairphoneUpdater/bin/classes/com/fairphone/updater/FairphoneUpdater$2.class
Binary files differ
diff --git a/FairphoneUpdater/bin/classes/com/fairphone/updater/FairphoneUpdater$DownloadBroadCastReceiver.class b/FairphoneUpdater/bin/classes/com/fairphone/updater/FairphoneUpdater$DownloadBroadCastReceiver.class
new file mode 100644
index 0000000..2e5f73d
--- /dev/null
+++ b/FairphoneUpdater/bin/classes/com/fairphone/updater/FairphoneUpdater$DownloadBroadCastReceiver.class
Binary files differ
diff --git a/FairphoneUpdater/bin/classes/com/fairphone/updater/FairphoneUpdater$UpdaterState.class b/FairphoneUpdater/bin/classes/com/fairphone/updater/FairphoneUpdater$UpdaterState.class
new file mode 100644
index 0000000..9164e62
--- /dev/null
+++ b/FairphoneUpdater/bin/classes/com/fairphone/updater/FairphoneUpdater$UpdaterState.class
Binary files differ
diff --git a/FairphoneUpdater/bin/classes/com/fairphone/updater/FairphoneUpdater.class b/FairphoneUpdater/bin/classes/com/fairphone/updater/FairphoneUpdater.class
new file mode 100644
index 0000000..1aeda13
--- /dev/null
+++ b/FairphoneUpdater/bin/classes/com/fairphone/updater/FairphoneUpdater.class
Binary files differ
diff --git a/FairphoneUpdater/bin/classes/com/fairphone/updater/R$attr.class b/FairphoneUpdater/bin/classes/com/fairphone/updater/R$attr.class
new file mode 100644
index 0000000..6bb9149
--- /dev/null
+++ b/FairphoneUpdater/bin/classes/com/fairphone/updater/R$attr.class
Binary files differ
diff --git a/FairphoneUpdater/bin/classes/com/fairphone/updater/R$dimen.class b/FairphoneUpdater/bin/classes/com/fairphone/updater/R$dimen.class
new file mode 100644
index 0000000..8b83e0e
--- /dev/null
+++ b/FairphoneUpdater/bin/classes/com/fairphone/updater/R$dimen.class
Binary files differ
diff --git a/FairphoneUpdater/bin/classes/com/fairphone/updater/R$drawable.class b/FairphoneUpdater/bin/classes/com/fairphone/updater/R$drawable.class
new file mode 100644
index 0000000..57672b6
--- /dev/null
+++ b/FairphoneUpdater/bin/classes/com/fairphone/updater/R$drawable.class
Binary files differ
diff --git a/FairphoneUpdater/bin/classes/com/fairphone/updater/R$id.class b/FairphoneUpdater/bin/classes/com/fairphone/updater/R$id.class
new file mode 100644
index 0000000..7e81278
--- /dev/null
+++ b/FairphoneUpdater/bin/classes/com/fairphone/updater/R$id.class
Binary files differ
diff --git a/FairphoneUpdater/bin/classes/com/fairphone/updater/R$layout.class b/FairphoneUpdater/bin/classes/com/fairphone/updater/R$layout.class
new file mode 100644
index 0000000..a72c62d
--- /dev/null
+++ b/FairphoneUpdater/bin/classes/com/fairphone/updater/R$layout.class
Binary files differ
diff --git a/FairphoneUpdater/bin/classes/com/fairphone/updater/R$raw.class b/FairphoneUpdater/bin/classes/com/fairphone/updater/R$raw.class
new file mode 100644
index 0000000..388ea34
--- /dev/null
+++ b/FairphoneUpdater/bin/classes/com/fairphone/updater/R$raw.class
Binary files differ
diff --git a/FairphoneUpdater/bin/classes/com/fairphone/updater/R$string.class b/FairphoneUpdater/bin/classes/com/fairphone/updater/R$string.class
new file mode 100644
index 0000000..5793c96
--- /dev/null
+++ b/FairphoneUpdater/bin/classes/com/fairphone/updater/R$string.class
Binary files differ
diff --git a/FairphoneUpdater/bin/classes/com/fairphone/updater/R$style.class b/FairphoneUpdater/bin/classes/com/fairphone/updater/R$style.class
new file mode 100644
index 0000000..62f757d
--- /dev/null
+++ b/FairphoneUpdater/bin/classes/com/fairphone/updater/R$style.class
Binary files differ
diff --git a/FairphoneUpdater/bin/classes/com/fairphone/updater/R.class b/FairphoneUpdater/bin/classes/com/fairphone/updater/R.class
new file mode 100644
index 0000000..29bed44
--- /dev/null
+++ b/FairphoneUpdater/bin/classes/com/fairphone/updater/R.class
Binary files differ
diff --git a/FairphoneUpdater/bin/classes/com/fairphone/updater/RSAUtils.class b/FairphoneUpdater/bin/classes/com/fairphone/updater/RSAUtils.class
new file mode 100644
index 0000000..b31ba53
--- /dev/null
+++ b/FairphoneUpdater/bin/classes/com/fairphone/updater/RSAUtils.class
Binary files differ
diff --git a/FairphoneUpdater/bin/classes/com/fairphone/updater/UpdaterService$DownloadBroadCastReceiver.class b/FairphoneUpdater/bin/classes/com/fairphone/updater/UpdaterService$DownloadBroadCastReceiver.class
new file mode 100644
index 0000000..fb68ad2
--- /dev/null
+++ b/FairphoneUpdater/bin/classes/com/fairphone/updater/UpdaterService$DownloadBroadCastReceiver.class
Binary files differ
diff --git a/FairphoneUpdater/bin/classes/com/fairphone/updater/UpdaterService.class b/FairphoneUpdater/bin/classes/com/fairphone/updater/UpdaterService.class
new file mode 100644
index 0000000..d51b6b1
--- /dev/null
+++ b/FairphoneUpdater/bin/classes/com/fairphone/updater/UpdaterService.class
Binary files differ
diff --git a/FairphoneUpdater/bin/classes/com/fairphone/updater/Version.class b/FairphoneUpdater/bin/classes/com/fairphone/updater/Version.class
new file mode 100644
index 0000000..552d679
--- /dev/null
+++ b/FairphoneUpdater/bin/classes/com/fairphone/updater/Version.class
Binary files differ
diff --git a/FairphoneUpdater/bin/classes/com/fairphone/updater/VersionParserHelper.class b/FairphoneUpdater/bin/classes/com/fairphone/updater/VersionParserHelper.class
new file mode 100644
index 0000000..f33d853
--- /dev/null
+++ b/FairphoneUpdater/bin/classes/com/fairphone/updater/VersionParserHelper.class
Binary files differ
diff --git a/FairphoneUpdater/gen/com/fairphone/updater/BuildConfig.java b/FairphoneUpdater/gen/com/fairphone/updater/BuildConfig.java
new file mode 100644
index 0000000..b128dff
--- /dev/null
+++ b/FairphoneUpdater/gen/com/fairphone/updater/BuildConfig.java
@@ -0,0 +1,6 @@
+/** Automatically generated file. DO NOT MODIFY */
+package com.fairphone.updater;
+
+public final class BuildConfig {
+ public final static boolean DEBUG = true;
+}
\ No newline at end of file
diff --git a/FairphoneUpdater/gen/com/fairphone/updater/R.java b/FairphoneUpdater/gen/com/fairphone/updater/R.java
new file mode 100644
index 0000000..b05542d
--- /dev/null
+++ b/FairphoneUpdater/gen/com/fairphone/updater/R.java
@@ -0,0 +1,76 @@
+/* AUTO-GENERATED FILE. DO NOT MODIFY.
+ *
+ * This class was automatically generated by the
+ * aapt tool from the resource data it found. It
+ * should not be modified by hand.
+ */
+
+package com.fairphone.updater;
+
+public final class R {
+ public static final class attr {
+ }
+ public static final class dimen {
+ /** Default screen margins, per the Android Design guidelines.
+ */
+ public static final int activity_horizontal_margin=0x7f050000;
+ public static final int activity_vertical_margin=0x7f050001;
+ }
+ public static final class drawable {
+ public static final int fairphone_updater_app_icon=0x7f020000;
+ public static final int fairphone_updater_app_icon_small=0x7f020001;
+ public static final int fairphone_updater_current_version=0x7f020002;
+ public static final int fairphone_updater_tray_icon=0x7f020003;
+ public static final int fairphone_updater_tray_icon_small=0x7f020004;
+ }
+ public static final class id {
+ public static final int currentVersionDescriptionText=0x7f080005;
+ public static final int currentVersionImage=0x7f080003;
+ public static final int currentVersionSeparator=0x7f080002;
+ public static final int currentVersionTitleSeparator=0x7f080001;
+ public static final int currentVersionTitleText=0x7f080004;
+ public static final int latestVersionGroup=0x7f080006;
+ public static final int messageText=0x7f08000c;
+ public static final int newVersionUpdateButton=0x7f08000d;
+ public static final int nextVersionDescriptionText=0x7f08000b;
+ public static final int nextVersionImage=0x7f080009;
+ public static final int nextVersionSeparator=0x7f080008;
+ public static final int nextVersionTitleSeparator=0x7f080007;
+ public static final int nextVersionTitleText=0x7f08000a;
+ public static final int titleText=0x7f080000;
+ }
+ public static final class layout {
+ public static final int activity_fairphone_updater=0x7f030000;
+ }
+ public static final class raw {
+ public static final int public_key=0x7f040000;
+ }
+ public static final class string {
+ public static final int app_name=0x7f060000;
+ public static final int currentVersion=0x7f06000a;
+ public static final int defaultAndroidVersionNumber=0x7f060008;
+ public static final int defaultVersionName=0x7f060007;
+ public static final int defaultVersionNumber=0x7f060006;
+ public static final int downloadMessage=0x7f060011;
+ public static final int downloadUpdateTitle=0x7f060012;
+ public static final int downloadUrl=0x7f060001;
+ public static final int fairphoneUpdateMessage=0x7f060010;
+ public static final int installVersion=0x7f06000c;
+ public static final int invalidDownloadMessage=0x7f06000f;
+ public static final int messageReadyToInstall=0x7f06000e;
+ public static final int newVersion=0x7f06000b;
+ public static final int rebootDevice=0x7f06000d;
+ public static final int updaterService=0x7f060009;
+ /** <string name="downloadUrl">http://www.kwamecorp.com/dev/latest.zip</string>
+ */
+ public static final int versionFilename=0x7f060002;
+ public static final int versionFilename_sig=0x7f060005;
+ public static final int versionFilename_xml=0x7f060004;
+ public static final int versionFilename_zip=0x7f060003;
+ public static final int wifiDiscaimerMessage=0x7f060014;
+ public static final int wifiDiscaimerTitle=0x7f060013;
+ }
+ public static final class style {
+ public static final int AppTheme=0x7f070000;
+ }
+}
diff --git a/FairphoneUpdater/libs/android-support-v4.jar b/FairphoneUpdater/libs/android-support-v4.jar
new file mode 100644
index 0000000..cf12d28
--- /dev/null
+++ b/FairphoneUpdater/libs/android-support-v4.jar
Binary files differ
diff --git a/FairphoneUpdater/proguard-project.txt b/FairphoneUpdater/proguard-project.txt
new file mode 100644
index 0000000..f2fe155
--- /dev/null
+++ b/FairphoneUpdater/proguard-project.txt
@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
diff --git a/FairphoneUpdater/project.properties b/FairphoneUpdater/project.properties
new file mode 100644
index 0000000..a3ee5ab
--- /dev/null
+++ b/FairphoneUpdater/project.properties
@@ -0,0 +1,14 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-17
diff --git a/FairphoneUpdater/res/drawable-hdpi/fairphone_updater_app_icon.png b/FairphoneUpdater/res/drawable-hdpi/fairphone_updater_app_icon.png
new file mode 100644
index 0000000..fe13aef
--- /dev/null
+++ b/FairphoneUpdater/res/drawable-hdpi/fairphone_updater_app_icon.png
Binary files differ
diff --git a/FairphoneUpdater/res/drawable-hdpi/fairphone_updater_app_icon_small.png b/FairphoneUpdater/res/drawable-hdpi/fairphone_updater_app_icon_small.png
new file mode 100644
index 0000000..ca5dddd
--- /dev/null
+++ b/FairphoneUpdater/res/drawable-hdpi/fairphone_updater_app_icon_small.png
Binary files differ
diff --git a/FairphoneUpdater/res/drawable-hdpi/fairphone_updater_current_version.png b/FairphoneUpdater/res/drawable-hdpi/fairphone_updater_current_version.png
new file mode 100644
index 0000000..7f4d80d
--- /dev/null
+++ b/FairphoneUpdater/res/drawable-hdpi/fairphone_updater_current_version.png
Binary files differ
diff --git a/FairphoneUpdater/res/drawable-hdpi/fairphone_updater_tray_icon.png b/FairphoneUpdater/res/drawable-hdpi/fairphone_updater_tray_icon.png
new file mode 100644
index 0000000..f3ccf85
--- /dev/null
+++ b/FairphoneUpdater/res/drawable-hdpi/fairphone_updater_tray_icon.png
Binary files differ
diff --git a/FairphoneUpdater/res/drawable-hdpi/fairphone_updater_tray_icon_small.png b/FairphoneUpdater/res/drawable-hdpi/fairphone_updater_tray_icon_small.png
new file mode 100644
index 0000000..ccd0b62
--- /dev/null
+++ b/FairphoneUpdater/res/drawable-hdpi/fairphone_updater_tray_icon_small.png
Binary files differ
diff --git a/FairphoneUpdater/res/layout/activity_fairphone_updater.xml b/FairphoneUpdater/res/layout/activity_fairphone_updater.xml
new file mode 100644
index 0000000..0cdc658
--- /dev/null
+++ b/FairphoneUpdater/res/layout/activity_fairphone_updater.xml
@@ -0,0 +1,173 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#000"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/titleText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="10dp"
+ android:drawableLeft="@drawable/fairphone_updater_app_icon_small"
+ android:drawablePadding="10dp"
+ android:gravity="center_vertical"
+ android:text="@string/app_name"
+ android:textColor="#fff"
+ android:textSize="20sp" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="2dp"
+ android:background="#33b5e5" />
+
+ <TextView
+ android:id="@+id/currentVersionTitleSeparator"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="3dp"
+ android:layout_marginLeft="20dp"
+ android:layout_marginTop="10dp"
+ android:text="@string/currentVersion"
+ android:textAllCaps="true"
+ android:textColor="#d3d3d3"
+ android:textSize="15sp" />
+
+ <View
+ android:id="@+id/currentVersionSeparator"
+ android:layout_width="match_parent"
+ android:layout_height="2dp"
+ android:layout_marginLeft="15dp"
+ android:layout_marginRight="15dp"
+ android:background="#d3d3d3" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="80dp"
+ android:layout_margin="15dp"
+ android:orientation="horizontal" >
+
+ <ImageView
+ android:id="@+id/currentVersionImage"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/fairphone_updater_current_version" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dp"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/currentVersionTitleText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:includeFontPadding="false"
+ android:text="@string/currentVersion"
+ android:textColor="#fff"
+ android:textSize="17sp" />
+
+ <TextView
+ android:id="@+id/currentVersionDescriptionText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:textColor="#fff" />
+ </LinearLayout>
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/latestVersionGroup"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="#000"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/nextVersionTitleSeparator"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="3dp"
+ android:layout_marginLeft="20dp"
+ android:layout_marginTop="20dp"
+ android:text="@string/newVersion"
+ android:textAllCaps="true"
+ android:textColor="#d3d3d3"
+ android:textSize="15sp" />
+
+ <View
+ android:id="@+id/nextVersionSeparator"
+ android:layout_width="match_parent"
+ android:layout_height="2dp"
+ android:layout_marginLeft="15dp"
+ android:layout_marginRight="15dp"
+ android:background="#d3d3d3" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="80dp"
+ android:layout_margin="15dp"
+ android:orientation="horizontal" >
+
+ <ImageView
+ android:id="@+id/nextVersionImage"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/fairphone_updater_app_icon" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dp"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/nextVersionTitleText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:includeFontPadding="false"
+ android:text="@string/newVersion"
+ android:textColor="#fff"
+ android:textSize="17sp" />
+
+ <TextView
+ android:id="@+id/nextVersionDescriptionText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:textColor="#fff" />
+ </LinearLayout>
+ </LinearLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <TextView
+ android:id="@+id/messageText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="15dp"
+ android:gravity="right"
+ android:textColor="#d3d3d3"
+ android:textSize="18.5sp" />
+
+ <Button
+ android:id="@+id/newVersionUpdateButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right"
+ android:layout_marginBottom="15dp"
+ android:layout_marginRight="15dp"
+ android:paddingLeft="15dp"
+ android:paddingRight="15dp"
+ android:text="@string/installVersion"
+ android:textColor="#ffffff" />
+ </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/FairphoneUpdater/res/raw/public_key.pem b/FairphoneUpdater/res/raw/public_key.pem
new file mode 100644
index 0000000..e25387d
--- /dev/null
+++ b/FairphoneUpdater/res/raw/public_key.pem
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0FRWtP59Lq3axya7c48b
+aZgJIc19Welf56rG1oXnJqG3qqVhaAg8OKLW6pLKeg38K/VI8ih5HVuj2fb7u35G
+BsOvSFcPRVbezermyFdnlbCfVgQlTfnVtv9oGRzgofg6dkXYQytObouQKMAW3QSX
+0475+9JFLlyW7aTtafsapP6sqCZX8cgLHT/nPqTPdA/MFB5tDPtBBsOf2LR7h5Kj
+NbU8exLV/6SGqqJq5ZmJOOIdW5W6IxiGUkHJ+uhQ5YDIxYRVsv7IV/PVFzMLD2pe
+9sa0wX1Gj0/h7pguVGorpR5wxK5AWpyXuAYbzyLTXRyIk5AgXlW9bDiP//wHqSlH
+pQIDAQAB
+-----END PUBLIC KEY-----
diff --git a/FairphoneUpdater/res/values-de/strings.xml b/FairphoneUpdater/res/values-de/strings.xml
new file mode 100644
index 0000000..9268890
--- /dev/null
+++ b/FairphoneUpdater/res/values-de/strings.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="updaterService">Aktualisierungsservice</string>
+ <string name="currentVersion">Aktuelle Version</string>
+ <string name="newVersion">Neue Version</string>
+ <string name="installVersion">Neue Version installieren</string>
+ <string name="rebootDevice">Gerät neustarten</string>
+ <string name="messageReadyToInstall">Neue Version bereit zur Installation…</string>
+ <string name="invalidDownloadMessage">Ungültige Datei runtergeladen</string>
+ <string name="fairphoneUpdateMessage">Neues Fairphone Update verfügbar</string>
+ <string name="downloadMessage">Lade Datei, bitte warten…</string>
+ <string name="downloadUpdateTitle">Neue Fairphone Version</string>
+ <string name="wifiDiscaimerTitle">WLAN deaktiviert</string>
+ <string name="wifiDiscaimerMessage">Die Datei, die Sie herunterladen möchten, ist zu groß für mobile Verbindungen (~200 MB). Bitte aktivieren Sie die WLAN-Verbindung und versuchen Sie es erneut.</string>
+</resources>
\ No newline at end of file
diff --git a/FairphoneUpdater/res/values-es/strings.xml b/FairphoneUpdater/res/values-es/strings.xml
new file mode 100644
index 0000000..0e7d6b3
--- /dev/null
+++ b/FairphoneUpdater/res/values-es/strings.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="updaterService">Servicio de actualización</string>
+ <string name="currentVersion">Versión actual</string>
+ <string name="newVersion">Nueva versión</string>
+ <string name="installVersion">Instalar nueva versión</string>
+ <string name="rebootDevice">Reiniciar dispositivo</string>
+ <string name="messageReadyToInstall">La nueva versión está lista para instalar…</string>
+ <string name="invalidDownloadMessage">Archivo descargado inválido</string>
+ <string name="fairphoneUpdateMessage">Nueva actualización para Fairphone disponible</string>
+ <string name="downloadMessage">Descargando actualización, ten paciencia…</string>
+ <string name="downloadUpdateTitle">Nueva actualización para Fairphone</string>
+ <string name="wifiDiscaimerTitle">Wi-Fi desconectado</string>
+ <string name="wifiDiscaimerMessage">El archivo que está intentando descargar es muy largo para conexiones móviles (~200mb). Por favor conéctese al Wi-Fi e intente otra vez.</string>
+</resources>
\ No newline at end of file
diff --git a/FairphoneUpdater/res/values-fr/strings.xml b/FairphoneUpdater/res/values-fr/strings.xml
new file mode 100644
index 0000000..4611351
--- /dev/null
+++ b/FairphoneUpdater/res/values-fr/strings.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="updaterService">Service de mise à jour</string>
+ <string name="currentVersion">Version actuelle</string>
+ <string name="newVersion">Nouvelle version</string>
+ <string name="installVersion">Installer la nouvelle version</string>
+ <string name="rebootDevice">Redémarrer l\'appareil</string>
+ <string name="messageReadyToInstall">Une nouvelle version est prête à installer…</string>
+ <string name="invalidDownloadMessage">Fichier téléchargé invalide</string>
+ <string name="fairphoneUpdateMessage">Nouvelle mise à jour de Fairphone disponible</string>
+ <string name="downloadMessage">Téléchargement de mise à jour, svp patienter…</string>
+ <string name="downloadUpdateTitle">Nouvelle mise à jour de Fairphones</string>
+ <string name="wifiDiscaimerTitle">Fonction Wi-Fi désactivée</string>
+ <string name="wifiDiscaimerMessage">Le fichier que vous essayez de télécharger est trop volumineux pour les connexions mobiles (~200 MB). Veuillez activer la connexion Wi-Fi et essayer à nouveau.</string>
+</resources>
\ No newline at end of file
diff --git a/FairphoneUpdater/res/values-nl/strings.xml b/FairphoneUpdater/res/values-nl/strings.xml
new file mode 100644
index 0000000..24a8f14
--- /dev/null
+++ b/FairphoneUpdater/res/values-nl/strings.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="updaterService">Updater Service</string>
+ <string name="currentVersion">Huidige Versie</string>
+ <string name="newVersion">Nieuwe Versie</string>
+ <string name="installVersion">Installeer nieuwe versie</string>
+ <string name="rebootDevice">Herstart apparaat</string>
+ <string name="messageReadyToInstall">Nieuwe versie staat klaar om te installeren…</string>
+ <string name="invalidDownloadMessage">Gedownloade bestand is ongeldig</string>
+ <string name="fairphoneUpdateMessage">Nieuwe Fairphone update beschikbaar</string>
+ <string name="downloadMessage">Downloaden update, een moment geduld…</string>
+ <string name="downloadUpdateTitle">Nieuwe Fairphone update</string>
+ <string name="wifiDiscaimerTitle">Wi-Fi niet beschikbaar</string>
+ <string name="wifiDiscaimerMessage">Het bestand dat je probeert te downloaden is te groot voor mobiele verbindingen (~200MB). Breng de Wi-Fi verbinding tot stand en probeer het opnieuw.</string>
+</resources>
\ No newline at end of file
diff --git a/FairphoneUpdater/res/values-pt/strings.xml b/FairphoneUpdater/res/values-pt/strings.xml
new file mode 100644
index 0000000..f996e80
--- /dev/null
+++ b/FairphoneUpdater/res/values-pt/strings.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="updaterService">Serviço de actualização</string>
+ <string name="currentVersion">Versão actual</string>
+ <string name="newVersion">Nova versão</string>
+ <string name="installVersion">Instalar nova versão</string>
+ <string name="rebootDevice">Reiniciar dispositivo</string>
+ <string name="messageReadyToInstall">Nova versão pronta para instalar…</string>
+ <string name="invalidDownloadMessage">Ficheiro descarregado inválido</string>
+ <string name="fairphoneUpdateMessage">Nova actualização Fairphone disponível</string>
+ <string name="downloadMessage">A descarregar nova versão, por favor aguarde…</string>
+ <string name="downloadUpdateTitle">Nova actualização Fairphone</string>
+ <string name="wifiDiscaimerTitle">Wi-Fi desligado</string>
+ <string name="wifiDiscaimerMessage">O ficheiro que está a tentar descarregar é muito grande para ligações móveis (~200mb). Por favor ligue-se ao Wi-Fi e tente outra vez.</string>
+</resources>
\ No newline at end of file
diff --git a/FairphoneUpdater/res/values/dimens.xml b/FairphoneUpdater/res/values/dimens.xml
new file mode 100644
index 0000000..a6dd140
--- /dev/null
+++ b/FairphoneUpdater/res/values/dimens.xml
@@ -0,0 +1,7 @@
+<resources>
+
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+
+</resources>
\ No newline at end of file
diff --git a/FairphoneUpdater/res/values/strings.xml b/FairphoneUpdater/res/values/strings.xml
new file mode 100644
index 0000000..31eb25d
--- /dev/null
+++ b/FairphoneUpdater/res/values/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_name">Fairphone Updater</string>
+ <string name="downloadUrl">http://www.fairphone.com/ota/latest.zip</string>
+ <!-- <string name="downloadUrl">http://www.kwamecorp.com/dev/latest.zip</string> -->
+ <string name="versionFilename">latest</string>
+ <string name="versionFilename_zip">.zip</string>
+ <string name="versionFilename_xml">.xml</string>
+ <string name="versionFilename_sig">.sig</string>
+
+ <string name="defaultVersionNumber">1.0</string>
+ <string name="defaultVersionName">Almond</string>
+ <string name="defaultAndroidVersionNumber">4.2.2</string>
+
+ <string name="updaterService">Updater Service</string>
+ <string name="currentVersion">Current Version</string>
+ <string name="newVersion">New Version</string>
+ <string name="installVersion">Install new version</string>
+ <string name="rebootDevice">Reboot device</string>
+ <string name="messageReadyToInstall">New version ready to install…</string>
+ <string name="invalidDownloadMessage">Invalid file downloaded</string>
+ <string name="fairphoneUpdateMessage">New Fairphone update available</string>
+ <string name="downloadMessage">Downloading version, please wait…</string>
+ <string name="downloadUpdateTitle">New Fairphone update</string>
+ <string name="wifiDiscaimerTitle">Wi-Fi disabled</string>
+ <string name="wifiDiscaimerMessage">The file you’re trying to download is too large for mobile connections (~200MB). Please enable Wi-Fi connection and try again.</string>
+</resources>
\ No newline at end of file
diff --git a/FairphoneUpdater/res/values/styles.xml b/FairphoneUpdater/res/values/styles.xml
new file mode 100644
index 0000000..fb69874
--- /dev/null
+++ b/FairphoneUpdater/res/values/styles.xml
@@ -0,0 +1,8 @@
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <style name="AppTheme" parent="android:Theme.Holo">
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowFullscreen">false</item>
+ </style>
+
+</resources>
\ No newline at end of file
diff --git a/FairphoneUpdater/src/com/fairphone/updater/BootBroadcastReceiver.java b/FairphoneUpdater/src/com/fairphone/updater/BootBroadcastReceiver.java
new file mode 100644
index 0000000..1ea31f5
--- /dev/null
+++ b/FairphoneUpdater/src/com/fairphone/updater/BootBroadcastReceiver.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 Fairphone Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.fairphone.updater;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import java.util.Calendar;
+
+public class BootBroadcastReceiver extends BroadcastReceiver {
+
+ final static long NOTIFICATION_INTERVAL_MILLIS = 1000 * 60 * 60 * 8;
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+
+ AlarmManager service = (AlarmManager) context
+ .getSystemService(Context.ALARM_SERVICE);
+ Intent i = new Intent(context, UpdaterService.class);
+ PendingIntent pending = PendingIntent.getService(context, 0, i, PendingIntent.FLAG_CANCEL_CURRENT);
+
+ Calendar cal = Calendar.getInstance();
+ // Start 30 seconds after boot completed
+ cal.add(Calendar.SECOND, 30);
+
+ // InexactRepeating allows Android to optimize the energy consumption
+ service.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), NOTIFICATION_INTERVAL_MILLIS, pending);
+ }
+
+}
diff --git a/FairphoneUpdater/src/com/fairphone/updater/FairphoneUpdater.java b/FairphoneUpdater/src/com/fairphone/updater/FairphoneUpdater.java
new file mode 100644
index 0000000..684ad51
--- /dev/null
+++ b/FairphoneUpdater/src/com/fairphone/updater/FairphoneUpdater.java
@@ -0,0 +1,652 @@
+/*
+ * Copyright (C) 2013 Fairphone Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.fairphone.updater;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.DownloadManager;
+import android.app.DownloadManager.Request;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.net.ConnectivityManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.PowerManager;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+public class FairphoneUpdater extends Activity {
+
+ protected static final String PREFERENCE_NEW_VERSION_NAME = "PREFERENCE_NEW_VERSION_NAME";
+ protected static final String PREFERENCE_NEW_VERSION_NUMBER = "PREFERENCE_NEW_VERSION_NUMBER";
+ protected static final String PREFERENCE_NEW_VERSION_MD5_SUM = "PREFERENCE_NEW_VERSION_MD5_SUM";
+ protected static final String PREFERENCE_NEW_VERSION_URL = "PREFERENCE_NEW_VERSION_URL";
+ protected static final String PREFERENCE_NEW_VERSION_ANDROID = "PREFERENCE_NEW_VERSION_ANDROID";
+
+ private static final String ANDROID_LABEL = "Android ";
+ private static final String FAIRPHONE_LABEL = "Fairphone ";
+
+ private static final String TAG = FairphoneUpdater.class.getSimpleName();
+
+ private static final String PREFERENCE_CURRENT_UPDATER_STATE = "CurrentUpdaterState";
+ private static final String PREFERENCE_DOWNLOAD_ID = "LatestUpdateDownloadId";
+ public static final String FAIRPHONE_UPDATER_PREFERENCES = "FairphoneUpdaterPreferences";
+
+ public static enum UpdaterState {
+ NORMAL, DOWNLOAD, PREINSTALL
+ };
+
+ private Version mDeviceVersion;
+ private Version mLatestVersion;
+
+ private UpdaterState mCurrentState;
+
+ private SharedPreferences mSharedPreferences;
+
+ // views
+ private TextView mViewCurrentVersionTitle;
+ private TextView mViewCurrentVersionText;
+
+ private TextView mViewUpdateVersionTitle;
+ private TextView mViewUpdateVersionText;
+
+ private TextView mViewMessageText;
+ private Button mViewUpdateButton;
+
+ private LinearLayout mLatestGroupLla;
+
+ private DownloadManager mDownloadManager;
+ private DownloadBroadCastReceiver mDownloadBroadCastReceiver;
+ private long mLatestUpdateDownloadId;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_fairphone_updater);
+
+ setupLayout();
+
+ mSharedPreferences = getSharedPreferences(
+ FAIRPHONE_UPDATER_PREFERENCES, MODE_PRIVATE);
+
+ // get system data
+ mDeviceVersion = VersionParserHelper.getDeviceVersion(this);
+
+ mLatestVersion = getLastestVersion();
+
+ // check current state
+ mCurrentState = getCurrentUpdaterState();
+
+ setupInstallationReceivers();
+
+ // TODO : remove this
+ Intent i = new Intent(this, UpdaterService.class);
+ startService(i);
+ }
+
+ private Version getLastestVersion() {
+ Version latest = null;
+
+ String newVersionName = mSharedPreferences.getString(
+ PREFERENCE_NEW_VERSION_NAME, null);
+
+ String number = mSharedPreferences.getString(
+ PREFERENCE_NEW_VERSION_NUMBER, null);
+ String url = mSharedPreferences.getString(PREFERENCE_NEW_VERSION_URL,
+ null);
+ String md5 = mSharedPreferences.getString(
+ PREFERENCE_NEW_VERSION_MD5_SUM, null);
+ String android = mSharedPreferences.getString(
+ PREFERENCE_NEW_VERSION_ANDROID, null);
+
+ if (newVersionName != null && number != null && url != null
+ && md5 != null && android != null) {
+ latest = new Version();
+
+ latest.setName(newVersionName);
+ latest.setNumber(number);
+ latest.setDownloadLink(url);
+ latest.setMd5Sum(md5);
+ latest.setAndroid(android);
+ }
+
+ return latest;
+ }
+
+ private void setupLayout() {
+ mViewCurrentVersionTitle = (TextView) findViewById(R.id.currentVersionTitleText);
+ mViewCurrentVersionTitle.setVisibility(View.VISIBLE);
+ mViewCurrentVersionText = (TextView) findViewById(R.id.currentVersionDescriptionText);
+ mViewCurrentVersionText.setVisibility(View.VISIBLE);
+
+ mViewUpdateVersionTitle = (TextView) findViewById(R.id.nextVersionTitleText);
+ mViewUpdateVersionText = (TextView) findViewById(R.id.nextVersionDescriptionText);
+
+ mViewUpdateButton = (Button) findViewById(R.id.newVersionUpdateButton);
+
+ mViewMessageText = (TextView) findViewById(R.id.messageText);
+
+ mViewUpdateButton.setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ if (mCurrentState == UpdaterState.NORMAL) {
+ startUpdateDownload();
+ } else if (mCurrentState == UpdaterState.PREINSTALL) {
+ startPreInstall();
+ }
+ }
+ });
+
+ mLatestGroupLla = (LinearLayout) findViewById(R.id.latestVersionGroup);
+
+ mLatestGroupLla.setVisibility(View.GONE);
+ }
+
+ public String getStringPreference(String key) {
+ return mSharedPreferences.getString(key, null);
+ }
+
+ public long getLongPreference(String key) {
+ return mSharedPreferences.getLong(key, 0);
+ }
+
+ public boolean getBooleanPreference(String key) {
+ return mSharedPreferences.getBoolean(key, false);
+ }
+
+ public void savePreference(String key, String value) {
+ Editor editor = mSharedPreferences.edit();
+
+ editor.putString(key, value);
+
+ editor.commit();
+ }
+
+ public void savePreference(String key, boolean value) {
+ Editor editor = mSharedPreferences.edit();
+
+ editor.putBoolean(key, value);
+
+ editor.commit();
+ }
+
+ public void savePreference(String key, long value) {
+ Editor editor = mSharedPreferences.edit();
+
+ editor.putLong(key, value);
+
+ editor.commit();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ registerBroadCastReceiver();
+ // check current state
+ mCurrentState = getCurrentUpdaterState();
+
+ if (mLatestVersion == null) {
+ mLatestVersion = VersionParserHelper.getLastestVersion(this);
+ }
+
+ mViewCurrentVersionTitle.setText(mDeviceVersion.getName());
+ mViewCurrentVersionText.setText(FAIRPHONE_LABEL
+ + mDeviceVersion.getNumber() + "\n" + ANDROID_LABEL
+ + mDeviceVersion.getAndroid());
+
+ setupState(mCurrentState);
+ }
+
+ private void setupState(UpdaterState state) {
+ switch (state) {
+ case NORMAL:
+ setupNormalState();
+ break;
+ case DOWNLOAD:
+ setupDownloadState();
+ break;
+ case PREINSTALL:
+ setupPreInstallState();
+ break;
+ }
+ }
+
+ private void changeState(UpdaterState newState) {
+ mCurrentState = newState;
+
+ Editor editor = mSharedPreferences.edit();
+
+ editor.putString(PREFERENCE_CURRENT_UPDATER_STATE, mCurrentState.name());
+
+ editor.commit();
+
+ setupState(mCurrentState);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ unregisterBroadCastReceiver();
+ }
+
+ private void setupNormalState() {
+
+ if (mLatestUpdateDownloadId != 0) {
+ // residue download ID
+ mDownloadManager.remove(mLatestUpdateDownloadId);
+
+ mLatestUpdateDownloadId = 0;
+ savePreference(PREFERENCE_DOWNLOAD_ID, mLatestUpdateDownloadId);
+ }
+
+ // check to see if there is a new version to install
+ if (mLatestVersion != null) {
+ mLatestGroupLla.setVisibility(View.VISIBLE);
+ mViewUpdateButton.setVisibility(View.VISIBLE);
+
+ mViewUpdateVersionTitle.setText(mLatestVersion.getName());
+ mViewUpdateVersionText.setText(FAIRPHONE_LABEL
+ + mLatestVersion.getNumber() + "\n" + ANDROID_LABEL
+ + mLatestVersion.getAndroid());
+
+ mViewMessageText.setVisibility(View.GONE);
+ mViewUpdateButton.setText(getResources().getString(
+ R.string.installVersion));
+ } else {
+ mLatestGroupLla.setVisibility(View.GONE);
+ }
+ }
+
+ private UpdaterState getCurrentUpdaterState() {
+
+ String currentState = getStringPreference(PREFERENCE_CURRENT_UPDATER_STATE);
+
+ if (currentState == null || currentState.isEmpty()) {
+ currentState = UpdaterState.NORMAL.name();
+
+ Editor editor = mSharedPreferences.edit();
+
+ editor.putString(currentState, currentState);
+
+ editor.commit();
+ }
+
+ return UpdaterState.valueOf(currentState);
+ }
+
+ private static String getVersionDownloadPath(Version version) {
+ return Environment.getExternalStorageDirectory()
+ + VersionParserHelper.UPDATER_FOLDER
+ + VersionParserHelper.getNameFromVersion(version);
+ }
+
+ // ************************************************************************************
+ // PRE INSTALL
+ // ************************************************************************************
+
+ private void setupPreInstallState() {
+
+ // the latest version data must exist
+ if (mLatestVersion != null) {
+
+ mViewUpdateVersionTitle.setText(mLatestVersion.getName());
+ mViewUpdateVersionText.setText(FAIRPHONE_LABEL
+ + mLatestVersion.getNumber() + "\n" + ANDROID_LABEL
+ + mLatestVersion.getAndroid());
+
+ // check the md5 of the file
+ File file = new File(getVersionDownloadPath(mLatestVersion));
+
+ if (file.exists()) {
+
+ if (FairphoneUpdater.checkMD5(mLatestVersion.getMd5Sum(), file)) {
+ mLatestGroupLla.setVisibility(View.VISIBLE);
+
+ mViewMessageText.setText(getResources().getString(
+ R.string.messageReadyToInstall));
+
+ mViewUpdateButton.setText(getResources().getString(
+ R.string.rebootDevice));
+ mViewUpdateButton.setVisibility(View.VISIBLE);
+
+ mViewMessageText.setVisibility(View.VISIBLE);
+ return;
+ } else {
+ mDownloadManager.remove(mLatestUpdateDownloadId);
+ mLatestUpdateDownloadId = 0;
+
+ savePreference(PREFERENCE_DOWNLOAD_ID,
+ mLatestUpdateDownloadId);
+
+ Toast.makeText(
+ this,
+ getResources().getString(
+ R.string.invalidDownloadMessage),
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ }
+
+ // remove the updater directory
+ File fileDir = new File(Environment.getExternalStorageDirectory()
+ + VersionParserHelper.UPDATER_FOLDER);
+ fileDir.delete();
+
+ // else if the perfect case does not happen, reset the download
+ changeState(UpdaterState.NORMAL);
+ }
+
+ private void startPreInstall() {
+ // set the command for the recovery
+ Process p;
+ try {
+ p = Runtime.getRuntime().exec("su");
+
+ DataOutputStream os = new DataOutputStream(p.getOutputStream());
+ os.writeBytes("rm -f /cache/recovery/command\n");
+ os.writeBytes("rm -f /cache/recovery/extendedcommand\n");
+
+ os.writeBytes("echo '--wipe_cache' >> /cache/recovery/command\n");
+
+ os.writeBytes("echo '--update_package=/"
+ + VersionParserHelper.RECOVERY_PATH
+ + VersionParserHelper.UPDATER_FOLDER
+ + VersionParserHelper.getNameFromVersion(mLatestVersion)
+ + "' >> /cache/recovery/command\n");
+
+ os.writeBytes("sync\n");
+ os.writeBytes("exit\n");
+ os.flush();
+ p.waitFor();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ // reboot the device into recovery
+ ((PowerManager) getSystemService(POWER_SERVICE)).reboot("recovery");
+ }
+
+ // ************************************************************************************
+ // DOWNLOAD UPDATE
+ // ************************************************************************************
+
+ private void startUpdateDownload() {
+ // use only on WiFi
+ if (isWiFiEnabled()) {
+ // set the download for the latest version on the download manager
+ String fileName = VersionParserHelper
+ .getNameFromVersion(mLatestVersion);
+ Request request = createDownloadRequest(
+ mLatestVersion.getDownloadLink(), fileName,
+ mLatestVersion.getName() + " FP Update");
+ mLatestUpdateDownloadId = mDownloadManager.enqueue(request);
+
+ // save it on the shared preferences
+ savePreference(PREFERENCE_DOWNLOAD_ID, mLatestUpdateDownloadId);
+
+ // change state to download
+ changeState(UpdaterState.DOWNLOAD);
+ } else {
+ Resources resources = this.getResources();
+
+ AlertDialog.Builder disclaimerDialog = new AlertDialog.Builder(this);
+
+ disclaimerDialog.setTitle(resources
+ .getString(R.string.wifiDiscaimerTitle));
+
+ // Setting Dialog Message
+ disclaimerDialog.setMessage(resources
+ .getString(R.string.wifiDiscaimerMessage));
+ disclaimerDialog.setPositiveButton(
+ resources.getString(android.R.string.ok),
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ // do nothing, since the state is still the same
+ }
+ });
+ disclaimerDialog.create();
+ disclaimerDialog.show();
+ }
+ }
+
+ private Request createDownloadRequest(String url, String fileName,
+ String downloadTitle) {
+
+ Request request = new Request(Uri.parse(url));
+ Environment.getExternalStoragePublicDirectory(
+ Environment.getExternalStorageDirectory()
+ + VersionParserHelper.UPDATER_FOLDER).mkdirs();
+
+ request.setDestinationInExternalPublicDir(
+ VersionParserHelper.UPDATER_FOLDER, fileName);
+ request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
+ request.setAllowedOverRoaming(false);
+
+ request.setTitle(downloadTitle);
+
+ return request;
+ }
+
+ private boolean isWiFiEnabled() {
+
+ ConnectivityManager manager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ boolean isWifi = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
+ .isConnectedOrConnecting();
+
+ return isWifi;
+ }
+
+ private void setupDownloadState() {
+ // setup the download state views
+ if (mLatestVersion == null) {
+ // we don't have the lastest.xml so get back to initial state
+ File updateDir = new File(Environment.getExternalStorageDirectory()
+ + VersionParserHelper.UPDATER_FOLDER);
+
+ updateDir.delete();
+
+ changeState(UpdaterState.NORMAL);
+
+ return;
+ }
+
+ mViewUpdateVersionTitle.setText(mLatestVersion.getName());
+ mViewUpdateVersionText.setText(FAIRPHONE_LABEL
+ + mLatestVersion.getNumber() + "\n" + ANDROID_LABEL
+ + mLatestVersion.getAndroid());
+
+ // if there is a download ID on the shared preferences
+ if (mLatestUpdateDownloadId == 0) {
+ mLatestUpdateDownloadId = getLongPreference(PREFERENCE_DOWNLOAD_ID);
+
+ // invalid download Id
+ if (mLatestUpdateDownloadId == 0) {
+
+ changeState(UpdaterState.NORMAL);
+
+ return;
+ }
+ }
+
+ mLatestGroupLla.setVisibility(View.VISIBLE);
+ mViewUpdateButton.setVisibility(View.GONE);
+ mViewMessageText.setVisibility(View.VISIBLE);
+ mViewMessageText.setText(getResources().getString(
+ R.string.downloadMessage));
+
+ updateDownloadFile();
+
+ }
+
+ private void updateDownloadFile() {
+
+ DownloadManager.Query query = new DownloadManager.Query();
+
+ query.setFilterById(mLatestUpdateDownloadId);
+
+ Cursor cursor = mDownloadManager.query(query);
+
+ if (cursor.moveToFirst()) {
+ int columnIndex = cursor
+ .getColumnIndex(DownloadManager.COLUMN_STATUS);
+ int status = cursor.getInt(columnIndex);
+
+ switch (status) {
+ case DownloadManager.STATUS_SUCCESSFUL:
+ changeState(UpdaterState.PREINSTALL);
+ break;
+ case DownloadManager.STATUS_RUNNING:
+ break;
+ case DownloadManager.STATUS_FAILED:
+ case DownloadManager.STATUS_PAUSED:
+ default:
+ changeState(UpdaterState.NORMAL);
+
+ mLatestUpdateDownloadId = 0;
+ savePreference(PREFERENCE_DOWNLOAD_ID, mLatestUpdateDownloadId);
+
+ break;
+ }
+ } else {
+ changeState(UpdaterState.NORMAL);
+ }
+ }
+
+ private void setupInstallationReceivers() {
+ mDownloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
+
+ mDownloadBroadCastReceiver = new DownloadBroadCastReceiver();
+ }
+
+ private void registerBroadCastReceiver() {
+ registerReceiver(mDownloadBroadCastReceiver, new IntentFilter(
+ DownloadManager.ACTION_DOWNLOAD_COMPLETE));
+ }
+
+ private void unregisterBroadCastReceiver() {
+ unregisterReceiver(mDownloadBroadCastReceiver);
+ }
+
+ private class DownloadBroadCastReceiver extends BroadcastReceiver {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+
+ if (mLatestUpdateDownloadId == 0) {
+ mLatestUpdateDownloadId = getLongPreference(PREFERENCE_DOWNLOAD_ID);
+ }
+
+ updateDownloadFile();
+
+ }
+ }
+
+ // **************************************************************************************************************
+ // HELPERS
+ // **************************************************************************************************************
+
+ public static boolean checkMD5(String md5, File updateFile) {
+
+ if (!updateFile.exists()) {
+ return false;
+ }
+
+ if (md5 == null || md5.equals("") || updateFile == null) {
+ Log.e(TAG, "MD5 String NULL or UpdateFile NULL");
+ return false;
+ }
+
+ String calculatedDigest = calculateMD5(updateFile);
+ if (calculatedDigest == null) {
+ Log.e(TAG, "calculatedDigest NULL");
+ return false;
+ }
+
+ return calculatedDigest.equalsIgnoreCase(md5);
+ }
+
+ public static String calculateMD5(File updateFile) {
+ MessageDigest digest;
+ try {
+ digest = MessageDigest.getInstance("MD5");
+ } catch (NoSuchAlgorithmException e) {
+ Log.e(TAG, "Exception while getting Digest", e);
+ return null;
+ }
+
+ InputStream is;
+ try {
+ is = new FileInputStream(updateFile);
+ } catch (FileNotFoundException e) {
+ Log.e(TAG, "Exception while getting FileInputStream", e);
+ return null;
+ }
+
+ byte[] buffer = new byte[8192];
+ int read;
+ try {
+ while ((read = is.read(buffer)) > 0) {
+ digest.update(buffer, 0, read);
+ }
+ byte[] md5sum = digest.digest();
+ BigInteger bigInt = new BigInteger(1, md5sum);
+ String output = bigInt.toString(16);
+ // Fill to 32 chars
+ output = String.format("%32s", output).replace(' ', '0');
+ return output;
+ } catch (IOException e) {
+ throw new RuntimeException("Unable to process file for MD5", e);
+ } finally {
+ try {
+ is.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Exception on closing MD5 input stream", e);
+ }
+ }
+ }
+}
diff --git a/FairphoneUpdater/src/com/fairphone/updater/RSAUtils.java b/FairphoneUpdater/src/com/fairphone/updater/RSAUtils.java
new file mode 100644
index 0000000..4a9b334
--- /dev/null
+++ b/FairphoneUpdater/src/com/fairphone/updater/RSAUtils.java
@@ -0,0 +1,182 @@
+package com.fairphone.updater;
+
+import android.content.Context;
+import android.util.Base64;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+public class RSAUtils {
+
+ private static final String TAG = RSAUtils.class
+ .getSimpleName();
+
+ public static final String SIGNATURE_ALGORITHM = "SHA1withRSA";
+
+ public static PublicKey readPublicKeyFormCertificate(Context context, int certificateResourceId) throws IOException, CertificateException{
+ InputStream in = context.getResources().openRawResource(certificateResourceId);
+ byte[] buff = new byte[4000];
+ int bytesRead;
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ while((bytesRead = in.read(buff)) != -1) {
+ out.write(buff, 0, bytesRead);
+ Log.i(TAG, "bytes read: " + bytesRead);
+ }
+
+ byte[] publicKeyBytes = out.toByteArray();
+
+ CertificateFactory cf = CertificateFactory.getInstance("X509");
+ Certificate cert = cf.generateCertificate(new ByteArrayInputStream(publicKeyBytes));
+
+ PublicKey pubKey = cert.getPublicKey();
+ Log.i(TAG, "Public Key Info: ");
+ Log.i(TAG, "Algorithm = " + pubKey.getAlgorithm());
+ Log.i(TAG, "toString = " + pubKey.toString());
+ return pubKey;
+ }
+
+ public static PublicKey readPublicKeyFromPemFormat(Context context, int publicKeyId)
+ throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
+
+ InputStream in = context.getResources().openRawResource(publicKeyId);
+ BufferedReader pemReader = new BufferedReader(new InputStreamReader(in));
+
+ StringBuffer content = new StringBuffer();
+ String line = null;
+ while ((line = pemReader.readLine()) != null) {
+ if (line.indexOf("-----BEGIN PUBLIC KEY-----") != -1) {
+ while ((line = pemReader.readLine()) != null) {
+ if (line.indexOf("-----END PUBLIC KEY") != -1) {
+ break;
+ }
+ content.append(line.trim());
+ }
+ break;
+ }
+ }
+ if (line == null) {
+ throw new IOException("PUBLIC KEY" + " not found");
+ }
+ Log.i("PUBLIC KEY: ", "PEM content = : " + content.toString());
+
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+
+ return keyFactory.generatePublic(new X509EncodedKeySpec(Base64.decode(content.toString(),
+ Base64.DEFAULT)));
+ }
+
+ public static byte[] readSignature(String input) throws IOException{
+ FileInputStream signStream = new FileInputStream(input);
+ byte[] signBytes = new byte[signStream.available()];
+ signStream.read(signBytes);
+ signStream.close();
+ return signBytes;
+ }
+
+ public static boolean verifySignature(String input, String algorithm, byte[] sign, PublicKey pubKey) throws Exception{
+ Signature sg = Signature.getInstance(algorithm);
+ sg.initVerify(pubKey);
+ Log.i(TAG, "Signature Object Info: ");
+ Log.i(TAG, "Algorithm = "+sg.getAlgorithm());
+ Log.i(TAG, "Provider = "+sg.getProvider());
+
+ FileInputStream in = new FileInputStream(input);
+ byte[] buff = new byte[in.available()];
+ in.read(buff);
+ in.close();
+
+ sg.update(buff);
+
+ boolean ok = sg.verify(sign);
+ Log.i(TAG, "Verify Processing Info: ");
+ Log.i(TAG, "Verification result = "+ok);
+ return ok;
+ }
+
+ public static boolean checkFileSignature(Context context, String filePath, String targetPath){
+ boolean valid = false;
+
+ unzip(filePath, targetPath);
+
+ try {
+ String filename = context.getResources().getString(R.string.versionFilename);
+ String fileXmlExt = context.getResources().getString(R.string.versionFilename_xml);
+ String fileSigExt = context.getResources().getString(R.string.versionFilename_sig);
+
+ PublicKey pubKey = RSAUtils.readPublicKeyFromPemFormat(context, R.raw.public_key);
+ byte[] sign = RSAUtils.readSignature(targetPath + filename + fileSigExt);
+ valid = RSAUtils.verifySignature(targetPath + filename + fileXmlExt, RSAUtils.SIGNATURE_ALGORITHM, sign, pubKey);
+ } catch (CertificateException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return valid;
+ }
+
+ private static void unzip(String filePath, String targetPath) {
+ new File(targetPath).mkdirs();
+ try {
+ FileInputStream fin = new FileInputStream(filePath);
+ ZipInputStream zin = new ZipInputStream(fin);
+ ZipEntry ze = null;
+
+ while ((ze = zin.getNextEntry()) != null) {
+ Log.d(TAG, "Unzipping " + ze.getName());
+
+ if (ze.isDirectory()) {
+ _dirChecker(ze.getName(), targetPath);
+ } else {
+ FileOutputStream fout = new FileOutputStream(targetPath + ze.getName());
+ byte buffer[] = new byte[2048];
+
+ int count = 0;
+
+ while ((count = zin.read(buffer)) != -1) {
+ fout.write(buffer, 0, count);
+ }
+
+ zin.closeEntry();
+ fout.close();
+ }
+ }
+ zin.close();
+ fin.close();
+ } catch (Exception e) {
+ Log.e("Decompress", "unzip", e);
+ }
+ }
+
+ private static void _dirChecker(String dir, String location) {
+ File f = new File(location + dir);
+
+ if (!f.isDirectory()) {
+ f.mkdirs();
+ }
+ }
+
+}
diff --git a/FairphoneUpdater/src/com/fairphone/updater/UpdaterService.java b/FairphoneUpdater/src/com/fairphone/updater/UpdaterService.java
new file mode 100644
index 0000000..45290ec
--- /dev/null
+++ b/FairphoneUpdater/src/com/fairphone/updater/UpdaterService.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2013 Fairphone Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.fairphone.updater;
+
+import android.app.DownloadManager;
+import android.app.DownloadManager.Request;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.app.TaskStackBuilder;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.BitmapFactory;
+import android.net.ConnectivityManager;
+import android.net.Uri;
+import android.os.Environment;
+import android.os.IBinder;
+import android.support.v4.app.NotificationCompat;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+
+public class UpdaterService extends Service {
+
+ private static final String TAG = UpdaterService.class.getSimpleName();
+ private static final String PREFERENCE_DATE_LAST_TIME_CHECKED = "LastTimeUpdateChecked";
+ private DownloadManager mDownloadManager;
+ private DownloadBroadCastReceiver mDownloadBroadCastReceiver;
+
+ private long mLatestFileDownloadId;
+
+ private SharedPreferences mSharedPreferences;
+ private SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.getDefault());
+
+ final static long DAY_IN_MILLIS = 1000 * 60 * 60 * 24;
+ private static final int MAX_DAYS_BEFORE_CHECKING = 8;
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+
+ mSharedPreferences = getApplicationContext().getSharedPreferences(FairphoneUpdater.FAIRPHONE_UPDATER_PREFERENCES, MODE_PRIVATE);
+
+ if(isFileStillValid()){
+ checkVersionValidation(getApplicationContext());
+ } else if(hasInternetConnection() ){
+ // remove the old file if its still there for some reason
+ removeLatestFile(getApplicationContext());
+
+ setupDownloadManager();
+
+ // start the download of the latest file
+ startDownloadLatest();
+ }
+
+ return Service.START_NOT_STICKY;
+ }
+
+ private void removeLatestFile(Context context) {
+ VersionParserHelper.removeFiles(context);
+
+ updateLastChecked("2013.01.01 00:00:00");
+ }
+
+ private boolean isFileStillValid() {
+ Date lastTimeChecked = getLastTimeCheckedDate();
+
+ int diffInDays = (int) ((System.currentTimeMillis() - lastTimeChecked.getTime())/ DAY_IN_MILLIS );
+
+ return diffInDays < MAX_DAYS_BEFORE_CHECKING;
+ }
+
+ private Date getLastTimeCheckedDate() {
+
+ String lastTimeDatePreference = mSharedPreferences.getString(PREFERENCE_DATE_LAST_TIME_CHECKED, "2013.01.01 00:00:00");
+
+ Date lastTimeDate = null;
+ try {
+ lastTimeDate = mDateFormat.parse(lastTimeDatePreference);
+ } catch (ParseException e) {
+ Calendar cal = Calendar.getInstance();
+ cal.add(Calendar.YEAR, -1);
+
+ lastTimeDate = cal.getTime();
+ }
+
+ return lastTimeDate;
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ public void startDownloadLatest() {
+ Resources resources = getApplicationContext().getResources();
+
+ // set the download for the latest version on the download manager
+ Request request = createDownloadRequest(resources.getString(R.string.downloadUrl), resources.getString(R.string.versionFilename) + resources.getString(R.string.versionFilename_zip));
+ mLatestFileDownloadId = mDownloadManager.enqueue(request);
+ }
+
+ private void setNotification() {
+
+ Context context = getApplicationContext();
+
+ NotificationManager manager = (NotificationManager) context
+ .getSystemService(Context.NOTIFICATION_SERVICE);
+
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(
+ context)
+ .setSmallIcon(R.drawable.fairphone_updater_tray_icon_small)
+ .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.fairphone_updater_tray_icon))
+ .setContentTitle(
+ context.getResources().getString(R.string.app_name))
+ .setContentText(getResources().getString(R.string.fairphoneUpdateMessage));
+
+ Intent resultIntent = new Intent(context, FairphoneUpdater.class);
+ TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
+
+ stackBuilder.addParentStack(FairphoneUpdater.class);
+
+ stackBuilder.addNextIntent(resultIntent);
+ PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+
+ builder.setContentIntent(resultPendingIntent);
+
+ Notification notificationWhileRunnig = builder.build();
+
+ // Add notification
+ manager.notify(0, notificationWhileRunnig);
+
+ }
+
+ private Request createDownloadRequest(String url, String fileName) {
+
+
+ Request request = new Request(Uri.parse(url));
+ Environment.getExternalStoragePublicDirectory(
+ Environment.getExternalStorageDirectory()
+ + VersionParserHelper.UPDATER_FOLDER).mkdirs();
+
+ request.setDestinationInExternalPublicDir(
+ VersionParserHelper.UPDATER_FOLDER, fileName);
+ request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
+ request.setAllowedOverRoaming(false);
+
+ Resources resources = getApplicationContext().getResources();
+ request.setTitle(resources.getString(R.string.downloadUpdateTitle));
+
+ return request;
+ }
+
+ private boolean hasInternetConnection() {
+
+ ConnectivityManager manager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ boolean is3g = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE)
+ .isConnectedOrConnecting();
+
+ boolean isWifi = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
+ .isConnectedOrConnecting();
+
+ return isWifi || is3g;
+ }
+
+ private void setupDownloadManager() {
+ mDownloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
+
+ mDownloadBroadCastReceiver = new DownloadBroadCastReceiver();
+
+ getApplicationContext().registerReceiver(mDownloadBroadCastReceiver,
+ new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
+ }
+
+ private void removeBroadcastReceiver() {
+ getApplicationContext().unregisterReceiver(mDownloadBroadCastReceiver);
+ }
+
+ private void checkVersionValidation(Context context){
+
+ Version latestVersion = VersionParserHelper
+ .getLastestVersion(getApplicationContext());
+ Version currentVersion = VersionParserHelper
+ .getDeviceVersion(getApplicationContext());
+
+ if(latestVersion != null){
+
+ String versionName = null;
+ String versionNumber = null;
+ String versionUrl = null;
+ String versionMd5 = null;
+ String versionAndroid = null;
+
+ if(latestVersion.isNewerVersionThan(currentVersion)){
+ // save the version in the share preferences
+ versionName = latestVersion.getName();
+ versionNumber = latestVersion.getNumber();
+ versionUrl = latestVersion.getDownloadLink();
+ versionMd5 = latestVersion.getMd5Sum();
+ versionAndroid = latestVersion.getAndroid();
+
+ setNotification();
+ } else {
+ VersionParserHelper.removeLatestVersionFile(getApplicationContext());
+ }
+
+ Editor editor = mSharedPreferences.edit();
+
+ editor.putString(FairphoneUpdater.PREFERENCE_NEW_VERSION_NAME, versionName);
+ editor.putString(FairphoneUpdater.PREFERENCE_NEW_VERSION_NUMBER, versionNumber);
+ editor.putString(FairphoneUpdater.PREFERENCE_NEW_VERSION_MD5_SUM, versionMd5);
+ editor.putString(FairphoneUpdater.PREFERENCE_NEW_VERSION_URL, versionUrl);
+ editor.putString(FairphoneUpdater.PREFERENCE_NEW_VERSION_ANDROID, versionAndroid);
+
+ editor.commit();
+
+ removeLatestFileDownload(context);
+ }
+ }
+
+ private void removeLatestFileDownload(Context context) {
+ if(mLatestFileDownloadId != 0){
+ mDownloadManager.remove(mLatestFileDownloadId);
+ mLatestFileDownloadId = 0;
+ }
+ VersionParserHelper.removeFiles(context);
+ }
+
+ private float parseVersion(String number) {
+ String finalNumber = number.replaceAll("\\.", "");
+ return Float.parseFloat(finalNumber);
+ }
+
+ private void updateLastChecked(String date) {
+ Editor editor = mSharedPreferences.edit();
+ editor.putString(PREFERENCE_DATE_LAST_TIME_CHECKED, date);
+
+ editor.commit();
+ }
+
+ private class DownloadBroadCastReceiver extends BroadcastReceiver {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ DownloadManager.Query query = new DownloadManager.Query();
+
+ query.setFilterById(mLatestFileDownloadId);
+ Cursor cursor = mDownloadManager.query(query);
+
+ if (cursor.moveToFirst()) {
+ int columnIndex = cursor
+ .getColumnIndex(DownloadManager.COLUMN_STATUS);
+ int status = cursor.getInt(columnIndex);
+
+ if (status == DownloadManager.STATUS_SUCCESSFUL) {
+
+ String filePath = mDownloadManager.getUriForDownloadedFile(
+ mLatestFileDownloadId).getPath();
+
+ String targetPath = Environment.getExternalStorageDirectory()
+ + VersionParserHelper.UPDATER_FOLDER;
+
+ if(RSAUtils.checkFileSignature(context, filePath, targetPath)){
+ updateLastChecked(mDateFormat.format(Calendar.getInstance().getTime()));
+ checkVersionValidation(context);
+ }else{
+ //invalid file
+ removeLatestFileDownload(context);
+ }
+ }
+ }
+
+ cursor.close();
+
+ removeBroadcastReceiver();
+ }
+ }
+}
\ No newline at end of file
diff --git a/FairphoneUpdater/src/com/fairphone/updater/Version.java b/FairphoneUpdater/src/com/fairphone/updater/Version.java
new file mode 100644
index 0000000..d129eb4
--- /dev/null
+++ b/FairphoneUpdater/src/com/fairphone/updater/Version.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2013 Fairphone Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.fairphone.updater;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.content.res.Resources;
+import android.text.TextUtils;
+import android.util.Log;
+
+public class Version {
+ public static final String FAIRPHONE_UPDATE_VERSION_NUMBER = "FairphoneUpdateVersionNumber";
+ public static final String FAIRPHONE_UPDATE_VERSION_NAME = "FairphoneUpdateVersionName";
+ public static final String FAIRPHONE_UPDATE_VERSION_ANDROID = "FairphoneUpdateVersionAndroid";
+ public static final String FAIRPHONE_UPDATE_VERSION_DOWNLOAD_LINK = "FairphoneUpdateVersionDownloadLink";
+ public static final String FAIRPHONE_UPDATE_VERSION_MD5 = "FairphoneUpdateVersionMD5";
+
+ private String mNumber;
+ private String mName;
+ private String mAndroid;
+ private String mDownloadLink;
+ private String mMd5Sum;
+ private String mChangeLog;
+
+ public static Version getVersionFromSharedPreferences(Context context) {
+ Version version = new Version();
+ SharedPreferences sharedPrefs = context.getSharedPreferences(
+ FairphoneUpdater.FAIRPHONE_UPDATER_PREFERENCES,
+ Context.MODE_PRIVATE);
+ Resources resources = context.getResources();
+
+ String defaultVersionNumber = resources
+ .getString(R.string.defaultVersionNumber);
+ version.setNumber(sharedPrefs.getString(
+ FAIRPHONE_UPDATE_VERSION_NUMBER, defaultVersionNumber));
+
+ String defaultVersionName = resources
+ .getString(R.string.defaultVersionName);
+ version.setName(sharedPrefs.getString(FAIRPHONE_UPDATE_VERSION_NAME,
+ defaultVersionName));
+
+ String defaultVersionAndroid = resources
+ .getString(R.string.defaultAndroidVersionNumber);
+ version.setAndroid(sharedPrefs.getString(
+ FAIRPHONE_UPDATE_VERSION_ANDROID, defaultVersionAndroid));
+
+ version.setDownloadLink(sharedPrefs.getString(
+ FAIRPHONE_UPDATE_VERSION_DOWNLOAD_LINK, ""));
+ version.setMd5Sum(sharedPrefs.getString(FAIRPHONE_UPDATE_VERSION_MD5,
+ ""));
+
+ if (TextUtils.isEmpty(version.getMd5Sum())
+ || TextUtils.isEmpty(version.getMd5Sum())) {
+ return null;
+ }
+ return version;
+ }
+
+ public void saveToSharedPreferences(Context context) {
+ SharedPreferences sharedPrefs = context.getSharedPreferences(
+ FairphoneUpdater.FAIRPHONE_UPDATER_PREFERENCES,
+ Context.MODE_PRIVATE);
+
+ Editor editor = sharedPrefs.edit();
+ editor.putString(FAIRPHONE_UPDATE_VERSION_NUMBER, getNumber());
+ editor.putString(FAIRPHONE_UPDATE_VERSION_NAME, getName());
+ editor.putString(FAIRPHONE_UPDATE_VERSION_ANDROID, getAndroid());
+ editor.putString(FAIRPHONE_UPDATE_VERSION_DOWNLOAD_LINK,
+ getDownloadLink());
+ editor.putString(FAIRPHONE_UPDATE_VERSION_MD5, getMd5Sum());
+ editor.commit();
+ }
+
+ public String getNumber() {
+ return mNumber;
+ }
+
+ public void setNumber(String number) {
+ this.mNumber = number;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public void setName(String mName) {
+ this.mName = mName;
+ }
+
+ public String getDownloadLink() {
+ return mDownloadLink;
+ }
+
+ public void setDownloadLink(String mDownloadLink) {
+ this.mDownloadLink = mDownloadLink;
+ }
+
+ public String getMd5Sum() {
+ return mMd5Sum;
+ }
+
+ public void setMd5Sum(String mMd5Sum) {
+ this.mMd5Sum = mMd5Sum;
+ }
+
+ public String getChangeLog() {
+ return mChangeLog;
+ }
+
+ public void setChangeLog(String mChangeLog) {
+ this.mChangeLog = mChangeLog;
+ }
+
+ public String getAndroid() {
+ return mAndroid;
+ }
+
+ public void setAndroid(String mAndroid) {
+ this.mAndroid = mAndroid;
+ }
+
+ public boolean isNewerVersionThan(Version version) {
+
+ boolean result = false;
+
+ try {
+ result = Version
+ .isNewVersion(version.getNumber(), this.getNumber());
+ } catch (Throwable t) {
+ Log.e(Version.class.getSimpleName(), "Invalid Number for Version",
+ t);
+ }
+
+ return result;
+ }
+
+ private static boolean isNewVersion(String versionA, String versionB)
+ throws IllegalArgumentException {
+
+ int[] versionAints = getVersionInt(versionA);
+ int[] versionBints = getVersionInt(versionB);
+
+ if (versionAints[0] == versionBints[0]) {
+ return versionAints[1] < versionBints[1];
+ }
+
+ return versionAints[0] < versionBints[0];
+ }
+
+ private static int[] getVersionInt(String version) {
+
+ if (version == null) {
+ throw new IllegalArgumentException("String is null");
+ }
+
+ String[] intStrs = version.split("\\.");
+
+ if (intStrs == null || intStrs.length != 2) {
+ throw new IllegalArgumentException("String " + version
+ + " not have the correct format [X.Y]");
+ }
+
+ int[] ints = new int[2];
+
+ try {
+ ints[0] = Integer.parseInt(intStrs[0]);
+ ints[1] = Integer.parseInt(intStrs[1]);
+ } catch (Throwable t) {
+ throw new IllegalArgumentException(
+ "String "
+ + version
+ + " should contain numbers separated by a dot [ReleaseNumber.VersionNumber]");
+ }
+
+ return ints;
+ }
+}
diff --git a/FairphoneUpdater/src/com/fairphone/updater/VersionParserHelper.java b/FairphoneUpdater/src/com/fairphone/updater/VersionParserHelper.java
new file mode 100644
index 0000000..e1b6e4e
--- /dev/null
+++ b/FairphoneUpdater/src/com/fairphone/updater/VersionParserHelper.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2013 Fairphone Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.fairphone.updater;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+import android.content.Context;
+import android.os.Environment;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.NoSuchElementException;
+import java.util.Scanner;
+
+public class VersionParserHelper {
+
+ private static final String TAG = VersionParserHelper.class.getSimpleName();
+
+ public static final String RECOVERY_PATH = "sdcard";
+ public static final String UPDATER_FOLDER = "/updater/";
+
+ private static final String CURRENT_FAIRPHONE_VERSION_NAME = "fairphone.ota.version.name";
+ private static final String CURRENT_FAIRPHONE_VERSION = "fairphone.ota.version";
+ private static final String CURRENT_ANDROID_VERSION = "fairphone.ota.android";
+
+ public static String getNameFromVersion(Version version) {
+ return "fp_update_" + version.getNumber() + ".zip";
+ }
+
+ public static Version getDeviceVersion(Context context) {
+
+ Version version = new Version();
+ version.setNumber(getSystemData(context, CURRENT_FAIRPHONE_VERSION));
+ version.setName(getSystemData(context, CURRENT_FAIRPHONE_VERSION_NAME));
+ version.setAndroid(getSystemData(context, CURRENT_ANDROID_VERSION));
+
+ return version;
+ }
+
+ public static String getSystemData(Context context, String property) {
+
+ if (property.equals(CURRENT_FAIRPHONE_VERSION)){
+ return getprop(CURRENT_FAIRPHONE_VERSION, context.getResources().getString(R.string.defaultVersionNumber));
+ }
+ if (property.equals(CURRENT_FAIRPHONE_VERSION_NAME)){
+ return getprop(CURRENT_FAIRPHONE_VERSION_NAME, context.getResources().getString(R.string.defaultVersionName));
+ }
+ if (property.equals(CURRENT_ANDROID_VERSION)){
+ return getprop(CURRENT_ANDROID_VERSION, context.getResources().getString(R.string.defaultAndroidVersionNumber));
+ }
+
+ return null;
+ }
+
+ public static void removeLatestVersionFile(Context context){
+ File file = new File(Environment.getExternalStorageDirectory() + UPDATER_FOLDER + context.getResources().getString(R.string.versionFilename));
+
+ if(file.exists()){
+ file.delete();
+ }
+ }
+
+ public static Version getLastestVersion(Context context) {
+
+ Version latest = Version.getVersionFromSharedPreferences(context);
+
+ if(latest == null){
+
+ String filePath = Environment.getExternalStorageDirectory()
+ + VersionParserHelper.UPDATER_FOLDER
+ + context.getResources().getString(R.string.versionFilename);
+ // check the /storage/sdcard0/updater/latest.xml
+ File file = new File(filePath + context.getResources().getString(R.string.versionFilename_xml));
+
+ if (file.exists()) {
+ try {
+ latest = parseLatestXML(context, file);
+ } catch (XmlPullParserException e) {
+ Log.e(TAG, "Could not start the XML parser", e);
+ } catch (IOException e) {
+ Log.e(TAG, "Invalid data in File", e);
+ // remove the files
+ removeFiles(context);
+ }
+ }
+ }
+
+ return latest;
+ }
+
+ private static Version parseLatestXML(Context context, File latestFile)
+ throws XmlPullParserException, IOException {
+
+ Version version = null;
+
+ XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+ factory.setNamespaceAware(true);
+
+ FileInputStream fis = new FileInputStream(latestFile);
+
+ XmlPullParser xpp = factory.newPullParser();
+
+ xpp.setInput(new InputStreamReader(fis));
+
+ int eventType = xpp.getEventType();
+
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ String tagName = null;
+ switch (eventType) {
+ case XmlPullParser.START_DOCUMENT:
+ break;
+ case XmlPullParser.START_TAG:
+ tagName = xpp.getName();
+
+ if (tagName.equalsIgnoreCase("version")) {
+ version = new Version();
+ version.setNumber(xpp.getAttributeValue(0));
+ } else if (version != null) {
+ if (tagName.equalsIgnoreCase("name")) {
+ version.setName(xpp.nextText());
+ } else if (tagName.equalsIgnoreCase("android")) {
+ version.setAndroid(xpp.nextText());
+ } else if (tagName.equalsIgnoreCase("md5sum")) {
+ version.setMd5Sum(xpp.nextText());
+ } else if (tagName.equalsIgnoreCase("link")) {
+ version.setDownloadLink(xpp.nextText());
+ }
+ }
+
+ break;
+ }
+
+ eventType = xpp.next();
+ }
+
+ if (version == null
+ || version.getNumber() == null
+ || version.getName() == null
+ || version.getAndroid() == null
+ || version.getDownloadLink() == null) {
+
+ Log.i(TAG, "Invalid data in version file");
+
+ version = null;
+ }else {
+ version.saveToSharedPreferences(context);
+ }
+
+ return version;
+ }
+
+ private static String getprop(String name, String defaultValue) {
+ ProcessBuilder pb = new ProcessBuilder("/system/bin/getprop", name);
+ pb.redirectErrorStream(true);
+
+ Process p = null;
+ InputStream is = null;
+ try {
+ p = pb.start();
+ is = p.getInputStream();
+ Scanner scan = new Scanner(is);
+ scan.useDelimiter("\n");
+ String prop = scan.next();
+ if (prop.length() == 0) {
+ return defaultValue;
+ }
+ return prop;
+ } catch (NoSuchElementException e) {
+ return defaultValue;
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ if (is != null) {
+ try { is.close(); }
+ catch (Exception e) { }
+ }
+ }
+ return defaultValue;
+ }
+
+ public static void removeFiles(Context context) {
+ String filePath = Environment.getExternalStorageDirectory()
+ + VersionParserHelper.UPDATER_FOLDER
+ + context.getResources().getString(R.string.versionFilename);
+
+ removeFile(filePath + context.getResources().getString(R.string.versionFilename_zip));
+ removeFile(filePath + context.getResources().getString(R.string.versionFilename_xml));
+ removeFile(filePath + context.getResources().getString(R.string.versionFilename_sig));
+ }
+
+ private static void removeFile(String filePath) {
+ File file = new File(filePath);
+ if(file.exists()){
+ file.delete();
+ }
+ }
+
+
+
+}