Merge lp:~humpolec-team/humpolec/UbuntuInstaller-refactor into lp:humpolec

Proposed by Ondrej Kubik
Status: Merged
Merged at revision: 72
Proposed branch: lp:~humpolec-team/humpolec/UbuntuInstaller-refactor
Merge into: lp:humpolec
Diff against target: 5595 lines (+2511/-1557) (has conflicts)
37 files modified
.bzrignore (+1/-1)
Android.mk (+1/-1)
AndroidManifest.xml (+38/-12)
ant.properties (+21/-0)
assets/archive-master.tar.xz.asc (+0/-17)
assets/system-image-upgrader (+28/-156)
assets/u-reboot-app.tar.xz.asc (+0/-17)
assets/upgrade-checker (+0/-16)
build.xml (+35/-37)
check-sdk.sh (+10/-0)
make_release.sh (+0/-16)
project.properties (+1/-1)
res/layout/ubuntu_dualboot_launch.xml (+152/-104)
res/menu/installer_menu.xml (+6/-10)
res/menu/launcher_menu.xml (+19/-10)
res/values/attrs.xml (+4/-4)
res/values/colors.xml (+4/-4)
res/values/ids.xml (+26/-0)
res/values/strings.xml (+70/-14)
res/values/styles.xml (+4/-4)
src/com/canonical/ubuntu/installer/BaseActivity.java (+70/-0)
src/com/canonical/ubuntu/installer/BootReceiver.java (+39/-0)
src/com/canonical/ubuntu/installer/InstallActivity.java (+184/-160)
src/com/canonical/ubuntu/installer/JsonChannelParser.java (+38/-16)
src/com/canonical/ubuntu/installer/LaunchActivity.java (+216/-52)
src/com/canonical/ubuntu/installer/NumberPickerDialog.java (+17/-3)
src/com/canonical/ubuntu/installer/TextPickerDialog.java (+17/-1)
src/com/canonical/ubuntu/installer/UbuntuInstallService.java (+1237/-723)
src/com/canonical/ubuntu/installer/Utils.java (+245/-9)
src/com/canonical/ubuntu/installer/VersionInfo.java (+0/-141)
src/com/canonical/ubuntu/widget/UbuntuButton.java (+4/-4)
src/com/canonical/ubuntu/widget/UbuntuCheckBox.java (+4/-4)
src/com/canonical/ubuntu/widget/UbuntuCheckBoxPreference.java (+4/-4)
src/com/canonical/ubuntu/widget/UbuntuEditText.java (+4/-4)
src/com/canonical/ubuntu/widget/UbuntuEditTextPreference.java (+4/-4)
src/com/canonical/ubuntu/widget/UbuntuPreference.java (+4/-4)
src/com/canonical/ubuntu/widget/UbuntuTextView.java (+4/-4)
Text conflict in AndroidManifest.xml
To merge this branch: bzr merge lp:~humpolec-team/humpolec/UbuntuInstaller-refactor
Reviewer Review Type Date Requested Status
Ondrej Kubik Approve
Review via email: mp+222493@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Ondrej Kubik (ondrak) wrote :

This has been dog food tested and released as version 1.0

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '.bzrignore'
--- .bzrignore 2013-12-08 16:01:23 +0000
+++ .bzrignore 2014-06-09 11:59:50 +0000
@@ -1,6 +1,6 @@
1.DS_Store
1.project2.project
2local.properties3local.properties
3bin4bin
4gen5gen
5android-ubuntu-launcher.apk
66
77
=== modified file 'Android.mk'
--- Android.mk 2013-12-08 16:01:23 +0000
+++ Android.mk 2014-06-09 11:59:50 +0000
@@ -1,4 +1,4 @@
1# UFA updater1# Dualboot installer
2LOCAL_PATH:= $(call my-dir)2LOCAL_PATH:= $(call my-dir)
33
4include $(CLEAR_VARS)4include $(CLEAR_VARS)
55
=== modified file 'AndroidManifest.xml'
--- AndroidManifest.xml 2014-03-05 15:35:14 +0000
+++ AndroidManifest.xml 2014-06-09 11:59:50 +0000
@@ -1,12 +1,34 @@
1<?xml version="1.0" encoding="utf-8"?>1<?xml version="1.0" encoding="utf-8"?>
2<!--
3/*
4 * This file is part of Ubuntu dualboot installer for Android.
5 * Copyright 2013 Canonical Ltd.
6 *
7 * Ubuntu dualboot installer is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation.
10 *
11 * Ubuntu dualboot installer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Ubuntu dualboot installer. If not, see <http://www.gnu.org/licenses/>.
18 */
19-->
2<manifest xmlns:android="http://schemas.android.com/apk/res/android"20<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3 package="com.canonical.ubuntu.installer"21 package="com.canonical.ubuntu.installer"
4 android:versionCode="20"22 android:versionCode="20"
23<<<<<<< TREE
5 android:versionName="0.3" >24 android:versionName="0.3" >
25=======
26 android:versionName="1.0.0" >
27>>>>>>> MERGE-SOURCE
628
7 <uses-sdk29 <uses-sdk
8 android:minSdkVersion="17"30 android:minSdkVersion="17"
9 android:targetSdkVersion="18" />31 android:targetSdkVersion="19" />
10 <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />32 <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
11 <uses-permission android:name="android.permission.GET_ACCOUNTS"/>33 <uses-permission android:name="android.permission.GET_ACCOUNTS"/>
12 <uses-permission android:name="android.permission.ACCESS_SUPERUSER"/>34 <uses-permission android:name="android.permission.ACCESS_SUPERUSER"/>
@@ -20,8 +42,6 @@
20 <uses-permission android:name="android.permission.WAKE_LOCK" />42 <uses-permission android:name="android.permission.WAKE_LOCK" />
21 <uses-permission android:name="android.permission.RECORD_AUDIO" />43 <uses-permission android:name="android.permission.RECORD_AUDIO" />
22 <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />44 <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
23 <uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" />
24 <uses-permission android:name="android.permission.REBOOT"/>
25 <uses-permission android:name="android.permission.ACCESS_SUPERUSER"/>45 <uses-permission android:name="android.permission.ACCESS_SUPERUSER"/>
2646
27 <application47 <application
@@ -46,23 +66,29 @@
46 android:label="@string/app_name">66 android:label="@string/app_name">
47 </activity>67 </activity>
48 68
49 <service android:name="com.canonical.ubuntu.installer.UbuntuInstallService">69 <receiver android:name=".BootReceiver" >
70 <intent-filter>
71 <action android:name="android.intent.action.BOOT_COMPLETED" />
72 </intent-filter>
73 </receiver>
74
75 <service android:name="com.canonical.ubuntu.installer.UbuntuInstallService"
76 android:exported="false">
50 <intent-filter>77 <intent-filter>
51 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.GET_CHANNEL_LIST" />78 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.GET_CHANNEL_LIST" />
52 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.DOWNLOAD_RELEASE" />79 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.DOWNLOAD_RELEASE" />
53 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.CANCEL_DOWNLOAD" />80 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.DOWNLOAD_UPDATE" />
54 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.PAUSE_DOWNLOAD" />81 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.PAUSE_DOWNLOAD" />
55 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.RESUME_DOWNLOAD" />82 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.RESUME_DOWNLOAD" />
56 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.CLEAN_DOWNLOADED" />83 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.DELETE_DOWNLOAD" />
57 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.INSTALL_UBUNTU" />84 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.INSTALL_UBUNTU" />
58 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.CANCEL_INSTALL" />
59 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.UINSTALL_UBUNTU" />85 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.UINSTALL_UBUNTU" />
60 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.CHECK_FOR_UPDATE" />86 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.DELETE_UBUNTU_USER_DATA" />
61 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.DELETE_USER_DATA" />
62 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.GET_SERVICE_STATE" />
63 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.GET_PROGRESS_STATUS" />
64 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.REBOOT_UBUNTU" />87 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.REBOOT_UBUNTU" />
65 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.IS_UBUNTU_UPGRADABLE" />88 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.UPDATE_STORAGE_USE" />
89 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.CHECK_IF_UPDATE_AVAILABLE" />
90 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.CHECK_PENDING_UPDATES" />
91 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.PREPARE_ANDROID_UPDATE" />
66 </intent-filter>92 </intent-filter>
67 </service>93 </service>
68 </application>94 </application>
6995
=== added file 'ant.properties'
--- ant.properties 1970-01-01 00:00:00 +0000
+++ ant.properties 2014-06-09 11:59:50 +0000
@@ -0,0 +1,21 @@
1# This file is used to override default values used by the Ant build system.
2#
3# This file must be checked in Version Control Systems, as it is
4# integral to the build system of your project.
5
6# This file is only used by the Ant script.
7
8# You can use this to override default values such as
9# 'source.dir' for the location of your java source folder and
10# 'out.dir' for the location of your output folder.
11
12# You can also use it define how the release builds are signed by declaring
13# the following properties:
14# 'key.store' for the location of your keystore and
15# 'key.alias' for the name of the key to use.
16# The password will be asked during the build when you use the 'release' target.
17
18java.encoding=UTF-8
19
20key.store=../humpolec.keystore
21key.alias=humpolec
022
=== removed file 'assets/archive-master.tar.xz'
1Binary files assets/archive-master.tar.xz 2013-12-08 16:01:23 +0000 and assets/archive-master.tar.xz 1970-01-01 00:00:00 +0000 differ23Binary files assets/archive-master.tar.xz 2013-12-08 16:01:23 +0000 and assets/archive-master.tar.xz 1970-01-01 00:00:00 +0000 differ
=== removed file 'assets/archive-master.tar.xz.asc'
--- assets/archive-master.tar.xz.asc 2013-12-08 16:01:23 +0000
+++ assets/archive-master.tar.xz.asc 1970-01-01 00:00:00 +0000
@@ -1,17 +0,0 @@
1-----BEGIN PGP SIGNATURE-----
2Version: GnuPG v1.4.12 (GNU/Linux)
3
4iQIcBAABAgAGBQJRzXznAAoJEAv7hH8/Jy9b9MEP/iTl7lfFQNOu+bR+hRHOh40B
5trXCwTeKYGLL98h7pbqrqFD5QppGWZ5Kpyh5QeNB7yU8Jk5bcIQg3iTBg4kQhbjZ
6CvfBAk5goKDzHF+tx2HWFmHie3kxDlOQ39dWqr38Q78elC1VtRfiWQNbz7E2955D
7d5/Lo+THwKS0aYD8RR/wHbiEnIiOSxZLZo9Bdkxlty9LXbY16SUPY3R7POGdds0S
8OvQmsmFsjoD4b68aTjw0Fx12EQ1fDBycBmxNbgQ6E/xKf78Ttsp8gRaoopdr6odH
9FZWUCv0Vr7mrbSr8MrotydVRth5K/FJv4xnfTI9rY50PZqA72xFNfQyQa35/qfuZ
103E+d9DdPk8KtovNCploTufRG5zvkXOn+rGJQCicLh4H2L7+YO5ZwHbDQFTDUrAhl
110wlqaqUuwYOC7fxk3SHA3IINZ97LCUYfPWZRUUVOM2uia4BhI0TfRj09I+HnJM+I
12cNlfjmzCedlLjMwgBOw6tj1l3FEPl/aEwCTs1Oc7dc05JPDNcRqdks45NnSS/Xg7
13pNHPS6wED0zYAKQeBDkji7Gf+9gR3eVWWbArSzbkqyCeWhgPyqwjTUQNMx6PIPNm
140lszQWe50Y9mOuwcRd2gA293zVjsnr7NxOJPhgZsHB9fRaZtSg7vWVOo1jopkPPZ
15Vt1nrVFGkrss7EJ+Vc53
16=Sszb
17-----END PGP SIGNATURE-----
180
=== added file 'assets/recovery-remount.tar.xz'
19Binary files assets/recovery-remount.tar.xz 1970-01-01 00:00:00 +0000 and assets/recovery-remount.tar.xz 2014-06-09 11:59:50 +0000 differ1Binary files assets/recovery-remount.tar.xz 1970-01-01 00:00:00 +0000 and assets/recovery-remount.tar.xz 2014-06-09 11:59:50 +0000 differ
=== modified file 'assets/system-image-upgrader'
--- assets/system-image-upgrader 2014-01-08 06:21:14 +0000
+++ assets/system-image-upgrader 2014-06-09 11:59:50 +0000
@@ -9,7 +9,7 @@
9fi9fi
1010
11BUSYBOX=busybox11BUSYBOX=busybox
12COMMAND_FILE=$1.applying12COMMAND_FILE=$1
13PRIVATE_DIR=$213PRIVATE_DIR=$2
14REMOVE_LIST="$COMMAND_FILE"14REMOVE_LIST="$COMMAND_FILE"
15TAR=u_tar15TAR=u_tar
@@ -22,129 +22,14 @@
2222
23# switch to the update command folder, which has the images23# switch to the update command folder, which has the images
24cd $UPDATE_FOLDER24cd $UPDATE_FOLDER
25mv $1 $1.applying
26
2725
28# Functions26# Functions
29verify_signature() {27
30 return 0
31 # $1 => validation keyring name
32 # $2 => path to validate
33
34 if [ ! -e $2 ]; then
35 echo "File doesn't exist: $2"
36 return 1
37 fi
38
39 # Check against the blacklist
40 if [ -e ${TMP}/system-image/blacklist/pubring.gpg ]; then
41 export GNUPGHOME=${TMP}/system-image/blacklist/
42 if gpg --verify $2 >/dev/null 2>&1; then
43 echo "File signed by a blacklisted key: $2"
44 return 1
45 fi
46 fi
47
48 # Check against the keyring
49 export GNUPGHOME=${TMP}/system-image/$1/
50 if [ ! -e "$GNUPGHOME" ]; then
51 echo "Keyring doesn't exist: $1"
52 return 1
53 fi
54
55 if gpg --verify $2 >/dev/null 2>&1; then
56 return 0
57 fi
58}
59
60install_keyring() {
61 # $1 => full path to tarball
62 # $2 => full path to signature
63
64 # Some basic checks
65 if [ ! -e "$1" ] || [ ! -e "$2" ]; then
66 echo "Missing keyring files: $1 => $2"
67 return 1
68 fi
69
70 # Unpacking
71 TMPDIR=$($BUSYBOX mktemp -d ${TMP}/tempdir.XXXXXXXX)
72 cd $TMPDIR
73 cat $1 | $BUSYBOX unxz | $TAR xf -
74 if [ ! -e keyring.json ] || [ ! -e keyring.gpg ]; then
75 rm -Rf $TMPDIR
76 echo "Invalid keyring: $1"
77 return 1
78 fi
79
80 # Extract the expiry
81 keyring_expiry=$(grep "^ \"expiry\": " keyring.json | $BUSYBOX cut -d: -f2 | $BUSYBOX sed -e "s/[ \",]//g")
82 if [ -n "$keyring_expiry" ] && [ "$keyring_expiry" -lt "$(date +%s)" ]; then
83 rm -Rf $TMPDIR
84 echo "Keyring expired: $1"
85 return 1
86 fi
87
88 # Extract the keyring type
89 keyring_type=$(grep "^ \"type\": " keyring.json | $BUSYBOX cut -d: -f2 | $BUSYBOX sed -e "s/[, \"]//g")
90 if [ -z "$keyring_type" ]; then
91 rm -Rf $TMPDIR
92 echo "Missing keyring type: $1"
93 return 1
94 fi
95
96 if [ -e ${TMP}/system-image/$keyring_type ]; then
97 rm -Rf $TMPDIR
98 echo "Keyring already loaded: $1"
99 return 1
100 fi
101
102 signer="unknown"
103 case "$keyring_type" in
104 archive-master)
105 signer=""
106 ;;
107
108 image-master)
109 signer="archive-master"
110 ;;
111
112 image-signing|blacklist)
113 signer="image-master"
114 ;;
115
116 device-signing)
117 signer="image-signing"
118 ;;
119 esac
120
121 if [ -n "$signer" ] && ! verify_signature $signer $2; then
122 rm -Rf $TMPDIR
123 echo "Invalid signature: $1"
124 return 1
125 fi
126
127 mkdir ${TMP}/system-image/$keyring_type
128 chmod 700 ${TMP}/system-image/$keyring_type
129 mv $TMPDIR/keyring.gpg ${TMP}/system-image/$keyring_type/pubring.gpg
130 chmod 600 ${TMP}/system-image/$keyring_type/pubring.gpg
131 chown 0:0 ${TMP}/system-image/$keyring_type/pubring.gpg
132 rm -Rf $TMPDIR
133 return 0
134}
135
136# print out if we will need to create SWAP file
137if [ ! -e /data/SWAP.img ]; then
138 echo "SWAP-file-missing" >&2
139fi
14028
141# Initialize GPG29# Initialize GPG
142rm -Rf ${TMP}/system-image30rm -Rf ${TMP}/system-image
143mkdir -p ${TMP}/system-image31mkdir -p ${TMP}/system-image
144if [ -e ${PWD}/archive-master.tar.xz ]; then32
145 echo "Loading keyring: archive-master.tar.xz"
146 install_keyring ${PWD}/archive-master.tar.xz ${PWD}/archive-master.tar.xz.asc
147fi
14833
149# Process the command file34# Process the command file
150FULL_IMAGE=035FULL_IMAGE=0
@@ -159,11 +44,14 @@
159 system)44 system)
160 FULL_IMAGE=145 FULL_IMAGE=1
161 rm -f /data/system.img46 rm -f /data/system.img
47 echo "Creating new system filesystem"
162 $BUSYBOX dd if=/dev/zero of=/data/system.img seek=500K bs=4096 count=148 $BUSYBOX dd if=/dev/zero of=/data/system.img seek=500K bs=4096 count=1
163 $BUSYBOX mkfs.ext2 -F /data/system.img49 $BUSYBOX mkfs.ext2 -F /data/system.img
50 echo "New system filesystem created"
164 ;;51 ;;
16552
166 data)53 data)
54 # formatting data partion -> just detele ubuntu bits
167 rm -f /data/SWAP.img55 rm -f /data/SWAP.img
168 rm -Rf /data/system-data56 rm -Rf /data/system-data
169 rm -Rf /data/user-data57 rm -Rf /data/user-data
@@ -176,25 +64,11 @@
176 ;;64 ;;
17765
178 load_keyring)66 load_keyring)
179 if [ ! -e "$UPDATE_FOLDER/$2" ] || [ ! -e "$UPDATE_FOLDER/$3" ]; then67 echo "Loading keys: $2 $3"
180 echo "Skipping missing file: $2"
181 continue
182 fi
183 REMOVE_LIST="$REMOVE_LIST $UPDATE_FOLDER/$2 $UPDATE_FOLDER/$3"
184
185 echo "Loading keyring: $2"
186 install_keyring $UPDATE_FOLDER/$2 $UPDATE_FOLDER/$3
187
188 if [ -e ${TMP}/system-image/image-master/pubring.gpg ] && \
189 [ ! -e ${TMP}/system-image/blacklist/pubring.gpg ] && \
190 [ -e /data/system-data/var/lib/system-image/blacklist.tar.xz ] && \
191 [ -e /data/system-data/var/lib/system-image/blacklist.tar.xz.asc ]; then
192 echo "Loading blacklist keyring"
193 install_keyring /data/system-data/var/lib/system-image/blacklist.tar.xz /data/system-data/var/lib/system-image/blacklist.tar.xz.asc
194 fi
195 ;;68 ;;
19669
197 mount)70 mount)
71 echo "Mounting: $2"
198 case "$2" in72 case "$2" in
199 system)73 system)
200 mkdir -p /cache/system74 mkdir -p /cache/system
@@ -208,8 +82,11 @@
208 ;;82 ;;
20983
210 unmount)84 unmount)
85 echo "Unmounting: $2"
211 case "$2" in86 case "$2" in
212 system)87 system)
88 # print out version info
89 cat /cache/system/etc/system-image/channel.ini || true
213 aloopmount umount /cache/system && echo .90 aloopmount umount /cache/system && echo .
214 rmdir /cache/system91 rmdir /cache/system
215 ;;92 ;;
@@ -221,17 +98,13 @@
221 ;;98 ;;
22299
223 update)100 update)
224 if [ ! -e "$UPDATE_FOLDER/$2" ] || [ ! -e "$UPDATE_FOLDER/$3" ]; then101 if [ ! -e "$UPDATE_FOLDER/$2" ]; then
225 echo "Skipping missing file: $2"102 echo "Skipping missing file: $2"
226 continue103 continue
227 fi104 fi
228105
229 REMOVE_LIST="$REMOVE_LIST $UPDATE_FOLDER/$2 $UPDATE_FOLDER/$3"106 REMOVE_LIST="$REMOVE_LIST $UPDATE_FOLDER/$2"
230 if ! verify_signature device-signing $UPDATE_FOLDER/$2 && \107
231 ! verify_signature image-signing $UPDATE_FOLDER/$2; then
232 echo "Invalid signature"
233 continue
234 fi
235108
236 echo "Applying update: $2"109 echo "Applying update: $2"
237 cd /cache110 cd /cache
@@ -239,17 +112,19 @@
239112
240 # Start by removing any file listed in "removed"113 # Start by removing any file listed in "removed"
241 if [ "$FULL_IMAGE" != "1" ]; then114 if [ "$FULL_IMAGE" != "1" ]; then
242 cat $UPDATE_FOLDER/$2 | $BUSYBOX unxz | $TAR xf - removed >/dev/null 2>&1 || true115 $BUSYBOX cat $UPDATE_FOLDER/$2 | $BUSYBOX unxz | $TAR --checkpoint=400 -xf - removed >/dev/null || true
243 if [ -e removed ]; then116 if [ -e removed ]; then
244 while read file; do117 echo "Removing old files..."
118 while read file; do
245 rm -Rf $file119 rm -Rf $file
246 done < removed120 done < removed
247 fi121 fi
248 rm -f removed122 rm -f removed
123 echo "Adding new files..."
249 fi124 fi
250125
251 # Unpack everything else on top of the system partition126 # Unpack everything else on top of the system partition
252 cat $UPDATE_FOLDER/$2 | $BUSYBOX unxz | $TAR --checkpoint=200 -xf -127 $BUSYBOX cat $UPDATE_FOLDER/$2 | $BUSYBOX unxz | $TAR --checkpoint=200 -xf -
253 rm -f removed128 rm -f removed
254129
255 if [ -e "partitions/boot.img" ]; then130 if [ -e "partitions/boot.img" ]; then
@@ -281,20 +156,17 @@
281156
282# Remove the update files157# Remove the update files
283for file in $REMOVE_LIST; do158for file in $REMOVE_LIST; do
284 echo rm $file159 rm $file
285done160done
286161
287# Create the SWAP image if missing162# Ensure we have sane permissions
288if [ ! -e /data/SWAP.img ]; then163chmod 600 /data/system.img
289 echo "Creating SWAP device."164chown 0:0 /data/system.img
290 echo "SWAP Checkpoint 0" >&2165
291 # create swap file in private folder, so service can watch progress166# calculate sizes
292 dd if=/dev/zero of=$PRIVATE_DIR/SWAP.img bs=4096 count=131072167busybox du -sm /data/system.img || true
293 echo "Moving SWAP device to final destination" >&2168busybox du -sm /data/system-data || true
294 mv $PRIVATE_DIR/SWAP.img /data/169busybox du -sm /data/user-data || true
295 echo "Calling mkswap on /data/SWAP.img" >&2
296 $BUSYBOX mkswap /data/SWAP.img
297fi
298170
299touch /data/.last_update || true171touch /data/.last_update || true
300sync172sync
301173
=== removed file 'assets/u-reboot-app.tar.xz.asc'
--- assets/u-reboot-app.tar.xz.asc 2013-12-12 02:02:35 +0000
+++ assets/u-reboot-app.tar.xz.asc 1970-01-01 00:00:00 +0000
@@ -1,17 +0,0 @@
1-----BEGIN PGP SIGNATURE-----
2Version: GnuPG v1.4.12 (GNU/Linux)
3
4iQIcBAABAgAGBQJRzXznAAoJEAv7hH8/Jy9b9MEP/iTl7lfFQNOu+bR+hRHOh40B
5trXCwTeKYGLL98h7pbqrqFD5QppGWZ5Kpyh5QeNB7yU8Jk5bcIQg3iTBg4kQhbjZ
6CvfBAk5goKDzHF+tx2HWFmHie3kxDlOQ39dWqr38Q78elC1VtRfiWQNbz7E2955D
7d5/Lo+THwKS0aYD8RR/wHbiEnIiOSxZLZo9Bdkxlty9LXbY16SUPY3R7POGdds0S
8OvQmsmFsjoD4b68aTjw0Fx12EQ1fDBycBmxNbgQ6E/xKf78Ttsp8gRaoopdr6odH
9FZWUCv0Vr7mrbSr8MrotydVRth5K/FJv4xnfTI9rY50PZqA72xFNfQyQa35/qfuZ
103E+d9DdPk8KtovNCploTufRG5zvkXOn+rGJQCicLh4H2L7+YO5ZwHbDQFTDUrAhl
110wlqaqUuwYOC7fxk3SHA3IINZ97LCUYfPWZRUUVOM2uia4BhI0TfRj09I+HnJM+I
12cNlfjmzCedlLjMwgBOw6tj1l3FEPl/aEwCTs1Oc7dc05JPDNcRqdks45NnSS/Xg7
13pNHPS6wED0zYAKQeBDkji7Gf+9gR3eVWWbArSzbkqyCeWhgPyqwjTUQNMx6PIPNm
140lszQWe50Y9mOuwcRd2gA293zVjsnr7NxOJPhgZsHB9fRaZtSg7vWVOo1jopkPPZ
15Vt1nrVFGkrss7EJ+Vc53
16=Sszb
17-----END PGP SIGNATURE-----
180
=== removed file 'assets/upgrade-checker'
--- assets/upgrade-checker 2013-12-25 11:32:41 +0000
+++ assets/upgrade-checker 1970-01-01 00:00:00 +0000
@@ -1,16 +0,0 @@
1#!/system/bin/sh
2# Copyright (C) 2013 Canonical Ltd.
3#
4# Check if ubuntu_command exist
5# print the path and exit 0 if found.
6
7FILES=$@
8
9for file in $FILES ; do
10 if [[ -f $file ]] ; then
11 echo $file
12 exit 1
13 fi
14done
15
16exit 0
170
=== modified file 'build.xml'
--- build.xml 2013-12-08 16:01:23 +0000
+++ build.xml 2014-06-09 11:59:50 +0000
@@ -1,31 +1,40 @@
1<?xml version="1.0" encoding="UTF-8"?>1<?xml version="1.0" encoding="UTF-8"?>
2<project name="MainActivity" default="help">2<project name="UbuntuInstaller" default="help">
33
4 <!-- The local.properties file is created and updated by the 'android' tool.4 <description>
5 It contains the path to the SDK. It should *NOT* be checked into5 *** Humpolec - Ubuntu Dual Boot for Android ***
6 Version Control Systems. -->6
7 http://launchpad.net/humpolec
8
9 Ubuntu Dual Boot is provided to developers who want to contribute to development
10 of Ubuntu for Phones and give them an ability to run Ubuntu and Android on
11 a single device. It is not intended to be used by regular users.
12
13 Make sure you have Android SDK installed!
14
15 Contact:
16 Ondrej Kubik ondrej.kubik@canonical.com
17 Michal Karnicki michal.karnicki@canonical.com
18 </description>
19
20 <!-- Check if android is present. -->
21 <exec executable="./check-sdk.sh" failonerror="true">
22 </exec>
23
24 <property file="project.properties" />
25
26 <exec executable="android">
27 <arg value="update" />
28 <arg value="project" />
29 <arg value="-p" />
30 <arg value="." />
31 <arg value="-t" />
32 <arg value="${target}" />
33 <!-- Watch out: using name argument will ignore the custom build.xml version-tag! -->
34 </exec>
35
7 <property file="local.properties" />36 <property file="local.properties" />
837
9 <!-- The ant.properties file can be created by you. It is only edited by the
10 'android' tool to add properties to it.
11 This is the place to change some Ant specific build properties.
12 Here are some properties you may want to change/update:
13
14 source.dir
15 The name of the source directory. Default is 'src'.
16 out.dir
17 The name of the output directory. Default is 'bin'.
18
19 For other overridable properties, look at the beginning of the rules
20 files in the SDK, at tools/ant/build.xml
21
22 Properties related to the SDK location or the project target should
23 be updated using the 'android' tool with the 'update' action.
24
25 This file is an integral part of the build system for your
26 application and should be checked into Version Control Systems.
27
28 -->
29 <property file="ant.properties" />38 <property file="ant.properties" />
3039
31 <!-- if sdk.dir was not set from one of the property file, then40 <!-- if sdk.dir was not set from one of the property file, then
@@ -37,17 +46,6 @@
37 <isset property="env.ANDROID_HOME" />46 <isset property="env.ANDROID_HOME" />
38 </condition>47 </condition>
3948
40 <!-- The project.properties file is created and updated by the 'android'
41 tool, as well as ADT.
42
43 This contains project specific properties such as project target, and library
44 dependencies. Lower level build properties are stored in ant.properties
45 (or in .classpath for Eclipse projects).
46
47 This file is an integral part of the build system for your
48 application and should be checked into Version Control Systems. -->
49 <loadproperties srcFile="project.properties" />
50
51 <!-- quick check on sdk.dir -->49 <!-- quick check on sdk.dir -->
52 <fail50 <fail
53 message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."51 message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
@@ -86,7 +84,7 @@
86 In all cases you must update the value of version-tag below to read 'custom' instead of an integer,84 In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
87 in order to avoid having your file be overridden by tools such as "android update project"85 in order to avoid having your file be overridden by tools such as "android update project"
88 -->86 -->
89 <!-- version-tag: 1 -->87 <!-- version-tag: custom -->
90 <import file="${sdk.dir}/tools/ant/build.xml" />88 <import file="${sdk.dir}/tools/ant/build.xml" />
9189
92</project>90</project>
9391
=== added file 'check-sdk.sh'
--- check-sdk.sh 1970-01-01 00:00:00 +0000
+++ check-sdk.sh 2014-06-09 11:59:50 +0000
@@ -0,0 +1,10 @@
1#!/bin/bash
2
3ANDROIDBIN=$(which android)
4if test -z "${ANDROIDBIN}"; then
5 echo "Android SDK tools not in PATH, fix with:" >&2
6 echo " PATH=\$PATH:/PathToSDK/tools" >&2
7 exit 1
8fi
9
10exit 0
011
=== removed file 'make_release.sh'
--- make_release.sh 2013-12-20 03:39:53 +0000
+++ make_release.sh 1970-01-01 00:00:00 +0000
@@ -1,16 +0,0 @@
1 #!/sbin/sh
2 KEY=$1
3 if [[ -z "$KEY" ]]; then
4 echo "Pass path to the keystore"
5 exit -1
6 fi
7 echo "Release tool, using key"
8 echo "Getting ready for build"
9 android update project --path .
10 echo "Removing old release"
11 rm -rf bin/
12 ant release
13 echo "Signing build"
14 jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore $KEY bin/MainActivity-release-unsigned.apk humpolec
15 mv bin/MainActivity-release-unsigned.apk bin/UbuntuInstaller.apk
16 echo "Signed relase is at bin/UbuntuInstaller.apk"
17\ No newline at end of file0\ No newline at end of file
181
=== modified file 'project.properties'
--- project.properties 2013-12-12 02:02:35 +0000
+++ project.properties 2014-06-09 11:59:50 +0000
@@ -11,4 +11,4 @@
11#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt11#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
1212
13# Project target.13# Project target.
14target=Google Inc.:Google APIs:1914target=android-19
1515
=== added file 'res/drawable-hdpi/ic_action_discard.png'
16Binary files res/drawable-hdpi/ic_action_discard.png 1970-01-01 00:00:00 +0000 and res/drawable-hdpi/ic_action_discard.png 2014-06-09 11:59:50 +0000 differ16Binary files res/drawable-hdpi/ic_action_discard.png 1970-01-01 00:00:00 +0000 and res/drawable-hdpi/ic_action_discard.png 2014-06-09 11:59:50 +0000 differ
=== added file 'res/drawable-hdpi/ic_action_refresh.png'
17Binary files res/drawable-hdpi/ic_action_refresh.png 1970-01-01 00:00:00 +0000 and res/drawable-hdpi/ic_action_refresh.png 2014-06-09 11:59:50 +0000 differ17Binary files res/drawable-hdpi/ic_action_refresh.png 1970-01-01 00:00:00 +0000 and res/drawable-hdpi/ic_action_refresh.png 2014-06-09 11:59:50 +0000 differ
=== added file 'res/drawable-hdpi/ic_action_share.png'
18Binary files res/drawable-hdpi/ic_action_share.png 1970-01-01 00:00:00 +0000 and res/drawable-hdpi/ic_action_share.png 2014-06-09 11:59:50 +0000 differ18Binary files res/drawable-hdpi/ic_action_share.png 1970-01-01 00:00:00 +0000 and res/drawable-hdpi/ic_action_share.png 2014-06-09 11:59:50 +0000 differ
=== added directory 'res/drawable-ldpi'
=== added file 'res/drawable-mdpi/ic_action_discard.png'
19Binary files res/drawable-mdpi/ic_action_discard.png 1970-01-01 00:00:00 +0000 and res/drawable-mdpi/ic_action_discard.png 2014-06-09 11:59:50 +0000 differ19Binary files res/drawable-mdpi/ic_action_discard.png 1970-01-01 00:00:00 +0000 and res/drawable-mdpi/ic_action_discard.png 2014-06-09 11:59:50 +0000 differ
=== added file 'res/drawable-mdpi/ic_action_refresh.png'
20Binary files res/drawable-mdpi/ic_action_refresh.png 1970-01-01 00:00:00 +0000 and res/drawable-mdpi/ic_action_refresh.png 2014-06-09 11:59:50 +0000 differ20Binary files res/drawable-mdpi/ic_action_refresh.png 1970-01-01 00:00:00 +0000 and res/drawable-mdpi/ic_action_refresh.png 2014-06-09 11:59:50 +0000 differ
=== added file 'res/drawable-mdpi/ic_action_share.png'
21Binary files res/drawable-mdpi/ic_action_share.png 1970-01-01 00:00:00 +0000 and res/drawable-mdpi/ic_action_share.png 2014-06-09 11:59:50 +0000 differ21Binary files res/drawable-mdpi/ic_action_share.png 1970-01-01 00:00:00 +0000 and res/drawable-mdpi/ic_action_share.png 2014-06-09 11:59:50 +0000 differ
=== added file 'res/drawable-xhdpi/ic_action_discard.png'
22Binary files res/drawable-xhdpi/ic_action_discard.png 1970-01-01 00:00:00 +0000 and res/drawable-xhdpi/ic_action_discard.png 2014-06-09 11:59:50 +0000 differ22Binary files res/drawable-xhdpi/ic_action_discard.png 1970-01-01 00:00:00 +0000 and res/drawable-xhdpi/ic_action_discard.png 2014-06-09 11:59:50 +0000 differ
=== added file 'res/drawable-xhdpi/ic_action_refresh.png'
23Binary files res/drawable-xhdpi/ic_action_refresh.png 1970-01-01 00:00:00 +0000 and res/drawable-xhdpi/ic_action_refresh.png 2014-06-09 11:59:50 +0000 differ23Binary files res/drawable-xhdpi/ic_action_refresh.png 1970-01-01 00:00:00 +0000 and res/drawable-xhdpi/ic_action_refresh.png 2014-06-09 11:59:50 +0000 differ
=== added file 'res/drawable-xhdpi/ic_action_share.png'
24Binary files res/drawable-xhdpi/ic_action_share.png 1970-01-01 00:00:00 +0000 and res/drawable-xhdpi/ic_action_share.png 2014-06-09 11:59:50 +0000 differ24Binary files res/drawable-xhdpi/ic_action_share.png 1970-01-01 00:00:00 +0000 and res/drawable-xhdpi/ic_action_share.png 2014-06-09 11:59:50 +0000 differ
=== added file 'res/drawable-xhdpi/ic_stat_notify_ubuntu.png'
25Binary files res/drawable-xhdpi/ic_stat_notify_ubuntu.png 1970-01-01 00:00:00 +0000 and res/drawable-xhdpi/ic_stat_notify_ubuntu.png 2014-06-09 11:59:50 +0000 differ25Binary files res/drawable-xhdpi/ic_stat_notify_ubuntu.png 1970-01-01 00:00:00 +0000 and res/drawable-xhdpi/ic_stat_notify_ubuntu.png 2014-06-09 11:59:50 +0000 differ
=== added file 'res/drawable-xxhdpi/ic_action_discard.png'
26Binary files res/drawable-xxhdpi/ic_action_discard.png 1970-01-01 00:00:00 +0000 and res/drawable-xxhdpi/ic_action_discard.png 2014-06-09 11:59:50 +0000 differ26Binary files res/drawable-xxhdpi/ic_action_discard.png 1970-01-01 00:00:00 +0000 and res/drawable-xxhdpi/ic_action_discard.png 2014-06-09 11:59:50 +0000 differ
=== added file 'res/drawable-xxhdpi/ic_action_refresh.png'
27Binary files res/drawable-xxhdpi/ic_action_refresh.png 1970-01-01 00:00:00 +0000 and res/drawable-xxhdpi/ic_action_refresh.png 2014-06-09 11:59:50 +0000 differ27Binary files res/drawable-xxhdpi/ic_action_refresh.png 1970-01-01 00:00:00 +0000 and res/drawable-xxhdpi/ic_action_refresh.png 2014-06-09 11:59:50 +0000 differ
=== added file 'res/drawable-xxhdpi/ic_action_share.png'
28Binary files res/drawable-xxhdpi/ic_action_share.png 1970-01-01 00:00:00 +0000 and res/drawable-xxhdpi/ic_action_share.png 2014-06-09 11:59:50 +0000 differ28Binary files res/drawable-xxhdpi/ic_action_share.png 1970-01-01 00:00:00 +0000 and res/drawable-xxhdpi/ic_action_share.png 2014-06-09 11:59:50 +0000 differ
=== modified file 'res/layout/ubuntu_dualboot_launch.xml'
--- res/layout/ubuntu_dualboot_launch.xml 2013-12-12 02:02:35 +0000
+++ res/layout/ubuntu_dualboot_launch.xml 2014-06-09 11:59:50 +0000
@@ -10,18 +10,6 @@
10 android:background="#FFFFFF"10 android:background="#FFFFFF"
11 android:orientation="vertical" >11 android:orientation="vertical" >
1212
13 <com.canonical.ubuntu.widget.UbuntuButton
14 android:id="@+id/download"
15 style="@style/Button.Grey"
16 android:layout_width="match_parent"
17 android:layout_height="wrap_content"
18 android:layout_alignParentBottom="true"
19 android:layout_gravity="center_horizontal"
20 android:adjustViewBounds="true"
21 android:text="hi"
22 android:textColor="@color/text"
23 u1f:customFont="Ubuntu-R.ttf" />
24
25 <com.canonical.ubuntu.widget.UbuntuTextView13 <com.canonical.ubuntu.widget.UbuntuTextView
26 android:id="@+id/title"14 android:id="@+id/title"
27 android:layout_width="wrap_content"15 android:layout_width="wrap_content"
@@ -54,7 +42,7 @@
54 android:layout_alignParentLeft="true"42 android:layout_alignParentLeft="true"
55 android:layout_centerHorizontal="true"43 android:layout_centerHorizontal="true"
56 android:layout_margin="2dp"44 android:layout_margin="2dp"
57 android:text="Info:"45 android:text="Build number:"
58 android:textAppearance="?android:attr/textAppearanceMedium"46 android:textAppearance="?android:attr/textAppearanceMedium"
59 android:textColor="@color/ubuntuorange"47 android:textColor="@color/ubuntuorange"
60 android:textStyle="bold"48 android:textStyle="bold"
@@ -84,7 +72,7 @@
84 android:layout_alignParentLeft="true"72 android:layout_alignParentLeft="true"
85 android:layout_centerHorizontal="true"73 android:layout_centerHorizontal="true"
86 android:layout_margin="2dp"74 android:layout_margin="2dp"
87 android:text="Info:"75 android:text="Channel:"
88 android:textAppearance="?android:attr/textAppearanceMedium"76 android:textAppearance="?android:attr/textAppearanceMedium"
89 android:textColor="@color/ubuntuorange"77 android:textColor="@color/ubuntuorange"
90 android:textStyle="bold"78 android:textStyle="bold"
@@ -97,7 +85,7 @@
97 android:layout_margin="2dp"85 android:layout_margin="2dp"
98 android:layout_toRightOf="@id/channel_label"86 android:layout_toRightOf="@id/channel_label"
99 android:singleLine="true"87 android:singleLine="true"
100 android:text="add version"88 android:text="add channel"
101 android:textAppearance="?android:attr/textAppearanceMedium"89 android:textAppearance="?android:attr/textAppearanceMedium"
102 android:textColor="@color/text"90 android:textColor="@color/text"
103 u1f:customFont="Ubuntu-R.ttf" />91 u1f:customFont="Ubuntu-R.ttf" />
@@ -108,13 +96,43 @@
108 android:layout_height="wrap_content" >96 android:layout_height="wrap_content" >
10997
110 <com.canonical.ubuntu.widget.UbuntuTextView98 <com.canonical.ubuntu.widget.UbuntuTextView
99 android:id="@+id/ref_channel_label"
100 android:layout_width="wrap_content"
101 android:layout_height="wrap_content"
102 android:layout_alignParentLeft="true"
103 android:layout_centerHorizontal="true"
104 android:layout_margin="2dp"
105 android:text="Target Channel:"
106 android:textAppearance="?android:attr/textAppearanceMedium"
107 android:textColor="@color/ubuntuorange"
108 android:textStyle="bold"
109 u1f:customFont="Ubuntu-R.ttf" />
110
111 <com.canonical.ubuntu.widget.UbuntuTextView
112 android:id="@+id/ref_channel"
113 android:layout_width="wrap_content"
114 android:layout_height="wrap_content"
115 android:layout_margin="2dp"
116 android:layout_toRightOf="@id/ref_channel_label"
117 android:singleLine="true"
118 android:text="add channel"
119 android:textAppearance="?android:attr/textAppearanceMedium"
120 android:textColor="@color/text"
121 u1f:customFont="Ubuntu-R.ttf" />
122 </RelativeLayout>
123
124 <RelativeLayout
125 android:layout_width="wrap_content"
126 android:layout_height="wrap_content" >
127
128 <com.canonical.ubuntu.widget.UbuntuTextView
111 android:id="@+id/description_label"129 android:id="@+id/description_label"
112 android:layout_width="wrap_content"130 android:layout_width="wrap_content"
113 android:layout_height="wrap_content"131 android:layout_height="wrap_content"
114 android:layout_alignParentLeft="true"132 android:layout_alignParentLeft="true"
115 android:layout_centerHorizontal="true"133 android:layout_centerHorizontal="true"
116 android:layout_margin="2dp"134 android:layout_margin="2dp"
117 android:text="Info:"135 android:text="Description:"
118 android:textAppearance="?android:attr/textAppearanceMedium"136 android:textAppearance="?android:attr/textAppearanceMedium"
119 android:textColor="@color/ubuntuorange"137 android:textColor="@color/ubuntuorange"
120 android:textStyle="bold"138 android:textStyle="bold"
@@ -125,43 +143,14 @@
125 android:layout_width="wrap_content"143 android:layout_width="wrap_content"
126 android:layout_height="wrap_content"144 android:layout_height="wrap_content"
127 android:layout_margin="2dp"145 android:layout_margin="2dp"
128 android:layout_toRightOf="@id/description_label"146 android:layout_below="@id/description_label"
129 android:singleLine="true"147 android:singleLine="true"
130 android:text="add version"148 android:text="add description"
131 android:textAppearance="?android:attr/textAppearanceMedium"149 android:textAppearance="?android:attr/textAppearanceMedium"
132 android:textColor="@color/text"150 android:textColor="@color/text"
133 u1f:customFont="Ubuntu-R.ttf" />151 u1f:customFont="Ubuntu-R.ttf" />
134 </RelativeLayout>152 </RelativeLayout>
135153
136 <RelativeLayout
137 android:layout_width="wrap_content"
138 android:layout_height="wrap_content" >
139
140 <com.canonical.ubuntu.widget.UbuntuTextView
141 android:id="@+id/total_label"
142 android:layout_width="wrap_content"
143 android:layout_height="wrap_content"
144 android:layout_alignParentLeft="true"
145 android:layout_centerHorizontal="true"
146 android:layout_margin="2dp"
147 android:text="Info:"
148 android:textAppearance="?android:attr/textAppearanceMedium"
149 android:textColor="@color/ubuntuorange"
150 android:textStyle="bold"
151 u1f:customFont="Ubuntu-R.ttf" />
152
153 <com.canonical.ubuntu.widget.UbuntuTextView
154 android:id="@+id/total"
155 android:layout_width="wrap_content"
156 android:layout_height="wrap_content"
157 android:layout_margin="2dp"
158 android:layout_toRightOf="@id/total_label"
159 android:singleLine="true"
160 android:text="add version"
161 android:textAppearance="?android:attr/textAppearanceMedium"
162 android:textColor="@color/text"
163 u1f:customFont="Ubuntu-R.ttf" />
164 </RelativeLayout>
165154
166 <View155 <View
167 android:id="@+id/divider"156 android:id="@+id/divider"
@@ -175,61 +164,120 @@
175 android:layout_marginLeft="10dp" >164 android:layout_marginLeft="10dp" >
176165
177 <com.canonical.ubuntu.widget.UbuntuTextView166 <com.canonical.ubuntu.widget.UbuntuTextView
178 android:id="@+id/app_label"167 android:id="@+id/rootfs_label"
179 android:layout_width="wrap_content"168 android:layout_width="wrap_content"
180 android:layout_height="wrap_content"169 android:layout_height="wrap_content"
181 android:layout_alignParentLeft="true"170 android:layout_alignParentLeft="true"
182 android:layout_centerHorizontal="true"171 android:layout_centerHorizontal="true"
183 android:layout_margin="2dp"172 android:layout_margin="2dp"
184 android:text="Info:"173 android:text="rootfs:"
185 android:textAppearance="?android:attr/textAppearanceMedium"174 android:textAppearance="?android:attr/textAppearanceMedium"
186 android:textColor="@color/text"175 android:textColor="@color/text"
187 android:textStyle="bold"176 android:textStyle="bold"
188 u1f:customFont="Ubuntu-R.ttf" />177 u1f:customFont="Ubuntu-R.ttf" />
189178
190 <com.canonical.ubuntu.widget.UbuntuTextView179 <com.canonical.ubuntu.widget.UbuntuTextView
191 android:id="@+id/appsize"180 android:id="@+id/rootfssize"
192 android:layout_width="wrap_content"181 android:layout_width="wrap_content"
193 android:layout_height="wrap_content"182 android:layout_height="wrap_content"
194 android:layout_margin="2dp"183 android:layout_margin="2dp"
195 android:layout_toRightOf="@id/app_label"184 android:layout_toRightOf="@id/rootfs_label"
196 android:singleLine="true"185 android:singleLine="true"
197 android:text="add version"186 android:text="used MB"
198 android:textAppearance="?android:attr/textAppearanceMedium"187 android:textAppearance="?android:attr/textAppearanceMedium"
199 android:textColor="@color/text"188 android:textColor="@color/text"
200 u1f:customFont="Ubuntu-R.ttf" />189 u1f:customFont="Ubuntu-R.ttf" />
201 </RelativeLayout>190 </RelativeLayout>
202191
203 <RelativeLayout192
204 android:layout_width="wrap_content"193
205 android:layout_height="wrap_content"194 <RelativeLayout
206 android:layout_marginLeft="10dp" >195 android:layout_width="wrap_content"
207196 android:layout_height="wrap_content"
208 <com.canonical.ubuntu.widget.UbuntuTextView197 android:layout_marginLeft="10dp" >
209 android:id="@+id/data_label"198
210 android:layout_width="wrap_content"199 <com.canonical.ubuntu.widget.UbuntuTextView
211 android:layout_height="wrap_content"200 android:id="@+id/system_data_label"
212 android:layout_alignParentLeft="true"201 android:layout_width="wrap_content"
213 android:layout_centerHorizontal="true"202 android:layout_height="wrap_content"
214 android:layout_margin="2dp"203 android:layout_alignParentLeft="true"
215 android:text="Info:"204 android:layout_centerHorizontal="true"
216 android:textAppearance="?android:attr/textAppearanceMedium"205 android:layout_margin="2dp"
217 android:textColor="@color/text"206 android:text="System-data:"
218 android:textStyle="bold"207 android:textAppearance="?android:attr/textAppearanceMedium"
219 u1f:customFont="Ubuntu-R.ttf" />208 android:textColor="@color/text"
220209 android:textStyle="bold"
221 <com.canonical.ubuntu.widget.UbuntuTextView210 u1f:customFont="Ubuntu-R.ttf" />
222 android:id="@+id/datasize"211
223 android:layout_width="wrap_content"212 <com.canonical.ubuntu.widget.UbuntuTextView
224 android:layout_height="wrap_content"213 android:id="@+id/system_data_size"
225 android:layout_margin="2dp"214 android:layout_width="wrap_content"
226 android:layout_toRightOf="@id/data_label"215 android:layout_height="wrap_content"
227 android:singleLine="true"216 android:layout_margin="2dp"
228 android:text="add version"217 android:layout_toRightOf="@id/system_data_label"
218 android:singleLine="true"
219 android:text="used MB"
220 android:textAppearance="?android:attr/textAppearanceMedium"
221 android:textColor="@color/text"
222 u1f:customFont="Ubuntu-R.ttf" />
223 </RelativeLayout>
224
225 <RelativeLayout
226 android:layout_width="wrap_content"
227 android:layout_height="wrap_content"
228 android:layout_marginLeft="10dp" >
229
230 <com.canonical.ubuntu.widget.UbuntuTextView
231 android:id="@+id/user_data_label"
232 android:layout_width="wrap_content"
233 android:layout_height="wrap_content"
234 android:layout_alignParentLeft="true"
235 android:layout_centerHorizontal="true"
236 android:layout_margin="2dp"
237 android:text="User-data:"
238 android:textAppearance="?android:attr/textAppearanceMedium"
239 android:textColor="@color/text"
240 android:textStyle="bold"
241 u1f:customFont="Ubuntu-R.ttf" />
242
243 <com.canonical.ubuntu.widget.UbuntuTextView
244 android:id="@+id/user_datasize"
245 android:layout_width="wrap_content"
246 android:layout_height="wrap_content"
247 android:layout_margin="2dp"
248 android:layout_toRightOf="@id/user_data_label"
249 android:singleLine="true"
250 android:text="used MB"
229 android:textAppearance="?android:attr/textAppearanceMedium"251 android:textAppearance="?android:attr/textAppearanceMedium"
230 android:textColor="@color/text"252 android:textColor="@color/text"
231 u1f:customFont="Ubuntu-R.ttf" />253 u1f:customFont="Ubuntu-R.ttf" />
232 </RelativeLayout>254 </RelativeLayout>
233 </LinearLayout>255 </LinearLayout>
234256
257 <com.canonical.ubuntu.widget.UbuntuButton
258 android:id="@+id/upgrade"
259 style="@style/Button.Grey"
260 android:layout_width="match_parent"
261 android:layout_height="wrap_content"
262 android:layout_centerHorizontal="true"
263 android:layout_marginBottom="14dp"
264 android:layout_above="@+id/reboot"
265 android:adjustViewBounds="true"
266 android:text="Install Upgrade"
267 android:textColor="@color/text"
268 u1f:customFont="Ubuntu-R.ttf" />
269
270 <com.canonical.ubuntu.widget.UbuntuButton
271 android:id="@+id/reboot"
272 style="@style/Button.Grey"
273 android:layout_width="match_parent"
274 android:layout_height="wrap_content"
275 android:layout_alignParentBottom="true"
276 android:layout_centerHorizontal="true"
277 android:layout_marginBottom="14dp"
278 android:adjustViewBounds="true"
279 android:text="Boot Ubuntu"
280 android:textColor="@color/text"
281 u1f:customFont="Ubuntu-R.ttf" />
282
235</RelativeLayout>283</RelativeLayout>
236\ No newline at end of file284\ No newline at end of file
237285
=== modified file 'res/menu/installer_menu.xml'
--- res/menu/installer_menu.xml 2013-12-25 03:13:44 +0000
+++ res/menu/installer_menu.xml 2014-06-09 11:59:50 +0000
@@ -1,19 +1,15 @@
1<menu xmlns:android="http://schemas.android.com/apk/res/android" >1<menu xmlns:android="http://schemas.android.com/apk/res/android" >
22
3 <item3 <item
4 android:id="@+id/action_delete_download"4 android:id="@+id/menu_action_delete_download"
5 android:orderInCategory="100"5 android:orderInCategory="100"
6 android:showAsAction="never"6 android:showAsAction="ifRoom"
7 android:icon="@drawable/ic_action_discard"
7 android:title="@string/action_detele_download"/>8 android:title="@string/action_detele_download"/>
8 <item9 <item
9 android:id="@+id/action_dump_terminal"10 android:id="@+id/menu_action_dump_terminal"
10 android:orderInCategory="100"11 android:orderInCategory="100"
11 android:showAsAction="never"12 android:showAsAction="ifRoom"
13 android:icon="@drawable/ic_action_share"
12 android:title="@string/action_dump_terminal"/>14 android:title="@string/action_dump_terminal"/>
13<!-- <item
14 android:id="@+id/action_settings"
15 android:orderInCategory="100"
16 android:showAsAction="never"
17 android:title="@string/action_settings"/>
18 -->
19</menu>15</menu>
2016
=== modified file 'res/menu/launcher_menu.xml'
--- res/menu/launcher_menu.xml 2013-12-20 03:39:53 +0000
+++ res/menu/launcher_menu.xml 2014-06-09 11:59:50 +0000
@@ -1,20 +1,29 @@
1<menu xmlns:android="http://schemas.android.com/apk/res/android" >1<menu xmlns:android="http://schemas.android.com/apk/res/android" >
22 <item
3 <item3 android:id="@+id/menu_action_update_android"
4 android:id="@+id/action_uninstall"4 android:orderInCategory="100"
5 android:showAsAction="never"
6 android:title="@string/android_update_menu_option"/>
7 <item
8 android:id="@+id/menu_action_uninstall"
5 android:orderInCategory="100"9 android:orderInCategory="100"
6 android:showAsAction="never"10 android:showAsAction="never"
7 android:title="@string/action_uninstall"/>11 android:title="@string/action_uninstall"/>
8 <item12 <item
9 android:id="@+id/action_del_user_data"13 android:id="@+id/menu_action_del_user_data"
10 android:orderInCategory="100"14 android:orderInCategory="100"
11 android:showAsAction="never"15 android:showAsAction="ifRoom"
16 android:icon="@drawable/ic_action_discard"
12 android:title="@string/action_delete_user_data"/>17 android:title="@string/action_delete_user_data"/>
13 18 <item
14<!-- <item19 android:id="@+id/menu_action_update_storage_use"
15 android:id="@+id/action_settings"
16 android:orderInCategory="100"20 android:orderInCategory="100"
17 android:showAsAction="never"21 android:showAsAction="never"
18 android:title="@string/action_settings"/>22 android:title="@string/action_update_storage_use"/>
19-->23 <item
24 android:id="@+id/menu_action_check_for_update"
25 android:orderInCategory="100"
26 android:showAsAction="ifRoom"
27 android:icon="@drawable/ic_action_refresh"
28 android:title="@string/action_check_for_update"/>
20</menu>29</menu>
2130
=== modified file 'res/values/attrs.xml'
--- res/values/attrs.xml 2013-12-10 14:26:08 +0000
+++ res/values/attrs.xml 2014-06-09 11:59:50 +0000
@@ -1,20 +1,20 @@
1<?xml version="1.0" encoding="utf-8"?>1<?xml version="1.0" encoding="utf-8"?>
2<!--2<!--
3/*3/*
4 * This file is part of Ubuntu for Android.4 * This file is part of Ubuntu dualboot installer for Android.
5 * Copyright 2013 Canonical Ltd.5 * Copyright 2013 Canonical Ltd.
6 * 6 *
7 * Ubuntu for Android is free software: you can redistribute it and/or modify7 * Ubuntu dualboot installer is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation.9 * the Free Software Foundation.
10 *10 *
11 * Ubuntu for Android is distributed in the hope that it will be useful,11 * Ubuntu dualboot installer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.13 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.14 * See the GNU General Public License for more details.
15 *15 *
16 * You should have received a copy of the GNU General Public License16 * You should have received a copy of the GNU General Public License
17 * along with Ubuntu for Android. If not, see <http://www.gnu.org/licenses/>.17 * along with Ubuntu dualboot installer. If not, see <http://www.gnu.org/licenses/>.
18 */18 */
19-->19-->
2020
2121
=== modified file 'res/values/colors.xml'
--- res/values/colors.xml 2013-12-10 14:26:08 +0000
+++ res/values/colors.xml 2014-06-09 11:59:50 +0000
@@ -1,20 +1,20 @@
1<?xml version="1.0" encoding="utf-8"?>1<?xml version="1.0" encoding="utf-8"?>
2<!--2<!--
3/*3/*
4 * This file is part of Ubuntu for Android.4 * This file is part of Ubuntu dualboot installer for Android.
5 * Copyright 2013 Canonical Ltd.5 * Copyright 2013 Canonical Ltd.
6 * 6 *
7 * Ubuntu for Android is free software: you can redistribute it and/or modify7 * Ubuntu dualboot installer is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation.9 * the Free Software Foundation.
10 *10 *
11 * Ubuntu for Android is distributed in the hope that it will be useful,11 * Ubuntu dualboot installer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.13 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.14 * See the GNU General Public License for more details.
15 *15 *
16 * You should have received a copy of the GNU General Public License16 * You should have received a copy of the GNU General Public License
17 * along with Ubuntu for Android. If not, see <http://www.gnu.org/licenses/>.17 * along with Ubuntu dualboot installer. If not, see <http://www.gnu.org/licenses/>.
18 */18 */
19-->19-->
2020
2121
=== added file 'res/values/ids.xml'
--- res/values/ids.xml 1970-01-01 00:00:00 +0000
+++ res/values/ids.xml 2014-06-09 11:59:50 +0000
@@ -0,0 +1,26 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!--
3/*
4 * This file is part of Ubuntu dualboot installer for Android.
5 * Copyright 2013 Canonical Ltd.
6 *
7 * Ubuntu dualboot installer is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation.
10 *
11 * Ubuntu dualboot installer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Ubuntu dualboot installer. If not, see <http://www.gnu.org/licenses/>.
18 */
19-->
20
21<resources>
22 <item type="id" name="ubuntu_notification" />
23 <item type="id" name="ubuntu_progress_notification" />
24 <item type="id" name="ubuntu_update_notification" />
25 <item type="id" name="android_update_notification" />
26</resources>
0\ No newline at end of file27\ No newline at end of file
128
=== modified file 'res/values/strings.xml'
--- res/values/strings.xml 2014-01-09 08:54:46 +0000
+++ res/values/strings.xml 2014-06-09 11:59:50 +0000
@@ -1,4 +1,23 @@
1<?xml version="1.0" encoding="utf-8"?>1<?xml version="1.0" encoding="utf-8"?>
2<!--
3/*
4 * This file is part of Ubuntu dualboot installer for Android.
5 * Copyright 2013 Canonical Ltd.
6 *
7 * Ubuntu dualboot installer is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation.
10 *
11 * Ubuntu dualboot installer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Ubuntu dualboot installer. If not, see <http://www.gnu.org/licenses/>.
18 */
19-->
20
2<resources>21<resources>
3 <string name="yes">Yes</string>22 <string name="yes">Yes</string>
4 <string name="no">No</string>23 <string name="no">No</string>
@@ -11,50 +30,87 @@
11 <string name="action_dump_terminal">Dump Terminal</string>30 <string name="action_dump_terminal">Dump Terminal</string>
12 <string name="action_install">Install</string>31 <string name="action_install">Install</string>
13 <string name="action_uninstall">Uninstall Ubuntu</string>32 <string name="action_uninstall">Uninstall Ubuntu</string>
33
14 <string name="action_uninstall_button">Uninstall</string>34 <string name="action_uninstall_button">Uninstall</string>
15 <string name="action_delete_user_data">Delete Ubuntu user data</string>35 <string name="action_uninstall_ubuntu">Uninstall Ubuntu</string>
36 <string name="action_delete_user_data">Delete Ubuntu data</string>
37 <string name="action_update_storage_use">Update storage use</string>
38 <string name="action_check_for_update">Check for update</string>
16 <string name="action_delete_udata_button">Delete</string>39 <string name="action_delete_udata_button">Delete</string>
17 <string name="cancel">Cancel</string>40 <string name="cancel">Cancel</string>
18 <string name="welcome_world">Your life is about to change, welcome in Ubuntu installer</string>41 <string name="welcome_world">Your life is about to change, welcome to the Ubuntu installer</string>
19 <string name="install_button_label_install">Choose channel to install</string>42 <string name="install_button_label_install">Choose which channel to install</string>
20 <string name="install_button_label_fetching"><![CDATA[Install Ubuntu<br/><small>fetching channel list</small>]]></string>43 <string name="install_button_label_fetching"><![CDATA[Install Ubuntu<br/><small>fetching channel list</small>]]></string>
21 <string name="install_button_label_no_channel"><![CDATA[Install Ubuntu<br/><small>no available channels</small>]]></string>44 <string name="install_button_label_no_channel"><![CDATA[Install Ubuntu<br/><small>no available channels</small>]]></string>
22 <string name="install_button_label_resume">Resume install</string>45 <string name="install_button_label_resume">Resume install</string>
23 <string name="install_button_label_cancel_download">Cancel download</string>46 <string name="install_button_label_resume_download">Resume download</string>
24 <string name="install_button_label_cancel_install">Cancel install</string>47 <string name="install_button_label_pause_download">Pause download</string>
25 <string name="channel_picker_dialog_title">Select channel to install</string>48 <string name="install_button_label_installing">Installing....</string>
26 <string name="version_picker_dialog_title">Select version to install</string>49 <string name="channel_picker_dialog_title">Select which channel to install</string>
50 <string name="version_picker_dialog_title">Select which version to install</string>
27 <string name="bootstrap_check">bootstrap</string>51 <string name="bootstrap_check">bootstrap</string>
28 <string name="latest_check">latest version</string>52 <string name="latest_check">latest version</string>
29 <string name="downloading_release">Downloading Ubuntu</string>53 <string name="downloading_release">Downloading Ubuntu</string>
30 <string name="downloading_index">Downloading images data</string>54 <string name="downloading_index">Downloading image data</string>
31 <string name="downloading_starting">Starting download</string>55 <string name="downloading_starting">Starting download</string>
32 <string name="installing_release">Installing Ubuntu</string>56 <string name="installing_release">Installing Ubuntu</string>
33 <string name="uninstall_dialog_title">Uninstall Ubuntu?</string>57 <string name="uninstall_dialog_title">Uninstall Ubuntu?</string>
58 <string name="uninstall_dialog_description">Ubuntu installation will be removed and resources freed. If not specified Ubuntu user data will not be deleted</string>
34 <string name="uninstalling_ubuntu">Uninstalling Ubuntu</string>59 <string name="uninstalling_ubuntu">Uninstalling Ubuntu</string>
35 <string name="deleting_user_data">Deleting Ubuntu user data</string>60 <string name="deleting_user_data">Deleting Ubuntu user data</string>
61 <string name="deleting_download">Deleting download</string>
36 <string name="fail_fetching_versions">Fail to fetch available versions</string>62 <string name="fail_fetching_versions">Fail to fetch available versions</string>
37 <string name="uninstall_dialog_message">This will remove all Ubuntu system files and Ubuntu swap file</string>63 <string name="uninstall_dialog_message">This will remove all Ubuntu system files and the Ubuntu swap file</string>
38 <string name="terminal_is_empty">Terminal is emtpy.</string>64 <string name="terminal_is_empty">Terminal is empty.</string>
39 <string name="terminal_dump_succ">Dump Terminal successfully to file on sdcard</string>65 <string name="terminal_dump_succ">Dump Terminal to file on sdcard successful</string>
40 <string name="terminal_dump_fail">Dump Terminal failed to file on sdcard</string>66 <string name="terminal_dump_fail">Dump Terminal to file on sdcard failed</string>
41 <string name="external_storage_unavailable">External Storage is not available</string>67 <string name="external_storage_unavailable">External Storage is not available</string>
4268
43 <string name="not_supported_title">Not supported</string>69 <string name="not_supported_title">Not supported</string>
44 <string name="not_supported_message_fmt">It appears that your device (%s) is not on the supported list of Ubuntu for Phone dual boot installer. Visit <a href="https://wiki.ubuntu.com/Touch/DualBootInstallation">https://wiki.ubuntu.com/Touch/DualBootInstallation</a> to see phones that is supported.</string>70 <string name="not_supported_message_fmt">It appears that your device (%s) is not supported by the Ubuntu for Phone dual boot installer. Visit <a href="https://wiki.ubuntu.com/Touch/DualBootInstallation">https://wiki.ubuntu.com/Touch/DualBootInstallation</a> to see which phones are supported.</string>
4571
46 <string name="no_network_dialog_title">Network not available</string>72 <string name="no_network_dialog_title">Network not available</string>
47 <string name="enable_network">Enable WiFi</string>73 <string name="enable_network">Enable WiFi</string>
74 <string name="not_available">Not available</string>
75
76 <string name="android_update_dialog_title">Android system update detected</string>
77 <string name="android_update_dialog_possitive">Prepare for update</string>
78 <string name="android_update_menu_option">Prepare for Android update</string>
79 <string name="android_update_dialog_description">Android system update has been detected. Original recovery needs to be restored to complete system update. This will not afect existing Ubuntu installation. Once system is prepared start Settings application and complete system update. It is likely update removes SuperUser capability, requiring reinstall of superuser(dualboot application), existing Ubuntu installation will be preserved.</string>
4880
49 <!-- Strings for LaunchActivity screen -->81 <!-- Strings for LaunchActivity screen -->
50 <string name="launch_title">Ubuntu</string>82 <string name="launch_title">Ubuntu</string>
51 <string name="label_channel">Channel:</string>83 <string name="label_channel">Channel:</string>
84 <string name="label_channel_target">Target channel:</string>
52 <string name="label_version">Version:</string>85 <string name="label_version">Version:</string>
53 <string name="label_description">Description:</string>86 <string name="label_description">Description:</string>
87 <string name="label_rootfs">rootfs:</string>
88 <string name="label_system_data">system-data:</string>
89 <string name="label_user_data">user-data:</string>
54 <string name="reboot_button_label">Reboot to Ubuntu</string>90 <string name="reboot_button_label">Reboot to Ubuntu</string>
5591 <string name="button_install_ubuntu_update">Install Ubuntu update</string>
92 <string name="button_install_android_update">Install pending Android update</string>
93
94 <string name="notification_title">Ubuntu</string>
95 <string name="notification_update_available">Ubuntu update available</string>
96 <string name="notification_update_installed">Ubuntu update installed</string>
97 <string name="notification_ubuntu_installed">Ubuntu installed</string>
98 <string name="notification_download_failed">Ubuntu download failed</string>
99 <string name="notification_installation_failed">Ubuntu installation failed</string>
100 <string name="notification_downloading_release">Downloading Ubuntu release</string>
101 <string name="notification_downloading_update">Downloading Ubuntu update</string>
102 <string name="notification_installing_release">Installing Ubuntu release</string>
103 <string name="notification_installing_update">Installing Ubuntu update</string>
104 <string name="notification_android_update">Android update available</string>
105 <string name="not_enough_charge_warning">Battery level is too low to continue with installation</string>
106
56 <string-array name="uninstall_options">107 <string-array name="uninstall_options">
57 <item>Delete user data</item>108 <item>Delete user data</item>
58 </string-array>109 </string-array>
110
111 <string-array name="update_android_options">
112 <item>Never ask again</item>
113 </string-array>
114
59</resources>115</resources>
60116
61117
=== modified file 'res/values/styles.xml'
--- res/values/styles.xml 2013-12-10 14:26:08 +0000
+++ res/values/styles.xml 2014-06-09 11:59:50 +0000
@@ -1,20 +1,20 @@
1<?xml version="1.0" encoding="utf-8"?>1<?xml version="1.0" encoding="utf-8"?>
2<!--2<!--
3/*3/*
4 * This file is part of Ubuntu for Android.4 * This file is part of Ubuntu dualboot installer for Android.
5 * Copyright 2013 Canonical Ltd.5 * Copyright 2013 Canonical Ltd.
6 * 6 *
7 * Ubuntu for Android is free software: you can redistribute it and/or modify7 * Ubuntu dualboot installer is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation.9 * the Free Software Foundation.
10 *10 *
11 * Ubuntu for Android is distributed in the hope that it will be useful,11 * Ubuntu dualboot installer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.13 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.14 * See the GNU General Public License for more details.
15 *15 *
16 * You should have received a copy of the GNU General Public License16 * You should have received a copy of the GNU General Public License
17 * along with Ubuntu for Android. If not, see <http://www.gnu.org/licenses/>.17 * along with Ubuntu dualboot installer. If not, see <http://www.gnu.org/licenses/>.
18 */18 */
19-->19-->
2020
2121
=== added file 'src/com/canonical/ubuntu/installer/BaseActivity.java'
--- src/com/canonical/ubuntu/installer/BaseActivity.java 1970-01-01 00:00:00 +0000
+++ src/com/canonical/ubuntu/installer/BaseActivity.java 2014-06-09 11:59:50 +0000
@@ -0,0 +1,70 @@
1/*
2 * This file is part of Ubuntu dualboot installer for Android.
3 * Copyright 2013 Canonical Ltd.
4 *
5 * Ubuntu dualboot installer is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation.
8 *
9 * Ubuntu dualboot installer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Ubuntu dualboot installer. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18package com.canonical.ubuntu.installer;
19
20import android.app.Activity;
21import android.content.ComponentName;
22import android.content.Context;
23import android.content.Intent;
24import android.content.ServiceConnection;
25import android.os.IBinder;
26
27public class BaseActivity extends Activity {
28 public UbuntuInstallService mInstallerService;
29 private boolean mServiceIsBound;
30
31 public BaseActivity() {
32 }
33
34 private ServiceConnection mConnection = new ServiceConnection() {
35 public void onServiceConnected(ComponentName className, IBinder service) {
36 mInstallerService = ((UbuntuInstallService.LocalBinder)service).getService();
37 onInstallerServiceConnected();
38 }
39
40 public void onServiceDisconnected(ComponentName className) {
41 mInstallerService = null;
42 onInstallerServiceDisconnected();
43 }
44 };
45
46 void doBindService() {
47 bindService(new Intent(this, UbuntuInstallService.class), mConnection, Context.BIND_AUTO_CREATE);
48 mServiceIsBound = true;
49 }
50
51 void doUnbindService() {
52 if (mServiceIsBound) {
53 // Detach our existing connection.
54 unbindService(mConnection);
55 mServiceIsBound = false;
56 }
57 }
58
59 /**
60 * Overwrite this function to handle service connected
61 */
62 protected void onInstallerServiceConnected() {
63 }
64
65 /**
66 * Overwrite this function to handle service disconnected
67 */
68 protected void onInstallerServiceDisconnected() {
69 }
70}
071
=== added file 'src/com/canonical/ubuntu/installer/BootReceiver.java'
--- src/com/canonical/ubuntu/installer/BootReceiver.java 1970-01-01 00:00:00 +0000
+++ src/com/canonical/ubuntu/installer/BootReceiver.java 2014-06-09 11:59:50 +0000
@@ -0,0 +1,39 @@
1/*
2 * This file is part of Ubuntu dualboot installer for Android.
3 * Copyright 2013 Canonical Ltd.
4 *
5 * Ubuntu dualboot installer is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation.
8 *
9 * Ubuntu dualboot installer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Ubuntu dualboot installer. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18package com.canonical.ubuntu.installer;
19
20import android.content.BroadcastReceiver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.SharedPreferences;
24import android.util.Log;
25
26public class BootReceiver extends BroadcastReceiver {
27 private static final String TAG = "UbuntuBootReceiver";
28
29 @Override
30 public void onReceive(Context context, Intent intent) {
31 // check if there is any Ubuntu update pending
32 SharedPreferences sp = context.getSharedPreferences( UbuntuInstallService.SHARED_PREF, Context.MODE_PRIVATE);
33 if (sp.getBoolean(UbuntuInstallService.PREF_KEY_UBUNTU_INSTALLED, false)) {
34 // register alarm for periodical update checks
35 Log.d(TAG, "Setting up alarm for update checks");
36 Utils.registerUpdateCheckAlarm(context, sp);
37 }
38 }
39}
040
=== modified file 'src/com/canonical/ubuntu/installer/InstallActivity.java'
--- src/com/canonical/ubuntu/installer/InstallActivity.java 2014-01-09 08:54:46 +0000
+++ src/com/canonical/ubuntu/installer/InstallActivity.java 2014-06-09 11:59:50 +0000
@@ -1,3 +1,20 @@
1/*
2 * This file is part of Ubuntu dualboot installer for Android.
3 * Copyright 2013 Canonical Ltd.
4 *
5 * Ubuntu dualboot installer is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation.
8 *
9 * Ubuntu dualboot installer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Ubuntu dualboot installer. If not, see <http://www.gnu.org/licenses/>.
16 */
17
1package com.canonical.ubuntu.installer;18package com.canonical.ubuntu.installer;
219
3import java.io.File;20import java.io.File;
@@ -13,7 +30,7 @@
13import com.canonical.ubuntu.installer.UbuntuInstallService;30import com.canonical.ubuntu.installer.UbuntuInstallService;
14import com.canonical.ubuntu.installer.JsonChannelParser.Image;31import com.canonical.ubuntu.installer.JsonChannelParser.Image;
15import com.canonical.ubuntu.installer.UbuntuInstallService.InstallerState;32import com.canonical.ubuntu.installer.UbuntuInstallService.InstallerState;
16import com.canonical.ubuntu.installer.VersionInfo.ReleaseType;33import com.canonical.ubuntu.installer.UbuntuInstallService.ReleaseType;
17import com.canonical.ubuntu.widget.UbuntuButton;34import com.canonical.ubuntu.widget.UbuntuButton;
1835
19import android.net.ConnectivityManager;36import android.net.ConnectivityManager;
@@ -22,7 +39,6 @@
22import android.os.Build;39import android.os.Build;
23import android.os.Bundle;40import android.os.Bundle;
24import android.os.Environment;41import android.os.Environment;
25import android.app.Activity;
26import android.app.AlertDialog;42import android.app.AlertDialog;
27import android.app.Dialog;43import android.app.Dialog;
28import android.app.DialogFragment;44import android.app.DialogFragment;
@@ -44,36 +60,53 @@
44import android.view.MenuItem;60import android.view.MenuItem;
45import android.view.View;61import android.view.View;
46import android.view.View.OnClickListener;62import android.view.View.OnClickListener;
63import android.view.ViewTreeObserver;
47import android.widget.ProgressBar;64import android.widget.ProgressBar;
48import android.widget.TextView;65import android.widget.TextView;
4966
50public class InstallActivity extends Activity {67public class InstallActivity extends BaseActivity {
51 private static final String TAG = "UbuntuInstaller";68 private static final String TAG = "UbuntuInstaller";
5269
53 private UbuntuButton mInstallButton;70 private UbuntuButton mInstallButton;
54 private boolean mObserversRegistered;
55
56 private InstallerState mStatus = InstallerState.READY;
57 private VersionInfo mDownloadedVersion = null;
58
59 private ProgressBar mProgressBar;71 private ProgressBar mProgressBar;
60 private TextView mProgressText;72 private TextView mProgressText;
61
62 private TextView mTerminal;73 private TextView mTerminal;
63 private HashMap<String, String> mAvailableChannels = new HashMap<String, String>();74 private ViewTreeObserver.OnGlobalLayoutListener mTerminalLayoutObserver;
75
76 private String mServerUrl;
77 private boolean mObserversRegistered;
78 private HashMap<String, String> mAvailableChannels = null;
79 private SharedPreferences mSp;
6480
65 @Override81 @Override
66 protected void onCreate(Bundle savedInstanceState) {82 protected void onCreate(Bundle savedInstanceState) {
67 super.onCreate(savedInstanceState);83 super.onCreate(savedInstanceState);
84 doBindService();
68 if (! Utils.isDeviceSupported()) {85 if (! Utils.isDeviceSupported()) {
69 Log.d(TAG, "Device is not supported: " + Build.DEVICE);86 Log.d(TAG, "Device is not supported: " + Build.DEVICE);
70 showNotCompatibleDialog();87 showNotCompatibleDialog();
71 }88 }
7289 mSp = getSharedPreferences(UbuntuInstallService.SHARED_PREF, Context.MODE_PRIVATE);
90 // Pick default server URL
91 mServerUrl = Utils.getReleaseServerUrl(this);
92
73 // check is there is already Ubuntu installed93 // check is there is already Ubuntu installed
74 checkIfUbuntuIsInstalled();
75 if (isFinishing()) return;94 if (isFinishing()) return;
7695
96 Intent i = getIntent();
97 String updateCommand = i.getStringExtra("updateCommand");
98 if (updateCommand != null) {
99 Log.e(TAG,"Started with upadteCommand:" + updateCommand);
100 File updateCommandFile = new File(updateCommand);
101 if (updateCommandFile.exists()) {
102 mSp.edit()
103 .putString(UbuntuInstallService.PREF_KEY_UPDATE_COMMAND, updateCommand)
104 .putInt(UbuntuInstallService.PREF_KEY_DOWNLOAD_TYPE, UbuntuInstallService.ReleaseType.FULL.getValue())
105 .commit();
106 Utils.parseAndUpdateInstallCommand(this, updateCommandFile);
107 }
108 }
109
77 setContentView(R.layout.ubuntu_dualboot_install);110 setContentView(R.layout.ubuntu_dualboot_install);
78 mInstallButton = (UbuntuButton) findViewById(R.id.download);111 mInstallButton = (UbuntuButton) findViewById(R.id.download);
79 mProgressBar = (ProgressBar) findViewById(R.id.progress);112 mProgressBar = (ProgressBar) findViewById(R.id.progress);
@@ -82,44 +115,55 @@
82 mTerminal.setMovementMethod(new ScrollingMovementMethod());115 mTerminal.setMovementMethod(new ScrollingMovementMethod());
83 mProgressBar.setEnabled(false);116 mProgressBar.setEnabled(false);
84 mProgressBar.setProgress(0);117 mProgressBar.setProgress(0);
85118 mTerminalLayoutObserver = new ViewTreeObserver.OnGlobalLayoutListener() {
86 SharedPreferences pref = getSharedPreferences(UbuntuInstallService.SHARED_PREF, Context.MODE_PRIVATE);119 @Override
87 pref.edit().putBoolean(UbuntuInstallService.PREF_KEY_DEVELOPER, true).commit();120 public void onGlobalLayout() {
88 }121 // update scrolling
89122 final int scrollAmount = mTerminal.getLayout().getLineTop(mTerminal.getLineCount()) - mTerminal.getHeight();
123 mTerminal.scrollTo(0, scrollAmount);
124
125 }
126 };
127 mSp.edit().putBoolean(UbuntuInstallService.PREF_KEY_DEVELOPER, true).commit();
128 }
129 @Override
130 protected void onDestroy() {
131 super.onDestroy();
132 doUnbindService();
133 }
134
90 @Override135 @Override
91 public void onResume() {136 public void onResume() {
92 super.onResume();137 super.onResume();
93 // check is there is already Ubuntu installed138 // check is there is already Ubuntu installed
94 checkIfUbuntuIsInstalled();139 checkActivityStillValid();
95 if (isFinishing()) return;140 if (isFinishing()) return;
96141
97 // verify if network is available for download.
98 isNetworkAvailable();
99
100 mInstallButton.setOnClickListener(mInstallButtonListener);142 mInstallButton.setOnClickListener(mInstallButtonListener);
101 IntentFilter filter = new IntentFilter();143 IntentFilter filter = new IntentFilter();
102 filter.addAction(UbuntuInstallService.AVAILABLE_CHANNELS);144 filter.addAction(UbuntuInstallService.AVAILABLE_CHANNELS);
103 filter.addAction(UbuntuInstallService.DOWNLOAD_RESULT);145 filter.addAction(UbuntuInstallService.DOWNLOAD_RESULT);
104 filter.addAction(UbuntuInstallService.PROGRESS);146 filter.addAction(UbuntuInstallService.PROGRESS);
147 filter.addAction(UbuntuInstallService.PROGRESS_OUPUT);
105 filter.addAction(UbuntuInstallService.INSTALL_RESULT);148 filter.addAction(UbuntuInstallService.INSTALL_RESULT);
106 filter.addAction(UbuntuInstallService.VERSION_UPDATE);149 filter.addAction(UbuntuInstallService.SERVICE_STATE_CHANGED);
107 filter.addAction(UbuntuInstallService.SERVICE_STATE);
108 registerReceiver(mServiceObserver, filter);150 registerReceiver(mServiceObserver, filter);
109 mObserversRegistered = true;151 mObserversRegistered = true;
110152
111 // do we know last activity153 // do we know last activity
112 if (mStatus == InstallerState.DOWNLOADING || mStatus == InstallerState.INSTALLING) {154 if (mInstallerService != null) {
113 // request last progress / status. this will update UI accordingly155 InstallerState state = mInstallerService.getServiceState();
114 startService(new Intent(UbuntuInstallService.GET_PROGRESS_STATUS));156 if (state == InstallerState.DOWNLOADING || state == InstallerState.INSTALLING) {
115 } else {157 // request last progress / status. this will update UI accordingly
116 // READY + mDownloadedVersion != null => READY_TO_INSTALL158 mProgressBar.setProgress(mInstallerService.getActionProgress());
117 mDownloadedVersion = UbuntuInstallService.getDownloadedVersion(this.getApplicationContext());
118 if (mDownloadedVersion == null) {
119 requestChannelList();
120 }159 }
160 updateUiElements();
161 updateOuputTextview();
121 }162 }
122 requestServiceState();163 // register view tree observer for terminal
164 ViewTreeObserver vto = mTerminal.getViewTreeObserver();
165 vto.addOnGlobalLayoutListener(mTerminalLayoutObserver);
166
123 }167 }
124 168
125 @Override169 @Override
@@ -131,6 +175,8 @@
131 unregisterReceiver(mServiceObserver);175 unregisterReceiver(mServiceObserver);
132 }176 }
133 mObserversRegistered = false;177 mObserversRegistered = false;
178 ViewTreeObserver vto = mTerminal.getViewTreeObserver();
179 vto.removeOnGlobalLayoutListener(mTerminalLayoutObserver);
134 }180 }
135181
136 @Override182 @Override
@@ -143,16 +189,12 @@
143 @Override189 @Override
144 public boolean onOptionsItemSelected(MenuItem item) {190 public boolean onOptionsItemSelected(MenuItem item) {
145 switch (item.getItemId()) {191 switch (item.getItemId()) {
146 case R.id.action_delete_download:192 case R.id.menu_action_delete_download:
147 // also attempt to uninstall ubuntu, since there should be none anyway, keep user data193 Intent action = new Intent(UbuntuInstallService.DELETE_DOWNLOAD);
148 Intent action = new Intent(UbuntuInstallService.UNINSTALL_UBUNTU);
149 action.putExtra(UbuntuInstallService.UNINSTALL_UBUNTU_EXTRA_REMOVE_USER_DATA, false);
150 startService(action);194 startService(action);
151 deleteDownload();195 Utils.showToast(this.getApplicationContext(), R.string.deleting_download);
152 mDownloadedVersion = null;
153 requestServiceState();
154 break;196 break;
155 case R.id.action_dump_terminal:197 case R.id.menu_action_dump_terminal:
156 CharSequence terminalText = mTerminal.getText();198 CharSequence terminalText = mTerminal.getText();
157 if (terminalText.length() == 0) {199 if (terminalText.length() == 0) {
158 Utils.showToast(this.getApplicationContext(), R.string.terminal_is_empty);200 Utils.showToast(this.getApplicationContext(), R.string.terminal_is_empty);
@@ -200,45 +242,42 @@
200 context.startActivity(intent);242 context.startActivity(intent);
201 }243 }
202244
203 private void checkIfUbuntuIsInstalled() {245 /**
246 * Check is this activity is still valid, or we should switch to another one
247 */
248 protected void checkActivityStillValid() {
204 // check is there is Ubuntu installed or is upgradeable249 // check is there is Ubuntu installed or is upgradeable
205 if (UbuntuInstallService.isUbuntuInstalled(getApplicationContext())) {250 if (mInstallerService != null
206 if(!UbuntuInstallService.isUpgradeable(getApplicationContext())) {251 && mSp.getBoolean(UbuntuInstallService.PREF_KEY_UBUNTU_INSTALLED, false)
207 Log.d(TAG, "go to launch screen, and kill Install activity");252 && mInstallerService.getServiceState() != InstallerState.INSTALLING
208 LaunchActivity.startFrom(this);253 && mInstallerService.getServiceState() != InstallerState.DOWNLOADING ) {
209 finish();254 Log.d(TAG, "go to launch screen, and kill Install activity");
210 }255 LaunchActivity.startFrom(this);
211 }256 mAvailableChannels = null;
257 finish();
258 }
212 }259 }
213260
214 private void requestChannelList() {261 private void requestChannelList() {
215 startService(new Intent(UbuntuInstallService.GET_CHANNEL_LIST));262 mAvailableChannels = null;
216 }263 Intent i = new Intent(UbuntuInstallService.GET_CHANNEL_LIST);
217 264 i.putExtra(UbuntuInstallService.GET_CHANNEL_LIST_EXTRA_SERVER_URL, mServerUrl);
218 private void requestServiceState() {265 startService(i);
219 startService(new Intent(UbuntuInstallService.GET_SERVICE_STATE));266 }
220 }267
221
222 private void deleteDownload() {
223 Intent action = new Intent(UbuntuInstallService.CLEAN_DOWNLOAD);
224 startService(action);
225 }
226
227 OnClickListener mInstallButtonListener = new OnClickListener() {268 OnClickListener mInstallButtonListener = new OnClickListener() {
228 @Override269 @Override
229 public void onClick(View v) {270 public void onClick(View v) {
230 // do we need to download release, or there is already one downloaded271 // do we need to download release, or there is already one downloaded
231 // user might have missed SU request, then we have downloaded release and we just need deploy it272 // user might have missed SU request, then we have downloaded release and we just need deploy it
232 // TODO: we will need to handle also download resume273 // we need to handle also download resume
233 if (mStatus == InstallerState.DOWNLOADING) {274 if (mInstallerService.getServiceState() == InstallerState.DOWNLOADING) {
234 Intent startInstall = new Intent(UbuntuInstallService.CANCEL_DOWNLOAD);275 mInstallerService.pauseDownload();
235 startService(startInstall);276 } else if (UbuntuInstallService.isReadyToInstall(mSp)) {
236 } else if (mStatus == InstallerState.INSTALLING) {277 UbuntuInstallService.startInstallationIfPossible(v.getContext());
237 Intent startInstall = new Intent(UbuntuInstallService.CANCEL_INSTALL);278 } else if (UbuntuInstallService.isDownloadActive(mSp)) {
238 startService(startInstall);279 startService(new Intent(UbuntuInstallService.RESUME_DOWNLOAD));
239 } else if (UbuntuInstallService.checkifReadyToInstall(v.getContext())) {280 } else if (mAvailableChannels != null && 0 != mAvailableChannels.size()) {
240 startInstallationIfPossible();
241 } else if (0 != mAvailableChannels.size()) {
242 // get list of aliases as array281 // get list of aliases as array
243 String channels[] = mAvailableChannels.keySet().toArray(new String[mAvailableChannels.size()]);282 String channels[] = mAvailableChannels.keySet().toArray(new String[mAvailableChannels.size()]);
244 // look for "trusty" as default channel283 // look for "trusty" as default channel
@@ -257,32 +296,21 @@
257 true /* default latest settings*/).show();296 true /* default latest settings*/).show();
258 } else {297 } else {
259 // there are no channels to pick from, this was mistake, disable button298 // there are no channels to pick from, this was mistake, disable button
260 requestServiceState();299 mAvailableChannels = null;
300 updateUiElements();
261 }301 }
262 }302 }
263 };303 };
264 304
265 private void updateInfoOnUiThread(final String text) {305 private void updateOuputTextview() {
266 this.runOnUiThread(new Runnable() {306 this.runOnUiThread(new Runnable() {
267 @Override307 @Override
268 public void run() {308 public void run() {
269 // keep old text in there 309 mTerminal.setText(mInstallerService.getActionOutput());
270 mTerminal.setText(mTerminal.getText().toString() + "\n" + text);
271 final int scrollAmount = mTerminal.getLayout().getLineTop(mTerminal.getLineCount()) - mTerminal.getHeight();
272 mTerminal.scrollTo(0, scrollAmount);
273 }310 }
274 });311 });
275 }312 }
276313
277 private void startInstallationIfPossible() {
278 // TODO: check if we have battery and progress to install
279 Intent startInstall = new Intent(UbuntuInstallService.INSTALL_UBUNTU);
280 startService(startInstall);
281 Utils.showToast(this, "Starting Ubuntu installation");
282 // reset progress bar
283 mProgressBar.setProgress(0);
284 }
285
286 TextPickerDialog.OnChannelPicktListener mInstallDialogListener 314 TextPickerDialog.OnChannelPicktListener mInstallDialogListener
287 = new TextPickerDialog.OnChannelPicktListener() {315 = new TextPickerDialog.OnChannelPicktListener() {
288 public void onChannelPicked(Context context, String channel, boolean bootstrap, boolean latest) {316 public void onChannelPicked(Context context, String channel, boolean bootstrap, boolean latest) {
@@ -297,16 +325,16 @@
297325
298 private void startDownload(final String channel, final boolean bootstrap, final int version) {326 private void startDownload(final String channel, final boolean bootstrap, final int version) {
299 Intent startDownload = new Intent(UbuntuInstallService.DOWNLOAD_RELEASE);327 Intent startDownload = new Intent(UbuntuInstallService.DOWNLOAD_RELEASE);
300 startDownload.putExtra(UbuntuInstallService.DOWNLOAD_RELEASE_EXTRA_CHANNEL_ALIAS, channel);328 startDownload.putExtra(UbuntuInstallService.DOWNLOAD_RELEASE_EXTRA_SERVER_URL,
329 mServerUrl);
301 startDownload.putExtra(UbuntuInstallService.DOWNLOAD_RELEASE_EXTRA_CHANNEL_URL, 330 startDownload.putExtra(UbuntuInstallService.DOWNLOAD_RELEASE_EXTRA_CHANNEL_URL,
302 mAvailableChannels.get(channel));331 mAvailableChannels.get(channel));
303 startDownload.putExtra(UbuntuInstallService.DOWNLOAD_RELEASE_EXTRA_BOOTSTRAP, bootstrap);332 startDownload.putExtra(UbuntuInstallService.DOWNLOAD_RELEASE_EXTRA_BOOTSTRAP, bootstrap);
304 if (version != -1) {333 if (version != -1) {
305 startDownload.putExtra(UbuntuInstallService.DOWNLOAD_RELEASE_EXTRA_VERSION, version);334 startDownload.putExtra(UbuntuInstallService.DOWNLOAD_RELEASE_EXTRA_VERSION, version);
306 }335 }
307 startDownload.putExtra(UbuntuInstallService.DOWNLOAD_RELEASE_EXTRA_TYPE, ReleaseType.FULL.getValue());336 startDownload.putExtra(UbuntuInstallService.DOWNLOAD_RELEASE_EXTRA_TYPE, ReleaseType.FULL.getValue());
308 startService(startDownload);337 startService(startDownload);
309 mTerminal.setText(R.string.downloading_starting);
310 mProgressBar.setProgress(0);338 mProgressBar.setProgress(0);
311 }339 }
312 340
@@ -317,9 +345,11 @@
317 new Thread(new Runnable() {345 new Thread(new Runnable() {
318 @Override346 @Override
319 public void run() {347 public void run() {
320 String jsonStr = Utils.httpDownload(UbuntuInstallService.BASE_URL 348 String jsonStr = Utils.httpDownload( mServerUrl + mAvailableChannels.get(channel));
321 + mAvailableChannels.get(channel));349 if (jsonStr == null) {
322 // TODO: handle malformed JSON350 Utils.showToast(context, "Wrong url to channel list");
351 return;
352 }
323 final List<Image> releases = JsonChannelParser.getAvailableReleases(jsonStr, ReleaseType.FULL);353 final List<Image> releases = JsonChannelParser.getAvailableReleases(jsonStr, ReleaseType.FULL);
324354
325 runOnUiThread(new Runnable() {355 runOnUiThread(new Runnable() {
@@ -351,21 +381,45 @@
351 }).start();381 }).start();
352 }382 }
353383
354 private void updateUiElements() {384 @Override
385 protected void onInstallerServiceConnected() {
386 updateUiElements();
387 updateOuputTextview();
388 }
389
390 protected void updateUiElements() {
391 checkActivityStillValid();
392 if (isFinishing()) return;
355 this.runOnUiThread(new Runnable() {393 this.runOnUiThread(new Runnable() {
356 @Override394 @Override
357 public void run() {395 public void run() {
358 Log.v(TAG,"updateUiElements(" + mStatus + ")");396 InstallerState state = mInstallerService.getServiceState();
359 switch (mStatus) {397 Log.v(TAG,"updateUiElements(" + state + ")");
398 // check if should fetch list of channels
399 if ( state == InstallerState.READY
400 && state != InstallerState.FETCHING_CHANNELS
401 && mAvailableChannels == null
402 && isNetworkAvailable()
403 && ! UbuntuInstallService.isDownloadActive(mSp)
404 && ! UbuntuInstallService.isReadyToInstall(mSp)) {
405 requestChannelList();
406 }
407 switch (state) {
360 case READY:408 case READY:
361 {409 {
362 if (mDownloadedVersion != null) {410 if (UbuntuInstallService.isDownloadActive(mSp)) {
411 mInstallButton.setText(R.string.install_button_label_resume_download);
412 mInstallButton.setEnabled(true);
413 mProgressBar.setEnabled(false);
414 mProgressBar.setProgress(0);
415 mProgressText.setText("");
416 } else if (UbuntuInstallService.isReadyToInstall(mSp)) {
363 mInstallButton.setText(R.string.install_button_label_resume);417 mInstallButton.setText(R.string.install_button_label_resume);
364 mInstallButton.setEnabled(true);418 mInstallButton.setEnabled(true);
365 mProgressBar.setEnabled(false);419 mProgressBar.setEnabled(false);
366 mProgressBar.setProgress(0);420 mProgressBar.setProgress(0);
367 mProgressText.setText("");421 mProgressText.setText("");
368 } else if (mAvailableChannels.size() > 0) {422 } else if (mAvailableChannels != null && mAvailableChannels.size() > 0) {
369 mInstallButton.setText(R.string.install_button_label_install);423 mInstallButton.setText(R.string.install_button_label_install);
370 mInstallButton.setEnabled(true);424 mInstallButton.setEnabled(true);
371 mProgressBar.setEnabled(false);425 mProgressBar.setEnabled(false);
@@ -388,18 +442,24 @@
388 mProgressText.setText("");442 mProgressText.setText("");
389 break; 443 break;
390 case DOWNLOADING:444 case DOWNLOADING:
391 mInstallButton.setText(R.string.install_button_label_cancel_download);445 mInstallButton.setText(R.string.install_button_label_pause_download);
392 mInstallButton.setEnabled(true);446 mInstallButton.setEnabled(true);
393 mProgressBar.setEnabled(true);447 mProgressBar.setEnabled(true);
394 mProgressText.setText(R.string.downloading_release);448 mProgressText.setText(R.string.downloading_release);
395 break;449 break;
396 case INSTALLING:450 case INSTALLING:
397 mInstallButton.setText(R.string.install_button_label_cancel_install);451 mInstallButton.setText(R.string.install_button_label_installing);
398 mInstallButton.setEnabled(true);452 mInstallButton.setEnabled(false);
399 mProgressBar.setEnabled(true);453 mProgressBar.setEnabled(true);
454 mProgressBar.setProgress(mInstallerService.getActionProgress());
400 mProgressText.setText(R.string.installing_release);455 mProgressText.setText(R.string.installing_release);
401 break;456 break;
457 default:
458 // ignore rest of the states
459 break;
402 }460 }
461 // dismiss notification we don't need
462 mInstallerService.dismissUbuntuNotification();
403 }463 }
404 });464 });
405 }465 }
@@ -410,63 +470,40 @@
410 @Override470 @Override
411 public void onReceive(Context context, Intent intent) {471 public void onReceive(Context context, Intent intent) {
412 String action = intent.getAction();472 String action = intent.getAction();
413 Log.v(TAG,"mServiceObserver.onReceive(" + action + ")");
414 // List of available channels fetched 473 // List of available channels fetched
415 if (action.equals(UbuntuInstallService.AVAILABLE_CHANNELS)) {474 if (action.equals(UbuntuInstallService.AVAILABLE_CHANNELS)) {
416 // ignore channel list if we have already downloaded release475 Log.v(TAG,"mServiceObserver: available channels received");
417 if (!UbuntuInstallService.checkifReadyToInstall(context)) {476 mAvailableChannels = (HashMap<String, String>)
418 mAvailableChannels = (HashMap<String, String>) 477 intent.getSerializableExtra(UbuntuInstallService.AVAILABLE_CHANNELS_EXTRA_CHANNELS);
419 intent.getSerializableExtra(UbuntuInstallService.AVAILABLE_CHANNELS_EXTRA_CHANNELS);
420 mStatus = InstallerState.READY;
421 updateUiElements();
422 }
423 // Handle progress478 // Handle progress
424 } else if (action.equals(UbuntuInstallService.PROGRESS)) {479 } else if (action.equals(UbuntuInstallService.PROGRESS)) {
425 String p = intent.getStringExtra(UbuntuInstallService.PROGRESS_EXTRA_TEXT);480 mProgressBar.setProgress(mInstallerService.getActionProgress());
426 int progress = intent.getIntExtra(UbuntuInstallService.PROGRESS_EXTRA_INT, -1);481 } else if (action.equals(UbuntuInstallService.PROGRESS_OUPUT)) {
427 if (progress != -1) {482 updateOuputTextview();
428 mProgressBar.setProgress(progress);
429 Log.d(TAG, "Progress: " + progress);
430 }
431 if (p != null && !p.equals("")) {
432 // update terminal with progress text
433 updateInfoOnUiThread(p);
434 }
435
436 // Handle install result 483 // Handle install result
437 } else if(action.equals(UbuntuInstallService.INSTALL_RESULT)) {484 } else if(action.equals(UbuntuInstallService.INSTALL_RESULT)) {
485 Log.v(TAG,"mServiceObserver: installaction finished");
438 int r = intent.getIntExtra(UbuntuInstallService.INSTALL_RESULT_EXTRA_INT, -1);486 int r = intent.getIntExtra(UbuntuInstallService.INSTALL_RESULT_EXTRA_INT, -1);
439 if (r == 0) {487 if (r == 0) {
440 Utils.showToast(context, "Install completed");488 Utils.showToast(context, "Install completed");
441 mProgressBar.setProgress(100);489 mProgressBar.setProgress(100);
442 deleteDownload();
443 // go to launch screen, and kill this activity.
444 LaunchActivity.startFrom(context);
445 finish();
446 } else {490 } else {
447 Utils.showToast(context, "Installation failed:");491 Utils.showToast(context, "Installation failed:");
448 String reason = intent.getStringExtra(UbuntuInstallService.INSTALL_RESULT_EXTRA_STR);492 String reason = intent.getStringExtra(UbuntuInstallService.INSTALL_RESULT_EXTRA_STR);
449 Utils.showToast(context, reason);493 Utils.showToast(context, reason);
450 updateInfoOnUiThread(reason);494 updateOuputTextview();
451 // if we still have download go back to resume installation
452 // TODO: we should distinguish between resume/retry
453 mDownloadedVersion = UbuntuInstallService.getDownloadedVersion(context);
454 if (UbuntuInstallService.checkifReadyToInstall(context)) {
455 mDownloadedVersion = UbuntuInstallService.getDownloadedVersion(context);
456 } else {
457 deleteDownload();
458 mDownloadedVersion = null;
459 requestChannelList();
460 }
461 updateUiElements();
462 }495 }
496 updateUiElements();
463497
464 // Handle download result498 // Handle download result
465 } else if(action.equals(UbuntuInstallService.DOWNLOAD_RESULT)) {499 } else if(action.equals(UbuntuInstallService.DOWNLOAD_RESULT)) {
500 Log.v(TAG,"mServiceObserver: download finished");
466 int r = intent.getIntExtra(UbuntuInstallService.DOWNLOAD_RESULT_EXTRA_INT, -1);501 int r = intent.getIntExtra(UbuntuInstallService.DOWNLOAD_RESULT_EXTRA_INT, -1);
467 if (r == 0) {502 if (r == 0) {
468 Utils.showToast(context, "Download completed, ready to install Ubuntu");503 if (mInstallerService.getServiceState() == InstallerState.READY) {
469 startInstallationIfPossible();504 UbuntuInstallService.startInstallationIfPossible(context);
505 mInstallerService.resetActionOutput();
506 }
470 } else {507 } else {
471 String reason = intent.getStringExtra(UbuntuInstallService.INSTALL_RESULT_EXTRA_STR);508 String reason = intent.getStringExtra(UbuntuInstallService.INSTALL_RESULT_EXTRA_STR);
472 // make sure it was not cancelled by user509 // make sure it was not cancelled by user
@@ -474,27 +511,13 @@
474 reason = "Download failed: " + reason;511 reason = "Download failed: " + reason;
475 }512 }
476 Utils.showToast(context, reason);513 Utils.showToast(context, reason);
477514 updateOuputTextview();
478 // check if network is available for download.
479 // isNetworkAvailable();
480
481 updateInfoOnUiThread(reason);
482 requestChannelList();
483 }
484 } else if (action.equals(UbuntuInstallService.VERSION_UPDATE)) {
485 checkIfUbuntuIsInstalled();
486 if (!isFinishing()) {
487 // check what button should be shown
488 if (UbuntuInstallService.checkifReadyToInstall(context)) {
489 mDownloadedVersion = UbuntuInstallService.getDownloadedVersion(context);
490 }
491 updateUiElements();515 updateUiElements();
492 }516 }
493 } else if (action.equals(UbuntuInstallService.SERVICE_STATE)) {517 } else if (action.equals(UbuntuInstallService.SERVICE_STATE_CHANGED)) {
494 checkIfUbuntuIsInstalled();518 Log.v(TAG,"mServiceObserver: service state changed");
519 checkActivityStillValid();
495 if (!isFinishing()) {520 if (!isFinishing()) {
496 mStatus = InstallerState.fromOrdian(intent.getIntExtra(UbuntuInstallService.SERVICE_STATE, 0));
497 mDownloadedVersion = UbuntuInstallService.getDownloadedVersion(context);
498 updateUiElements();521 updateUiElements();
499 }522 }
500 }523 }
@@ -507,7 +530,7 @@
507 * 530 *
508 * @return true if network is available531 * @return true if network is available
509 */532 */
510 private boolean isNetworkAvailable () {533 private boolean isNetworkAvailable() {
511 final ConnectivityManager conMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);534 final ConnectivityManager conMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
512 final NetworkInfo activeNetwork = conMgr.getActiveNetworkInfo();535 final NetworkInfo activeNetwork = conMgr.getActiveNetworkInfo();
513 if (activeNetwork != null && activeNetwork.isConnected()) {536 if (activeNetwork != null && activeNetwork.isConnected()) {
@@ -516,11 +539,12 @@
516539
517 Utils.createConfirmationDialog(this,540 Utils.createConfirmationDialog(this,
518 R.string.no_network_dialog_title,541 R.string.no_network_dialog_title,
542 0,
519 R.string.enable_network,543 R.string.enable_network,
520 R.string.cancel,544 R.string.cancel,
521 new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK),545 new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK),
522 -1, // toastText546 0, // toastText
523 -1, // choiceItemsArray547 0, // choiceItemsArray
524 null, // defaultChoiceValues548 null, // defaultChoiceValues
525 null // choiceClickListener549 null // choiceClickListener
526 ).show();550 ).show();
527551
=== modified file 'src/com/canonical/ubuntu/installer/JsonChannelParser.java'
--- src/com/canonical/ubuntu/installer/JsonChannelParser.java 2013-12-16 02:11:14 +0000
+++ src/com/canonical/ubuntu/installer/JsonChannelParser.java 2014-06-09 11:59:50 +0000
@@ -1,3 +1,20 @@
1/*
2 * This file is part of Ubuntu dualboot installer for Android.
3 * Copyright 2013 Canonical Ltd.
4 *
5 * Ubuntu dualboot installer is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation.
8 *
9 * Ubuntu dualboot installer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Ubuntu dualboot installer. If not, see <http://www.gnu.org/licenses/>.
16 */
17
1package com.canonical.ubuntu.installer;18package com.canonical.ubuntu.installer;
219
3import java.util.Collections;20import java.util.Collections;
@@ -5,7 +22,7 @@
5import java.util.LinkedList;22import java.util.LinkedList;
6import java.util.List;23import java.util.List;
724
8import com.canonical.ubuntu.installer.VersionInfo.ReleaseType;25import com.canonical.ubuntu.installer.UbuntuInstallService.ReleaseType;
9import com.google.gson.Gson;26import com.google.gson.Gson;
10import com.google.gson.JsonArray;27import com.google.gson.JsonArray;
11import com.google.gson.JsonObject;28import com.google.gson.JsonObject;
@@ -26,6 +43,7 @@
26 }43 }
2744
28 public class Image {45 public class Image {
46 Integer base;
29 String description;47 String description;
30 Integer version;48 Integer version;
31 String type;49 String type;
@@ -41,21 +59,25 @@
41 static public List<Image> getAvailableReleases(String jsonStr, ReleaseType filter) {59 static public List<Image> getAvailableReleases(String jsonStr, ReleaseType filter) {
42 LinkedList<Image> releases = new LinkedList<Image>();60 LinkedList<Image> releases = new LinkedList<Image>();
43 61
44 JsonObject index = new JsonParser().parse(jsonStr).getAsJsonObject();62 try {
45 JsonArray images = index.get("images").getAsJsonArray();63 JsonObject index = new JsonParser().parse(jsonStr).getAsJsonObject();
46 int size = images.size();64 JsonArray images = index.get("images").getAsJsonArray();
4765 int size = images.size();
48 for(int j = 0; j < size; j++) {66
49 Image image = new Gson().fromJson(images.get(j), Image.class);67 for(int j = 0; j < size; j++) {
50 ReleaseType type = ReleaseType.UNKNOWN;68 Image image = new Gson().fromJson(images.get(j), Image.class);
51 if (FULL_RELEASE.equals(image.type)) {69 ReleaseType type = ReleaseType.UNKNOWN;
52 type = ReleaseType.FULL;70 if (FULL_RELEASE.equals(image.type)) {
53 } else if (DELTA_RELEASE.equals(image.type)) {71 type = ReleaseType.FULL;
54 type = ReleaseType.DELTA;72 } else if (DELTA_RELEASE.equals(image.type)) {
55 }73 type = ReleaseType.DELTA;
56 if (filter == type) {74 }
57 releases.add(image);75 if (filter == type) {
58 }76 releases.add(image);
77 }
78 }
79 } catch (com.google.gson.JsonSyntaxException e) {
80 // ignore, empty list will be returned
59 }81 }
60 // sort list82 // sort list
61 Collections.sort(releases, imageComparator());83 Collections.sort(releases, imageComparator());
6284
=== modified file 'src/com/canonical/ubuntu/installer/LaunchActivity.java'
--- src/com/canonical/ubuntu/installer/LaunchActivity.java 2014-01-09 08:54:46 +0000
+++ src/com/canonical/ubuntu/installer/LaunchActivity.java 2014-06-09 11:59:50 +0000
@@ -1,12 +1,30 @@
1/*
2 * This file is part of Ubuntu dualboot installer for Android.
3 * Copyright 2013 Canonical Ltd.
4 *
5 * Ubuntu dualboot installer is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation.
8 *
9 * Ubuntu dualboot installer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Ubuntu dualboot installer. If not, see <http://www.gnu.org/licenses/>.
16 */
17
1package com.canonical.ubuntu.installer;18package com.canonical.ubuntu.installer;
219
3import android.app.Activity;20import java.util.Locale;
4import android.app.AlertDialog;21
5import android.content.BroadcastReceiver;22import android.content.BroadcastReceiver;
6import android.content.Context;23import android.content.Context;
7import android.content.DialogInterface;24import android.content.DialogInterface;
8import android.content.Intent;25import android.content.Intent;
9import android.content.IntentFilter;26import android.content.IntentFilter;
27import android.content.SharedPreferences;
10import android.os.Bundle;28import android.os.Bundle;
11import android.util.Log;29import android.util.Log;
12import android.view.Menu;30import android.view.Menu;
@@ -15,80 +33,121 @@
15import android.view.View.OnClickListener;33import android.view.View.OnClickListener;
16import android.widget.TextView;34import android.widget.TextView;
1735
36import com.canonical.ubuntu.installer.UbuntuInstallService.InstallerState;
18import com.canonical.ubuntu.widget.UbuntuButton;37import com.canonical.ubuntu.widget.UbuntuButton;
1938
20public class LaunchActivity extends Activity {39public class LaunchActivity extends BaseActivity {
21 private static final String TAG = "UbuntuLaunchActivity";40 private static final String TAG = "UbuntuLaunchActivity";
22 private UbuntuButton mRebootButton;41
42 private SharedPreferences mSharedPreferences;
43 private TextView mTextTitle;
23 private TextView mTextChannel;44 private TextView mTextChannel;
24 private TextView mTextChannelLabel;45 private TextView mTextChannelLabel;
46 private TextView mTextRefChannel;
47 private TextView mTextRefChannelLabel;
25 private TextView mTextVersion;48 private TextView mTextVersion;
26 private TextView mTextVersionLabel;49 private TextView mTextVersionLabel;
27 private TextView mTextTitle;
28 private TextView mTextDescriptionLabel;50 private TextView mTextDescriptionLabel;
29 private TextView mTextDescription;51 private TextView mTextDescription;
30 private VersionInfo mUbuntuVersion;52 private TextView mTextUseRootfs;
53 private TextView mTextUseRootfsLabel;
54 private TextView mTextUseSystemData;
55 private TextView mTextUseSystemDataLabel;
56 private TextView mTextUseUserData;
57 private TextView mTextUseUserDataLabel;
58 private UbuntuButton mRebootButton;
59 private UbuntuButton mUpdateButton;
60 private boolean mAndroidUpdatePending;
61 private Menu mMenu;
3162
32 @Override63 @Override
33 protected void onCreate(Bundle savedInstanceState) {64 protected void onCreate(Bundle savedInstanceState) {
34 super.onCreate(savedInstanceState);65 super.onCreate(savedInstanceState);
35 // check if Ubuntu is installed66 doBindService();
36 ensureUbuntuIsInstalled();67 mSharedPreferences = getSharedPreferences( UbuntuInstallService.SHARED_PREF, Context.MODE_PRIVATE);
37 if (isFinishing()) return;
38
39 setContentView(R.layout.ubuntu_dualboot_launch);68 setContentView(R.layout.ubuntu_dualboot_launch);
40 mRebootButton = (UbuntuButton) findViewById(R.id.download);
41 mTextChannel = (TextView) findViewById(R.id.channel);69 mTextChannel = (TextView) findViewById(R.id.channel);
70 mTextChannelLabel = (TextView) findViewById(R.id.channel_label);
71 mTextRefChannel = (TextView) findViewById(R.id.ref_channel);
72 mTextRefChannelLabel = (TextView) findViewById(R.id.ref_channel_label);
42 mTextVersion = (TextView) findViewById(R.id.version);73 mTextVersion = (TextView) findViewById(R.id.version);
43 mTextChannelLabel = (TextView) findViewById(R.id.channel_label);
44 mTextVersionLabel = (TextView) findViewById(R.id.version_label);74 mTextVersionLabel = (TextView) findViewById(R.id.version_label);
45 mTextTitle = (TextView) findViewById(R.id.title);
46 mTextDescriptionLabel = (TextView) findViewById(R.id.description_label);75 mTextDescriptionLabel = (TextView) findViewById(R.id.description_label);
47 mTextDescription = (TextView) findViewById(R.id.description);76 mTextDescription = (TextView) findViewById(R.id.description);
77 mTextUseRootfs = (TextView) findViewById(R.id.rootfssize);
78 mTextUseRootfsLabel = (TextView) findViewById(R.id.rootfs_label);
79 mTextUseSystemData = (TextView) findViewById(R.id.system_data_size);
80 mTextUseSystemDataLabel = (TextView) findViewById(R.id.system_data_label);
81 mTextUseUserData = (TextView) findViewById(R.id.user_datasize);
82 mTextUseUserDataLabel = (TextView) findViewById(R.id.user_data_label);
83 mTextTitle = (TextView) findViewById(R.id.title);
48 mTextTitle.setText(R.string.launch_title);84 mTextTitle.setText(R.string.launch_title);
85 mUpdateButton = (UbuntuButton) findViewById(R.id.upgrade);
86 mRebootButton = (UbuntuButton) findViewById(R.id.reboot);
49 mRebootButton.setText(R.string.reboot_button_label);87 mRebootButton.setText(R.string.reboot_button_label);
50 fillInstalledVersionInfo();88 mUpdateButton.setText(R.string.button_install_ubuntu_update);
5189 mTextVersionLabel.setText(R.string.label_version);
52 // check the upgradeable image.90 mTextChannelLabel.setText(R.string.label_channel);
53 startService(new Intent(UbuntuInstallService.IS_UBUNTU_UPGRADABLE));91 mTextRefChannelLabel.setText(R.string.label_channel_target);
54 }92 mTextDescriptionLabel.setText(R.string.label_description);
5593 mTextUseRootfsLabel.setText(R.string.label_rootfs);
94 mTextUseSystemDataLabel.setText(R.string.label_system_data);
95 mTextUseUserDataLabel.setText(R.string.label_user_data);
96 // check for updates
97 startService(new Intent(UbuntuInstallService.CHECK_PENDING_UPDATES));
98 }
99
100 @Override
101 protected void onDestroy() {
102 super.onDestroy();
103 doUnbindService();
104 }
105
56 @Override106 @Override
57 public void onResume() {107 public void onResume() {
58 super.onResume();108 super.onResume();
59 // check is there is Ubuntu installed109 // check is there is Ubuntu installed
60 ensureUbuntuIsInstalled();110 checkActivityStillValid();
61 if (isFinishing()) return;111 if (isFinishing()) return;
62 112
63 mRebootButton.setOnClickListener(mRebootButtonListener);113 mRebootButton.setOnClickListener(mRebootButtonListener);
114 mUpdateButton.setOnClickListener(mRebootButtonListener);
64 IntentFilter filter = new IntentFilter();115 IntentFilter filter = new IntentFilter();
65 filter.addAction(UbuntuInstallService.VERSION_UPDATE);116 filter.addAction(UbuntuInstallService.SERVICE_STATE_CHANGED);
117 filter.addAction(UbuntuInstallService.STORAGE_USE_UPDATED);
118 filter.addAction(UbuntuInstallService.ANDROID_UPDATE_PENDING);
119 filter.addAction(UbuntuInstallService.UBUNTU_UPDATE_PENDING);
120 filter.addAction(UbuntuInstallService.UBUNTU_UPDATE_AVAILABLE);
66 registerReceiver(mServiceObserver, filter);121 registerReceiver(mServiceObserver, filter);
122 updateUiElements();
67 }123 }
68124
69 @Override125 @Override
70 public void onPause() {126 public void onPause() {
71 super.onPause();127 super.onPause();
72 mRebootButton.setOnClickListener(null);128 mRebootButton.setOnClickListener(null);
129 mUpdateButton.setOnClickListener(null);
73 // cancel observer if there is any130 // cancel observer if there is any
74 unregisterReceiver(mServiceObserver);131 unregisterReceiver(mServiceObserver);
75 }132 }
76133
77 @Override134 @Override
78 public boolean onCreateOptionsMenu(Menu menu) {135 public boolean onCreateOptionsMenu(Menu menu) {
79 // Inflate the menu; this adds items to the action bar if it is present.
80 getMenuInflater().inflate(R.menu.launcher_menu, menu);136 getMenuInflater().inflate(R.menu.launcher_menu, menu);
137 menu.findItem(R.id.menu_action_update_android).setShowAsAction( MenuItem.SHOW_AS_ACTION_NEVER);
138 mMenu = menu;
81 return true;139 return true;
82 }140 }
83 141
84 @Override142 @Override
85 public boolean onOptionsItemSelected(MenuItem item) {143 public boolean onOptionsItemSelected(MenuItem item) {
86 switch (item.getItemId()) {144 switch (item.getItemId()) {
87 case R.id.action_uninstall:145 case R.id.menu_action_uninstall:
88 // show dialog146 // show dialog
89 final Intent uninstall = new Intent(UbuntuInstallService.UNINSTALL_UBUNTU);147 final Intent uninstall = new Intent(UbuntuInstallService.UNINSTALL_UBUNTU);
90 Utils.createConfirmationDialog(this,148 Utils.createConfirmationDialog(this,
91 R.string.uninstall_dialog_title,149 R.string.uninstall_dialog_title,
150 R.string.uninstall_dialog_description,
92 R.string.action_uninstall_button,151 R.string.action_uninstall_button,
93 R.string.cancel,152 R.string.cancel,
94 uninstall,153 uninstall,
@@ -103,71 +162,176 @@
103 }162 }
104 }).show();163 }).show();
105 break;164 break;
106 case R.id.action_del_user_data:165 case R.id.menu_action_del_user_data:
107 Intent action = new Intent(UbuntuInstallService.DELETE_UBUNTU_USER_DATA);166 final Intent action = new Intent(UbuntuInstallService.DELETE_UBUNTU_USER_DATA);
108 Utils.createConfirmationDialog(this,167 Utils.createConfirmationDialog(this,
109 R.string.action_delete_user_data,168 R.string.action_delete_user_data,
169 0,
110 R.string.action_delete_udata_button,170 R.string.action_delete_udata_button,
111 R.string.cancel,171 R.string.cancel,
112 action,172 action,
113 R.string.deleting_user_data,173 R.string.deleting_user_data,
114 -1,174 0, // choiceItemsArray
115 null,175 null,
116 null).show(); 176 null).show();
117 break;177 break;
178 case R.id.menu_action_update_storage_use:
179 final Intent updateStorage = new Intent(UbuntuInstallService.UPDATE_STORAGE_USE);
180 startService(updateStorage);
181 break;
182 case R.id.menu_action_check_for_update:
183 final Intent checkForUpdate = new Intent(UbuntuInstallService.CHECK_IF_UPDATE_AVAILABLE);
184 startService(checkForUpdate);
185 break;
186 case R.id.menu_action_update_android:
187 showAndroidUpdateDialog();
188 break;
118 }189 }
119 return super.onOptionsItemSelected(item);190 return super.onOptionsItemSelected(item);
120 }191 }
121192
193 public void showAndroidUpdateDialog() {
194 final Intent update = new Intent(UbuntuInstallService.PREPARE_ANDROID_UPDATE);
195 Utils.createAndroidUpdateConfirmationDialog(this,
196 R.string.android_update_dialog_title,
197 R.string.android_update_dialog_description,
198 R.string.android_update_dialog_possitive,
199 R.string.cancel,
200 update,
201 0,
202 R.array.update_android_options,
203 new boolean[]{mSharedPreferences.getBoolean(UbuntuInstallService.PREF_KEY_ANDROID_UPDATE_DISMISSED, false)},
204 new DialogInterface.OnMultiChoiceClickListener() {
205 @Override
206 public void onClick(DialogInterface dialog, int which, boolean isChecked) {
207 // update data in the shared preferences
208 mSharedPreferences.edit()
209 .putBoolean(UbuntuInstallService.PREF_KEY_ANDROID_UPDATE_DISMISSED, isChecked)
210 .commit();
211 mAndroidUpdatePending = !isChecked;
212 }
213 }).show();
214 }
215
122 public static void startFrom(Context context) {216 public static void startFrom(Context context) {
123 Intent intent = new Intent(context, LaunchActivity.class);217 Intent intent = new Intent(context, LaunchActivity.class);
124 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);218 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
125 context.startActivity(intent);219 context.startActivity(intent);
126 }220 }
127221
128 private void fillInstalledVersionInfo() {222 @Override
129 mTextChannel.setText(mUbuntuVersion.getChannelAlias());223 protected void onInstallerServiceConnected() {
130 mTextVersion.setText(Integer.toString(mUbuntuVersion.getVersion()));224 updateUiElements();
131 mTextDescription.setText(mUbuntuVersion.getDescription());225 }
132 mTextChannelLabel.setText(R.string.label_channel);226
133 mTextVersionLabel.setText(R.string.label_version);227 protected void updateUiElements() {
134 mTextDescriptionLabel.setText(R.string.label_description);228 checkActivityStillValid();
135 }229 if (isFinishing()) return;
136230 this.runOnUiThread(new Runnable() {
231 @Override
232 public void run() {
233 String defValue = getString(R.string.not_available);
234 mTextChannel.setText(mSharedPreferences.getString(UbuntuInstallService.PREF_KEY_VERSION_CHANNEL, defValue));
235 mTextRefChannel.setText(mSharedPreferences.getString(UbuntuInstallService.PREF_KEY_VERSION_CHANNEL_TARGET, defValue));
236 mTextVersion.setText(mSharedPreferences.getString(UbuntuInstallService.PREF_KEY_VERSION_NUMBER, defValue));
237 mTextDescription.setText(mSharedPreferences.getString(UbuntuInstallService.PREF_KEY_VERSION_DESCRIPTION, defValue));
238 mTextUseRootfs.setText(formatSize(mSharedPreferences.getInt(UbuntuInstallService.PREF_KEY_SIZE_ROOTFS, -1)));
239 mTextUseSystemData.setText(formatSize(mSharedPreferences.getInt(UbuntuInstallService.PREF_KEY_SIZE_SYSTEM_DATA, -1)));
240 mTextUseUserData.setText(formatSize(mSharedPreferences.getInt(UbuntuInstallService.PREF_KEY_SIZE_USER_DATA, -1)));
241 if (mSharedPreferences.getBoolean(UbuntuInstallService.PREF_KEY_PENDING_UPDATE, false)) {
242 mUpdateButton.setVisibility(View.VISIBLE);
243 } else {
244 mUpdateButton.setVisibility(View.GONE);
245 }
246 // dismiss notification we don't need
247 if (mInstallerService != null) {
248 mInstallerService.dismissUbuntuNotification();
249 mInstallerService.dismissUbuntuUpdateNotification();
250 mInstallerService.dismissAndroidNotification();
251 }
252 if (mAndroidUpdatePending) {
253 showAndroidUpdateDialog();
254 }
255 }
256 });
257 }
258
259 String formatSize(int size) {
260 if (size != -1) {
261 return String.format(Locale.US,"%d MB", size);
262 } else {
263 return getString(R.string.not_available);
264 }
265 }
266
137 /**267 /**
138 * Get installed version to check Ubuntu is installed268 * Check is this activity is still valid, or we should switch to another one
139 */269 */
140 private void ensureUbuntuIsInstalled() {270 private void checkActivityStillValid() {
141 VersionInfo v = UbuntuInstallService.getInstalledVersion(this.getApplicationContext());271
142 if (v == null) {272 if (! mSharedPreferences.getBoolean(UbuntuInstallService.PREF_KEY_UBUNTU_INSTALLED, false)
273 || (mInstallerService != null
274 && (mInstallerService.getServiceState() == InstallerState.INSTALLING
275 || mInstallerService.getServiceState() == InstallerState.DOWNLOADING)
276 )
277 ) {
143 // go back to install screen, and release myself.278 // go back to install screen, and release myself.
144 InstallActivity.startFrom(this);279 InstallActivity.startFrom(this);
145 finish();280 finish();
146 } else {
147 mUbuntuVersion = v;
148 }281 }
149 }282 }
150 283
151 OnClickListener mRebootButtonListener = new OnClickListener() {284 OnClickListener mRebootButtonListener = new OnClickListener() {
152 @Override285 @Override
153 public void onClick(View v) {286 public void onClick(View v) {
154 startService(new Intent(UbuntuInstallService.REBOOT_UBUNTU));287 if (v.getId() == R.id.reboot) {
288 startService(new Intent(UbuntuInstallService.REBOOT_UBUNTU));
289 } else if (v.getId() == R.id.upgrade) {
290 if (UbuntuInstallService.isReadyToInstall(mSharedPreferences)) {
291 UbuntuInstallService.startInstallationIfPossible(v.getContext());
292 } else if (UbuntuInstallService.isDownloadActive(mSharedPreferences)) {
293 startService(new Intent(UbuntuInstallService.RESUME_DOWNLOAD));
294 } else {
295 startService(new Intent(UbuntuInstallService.DOWNLOAD_UPDATE));
296 }
297 }
155 }298 }
156 };299 };
157300
158 BroadcastReceiver mServiceObserver = new BroadcastReceiver() {301 BroadcastReceiver mServiceObserver = new BroadcastReceiver() {
159 @SuppressWarnings("unchecked")
160 @Override302 @Override
161 public void onReceive(Context context, Intent intent) {303 public void onReceive(Context context, Intent intent) {
162 String action = intent.getAction();304 String action = intent.getAction();
163 if (action.equals(UbuntuInstallService.VERSION_UPDATE)) {305 if (action.equals(UbuntuInstallService.SERVICE_STATE_CHANGED)) {
164 ensureUbuntuIsInstalled();306 InstallerState newState = mInstallerService.getServiceState();
165 if(UbuntuInstallService.isUpgradeable(getApplicationContext())) {307 Log.d(TAG,"New Service state:" + newState);
166 Log.d(TAG, "Found upgradeable file, kill LaunchActivity");308 switch(newState) {
167 InstallActivity.startFrom(context);309 case DOWNLOADING:
168 finish();310 case INSTALLING:
169 }311 // switch back to install activity to minitor ongoing task
312 InstallActivity.startFrom(context);
313 finish();
314 break;
315 default:
316 checkActivityStillValid();
317 break;
318 }
319 } else if (action.equals(UbuntuInstallService.STORAGE_USE_UPDATED)) {
320 updateUiElements();
321 }else if (action.equals(UbuntuInstallService.ANDROID_UPDATE_PENDING)) {
322 if (!mSharedPreferences.getBoolean(UbuntuInstallService.PREF_KEY_ANDROID_UPDATE_DISMISSED, false)) {
323 mAndroidUpdatePending = true;
324 }
325 if (mMenu != null) {
326 mMenu.findItem(R.id.menu_action_update_android).setShowAsAction( MenuItem.SHOW_AS_ACTION_ALWAYS);
327 }
328 updateUiElements();
329 } else if (action.equals(UbuntuInstallService.UBUNTU_UPDATE_PENDING)) {
330 mUpdateButton.setVisibility(View.VISIBLE);
331 } else if (action.equals(UbuntuInstallService.UBUNTU_UPDATE_AVAILABLE)) {
332 mUpdateButton.setVisibility(View.VISIBLE);
170 }333 }
334
171 }335 }
172 };336 };
173}337}
174338
=== modified file 'src/com/canonical/ubuntu/installer/NumberPickerDialog.java'
--- src/com/canonical/ubuntu/installer/NumberPickerDialog.java 2013-12-13 01:06:14 +0000
+++ src/com/canonical/ubuntu/installer/NumberPickerDialog.java 2014-06-09 11:59:50 +0000
@@ -1,3 +1,20 @@
1/*
2 * This file is part of Ubuntu dualboot installer for Android.
3 * Copyright 2013 Canonical Ltd.
4 *
5 * Ubuntu dualboot installer is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation.
8 *
9 * Ubuntu dualboot installer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Ubuntu dualboot installer. If not, see <http://www.gnu.org/licenses/>.
16 */
17
1package com.canonical.ubuntu.installer;18package com.canonical.ubuntu.installer;
219
3import com.canonical.ubuntu.installer.R;20import com.canonical.ubuntu.installer.R;
@@ -5,15 +22,12 @@
5import android.app.AlertDialog;22import android.app.AlertDialog;
6import android.content.Context;23import android.content.Context;
7import android.content.DialogInterface;24import android.content.DialogInterface;
8import android.content.SharedPreferences;
9import android.content.DialogInterface.OnClickListener;25import android.content.DialogInterface.OnClickListener;
10import android.content.res.Resources;26import android.content.res.Resources;
11import android.os.Bundle;27import android.os.Bundle;
12import android.view.LayoutInflater;28import android.view.LayoutInflater;
13import android.view.View;29import android.view.View;
14import android.widget.CheckBox;
15import android.widget.NumberPicker;30import android.widget.NumberPicker;
16import android.widget.TextView;
1731
18/**32/**
19 * A text picker dialog that prompts the user for to select one of the text options33 * A text picker dialog that prompts the user for to select one of the text options
2034
=== modified file 'src/com/canonical/ubuntu/installer/TextPickerDialog.java'
--- src/com/canonical/ubuntu/installer/TextPickerDialog.java 2013-12-13 01:06:14 +0000
+++ src/com/canonical/ubuntu/installer/TextPickerDialog.java 2014-06-09 11:59:50 +0000
@@ -1,3 +1,20 @@
1/*
2 * This file is part of Ubuntu dualboot installer for Android.
3 * Copyright 2013 Canonical Ltd.
4 *
5 * Ubuntu dualboot installer is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation.
8 *
9 * Ubuntu dualboot installer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Ubuntu dualboot installer. If not, see <http://www.gnu.org/licenses/>.
16 */
17
1package com.canonical.ubuntu.installer;18package com.canonical.ubuntu.installer;
219
3import com.canonical.ubuntu.installer.R;20import com.canonical.ubuntu.installer.R;
@@ -13,7 +30,6 @@
13import android.view.View;30import android.view.View;
14import android.widget.CheckBox;31import android.widget.CheckBox;
15import android.widget.NumberPicker;32import android.widget.NumberPicker;
16import android.widget.TextView;
1733
18/**34/**
19 * A text picker dialog that prompts the user for to select one of the text options35 * A text picker dialog that prompts the user for to select one of the text options
2036
=== modified file 'src/com/canonical/ubuntu/installer/UbuntuInstallService.java'
--- src/com/canonical/ubuntu/installer/UbuntuInstallService.java 2014-01-06 15:07:12 +0000
+++ src/com/canonical/ubuntu/installer/UbuntuInstallService.java 2014-06-09 11:59:50 +0000
@@ -1,7 +1,25 @@
1/*
2 * This file is part of Ubuntu dualboot installer for Android.
3 * Copyright 2013 Canonical Ltd.
4 *
5 * Ubuntu dualboot installer is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation.
8 *
9 * Ubuntu dualboot installer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Ubuntu dualboot installer. If not, see <http://www.gnu.org/licenses/>.
16 */
17
1package com.canonical.ubuntu.installer;18package com.canonical.ubuntu.installer;
219
3import java.io.DataOutputStream;20import java.io.DataOutputStream;
4import java.io.File;21import java.io.File;
22import java.io.FileFilter;
5import java.io.FileNotFoundException;23import java.io.FileNotFoundException;
6import java.io.FileOutputStream;24import java.io.FileOutputStream;
7import java.io.IOException;25import java.io.IOException;
@@ -22,18 +40,49 @@
22import org.json.JSONTokener;40import org.json.JSONTokener;
2341
24import com.canonical.ubuntu.installer.JsonChannelParser.Image;42import com.canonical.ubuntu.installer.JsonChannelParser.Image;
25import com.canonical.ubuntu.installer.VersionInfo.ReleaseType;
2643
44import android.annotation.SuppressLint;
27import android.app.IntentService;45import android.app.IntentService;
46import android.app.Notification;
47import android.app.NotificationManager;
48import android.app.PendingIntent;
28import android.content.Context;49import android.content.Context;
29import android.content.Intent;50import android.content.Intent;
51import android.content.IntentFilter;
30import android.content.SharedPreferences;52import android.content.SharedPreferences;
53import android.net.ConnectivityManager;
54import android.net.NetworkInfo;
55import android.net.wifi.WifiManager;
56import android.os.BatteryManager;
57import android.os.Binder;
58import android.os.Build;
59import android.os.IBinder;
31import android.os.PowerManager;60import android.os.PowerManager;
32import android.util.Log;61import android.util.Log;
33import android.webkit.URLUtil;62import android.webkit.URLUtil;
3463
35public class UbuntuInstallService extends IntentService {64public class UbuntuInstallService extends IntentService {
36 private static final String TAG = "UbuntuInstallService";65 private static final String TAG = "UbuntuInstallService";
66
67 // =================================================================================================
68 // Behaviour constants
69 // =================================================================================================
70 // Default update server address
71 public static final String SERVER_URL = "http://system-image.ubuntu.com";
72 // Flag if channel list should also include hidden channels
73 private static final boolean INCLUDE_HIDDEN = false;
74 // Flag if channel list should include saucy channels
75 private static final boolean INCLUDE_SAUCY = false;
76 // How often service should check for update for normal channel
77 public static final int UPDATE_CHECK_ALARM_HOURS = 48; // every 2 days
78 // How often service should check for update for proposed channel
79 public static final int UPDATE_CHECK_PROPOSED_ALARM_HOURS = 10; // every 10 hours
80
81 // Minimum battery charge in % for install to progress
82 public static final int MIN_INSTALL_BATTERY_CHARGE = 30;
83
84 // Bring up mode, support any device
85 public static final boolean BRINGUP_MODE = false;
37 86
38 // =================================================================================================87 // =================================================================================================
39 // Shared preferences88 // Shared preferences
@@ -41,14 +90,41 @@
41 public final static String SHARED_PREF = "UInstallerPref";90 public final static String SHARED_PREF = "UInstallerPref";
42 // Key for string value: absolute path to update file91 // Key for string value: absolute path to update file
43 public final static String PREF_KEY_UPDATE_COMMAND = "update_command";92 public final static String PREF_KEY_UPDATE_COMMAND = "update_command";
44 // Key for String set value: version information: alias, Json, version, description 93
45 private final static String PREF_KEY_DOWNLOADED_VERSION = "d_version";94 // Key strings describing active download
46 // Key for String set value: version information: alias, Json, version, description95 public final static String PREF_KEY_DOWNLOAD_ACTIVE = "d_active";
47 private final static String PREF_KEY_INSTALLED_VERSION = "i_version";96 public final static String PREF_KEY_DOWNLOAD_SERVER = "server_url";
97 public final static String PREF_KEY_DOWNLOAD_CHANNEL = "channel_json";
98 public final static String PREF_KEY_DOWNLOAD_BOOTSTRAP = "bootstrap";
99 public final static String PREF_KEY_DOWNLOAD_VERSION = "d_version";
100 public final static String PREF_KEY_DOWNLOAD_TYPE = "d_type";
101 public final static String PREF_KEY_DOWNLOAD_COMPLETED = "d_completed";
102
103 // Key strings describing installed version
104 public static final String PREF_KEY_VERSION_NUMBER = "version_number";
105 public static final String PREF_KEY_VERSION_CHANNEL = "version_channel";
106 public static final String PREF_KEY_VERSION_CHANNEL_TARGET = "version_channel_target";
107 public static final String PREF_KEY_VERSION_DESCRIPTION = "version_description";
108 public static final String PREF_KEY_VERSION_BASE = "version_base";
109
110 public static final String PREF_KEY_UBUNTU_INSTALLED = "u_installed";
111
112 // Key for pending update, type boolean
113 public static final String PREF_KEY_PENDING_UPDATE = "pending_update";
114
115 // Key for android update notification being dismissed, type boolean
116 public static final String PREF_KEY_ANDROID_UPDATE_DISMISSED = "android_u_dismissed";
117
48 // Key for boolean value: true if developer option is enabled118 // Key for boolean value: true if developer option is enabled
49 public final static String PREF_KEY_DEVELOPER = "developer";119 public final static String PREF_KEY_DEVELOPER = "developer";
50 // Key for int value: estimated number of checkpoints for installation120
51 public final static String PREF_KEY_ESTIMATED_CHECKPOINTS = "est_checkpoints";121 // Kyes describing occupied storage space, all values are stored as string
122 // key for int value: rootfs size in MB
123 public final static String PREF_KEY_SIZE_ROOTFS = "size_rootfs";
124 // key for int value: system data size in MB
125 public final static String PREF_KEY_SIZE_SYSTEM_DATA = "size_system_data";
126 // key for int value: user data size in MB
127 public final static String PREF_KEY_SIZE_USER_DATA = "size_user_data";
52 128
53 // =================================================================================================129 // =================================================================================================
54 // Default values to be used130 // Default values to be used
@@ -70,66 +146,69 @@
70 public final static String MAKO_PARTITION_RECOVERY = "/dev/block/platform/msm_sdcc.1/by-name/recovery";146 public final static String MAKO_PARTITION_RECOVERY = "/dev/block/platform/msm_sdcc.1/by-name/recovery";
71 public final static String MANTA_PARTITION_BOOT = "/dev/block/platform/dw_mmc.0/by-name/boot";147 public final static String MANTA_PARTITION_BOOT = "/dev/block/platform/dw_mmc.0/by-name/boot";
72 public final static String MANTA_PARTITION_RECOVERY = "/dev/block/platform/dw_mmc.0/by-name/recovery";148 public final static String MANTA_PARTITION_RECOVERY = "/dev/block/platform/dw_mmc.0/by-name/recovery";
149 public final static String DEFAULT_PARTITION_BOOT = "/dev/bootimg"; // this is used for bringup devices
150 public final static String DEFAULT_PARTITION_RECOVERY = "/dev/recovery"; // this is used for bringup devices
151
152
153 // =================================================================================================
154 // Ubuntu parts
155 // =================================================================================================
156 public static final String UBUNTU_ROOTFS = "/data/system.img";
157 public static final String UBUNTU_SYSTEM_DATA = "/data/system-data";
158 public static final String UBUNTU_USER_DATA = "/data/user-data";
73 159
74 // =================================================================================================160 // =================================================================================================
75 // Service Actions161 // Service Actions
162 public static final String BASE_PACKAGE = "com.canonical.ubuntuinstaller.UbuntuInstallService.";
76 // =================================================================================================163 // =================================================================================================
77 // Get list of channels164 // Get list of channels
78 public static final String GET_CHANNEL_LIST = "com.canonical.ubuntuinstaller.UbuntuInstallService.GET_CHANNEL_LIST";165 public static final String GET_CHANNEL_LIST = BASE_PACKAGE + "GET_CHANNEL_LIST";
166 public static final String GET_CHANNEL_LIST_EXTRA_SERVER_URL = "url"; // string
79 // Download latest release from given channel167 // Download latest release from given channel
80 public static final String DOWNLOAD_RELEASE = "com.canonical.ubuntuinstaller.UbuntuInstallService.DOWNLOAD_RELEASE";168 public static final String DOWNLOAD_RELEASE = BASE_PACKAGE + "DOWNLOAD_RELEASE";
81 public static final String DOWNLOAD_RELEASE_EXTRA_CHANNEL_ALIAS = "alias"; // string169 public static final String DOWNLOAD_RELEASE_EXTRA_SERVER_URL = "url_server"; // string
82 public static final String DOWNLOAD_RELEASE_EXTRA_CHANNEL_URL = "url"; // string170 public static final String DOWNLOAD_RELEASE_EXTRA_CHANNEL_URL = "url_channel"; // string
83 public static final String DOWNLOAD_RELEASE_EXTRA_BOOTSTRAP = "bootstrap"; // boolean171 public static final String DOWNLOAD_RELEASE_EXTRA_BOOTSTRAP = "bootstrap"; // boolean
84 public static final String DOWNLOAD_RELEASE_EXTRA_VERSION = "version"; // int172 public static final String DOWNLOAD_RELEASE_EXTRA_VERSION = "version"; // int
85 public static final String DOWNLOAD_RELEASE_EXTRA_TYPE = "type"; // JsonChannelParser.ReleaseType173 public static final String DOWNLOAD_RELEASE_EXTRA_TYPE = "type"; // JsonChannelParser.ReleaseType
86 public static final String CANCEL_DOWNLOAD = "com.canonical.ubuntuinstaller.UbuntuInstallService.CANCEL_DOWNLOAD";174 public static final String DOWNLOAD_UPDATE = BASE_PACKAGE + "DOWNLOAD_UPDATE";
87 public static final String PAUSE_DOWNLOAD = "com.canonical.ubuntuinstaller.UbuntuInstallService.PAUSE_DOWNLOAD";175 public static final String RESUME_DOWNLOAD = BASE_PACKAGE + "RESUME_DOWNLOAD";
88 public static final String RESUME_DOWNLOAD = "com.canonical.ubuntuinstaller.UbuntuInstallService.RESUME_DOWNLOAD";176 public static final String DELETE_DOWNLOAD = BASE_PACKAGE + "DELETE_DOWNLOAD";
89 public static final String CLEAN_DOWNLOAD = "com.canonical.ubuntuinstaller.UbuntuInstallService.CLEAN_DOWNLOADED";177 public static final String INSTALL_UBUNTU = BASE_PACKAGE + "INSTALL_UBUNTU";
90 public static final String INSTALL_UBUNTU = "com.canonical.ubuntuinstaller.UbuntuInstallService.INSTALL_UBUNTU";178 public static final String UNINSTALL_UBUNTU = BASE_PACKAGE + "UINSTALL_UBUNTU";
91 public static final String CANCEL_INSTALL = "com.canonical.ubuntuinstaller.UbuntuInstallService.CANCEL_INSTALL";179 public static final String UNINSTALL_UBUNTU_EXTRA_REMOVE_USER_DATA = "user_data";
92 public static final String UNINSTALL_UBUNTU = "com.canonical.ubuntuinstaller.UbuntuInstallService.UINSTALL_UBUNTU";180 public static final String DELETE_UBUNTU_USER_DATA = BASE_PACKAGE + "DELETE_UBUNTU_USER_DATA";
93 public static final String IS_UBUNTU_UPGRADABLE = "com.canonical.ubuntuinstaller.UbuntuInstallService.IS_UBUNTU_UPGRADABLE";181 public static final String REBOOT_UBUNTU = BASE_PACKAGE + "REBOOT_UBUNTU";
94 public static final String UNINSTALL_UBUNTU_EXTRA_REMOVE_USER_DATA = "user_data";182 public static final String UPDATE_STORAGE_USE = BASE_PACKAGE + "UPDATE_STORAGE_USE";
95 public static final String CHECK_FOR_UPDATE = "com.canonical.ubuntuinstaller.UbuntuInstallService.CHECK_FOR_UPDATE";183 public static final String CHECK_IF_UPDATE_AVAILABLE = BASE_PACKAGE + "CHECK_IF_UPDATE_AVAILABLE";
96 public static final String DELETE_UBUNTU_USER_DATA = "com.canonical.ubuntuinstaller.UbuntuInstallService.DELETE_USER_DATA";184 public static final String CHECK_PENDING_UPDATES = BASE_PACKAGE + "CHECK_PENDING_UPDATES";
97 public static final String GET_SERVICE_STATE = "com.canonical.ubuntuinstaller.UbuntuInstallService.GET_SERVICE_STATE";185 public static final String PREPARE_ANDROID_UPDATE = BASE_PACKAGE + "PREPARE_ANDROID_UPDATE";
98 public static final String GET_PROGRESS_STATUS = "com.canonical.ubuntuinstaller.UbuntuInstallService.GET_PROGRESS_STATUS";
99 public static final String REBOOT_UBUNTU = "com.canonical.ubuntuinstaller.UbuntuInstallService.REBOOT_UBUNTU";
100186
101 // =================================================================================================187 // =================================================================================================
102 // Service broadcast188 // Service broadcast
103 // =================================================================================================189 // =================================================================================================
104 public static final String SERVICE_STATE = "com.canonical.ubuntuinstaller.UbuntuInstallService.SERVICE_STATE";190 public static final String SERVICE_STATE_CHANGED = BASE_PACKAGE + "SERVICE_STATE";
105 public static final String SERVICE_STATE_EXTRA_STATE = "state"; // InstallerState enum191 public static final String AVAILABLE_CHANNELS = BASE_PACKAGE + "AVAILABLE_CHANNELS";
106 public static final String AVAILABLE_CHANNELS = "com.canonical.ubuntuinstaller.UbuntuInstallService.AVAILABLE_CHANNELS";192 public static final String AVAILABLE_CHANNELS_EXTRA_CHANNELS = "channels"; // HashMap<String,String> channel aliases and json url
107 public static final String AVAILABLE_CHANNELS_EXTRA_CHANNELS = "channels"; // HashMap<String,String> channel aliases and json url193 public static final String DOWNLOAD_RESULT = BASE_PACKAGE + "DOWNLOAD_RESULT";
108 public static final String DOWNLOAD_RESULT = "com.canonical.ubuntuinstaller.UbuntuInstallService.DOWNLOAD_RESULT";194 public static final String DOWNLOAD_RESULT_EXTRA_INT = "res_int"; // 0-success, -1 fail
109 public static final String DOWNLOAD_RESULT_EXTRA_INT = "res_int"; // 0-success, -1 fail195 public static final String DOWNLOAD_RESULT_EXTRA_STR = "res_str"; // empty for success, or error text
110 public static final String DOWNLOAD_RESULT_EXTRA_STR = "res_str"; // empty for success, or error text196 public static final String PROGRESS = BASE_PACKAGE + "PROGRESS";
111 public static final String PROGRESS = "com.canonical.ubuntuinstaller.UbuntuInstallService.PROGRESS";197 public static final String PROGRESS_OUPUT = BASE_PACKAGE + "PROGRESS_OUTPUT";
112 public static final String PROGRESS_EXTRA_TEXT = "text"; // value will carry name of file currently downloaded 198 public static final String INSTALL_RESULT = BASE_PACKAGE + "INSTALL_COMPLETED";
113 public static final String PROGRESS_EXTRA_INT = "progress"; // value between 0-100 of current progress199 public static final String INSTALL_RESULT_EXTRA_INT = "res_int"; // 0-success, -1 fail
114 public static final String INSTALL_RESULT = "com.canonical.ubuntuinstaller.UbuntuInstallService.INSTALL_COMPLETED";200 public static final String INSTALL_RESULT_EXTRA_STR = "res_str"; // empty for success, or error text
115 public static final String INSTALL_RESULT_EXTRA_INT = "res_int"; // 0-success, -1 fail201 public static final String STORAGE_USE_UPDATED = BASE_PACKAGE + "STORAGE_USE_UPDATED";
116 public static final String INSTALL_RESULT_EXTRA_STR = "res_str"; // empty for success, or error text202 public static final String ANDROID_UPDATE_PENDING = BASE_PACKAGE + "ANDROID_UPDATE";
117 public static final String VERSION_UPDATE = "com.canonical.ubuntuinstaller.UbuntuInstallService.VERSION_UPDATE";203 public static final String UBUNTU_UPDATE_PENDING = BASE_PACKAGE + "UBUNTU_UPDATE_PENDING";
118 public static final String VERSION_UPDATE_EXTRA_VERSION = "version"; // int new version204 public static final String UBUNTU_UPDATE_AVAILABLE = BASE_PACKAGE + "UBUNTU_UPDATE_AVAILABLE";
119 public static final String VERSION_UPDATE_EXTRA_DESCRIPTION = "description"; // string
120 public static final String VERSION_UPDATE_EXTRA_ALIAS = "alias"; // string
121 205
122 // =================================================================================================206 // =================================================================================================
123 // Download url strings207 // Other constants
124 // =================================================================================================208 // =================================================================================================
125 public static final String BASE_URL = "http://system-image.ubuntu.com";
126 private static final String CHANNELS_JSON = "/channels.json";209 private static final String CHANNELS_JSON = "/channels.json";
127 private static final String URL_IMAGE_MASTER = "gpg/image-master.tar.xz";210 // 2G for file system
128 private static final String URL_IMAGE_SIGNING = "gpg/image-signing.tar.xz";211 private static long INSTALL_SIZE_REQUIRED = 2048L * 1024L * 1024L;
129 private static final String ASC_SUFFIX = ".asc";
130
131 // 2G for file system, 512M for swap.
132 private static long INSTALL_SIZE_REQUIRED = (2048L + 512L) * 1024L * 1024L;
133 // 15M extra space to keep it safe.212 // 15M extra space to keep it safe.
134 private static long EXTRA_SIZE_REQUIRED = 15 * 1024 * 1024;213 private static long EXTRA_SIZE_REQUIRED = 15 * 1024 * 1024;
135214
@@ -138,7 +217,7 @@
138 * State of the service 217 * State of the service
139 */218 */
140 public enum InstallerState {219 public enum InstallerState {
141 READY, FETCHING_CHANNELS, DOWNLOADING, INSTALLING, UNINSTALLING, DELETING_USER_DATA;220 READY, FETCHING_CHANNELS, DOWNLOADING, INSTALLING, UNINSTALLING, DELETING_USER_DATA, CALCULATING_USAGE;
142 public static InstallerState fromOrdian(int ordianl) {221 public static InstallerState fromOrdian(int ordianl) {
143 return InstallerState.values()[ordianl];222 return InstallerState.values()[ordianl];
144 }223 }
@@ -152,53 +231,76 @@
152 private static final String TAR = "u_tar";231 private static final String TAR = "u_tar";
153 private static final String ANDROID_LOOP_MOUNT = "aloopmount";232 private static final String ANDROID_LOOP_MOUNT = "aloopmount";
154 private static final String ANDROID_BOOTMGR = "bootmgr";233 private static final String ANDROID_BOOTMGR = "bootmgr";
155 private static final String UPGRADECHECKER = "upgrade-checker";
156 private static final String UPDATE_SCRIPT = "system-image-upgrader";234 private static final String UPDATE_SCRIPT = "system-image-upgrader";
157 private static final String ARCHIVE_MASTER = "archive-master.tar.xz";235 public static final String U_REBOOT_APP = "u-reboot-app.tar.xz";
158 private static final String ARCHIVE_MASTER_ASC = "archive-master.tar.xz.asc";236 public static final String RECOVERY_REMOUNT = "recovery-remount.tar.xz";
159 private static final String U_REBOOT_APP = "u-reboot-app.tar.xz";
160 private static final String U_REBOOT_APP_ASC = "u-reboot-app.tar.xz.asc";
161237
162 // =================================================================================================238 // =================================================================================================
163 // Update command file constants239 // Update command file constants
164 // =================================================================================================240 // =================================================================================================
165 private static final String UPDATE_COMMAND = "update_command";241 public static final String UPDATE_COMMAND = "update_command";
166 private static final String COMMAND_FORMAT = "format";242 public static final String COMMAND_FORMAT = "format";
167 private static final String COMMAND_MOUNT = "mount";243 public static final String COMMAND_MOUNT = "mount";
168 private static final String COMMAND_UMOUNT = "unmount";244 public static final String COMMAND_UMOUNT = "unmount";
169 private static final String COMMAND_LOAD_KEYRING = "load_keyring";245 public static final String COMMAND_UPDATE = "update";
170 private static final String COMMAND_UPDATE = "update";246 public static final String PARTITION_DATA = "data";
171 private static final String PARTITION_DATA = "data";247 public static final String PARTITION_SYSTEM = "system";
172 private static final String PARTITION_SYSTEM = "system";
173 248
174 // other constants249 // other constants
250 public static final String CUSTOM_SERVER="custom_server";
175 private static final String RELEASE_FOLDER = "/ubuntu_release";251 private static final String RELEASE_FOLDER = "/ubuntu_release";
252 private static final String LINKED_UPGRADER_COMMAND = "recovery/ubuntu_command";
253 private static final String PENDING_ANDROID_UPDATE = "android_update";
176 private static final String TEMP_FOLDER = "/uTemp";254 private static final String TEMP_FOLDER = "/uTemp";
177 private static final int PROGRESS_UBUNTU_ADJUSTMENT = 563979;255 private static final int PROGRESS_UBUNTU_ADJUSTMENT = 563979;
178 private static final int PROGRESS_DEVICE_ADJUSTMENT = 651093;256 private static final int PROGRESS_DEVICE_ADJUSTMENT = 651093;
179 private static final int PROGRESS_CUSTOM_ADJUSTMENT = 2036039;257 private static final int PROGRESS_CUSTOM_ADJUSTMENT = 2036039;
180 private static final int PROGRESS_SWAP_CREATION_ADJUSTMENT = 85; // equivalent of time tar --checkpoint=200
181 private static final int PROGRESS_MKSWAP_ADJUSTMENT = 17; // equivalent of time tar --checkpoint=200
182 private PowerManager mPowerManager;
183 private PowerManager.WakeLock mWakeLock;258 private PowerManager.WakeLock mWakeLock;
184 // FIXME make workPath in Cache a private function259 private WifiManager.WifiLock mWifiLock;
185 private boolean workPathInCache = false;
186 private String mRootOfWorkPath;
187 private volatile boolean mIsCanceled;260 private volatile boolean mIsCanceled;
261 private boolean mBringup;
188 262
189 // progress values263 // progress values
190 private long mProgress; // so far handled amount downloaded/processed 264 private long mProgress; // so far handled amount downloaded/processed
191 private int mLastSignalledProgress;265 private int mLastSignalledProgress;
266 private String mActionOutput;
192 private long mTotalSize; // calculated267 private long mTotalSize; // calculated
193 private InstallerState mInstallerState;268 private InstallerState mServiceState;
269 private File mReleaseFolder;
270 private SharedPreferences mSharedPreferences;
271 private Notification mUbuntuNotification;
272 private Notification mUbuntuUpdateNotification;
273 private Notification mUbuntuProgressNotification;
274 private Notification mAndroidUpdateNotification;
275 NotificationManager mNotificationManager;
194 276
195 public class Channel {277 public enum ReleaseType {
196 String alias;278 FULL(0),
197 File[] files;279 DELTA(1),
198 boolean hiden;280 UNKNOWN(2);
281 private final int value;
282
283 private ReleaseType(final int newValue) {
284 value = newValue;
285 }
286
287 public int getValue() {
288 return value;
289 }
290
291 public static ReleaseType fromValue(final int value) {
292 switch (value) {
293 case 0: // FULL
294 return FULL;
295 case 1: // DELTA
296 return DELTA;
297 }
298 return UNKNOWN;
299 }
199 };300 };
200 301
201 class ECancelException extends Exception {302 class ECancelException extends Exception {
303 private static final long serialVersionUID = 1L;
202 long mDownloadedSize;304 long mDownloadedSize;
203 305
204 public ECancelException(long downloadedSize){306 public ECancelException(long downloadedSize){
@@ -208,6 +310,8 @@
208 };310 };
209311
210 class ESumNotMatchException extends Exception {312 class ESumNotMatchException extends Exception {
313 private static final long serialVersionUID = 1L;
314
211 public ESumNotMatchException(){315 public ESumNotMatchException(){
212 super();316 super();
213 }317 }
@@ -218,6 +322,7 @@
218 };322 };
219323
220 class EShellExecException extends Exception {324 class EShellExecException extends Exception {
325 private static final long serialVersionUID = 1L;
221 public EShellExecException(){326 public EShellExecException(){
222 super();327 super();
223 }328 }
@@ -228,134 +333,195 @@
228 };333 };
229334
230 public UbuntuInstallService() {335 public UbuntuInstallService() {
231 super(TAG);336 super(UbuntuInstallService.class.getName());
232 }337 }
338
339 /**
340 * Class for clients to get hold of this service
341 * this only works as long as service runs in same process as client
342 */
343 public class LocalBinder extends Binder {
344 UbuntuInstallService getService() {
345 return UbuntuInstallService.this;
346 }
347 }
348
349 @Override
350 public IBinder onBind(Intent intent) {
351 return mBinder;
352 }
353 private final IBinder mBinder = new LocalBinder();
233354
234 @Override355 @Override
235 public void onCreate() {356 public void onCreate() {
236 super.onCreate();357 super.onCreate();
237 mPowerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);358 mReleaseFolder = new File(getFilesDir(), RELEASE_FOLDER);
238 // SharedPreferences sharedPref = this.getSharedPreferences(, MODE_PRIVATE);359 mServiceState = InstallerState.READY;
239 // do we have cache permissions?360 mSharedPreferences = getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE);
240 File testDir = new File("/cache/testDir");361 mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
241 if (testDir.mkdir()) {362 mWakeLock = ((PowerManager)getSystemService(Context.POWER_SERVICE))
242 testDir.delete();363 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ubuntu-dualboot");
243 mRootOfWorkPath = "/cache";364 WifiManager wm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
244 workPathInCache = true;365 mWifiLock = wm.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, TAG);
245 } else {366 mBringup = Utils.isBringupMode();
246 mRootOfWorkPath = getFilesDir().toString(); // "/data/data/com.canonical.ubuntu.installer/files";367 }
247 workPathInCache = false;368
248 }369 /**
249 mInstallerState = InstallerState.READY;370 * Get service state
250 }371 * @return service state
251372 */
252 @Override373 public InstallerState getServiceState(){
253 public int onStartCommand(Intent intent, int flags, int startId) {374 return mServiceState;
254 // if service is not in ready state, handle specific requests here375 }
255 if (mInstallerState != InstallerState.READY) {376
256 String action = intent.getAction(); 377 /**
257 if (action.equals(CANCEL_DOWNLOAD)) {378 * Get ongoing action progress
258 // set the cancel flag, but let it remove downloaded files on worker thread379 * @return last known progress
259 mIsCanceled = true;380 */
260 } else if (action.equals(GET_PROGRESS_STATUS)) {381 public int getActionProgress() {
261 broadcastProgress(mLastSignalledProgress, ""); 382 return mLastSignalledProgress;
262 } else if (action.equals(GET_SERVICE_STATE)) {383 }
263 broadcastInstallerState();384
264 }385 /**
265 }386 * Pause ongoing download
266 return super.onStartCommand(intent, flags, startId);387 */
267 }388 public void pauseDownload() {
268 389 if (mServiceState == InstallerState.DOWNLOADING) {
390 mIsCanceled = true;
391 }
392 }
393
394 /**
395 * Get action output
396 * @return action output buffer
397 */
398 public String getActionOutput() {
399 return mActionOutput;
400 }
401
402 /**
403 * Reset action output buffer
404 */
405 public void resetActionOutput() {
406 mActionOutput = "";
407 }
408
269 @Override409 @Override
270 protected void onHandleIntent(Intent intent) {410 protected void onHandleIntent(Intent intent) {
411 // reset progress for new action
412 if (intent == null) {
413 // ignore
414 return;
415 }
416 mLastSignalledProgress = 0;
271 String action = intent.getAction();417 String action = intent.getAction();
418 String debugAction = action;
419 if (action.startsWith(BASE_PACKAGE)) {
420 debugAction = action.substring(BASE_PACKAGE.length());
421 }
422 Log.d(TAG, "onHandleIntent<<: " + debugAction);
272 Intent result = null;423 Intent result = null;
273
274 Log.d(TAG, this.toString() + " onHandleIntent: " + action);
275 if (action.equals(GET_CHANNEL_LIST)) {424 if (action.equals(GET_CHANNEL_LIST)) {
276 updateInstallerState(InstallerState.FETCHING_CHANNELS);425 updateInstallerState(InstallerState.FETCHING_CHANNELS);
277 result = doGetChannelList(intent);426 result = getChannelList(intent);
278 } else if (action.equals(DOWNLOAD_RELEASE)) {427 } else if (action.equals(DOWNLOAD_RELEASE)) {
279 updateInstallerState(InstallerState.DOWNLOADING);428 updateInstallerState(InstallerState.DOWNLOADING);
280 result = doDownloadRelease(intent);429 result = downloadRelease(intent);
281 } else if (action.equals(CANCEL_DOWNLOAD)) {430 } else if (action.equals(DOWNLOAD_UPDATE)) {
282 // download should be already cancelled, don't delete files for might resume latter431 updateInstallerState(InstallerState.DOWNLOADING);
283 // result = doRemoreDownload(intent);432 result = downloadUpdate();
284 result = new Intent(SERVICE_STATE);
285 result.putExtra(SERVICE_STATE_EXTRA_STATE, mInstallerState.ordinal());
286 } else if (action.equals(PAUSE_DOWNLOAD)) {
287 // TODO: handle download
288 } else if (action.equals(RESUME_DOWNLOAD)) {433 } else if (action.equals(RESUME_DOWNLOAD)) {
289 updateInstallerState(InstallerState.DOWNLOADING);434 updateInstallerState(InstallerState.DOWNLOADING);
290 // TODO: handle download435 result = resumeDownload();
291 } else if (action.equals(CLEAN_DOWNLOAD)) {436 } else if (action.equals(DELETE_DOWNLOAD)) {
292 result = doRemoreDownload(intent);437 doDeleteDownloadedRelease();
293 } else if (action.equals(INSTALL_UBUNTU)) {438 } else if (action.equals(INSTALL_UBUNTU)) {
294 updateInstallerState(InstallerState.INSTALLING);439 updateInstallerState(InstallerState.INSTALLING);
295 result = doInstallUbuntu(intent);440 result = doInstallUbuntu();
296 } else if (action.equals(IS_UBUNTU_UPGRADABLE)) {441 } else if (action.equals(CHECK_PENDING_UPDATES)) {
297 // check if the upgradeable images available.442 // check if the upgradeable images available.
298 if(findInstallCommand()) {443 findPendingUpdates();
299 Log.d(TAG, "There is a upgradeable file. send VERSION_UPDATE");444 } else if (action.equals(CHECK_IF_UPDATE_AVAILABLE)) {
300 result = new Intent(VERSION_UPDATE);445 checkForAvailableUpdate();
301 }
302 } else if (action.equals(CANCEL_INSTALL)) {
303 // install should be already cancelled, try to delete it now
304 updateInstallerState(InstallerState.UNINSTALLING);
305 result = doUninstallUbuntu(intent);
306 } else if (action.equals(UNINSTALL_UBUNTU)) {446 } else if (action.equals(UNINSTALL_UBUNTU)) {
307 updateInstallerState(InstallerState.UNINSTALLING);447 updateInstallerState(InstallerState.UNINSTALLING);
308 result = doUninstallUbuntu(intent);448 doUninstallUbuntu(intent);
309 } else if (action.equals(DELETE_UBUNTU_USER_DATA)) { 449 } else if (action.equals(DELETE_UBUNTU_USER_DATA)) {
310 updateInstallerState(InstallerState.DELETING_USER_DATA);450 updateInstallerState(InstallerState.DELETING_USER_DATA);
311 result = doDeleteUbuntuUserData(intent);451 deleteUbuntuUserData();
312 } else if(action.equals(REBOOT_UBUNTU)) {452 } else if(action.equals(REBOOT_UBUNTU)) {
313 Log.d(TAG, this.toString() + ": REBOOT_UBUNTU");453 rebootToUbuntu();
314 doReboot(intent);454 return;
315 return;455 } else if (action.equals(PREPARE_ANDROID_UPDATE)) {
456 prepareAndroidUpdate();
457 return;
458 } else if (action.equals(UPDATE_STORAGE_USE)) {
459 updateInstallerState(InstallerState.CALCULATING_USAGE);
460 doUpdateStorageUse();
316 } else {461 } else {
317 // for any other request broadcast service state462 // for any other request broadcast service state
318 result = new Intent(SERVICE_STATE);463 result = new Intent(SERVICE_STATE_CHANGED);
319 result.putExtra(SERVICE_STATE_EXTRA_STATE, mInstallerState.ordinal());
320 }464 }
321 if (result != null) {465 if (result != null) {
322 sendBroadcast(result);466 sendBroadcast(result);
323 }467 }
324 updateInstallerState(InstallerState.READY);468 updateInstallerState(InstallerState.READY);
325 Log.d(TAG, this.toString() + " onHandleIntent: " + action + " END");469 Log.d(TAG, " onHandleIntent>>: " + debugAction);
326 }470 }
327471
328 private Intent doGetChannelList(Intent intent) {472 private Intent getChannelList(Intent intent) {
473 String serverUrl = intent.getStringExtra(GET_CHANNEL_LIST_EXTRA_SERVER_URL);
474 if (serverUrl == null) {
475 // use default server
476 serverUrl = Utils.getReleaseServerUrl(this);;
477 }
478 boolean includeProposed = mSharedPreferences.getBoolean(PREF_KEY_DEVELOPER, false);
479 HashMap<String, String> channels = doGetChannels(serverUrl, true, INCLUDE_SAUCY, INCLUDE_HIDDEN, includeProposed );
329 Intent result = new Intent(AVAILABLE_CHANNELS);480 Intent result = new Intent(AVAILABLE_CHANNELS);
330481 result.putExtra(AVAILABLE_CHANNELS_EXTRA_CHANNELS, channels);
331 HashMap<String, String> channels= new HashMap<String, String>();482 return result;
332 boolean includeHidden = getSharedPreferences( SHARED_PREF, Context.MODE_PRIVATE).getBoolean(PREF_KEY_DEVELOPER, false);483 }
484
485 private HashMap<String, String> doGetChannels( String serverAddress,
486 boolean friendlyName,
487 boolean includeSaucy,
488 boolean includeHiden,
489 boolean includeProposed) {
490 HashMap<String, String> channels = new HashMap<String, String>();
333 String deviceModel = Utils.getDeviceModel();491 String deviceModel = Utils.getDeviceModel();
334 String channelJsonStr = Utils.httpDownload(BASE_URL + CHANNELS_JSON);492 String channelJsonStr = Utils.httpDownload(serverAddress + CHANNELS_JSON);
335 if (channelJsonStr != null) {493 if (channelJsonStr != null) {
336 JSONObject list;494 JSONObject list;
337 try {495 try {
338 list = (JSONObject) new JSONTokener(channelJsonStr).nextValue();496 list = (JSONObject) new JSONTokener(channelJsonStr).nextValue();
497 @SuppressWarnings("unchecked")
339 Iterator<String> keys = list.keys();498 Iterator<String> keys = list.keys();
340 while(keys.hasNext()){499 while(keys.hasNext()){
341 String key = keys.next();500 String key = keys.next();
342 JSONObject channel = list.optJSONObject(key);501 final JSONObject channel = list.optJSONObject(key);
343 if (channel != null) {502 if (channel != null) {
344 JSONObject devices = channel.optJSONObject("devices");503 final JSONObject devices = channel.optJSONObject("devices");
345 if (devices != null) {504 if (devices != null) {
346 JSONObject device = devices.optJSONObject(deviceModel);505 final JSONObject device = devices.optJSONObject(deviceModel);
347 if (device != null) {506 if (device != null) {
348 String url = device.optString("index");507 final String url = device.optString("index");
349 if (url != null) {508 if (url != null) {
350 // bingo, add to list if not hidden or developer509 // bingo, add to list if not hidden or developer
351 boolean hidden = channel.optBoolean("hiden"); // by default not hidden510 final boolean hidden = channel.optBoolean("hidden"); // by default not hidden
352 String alias = channel.optString("alias");511 // try to remove "ubuntu-touch/" so it's more human friendly
353 if (alias == null || alias.equals("")) {512 if (friendlyName && key.startsWith("ubuntu-touch/")) {
354 alias = key; // use key instead513 key = key.substring("ubuntu-touch/".length());
355 }514 }
356 // Log.v(TAG, "Channel:" + alias + " url:" + url); 515 // Log.v(TAG, "Channel:" + key + " url:" + url);
357 if (!hidden || includeHidden) {516 if (
358 channels.put(alias, url);517 ( includeSaucy || ! key.contains("saucy"))
518 && (
519 !hidden
520 || includeHiden
521 || ( includeProposed && key.contains("-proposed"))
522 )
523 ) {
524 channels.put(key, url);
359 }525 }
360 }526 }
361 }527 }
@@ -363,44 +529,29 @@
363 }529 }
364 } 530 }
365 } catch (JSONException e) {531 } catch (JSONException e) {
366 // TODO Auto-generated catch block
367 e.printStackTrace();532 e.printStackTrace();
368 }533 }
369 }534 }
370 result.putExtra(AVAILABLE_CHANNELS_EXTRA_CHANNELS, channels);535 return channels;
371 return result;
372 }536 }
373 537
374 private Intent doRemoreDownload(Intent intent) {538 private Intent doInstallUbuntu() {
375 Intent result = new Intent(SERVICE_STATE);
376 String s = deleteRelease();
377 if (s!= null) {
378 broadcastProgress(-1, s);
379 // delete failed
380 }
381 result.putExtra(SERVICE_STATE, InstallerState.READY.ordinal());
382 return result;
383 }
384
385 private Intent doInstallUbuntu(Intent intent) {
386 Log.w(TAG, "doInstallUbuntu");539 Log.w(TAG, "doInstallUbuntu");
387 Intent result = new Intent(INSTALL_RESULT);540 Intent result = new Intent(INSTALL_RESULT);
388541
389 // get update command file542 // get update command file
390 String updateCommand = getUpdateCommand();543 String updateCommand = getUpdateCommand();
391544 dismissUbuntuNotification();
392 // 1. check if update command exist.545 // check if update command exist.
393 // 2. However, if the udpate command is in "/cache",
394 // the app can not access to /cache sometimes.
395 if (updateCommand.equals("") ||546 if (updateCommand.equals("") ||
396 (!new File(updateCommand).exists() &&547 (!new File(updateCommand).exists())) {
397 !updateCommand.startsWith("/cache"))) {548
398 return handleInstallFail(result, -1, "Missing update command");549 return handleInstallError(result, -1, "Missing update command");
399 }550 }
400551
401 SharedPreferences pref = getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE);552 mTotalSize = estimateCheckpooint(updateCommand);
402 mTotalSize = pref.getInt(PREF_KEY_ESTIMATED_CHECKPOINTS, 0);
403 mLastSignalledProgress = 0;553 mLastSignalledProgress = 0;
554 mProgress = 0;
404555
405 List<String> shellcmds = new ArrayList<String>();556 List<String> shellcmds = new ArrayList<String>();
406 {557 {
@@ -427,37 +578,68 @@
427 UBUNTU_BOOT_IMG,578 UBUNTU_BOOT_IMG,
428 Utils.getRecoveryPartitionPath()579 Utils.getRecoveryPartitionPath()
429 ));580 ));
581 // remove downloaded release
582 shellcmds.add(String.format("rm -rf %s\n", new File(updateCommand).getParent()));
430 shellcmds.add("exit");583 shellcmds.add("exit");
431 }584 }
432585
433 broadcastProgress(-1, "Starting update script - " + updateCommand);586 broadcastProgress("Starting update script - " + updateCommand);
434 try {587 try {
435 int ret = executeSUCommands(shellcmds.toArray(new String[shellcmds.size()]));588 int ret = executeSUCommands(shellcmds.toArray(new String[shellcmds.size()]));
436 result.putExtra(INSTALL_RESULT_EXTRA_INT, ret);589 result.putExtra(INSTALL_RESULT_EXTRA_INT, ret);
437 } catch (EShellExecException e) {590 } catch (EShellExecException e) {
438 return handleInstallFail(result, -1, e.getMessage());591 return handleInstallError(result, -1, e.getMessage());
439 }592 }
440593 Log.d(TAG, "doInstallUbuntu-update script finished");
594 mLastSignalledProgress = 100;
595 handleInstallFinish();
596 return result;
597 }
598
599 /**
600 * Returns true if download or install is update operation
601 * @return
602 */
603 private boolean isUpdate() {
604 // if not defined, default value is DELTA, for updates downloaded by Ubuntu upgrader
605 return ( ReleaseType.DELTA == ReleaseType.fromValue(
606 mSharedPreferences.getInt(PREF_KEY_DOWNLOAD_TYPE, ReleaseType.DELTA.getValue())));
607 }
608
609 private void handleInstallFinish() {
441 // we done.610 // we done.
611 dismissUbuntuUpdateNotification();
442 cleanUpdateCommand();612 cleanUpdateCommand();
443 VersionInfo v = new VersionInfo(pref, PREF_KEY_DOWNLOADED_VERSION);613 checkChannelAddress();
444 v.storeVersion(pref.edit(), PREF_KEY_INSTALLED_VERSION);614 mSharedPreferences.edit()
445 mProgress = 100;615 .putBoolean(PREF_KEY_UBUNTU_INSTALLED, true)
446 return result;616 .putBoolean(PREF_KEY_PENDING_UPDATE, false)
617 .commit();
618 Utils.registerUpdateCheckAlarm(this, mSharedPreferences);
619 // update notifications
620 if ( isUpdate()) {
621 showUbuntuNotification(R.string.notification_update_installed, LaunchActivity.class);
622 } else {
623 showUbuntuNotification(R.string.notification_ubuntu_installed, LaunchActivity.class);
624 }
447 }625 }
448626
449 private Intent handleInstallFail(Intent i, int res, String failReason) {627 private Intent handleInstallError(Intent i, int res, String reason) {
628 mActionOutput += "\n" + reason;
629 if (isUpdate()) {
630 showUbuntuNotification(R.string.notification_installation_failed, LaunchActivity.class);
631 } else {
632 showUbuntuNotification(R.string.notification_installation_failed, InstallActivity.class);
633 }
450 i.putExtra(INSTALL_RESULT_EXTRA_INT, -1);634 i.putExtra(INSTALL_RESULT_EXTRA_INT, -1);
451 i.putExtra(INSTALL_RESULT_EXTRA_STR, failReason);635 i.putExtra(INSTALL_RESULT_EXTRA_STR, reason);
452 // we don't want to unstainll if we failed to install a update.
453 // doUninstallUbuntu(i);
454 return i;636 return i;
455 }637 }
456638
457 private Intent doUninstallUbuntu(Intent intent) {639 private void doUninstallUbuntu(Intent intent) {
458 File workingFolder = new File(mRootOfWorkPath, TEMP_FOLDER);640 mActionOutput = "";
641 File workingFolder = new File(getFilesDir(), TEMP_FOLDER);
459 File updateCommand = new File(workingFolder, UPDATE_COMMAND);642 File updateCommand = new File(workingFolder, UPDATE_COMMAND);
460 Intent result = new Intent(VERSION_UPDATE);
461 boolean removeUserData = intent.getBooleanExtra(UNINSTALL_UBUNTU_EXTRA_REMOVE_USER_DATA, false);643 boolean removeUserData = intent.getBooleanExtra(UNINSTALL_UBUNTU_EXTRA_REMOVE_USER_DATA, false);
462 Log.d(TAG, "doUninstallUbuntu");644 Log.d(TAG, "doUninstallUbuntu");
463645
@@ -476,7 +658,7 @@
476658
477 // 1. force unmount659 // 1. force unmount
478 // 2. restore android recovery partition, and deleted it.660 // 2. restore android recovery partition, and deleted it.
479 // 3. delete system.img and SWAP.img.661 // 3. delete system.img
480 try {662 try {
481 int r = executeSUCommands(663 int r = executeSUCommands(
482 new String[]{664 new String[]{
@@ -492,67 +674,86 @@
492 Utils.getRecoveryPartitionPath()),674 Utils.getRecoveryPartitionPath()),
493 (String.format("rm -f %s/%s || true\n", getFilesDir().toString(), ANDROID_REOCVERY_IMG)),675 (String.format("rm -f %s/%s || true\n", getFilesDir().toString(), ANDROID_REOCVERY_IMG)),
494 ("rm -rf /data/system.img || true\n"),676 ("rm -rf /data/system.img || true\n"),
495 ("rm -rf /data/SWAP.img || true\n"),
496 } );677 } );
497678
498 if (r == 0) {679 if (r == 0) {
499 // delete installed version in preferences680 // delete installed version in preferences
500 cleanUpdateCommand();681 cleanUpdateCommand();
501 VersionInfo.storeEmptyVersion(682 if (removeUserData) {
502 getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE).edit(), PREF_KEY_INSTALLED_VERSION);683 mSharedPreferences.edit()
684 .putInt( PREF_KEY_SIZE_SYSTEM_DATA, 0)
685 .putInt(PREF_KEY_SIZE_USER_DATA, 0)
686 .commit();
687 }
688 setUbuntuUninstalled();
503 }689 }
504 result.putExtra("result", r);
505 } catch (EShellExecException e) {690 } catch (EShellExecException e) {
506 result.putExtra("result", -1);691 // ignore error
507 }692 }
508
509 return result;
510 }693 }
511694
512 private Intent doDeleteUbuntuUserData(Intent intent) {695 private void deleteUbuntuUserData() {
513 Intent result = new Intent(VERSION_UPDATE);696 File workingFolder = new File(getFilesDir(), TEMP_FOLDER);
514 File workingFolder = new File(mRootOfWorkPath, TEMP_FOLDER);
515 File updateCommand = new File(workingFolder, UPDATE_COMMAND);697 File updateCommand = new File(workingFolder, UPDATE_COMMAND);
516698
517 try {699 try {
518 int r = executeSUCommands(new String[]{700 mSharedPreferences.edit()
519 String.format("echo \"%s %s\" > %s\n", COMMAND_FORMAT, PARTITION_DATA, UPDATE_COMMAND),701 .putInt(PREF_KEY_SIZE_SYSTEM_DATA, 0)
702 .putInt(PREF_KEY_SIZE_USER_DATA, 0)
703 .commit();
704
705 executeSUCommands(new String[]{
706 String.format("echo \"%s %s\" > %s\n", COMMAND_FORMAT, PARTITION_DATA, updateCommand.getAbsolutePath()),
520 ("sh " + UPDATE_SCRIPT + " " + updateCommand.getAbsolutePath() + " " + getFilesDir().toString() + "\n")707 ("sh " + UPDATE_SCRIPT + " " + updateCommand.getAbsolutePath() + " " + getFilesDir().toString() + "\n")
521 } );708 } );
522 result.putExtra("result", r);
523 } catch (EShellExecException e) {709 } catch (EShellExecException e) {
524 result.putExtra("fail_description", e.getMessage());710 Log.e(TAG,e.getMessage());
525 result.putExtra("result", -1);
526 }711 }
527 return result;
528 }712 }
529713
530 private void doReboot(Intent intent) {714 private void rebootToUbuntu() {
531 // Reboot to recovery to complete update, try power manager if we have permissions715 // update storage use before reboot
716 doUpdateStorageUse();
532 try {717 try {
533 PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);718 int r = executeSUCommands(new String[] {
534 powerManager.reboot("recovery");719 String.format("%s -b %s/%s %s || true\n",
535 } catch (SecurityException e) {720 ANDROID_BOOTMGR,
536 // FIXME: in Android 4.4, we do not get power manager permission.721 getFilesDir().getAbsolutePath(),
537 // try it with SU permissions722 UBUNTU_BOOT_IMG,
538 try {723 Utils.getRecoveryPartitionPath()),
539 int r = executeSUCommands(new String[] {724 "reboot recovery\n"
540 String.format("%s -b %s/%s %s || true\n",725 });
541 ANDROID_BOOTMGR,726 if(r != 255) {
542 getFilesDir().getAbsolutePath(),727 Utils.showToast(this.getApplicationContext(), "Rebooting to Ubuntu");
543 UBUNTU_BOOT_IMG,728 } else {
544 Utils.getRecoveryPartitionPath()),
545 "reboot recovery\n"
546 });
547 if(r != 255) {
548 Utils.showToast(this.getApplicationContext(), "Rebooting to Ubuntu");
549 } else {
550 Utils.showToast(this.getApplicationContext(), "No permissions to reboot to recovery");
551 }
552 } catch (EShellExecException e1) {
553 Utils.showToast(this.getApplicationContext(), "No permissions to reboot to recovery");729 Utils.showToast(this.getApplicationContext(), "No permissions to reboot to recovery");
554 }730 }
555 }731 } catch (EShellExecException e1) {
732 Utils.showToast(this.getApplicationContext(), "No permissions to reboot to recovery");
733 }
734 }
735
736 /**
737 * Install back original recovery image
738 */
739 private void prepareAndroidUpdate() {
740 try {
741 int r = executeSUCommands(new String[] {
742 String.format("%s -b %s/%s %s || true\n",
743 ANDROID_BOOTMGR,
744 getFilesDir().getAbsolutePath(),
745 ANDROID_REOCVERY_IMG,
746 Utils.getRecoveryPartitionPath())
747 });
748 if(r != 255) {
749 Utils.showToast(this.getApplicationContext(), "Restoring original recovery for Android updates");
750 } else {
751 Utils.showToast(this.getApplicationContext(), "No permissions to restore recovery");
752 }
753 } catch (EShellExecException e1) {
754 Utils.showToast(this.getApplicationContext(), "No permissions to restore recovery");
755 }
756
556 }757 }
557758
558 /**759 /**
@@ -563,16 +764,27 @@
563 * @throws EShellExecException764 * @throws EShellExecException
564 */765 */
565 private int executeSUCommands(String[] commands) throws EShellExecException {766 private int executeSUCommands(String[] commands) throws EShellExecException {
767 mWakeLock.acquire(2 * 60 * 1000); // 2 minutes
768 try {
769 return doExecuteSUCommands(commands);
770 } finally {
771 if (mWakeLock.isHeld() ) {
772 mWakeLock.release();
773 }
774 Log.d(TAG, "executeSUCommands-releasing wakelocks");
775 }
776 }
777
778 private int doExecuteSUCommands(String[] commands) throws EShellExecException {
566 int ret = 0;779 int ret = 0;
567 File rootFolder = new File(mRootOfWorkPath);780 File workingFolder = new File(getFilesDir(), TEMP_FOLDER);
568 File workingFolder = new File(rootFolder, TEMP_FOLDER);
569 String workingFolderPath = workingFolder.getAbsolutePath();781 String workingFolderPath = workingFolder.getAbsolutePath();
570782
571 if (!workingFolder.exists() && !workingFolder.mkdir()) {783 if (!workingFolder.exists() && !workingFolder.mkdir()) {
572 throw(new EShellExecException("Failed to create working folder"));784 throw(new EShellExecException("Failed to create working folder"));
573 }785 }
574786
575 broadcastProgress(0, "Extracting supporting files at " + workingFolder.getAbsolutePath());787 broadcastProgress("Extracting supporting files at " + workingFolder.getAbsolutePath());
576 try {788 try {
577 // extract utils into working folder.789 // extract utils into working folder.
578 Utils.extractExecutableAsset(this, ANDROID_BOOTMGR, workingFolderPath, true);790 Utils.extractExecutableAsset(this, ANDROID_BOOTMGR, workingFolderPath, true);
@@ -581,12 +793,10 @@
581 Utils.extractExecutableAsset(this, GPG, workingFolderPath, true);793 Utils.extractExecutableAsset(this, GPG, workingFolderPath, true);
582 Utils.extractExecutableAsset(this, TAR, workingFolderPath, true);794 Utils.extractExecutableAsset(this, TAR, workingFolderPath, true);
583 Utils.extractExecutableAsset(this, UPDATE_SCRIPT, workingFolderPath, true);795 Utils.extractExecutableAsset(this, UPDATE_SCRIPT, workingFolderPath, true);
584 Utils.extractExecutableAsset(this, UPGRADECHECKER, workingFolderPath, true);
585 } catch (IOException e) {796 } catch (IOException e) {
586 throw(new EShellExecException("Failed to extract supporting utils"));797 throw(new EShellExecException("Failed to extract supporting utils"));
587 }798 }
588799
589 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "shelling");
590 try {800 try {
591 Process process = Runtime.getRuntime().exec("su", null, workingFolder);801 Process process = Runtime.getRuntime().exec("su", null, workingFolder);
592 DataOutputStream os = new DataOutputStream(process.getOutputStream());802 DataOutputStream os = new DataOutputStream(process.getOutputStream());
@@ -615,6 +825,7 @@
615 InputStream es = process.getErrorStream();825 InputStream es = process.getErrorStream();
616 boolean running = true;826 boolean running = true;
617 boolean scriptExecuted = false;827 boolean scriptExecuted = false;
828 long time = System.currentTimeMillis();
618 do {829 do {
619 while( is.available() > 0) {830 while( is.available() > 0) {
620 read = is.read(buff);831 read = is.read(buff);
@@ -623,30 +834,24 @@
623 }834 }
624 scriptExecuted = true;835 scriptExecuted = true;
625 String seg = new String(buff, 0, read);836 String seg = new String(buff, 0, read);
626 Log.i(TAG, "Script Output: " + seg);837
627 broadcastProgress(-1, seg);838 Log.i(TAG, "Time(" + ((System.currentTimeMillis() - time)/1000) + "):Script Output: " + seg);
839 broadcastProgress(seg);
840 scanOutPut(seg);
628 }841 }
629 while( es.available() > 0) {842 while( es.available() > 0) {
630 read = es.read(buff);843 read = es.read(buff);
631 if ( read <= 0 ) {844 if ( read <= 0 ) {
632 break;845 break;
633 }846 }
634 scriptExecuted = true;847 scriptExecuted = true;
635 String seg = new String(buff,0,read);848 mProgress++;
636 849 if (mTotalSize > 0 && mLastSignalledProgress < (mProgress * 100 / mTotalSize)) {
637 if (seg.startsWith("SWAP-file-missing")) {850 // update and signal new progress
638 // this is signal that we will also install swap, adjust progress estimates851 mLastSignalledProgress = (int) (mProgress * 100 / mTotalSize);
639 mTotalSize += PROGRESS_MKSWAP_ADJUSTMENT + PROGRESS_SWAP_CREATION_ADJUSTMENT;852 broadcastProgress(null);
640 } else {
641 mProgress++;
642 if (mTotalSize > 0 && mLastSignalledProgress < (mProgress * 100 / mTotalSize)) {
643 // update and signal new progress
644 mLastSignalledProgress = (int) (mProgress * 100 / mTotalSize);
645 broadcastProgress(mLastSignalledProgress, null);
646 }
647 }853 }
648854 // Log.i(TAG, "Stderr Output: " + new String(buff,0,read));
649 Log.i(TAG, "Stderr Output: " + seg);
650 }855 }
651 try {856 try {
652 ret = process.exitValue();857 ret = process.exitValue();
@@ -663,335 +868,467 @@
663 } while (running);868 } while (running);
664 } catch (IOException e) {869 } catch (IOException e) {
665 throw(new EShellExecException("Script execution exception " + e.getMessage()));870 throw(new EShellExecException("Script execution exception " + e.getMessage()));
871 }
872 Log.d(TAG, "executeSUCommands-done");
873 return ret;
874 }
875
876 /**
877 * Scan output stream for additional information about installed system
878 * It scans for:
879 * - usage data statistics
880 * - installed version information
881 * - update channel url if needed
882 *
883 * @param seg
884 */
885 private void scanOutPut(String seg) {
886 for( String line : seg.split("\n")) {
887 if (line.endsWith(UBUNTU_ROOTFS)) {
888 storeStorageUse(line, PREF_KEY_SIZE_ROOTFS);
889 } else if (line.endsWith(UBUNTU_SYSTEM_DATA)) {
890 storeStorageUse(line, PREF_KEY_SIZE_SYSTEM_DATA);
891 } else if (line.endsWith(UBUNTU_USER_DATA)) {
892 storeStorageUse(line, PREF_KEY_SIZE_USER_DATA);
893 } else if (line.startsWith("build_number:")) {
894 parseVersion(line, PREF_KEY_VERSION_NUMBER);
895 } else if (line.startsWith("channel:")) {
896 parseVersion(line, PREF_KEY_VERSION_CHANNEL);
897 } else if (line.startsWith("channel_target:")) {
898 parseVersion(line, PREF_KEY_VERSION_CHANNEL_TARGET);
899 } else if (line.startsWith("version_detail:")) {
900 parseVersion(line, PREF_KEY_VERSION_DESCRIPTION);
901 } else if (line.startsWith("base:")) {
902 parseVersion(line, PREF_KEY_VERSION_BASE);
903 }
904 }
905 }
906
907 /**
908 * if channel address is empty, try to reconstruct it from version info
909 */
910 private void checkChannelAddress() {
911 if (!mSharedPreferences.contains(PREF_KEY_DOWNLOAD_CHANNEL)
912 || !mSharedPreferences.contains(PREF_KEY_DOWNLOAD_SERVER)){
913 final String base = mSharedPreferences.getString(PREF_KEY_VERSION_BASE, "");
914 String channel = mSharedPreferences.getString(PREF_KEY_VERSION_CHANNEL, "");
915 // if we have network, try to ping server, otherwise guess
916 String channelUrl = null;
917 if (isNetworkAvailable()) {
918 channelUrl = doGetChannels(String.format("http://%s", base), false, true, true, true).get(channel);
919 }
920
921 if (channelUrl == null) {
922 // guess name
923 if (channel.contains("ubuntu-touch/")) {
924 channelUrl = String.format("%s/%s/index.json", channel, Utils.getDeviceModel());
925 } else {
926 channelUrl = String.format("ubuntu-touch/%s/%s/index.json", channel, Utils.getDeviceModel());
927 }
928 }
929 Log.d(TAG, "Constructed channel url:" + base + "/" + channelUrl);
930 mSharedPreferences.edit()
931 .putString(PREF_KEY_DOWNLOAD_CHANNEL, channelUrl)
932 .putString(PREF_KEY_DOWNLOAD_SERVER, String.format("http://%s", base))
933 .commit();
934 }
935 }
936
937 private void storeStorageUse(String value, String key) {
938 final String[] spl = value.split("\t");
939 if (spl.length != 0) {
940 final int size = Integer.valueOf(spl[0]);
941 mSharedPreferences.edit().putInt(key, size).commit();
942 final Intent notification = new Intent(STORAGE_USE_UPDATED);
943 sendBroadcast(notification);
944 }
945 }
946
947 private void parseVersion(String value, String key) {
948 final String[] spl = value.split(": ");
949 if (spl.length >= 2) {
950 mSharedPreferences.edit().putString(key, spl[1]).commit();
951 }
952 }
953
954 private Intent downloadRelease(Intent intent) {
955 String channel = intent.getStringExtra(DOWNLOAD_RELEASE_EXTRA_CHANNEL_URL);
956 String serverUrl = intent.getStringExtra(DOWNLOAD_RELEASE_EXTRA_SERVER_URL);
957 boolean bootstrap = intent.getBooleanExtra(DOWNLOAD_RELEASE_EXTRA_BOOTSTRAP,true); // default bootstrap on
958 int version = intent.getIntExtra(DOWNLOAD_RELEASE_EXTRA_VERSION, -1);
959 ReleaseType releaseType = ReleaseType.fromValue(
960 intent.getIntExtra(DOWNLOAD_RELEASE_EXTRA_TYPE, ReleaseType.FULL.getValue())); // by default look for full releases
961 // First delete old release if it exists
962 doDeleteDownloadedRelease();
963 mSharedPreferences.edit().
964 putString(PREF_KEY_DOWNLOAD_SERVER, serverUrl).
965 putString(PREF_KEY_DOWNLOAD_CHANNEL, channel).
966 commit();
967 return downloadAllPackages(bootstrap, version, releaseType);
968 }
969
970 /**
971 * Download first available download
972 */
973 private Intent downloadUpdate() {
974 // -1 will pick update available for this release
975 return downloadAllPackages(false, -1, ReleaseType.DELTA);
976 }
977
978 private Intent resumeDownload() {
979 boolean bootstrap = mSharedPreferences.getBoolean(PREF_KEY_DOWNLOAD_BOOTSTRAP, false);
980 int version = mSharedPreferences.getInt(PREF_KEY_DOWNLOAD_VERSION, -1);
981 ReleaseType releaseType = ReleaseType.fromValue(
982 mSharedPreferences.getInt(PREF_KEY_DOWNLOAD_TYPE, ReleaseType.FULL.getValue()));
983 return downloadAllPackages(bootstrap, version, releaseType);
984 }
985
986 @SuppressLint("Wakelock")
987 private Intent downloadAllPackages(boolean bootstrap, int version, ReleaseType releaseType ) {
988 mWakeLock.acquire();
989 mWifiLock.acquire();
990 try {
991 return doDownloadAllPackages( bootstrap, version, releaseType);
666 } finally {992 } finally {
667 if (mWakeLock != null && mWakeLock.isHeld()) {993 Log.d(TAG, "downloadAllPackages-releasing wakelocks");
994 if (mWakeLock.isHeld() ) {
668 mWakeLock.release();995 mWakeLock.release();
669 }996 }
997 if (mWifiLock.isHeld()) {
998 mWifiLock.release();
999 }
670 }1000 }
671 return ret;
672 }1001 }
6731002 @SuppressLint("CommitPrefEdits")
674 private Intent doDownloadRelease(Intent intent) {1003 private Intent doDownloadAllPackages(boolean bootstrap, int version, ReleaseType releaseType ) {
675 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ufa-downloading");
676 mIsCanceled = false;1004 mIsCanceled = false;
677 SharedPreferences.Editor editor = getSharedPreferences( SHARED_PREF, Context.MODE_PRIVATE).edit();1005 dismissUbuntuNotification();
6781006 mActionOutput = "";
1007 broadcastProgress(getString(R.string.downloading_starting));
1008 String channel = mSharedPreferences.getString(PREF_KEY_DOWNLOAD_CHANNEL, null);
1009 String serverUrl = mSharedPreferences.getString(PREF_KEY_DOWNLOAD_SERVER, null);
679 Intent result = new Intent(DOWNLOAD_RESULT);1010 Intent result = new Intent(DOWNLOAD_RESULT);
680 VersionInfo prevDownload = getDownloadVersion(this.getApplicationContext());1011 if (channel == null || serverUrl == null) {
681 try {1012 doDeleteDownloadedRelease();
682 File rootFolder = new File(mRootOfWorkPath);1013 return handleDownloadError(result, -1, "Missing update server or channel url");
6831014 }
684 // first get from JSON list of files to download1015
685 String alias = intent.getStringExtra(DOWNLOAD_RELEASE_EXTRA_CHANNEL_ALIAS);1016 String jsonStr = Utils.httpDownload(String.format("%s/%s", serverUrl, channel));
686 String jsonUrl = intent.getStringExtra(DOWNLOAD_RELEASE_EXTRA_CHANNEL_URL);1017 if (jsonStr == null) {
687 boolean bootstrap = intent.getBooleanExtra(DOWNLOAD_RELEASE_EXTRA_BOOTSTRAP,true); // default bootstrap on1018 Log.e(TAG, "Failed to fetch channel content");
688 int version = intent.getIntExtra(DOWNLOAD_RELEASE_EXTRA_VERSION, -1);1019 return handleDownloadError(result, -1, "Failed to fetch channel content, check url");
689 ReleaseType releaseType = ReleaseType.fromValue(1020 }
690 intent.getIntExtra(DOWNLOAD_RELEASE_EXTRA_TYPE, ReleaseType.FULL.getValue())); // by default look for full releases1021 List<Image> releases = JsonChannelParser.getAvailableReleases(jsonStr, releaseType);
6911022 if (releases.size() == 0 || releases.get(0).files.length == 0 ) {
692 String jsonStr = Utils.httpDownload(BASE_URL + jsonUrl);1023 // something is wrong, empty release
693 List<Image> releases = JsonChannelParser.getAvailableReleases(jsonStr, ReleaseType.FULL);1024 Log.e(TAG, "Empty releas");
694 if (releases.size() == 0 || releases.get(0).files.length == 0 ) {1025 return handleDownloadError(result, -1, "Empty release");
695 // something is wrong, empty release1026 }
696 Log.e(TAG, "Empty releas");1027 // get right version, otherwise first since that is most recent one
697 return handleDownloadError(result, -1, "Empty release");1028 Image choosenRelease = null;
1029 if (version != -1) {
1030 // look for given release
1031 for (Image i : releases) {
1032 if (i.version == version) {
1033 choosenRelease = i;
1034 break;
1035 }
698 }1036 }
699 // get right version, otherwise first since that is most recent one1037 } else {
700 Image choosenRelease = null;1038 if (releaseType == ReleaseType.FULL) {
701 if (version != -1) {1039 choosenRelease = releases.get(0);
702 // look for given release1040 } else {
703 for (Image i : releases) {1041 // this is update, found release wich relates to installed one
704 if (i.version == version) {1042 String baseStr = mSharedPreferences.getString(PREF_KEY_VERSION_NUMBER, "0");
1043 int base = Integer.valueOf(baseStr);
1044 for(Image i : releases) {
1045 if (i.base == base) {
705 choosenRelease = i;1046 choosenRelease = i;
706 break;1047 break;
707 }1048 }
708 }1049 }
709 if (choosenRelease == null) {1050 }
710 Log.e(TAG, "wrong release vwersion");1051 }
711 return handleDownloadError(result, -1, "wrong release vwersion");1052 if (choosenRelease == null) {
1053 Log.e(TAG, "wrong release vwersion");
1054 return handleDownloadError(result, -1, "wrong release version");
1055 }
1056
1057 JsonChannelParser.File updateFiles[] = choosenRelease.files;
1058 // sort update files
1059 List<JsonChannelParser.File> filesArray = new LinkedList<JsonChannelParser.File>();
1060 for(JsonChannelParser.File f: updateFiles) {
1061 // In bring up mode, skip device package updates
1062 if (mBringup) {
1063 if (!f.path.contains("device-")){
1064 filesArray.add(f);
712 }1065 }
713 } else {1066 } else {
714 choosenRelease = releases.get(0);
715 }
716 JsonChannelParser.File updateFiles[] = choosenRelease.files;
717 // sort update files
718 List<JsonChannelParser.File> filesArray = new LinkedList<JsonChannelParser.File>();
719 for(JsonChannelParser.File f: updateFiles) {
720 filesArray.add(f);1067 filesArray.add(f);
721 }1068 }
722 Collections.sort(filesArray, JsonChannelParser.fileComparator());1069 }
723 String updateFilenames[] = new String[updateFiles.length * 2];1070 Collections.sort(filesArray, JsonChannelParser.fileComparator());
7241071 String updateFilenames[] = new String[updateFiles.length];
725 // get list of keyrings to download1072
726 String keyrings[] = {1073 // make sure release folder exists
727 String.format("%s/%s",BASE_URL, URL_IMAGE_MASTER),1074 mReleaseFolder.mkdir();
728 String.format("%s/%s",BASE_URL, URL_IMAGE_SIGNING),1075 // download release
729 }; 1076 long time = System.currentTimeMillis();
730 String keyringsFilenames[] = new String[keyrings.length * 2];1077 mLastSignalledProgress = 0;
7311078 mProgress = 0;
732 // First delete old release if it exists1079 broadcastProgress(null);
733 {1080 mTotalSize = Utils.calculateDownloadSize(filesArray);
734 boolean toDeleteOld = true;1081 long neededSize = mTotalSize;
735 if (prevDownload != null) {1082 boolean resuming = mSharedPreferences.getBoolean(PREF_KEY_DOWNLOAD_ACTIVE, false);
736 if (prevDownload.equals(jsonUrl, choosenRelease.version, releaseType) &&1083 if (resuming ) {
737 prevDownload.mDownloadedSize > 0) {1084 neededSize = mTotalSize - mSharedPreferences.getLong(PREF_KEY_DOWNLOAD_COMPLETED, 0);
738 toDeleteOld = false;1085 }
739 }1086 boolean isStorageEnough = isStorageSpaceEnoughBFDownload(neededSize);
740 }1087 if (! isStorageEnough) {
741 if (toDeleteOld) {1088 String msg = "Need more storage: ";
742 String s = deleteRelease();1089 msg += "/data need 2.5G for system plus " + String.valueOf(mTotalSize) + " bytes for download";
743 if (s != null) {1090 Log.i(TAG, msg);
744 // remove failed1091 return handleDownloadError(result, -1, msg);
745 return handleDownloadError(result, -1, s);1092 }
746 }1093
747 }1094 // Store download info
748 }1095 mSharedPreferences.edit()
7491096 .putBoolean(PREF_KEY_DOWNLOAD_BOOTSTRAP, bootstrap)
750 // make sure release folder exists1097 .putInt(PREF_KEY_DOWNLOAD_VERSION, version)
751 File release = new File(rootFolder, RELEASE_FOLDER);1098 .putInt(PREF_KEY_DOWNLOAD_TYPE, releaseType.getValue())
752 release.mkdir();1099 .putBoolean(PREF_KEY_DOWNLOAD_ACTIVE, true)
753 // download release1100 .putString(PREF_KEY_DOWNLOAD_SERVER, serverUrl)
754 long time = System.currentTimeMillis();1101 .putString(PREF_KEY_DOWNLOAD_CHANNEL, channel)
755 mLastSignalledProgress = 0;1102 .commit();
756 mProgress = 0;1103
757 broadcastProgress(mLastSignalledProgress, null);1104 // mProgressSteps = mTotalDownloadSize / 100; // we want 1% steps
758 mTotalSize = Utils.calculateDownloadSize(filesArray);1105 long downloadedSize = 0;
759 long neededSize = mTotalSize;1106 JsonChannelParser.File currentDownloadingFile = null;
760 if (prevDownload != null) {1107 try {
761 neededSize = mTotalSize - prevDownload.mDownloadedSize;1108 int i = 0;
762 }1109 // download all update packages
763 boolean isStorageEnough = isStorageSpaceEnoughBFDownload(neededSize);1110 i = 0;
764 if (! isStorageEnough) {1111 for (JsonChannelParser.File file : filesArray){
765 String msg = "Need more storage: ";1112 URL url = new URL(serverUrl + file.path);
766 if (workPathInCache) {1113 String fileName = URLUtil.guessFileName(url.toString(), null, null);
767 msg += "/cache need " + String.valueOf(mTotalSize) + " bytes for download and /data need 2.5G for system";1114 File f = new File(mReleaseFolder, fileName);
1115
1116 boolean fileNeedDownload = true;
1117 if (resuming) {
1118 long length = f.length();
1119 if (length == file.size) {
1120 fileNeedDownload = false;
1121 } else if (length > file.size) {
1122 f.delete();
1123 }
1124 }
1125 if (fileNeedDownload) {
1126 currentDownloadingFile = file;
1127 updateFilenames[i] = doDownloadFile(serverUrl, file, mReleaseFolder);
1128 currentDownloadingFile = null;
768 } else {1129 } else {
769 msg += "/data need 2.5G for system plus " + String.valueOf(mTotalSize) + " bytes for download";1130 updateFilenames[i] = fileName;
770 }1131 mProgress += file.size;
771 Log.i(TAG, msg);1132 mLastSignalledProgress = (int) (mProgress * 100 / mTotalSize);
772 return handleDownloadError(result, -1, msg);1133 broadcastProgress(null);
773 }1134 }
7741135
775 // mProgressSteps = mTotalDownloadSize / 100; // we want 1% steps1136 // check file size and check sum
776 long downloadedSize = 0;1137 long length = f.length();
777 JsonChannelParser.File currentDownloadingFile = null;1138 if (length != file.size) {
1139 f.delete();
1140 throw new ESumNotMatchException();
1141 }
1142 broadcastProgress("Checksum Verifying: " + fileName);
1143 String sha256sum = Utils.getSha256Sum(f);
1144 if (! sha256sum.equals(file.checksum)) {
1145 broadcastProgress("Checksum Verify failed: " + fileName);
1146 f.delete();
1147 throw new ESumNotMatchException();
1148 }
1149 broadcastProgress("Checksum Verified: " + fileName);
1150 downloadedSize += file.size;
1151 i++;
1152 }
1153
1154 // data required for installation.
1155 // Ubuntu reboot apps.
1156 Utils.extractExecutableAsset(this, U_REBOOT_APP, mReleaseFolder.getAbsolutePath(), false);
1157 Utils.extractExecutableAsset(this, RECOVERY_REMOUNT, mReleaseFolder.getAbsolutePath(), false);
1158 } catch (MalformedURLException e) {
1159 Log.e(TAG, "Failed to download release:", e);
1160 return handleDownloadError(result, -1, "Malformed release url");
1161 } catch (FileNotFoundException e) {
1162 Log.e(TAG, "Failed to download release:", e);
1163 return handleDownloadError(result, -1, "File not found");
1164 } catch (IOException e){
1165 if (currentDownloadingFile != null) {
1166 try {
1167 URL url = new URL(serverUrl + currentDownloadingFile.path);
1168 String fileName = URLUtil.guessFileName(url.toString(), null, null);
1169 File f = new File(mReleaseFolder, fileName);
1170 downloadedSize += f.length();
1171 } catch (MalformedURLException e1) {
1172 // shouldn't happen for it should already happen.
1173 }
1174 }
1175
1176 if (downloadedSize == 0) {
1177 doDeleteDownloadedRelease();
1178 mSharedPreferences.edit().putBoolean(PREF_KEY_DOWNLOAD_ACTIVE, false).commit();
1179 } else {
1180 mSharedPreferences.edit().putLong(PREF_KEY_DOWNLOAD_COMPLETED, downloadedSize).commit();
1181 }
1182
1183 Log.e(TAG, "Failed to download release:", e);
1184 return handleDownloadError(result, -1, "IO Error");
1185 } catch (ESumNotMatchException e) {
1186 // Download file check sum error !!
1187 doDeleteDownloadedRelease();
1188 return handleDownloadError(result, -1, "Download check sum error");
1189 } catch (ECancelException e) {
1190 // Download was cancelled by user
1191 downloadedSize += e.mDownloadedSize;
1192 if (downloadedSize == 0) {
1193 mSharedPreferences.edit().putBoolean(PREF_KEY_DOWNLOAD_ACTIVE, false).commit();
1194 } else {
1195 mSharedPreferences.edit().putLong(PREF_KEY_DOWNLOAD_COMPLETED, downloadedSize).commit();
1196 }
1197
1198 return handleDownloadError(result, -2, "Download cancelled by user");
1199 }
1200
1201 Log.i(TAG, "Download done in " + (System.currentTimeMillis() - time )/1000 + " seconds");
1202 broadcastProgress("Generating update command");
1203
1204 // generate update_command
1205 File updateCommand = new File(mReleaseFolder, UPDATE_COMMAND);
1206 try {
1207 FileOutputStream fos = new FileOutputStream(updateCommand);
778 try {1208 try {
1209 if (bootstrap) {
1210 fos.write((String.format("%s %s\n", COMMAND_FORMAT, PARTITION_DATA)).getBytes());
1211 }
1212 if (releaseType == ReleaseType.FULL) {
1213 fos.write((String.format("%s %s\n", COMMAND_FORMAT, PARTITION_SYSTEM)).getBytes());
1214 }
1215 fos.write((String.format("%s %s\n", COMMAND_MOUNT, PARTITION_SYSTEM)).getBytes());
1216
1217 // add update commands
779 int i = 0;1218 int i = 0;
780 for(String url : keyrings){1219 while (i < updateFilenames.length) {
781 keyringsFilenames[i++] = doDownloadUrl(new URL(url), release);1220 fos.write((String.format("%s %s\n",
782 // download signature1221 COMMAND_UPDATE,
783 keyringsFilenames[i++] = doDownloadUrl(new URL(url+ASC_SUFFIX), release);1222 updateFilenames[i++])).getBytes());
784 }1223 }
7851224
786 // download all update images1225 // add Ubuntu reboot app and recovery remount update packages
787 i = 0;1226 if (releaseType == ReleaseType.FULL) {
788 for (JsonChannelParser.File file : filesArray){1227 fos.write((String.format("%s %s\n",
789 URL url = new URL(BASE_URL + file.path);1228 COMMAND_UPDATE,
790 String fileName = URLUtil.guessFileName(url.toString(), null, null);1229 U_REBOOT_APP)).getBytes());
791 File f = new File(release, fileName);1230
7921231 fos.write((String.format("%s %s\n",
793 boolean fileNeedDownload = true;1232 COMMAND_UPDATE,
794 if (prevDownload != null) {1233 RECOVERY_REMOUNT)).getBytes());
795 long length = f.length();1234 }
796 if (length == file.size) {1235 fos.write((String.format("%s %s\n", COMMAND_UMOUNT, PARTITION_SYSTEM)).getBytes());
797 fileNeedDownload = false;1236 fos.flush();
798 } else if (length > file.size) {1237 } finally {
799 f.delete();1238 fos.close();
800 }1239 }
801 }1240 } catch (IOException e) {
802 if (fileNeedDownload) {1241 e.printStackTrace();
803 currentDownloadingFile = file;1242 doDeleteDownloadedRelease();
804 updateFilenames[i] = doDownloadFile(file, release);1243 mSharedPreferences.edit().putBoolean(PREF_KEY_DOWNLOAD_ACTIVE, false).commit();
805 currentDownloadingFile = null;1244 return handleDownloadError(result, -1, "Failed to generate update command");
806 } else {1245 }
807 updateFilenames[i] = fileName;1246
808 mProgress += file.size;1247 mLastSignalledProgress = 100;
809 mLastSignalledProgress = (int) (mProgress * 100 / mTotalSize);1248 broadcastProgress("Download done in " + (System.currentTimeMillis() - time )/1000 + " seconds");
810 broadcastProgress(mLastSignalledProgress, null);1249 // store update command
811 }1250 setUpdateCommand(updateCommand.getAbsolutePath());
8121251 mSharedPreferences.edit().putBoolean(PREF_KEY_DOWNLOAD_ACTIVE, false).commit();
813 // check file size and check sum1252 dismissProgressNotification();
814 long length = f.length();1253 // check if we should also do install
815 if (length != file.size) {1254 if ( MIN_INSTALL_BATTERY_CHARGE < getBatteryCharge(this)) {
816 f.delete();1255 updateInstallerState(InstallerState.INSTALLING);
817 throw new ESumNotMatchException();1256 return doInstallUbuntu();
818 }
819 broadcastProgress(mLastSignalledProgress, "Checksum Verifying: " + fileName);
820 String sha256sum = Utils.getSha256Sum(f);
821 if (! sha256sum.equals(file.checksum)) {
822 broadcastProgress(mLastSignalledProgress, "Checksum Verify failed: " + fileName);
823 f.delete();
824 throw new ESumNotMatchException();
825 }
826 broadcastProgress(mLastSignalledProgress, "Checksum Verified: " + fileName);
827 downloadedSize += file.size;
828 i++;
829
830 // signature file size is not accounted for resume since it's quite small
831 updateFilenames[i] = doDownloadFileSignature(file, release);
832 i++;
833 }
834
835 // data required for installation.
836 Utils.extractExecutableAsset(this, ARCHIVE_MASTER_ASC, release.getAbsolutePath(), false);
837 Utils.extractExecutableAsset(this, ARCHIVE_MASTER, release.getAbsolutePath(), false);
838 // Ubuntu reboot apps.
839 Utils.extractExecutableAsset(this, U_REBOOT_APP_ASC, release.getAbsolutePath(), false);
840 Utils.extractExecutableAsset(this, U_REBOOT_APP, release.getAbsolutePath(), false);
841 } catch (MalformedURLException e) {
842 Log.e(TAG, "Failed to download release:", e);
843 return handleDownloadError(result, -1, "Malformed release url");
844 } catch (FileNotFoundException e) {
845 Log.e(TAG, "Failed to download release:", e);
846 return handleDownloadError(result, -1, "File not found");
847 } catch (IOException e){
848 if (currentDownloadingFile != null) {
849 try {
850 URL url = new URL(BASE_URL + currentDownloadingFile.path);
851 String fileName = URLUtil.guessFileName(url.toString(), null, null);
852 File f = new File(release, fileName);
853 downloadedSize += f.length();
854 } catch (MalformedURLException e1) {
855 // shouldn't happen for it should already happen.
856 }
857 }
858
859 if (downloadedSize > 0) {
860 VersionInfo v = new VersionInfo(alias, jsonUrl, choosenRelease.description, choosenRelease.version,
861 downloadedSize, releaseType);
862 v.storeVersion(editor, PREF_KEY_DOWNLOADED_VERSION);
863 } else {
864 editor.putString(PREF_KEY_UPDATE_COMMAND, "");
865 VersionInfo.storeEmptyVersion(editor, PREF_KEY_DOWNLOADED_VERSION);
866 }
867
868 Log.e(TAG, "Failed to download release:", e);
869 return handleDownloadError(result, -1, "IO Error");
870 } catch (ESumNotMatchException e) {
871 // Download file check sum error !!
872 return handleDownloadError(result, -1, "Download check sum error");
873 } catch (ECancelException e) {
874 // Download was cancelled by user
875 downloadedSize += e.mDownloadedSize;
876 if (downloadedSize > 0) {
877 VersionInfo v = new VersionInfo(alias, jsonUrl, choosenRelease.description, choosenRelease.version,
878 downloadedSize, releaseType);
879 v.storeVersion(editor, PREF_KEY_DOWNLOADED_VERSION);
880 }
881 return handleDownloadError(result, -2, "Download cancelled by user");
882 }
883
884 Log.i(TAG, "Download done in " + (System.currentTimeMillis() - time )/1000 + " seconds");
885 broadcastProgress(-1, "Generating update command");
886
887 // generate update_command
888 File updateCommand = new File(release, UPDATE_COMMAND);
889 try {
890 FileOutputStream fos = new FileOutputStream(updateCommand);
891 try {
892 if (bootstrap) {
893 fos.write((String.format("%s %s\n", COMMAND_FORMAT, PARTITION_DATA)).getBytes());
894 }
895 if (releaseType == ReleaseType.FULL) {
896 fos.write((String.format("%s %s\n", COMMAND_FORMAT, PARTITION_SYSTEM)).getBytes());
897 }
898 // load keyrings
899 int i = 0;
900 while (i < keyringsFilenames.length) {
901 fos.write((String.format("%s %s %s\n",
902 COMMAND_LOAD_KEYRING,
903 keyringsFilenames[i++],
904 keyringsFilenames[i++])).getBytes());
905 }
906 fos.write((String.format("%s %s\n", COMMAND_MOUNT, PARTITION_SYSTEM)).getBytes());
907
908 // add update commands
909 i = 0;
910 while (i < updateFilenames.length) {
911 fos.write((String.format("%s %s %s\n",
912 COMMAND_UPDATE,
913 updateFilenames[i++],
914 updateFilenames[i++])).getBytes());
915 }
916
917 // add Ubuntu reboot app update package
918 if (releaseType == ReleaseType.FULL) {
919 fos.write((String.format("%s %s %s\n",
920 COMMAND_UPDATE,
921 U_REBOOT_APP,
922 U_REBOOT_APP_ASC)).getBytes());
923 }
924 if(releaseType == ReleaseType.DELTA) {
925 // TODO:
926 }
927 fos.write((String.format("%s %s\n", COMMAND_UMOUNT, PARTITION_SYSTEM)).getBytes());
928 fos.flush();
929 } finally {
930 fos.close();
931 }
932 } catch (IOException e) {
933 e.printStackTrace();
934 return handleDownloadError(result, -1, "Failed to generate update command");
935 }
936 broadcastProgress(-1, "Download done in " + (System.currentTimeMillis() - time )/1000 + " seconds");
937 int estimatedCheckCount = 0;
938 for (JsonChannelParser.File file : filesArray){
939 if (file.path.contains("ubuntu-")) {
940 estimatedCheckCount += (file.size / PROGRESS_UBUNTU_ADJUSTMENT);
941 } else if (file.path.contains("device-")) {
942 estimatedCheckCount += (file.size / PROGRESS_DEVICE_ADJUSTMENT);
943 } else if (file.path.contains("custom-")) {
944 estimatedCheckCount += (file.size / PROGRESS_CUSTOM_ADJUSTMENT);
945 }
946 }
947 // store update command
948 setUpdateCommand(updateCommand.getAbsolutePath());
949
950 // updated downloaded information.
951 VersionInfo v = new VersionInfo(alias, jsonUrl, choosenRelease.description, choosenRelease.version, 0, releaseType);
952
953 editor.putInt(PREF_KEY_ESTIMATED_CHECKPOINTS, estimatedCheckCount);
954 v.storeVersion(editor, PREF_KEY_DOWNLOADED_VERSION);
955 mProgress = 100;
956 } finally {
957 if (mWakeLock != null && mWakeLock.isHeld()) {
958 mWakeLock.release();
959 }
960 }1257 }
961 result.putExtra(DOWNLOAD_RESULT_EXTRA_INT, 0);1258 result.putExtra(DOWNLOAD_RESULT_EXTRA_INT, 0);
962 return result;1259 return result;
963 }1260 }
964 1261
1262 /**
1263 * Go through update folder and based on size estimate number of install checkpoint
1264 * @param updateCommand update command file
1265 * @return number of checkpoints
1266 */
1267 private int estimateCheckpooint(String updateCommand) {
1268
1269 long estimatedCheckCount = 0;
1270 ReleaseType releaseType = ReleaseType.fromValue( // use delta as default for unknown updates
1271 mSharedPreferences.getInt(PREF_KEY_DOWNLOAD_TYPE, ReleaseType.DELTA.getValue()));
1272 File command = new File(updateCommand);
1273 File updateFolder = command.getParentFile();
1274 if (updateFolder != null && updateFolder.isDirectory()) {
1275 // looks for any file in this folder
1276 File[] files = updateFolder.listFiles(
1277 new FileFilter(){
1278 public boolean accept (File pathname) {
1279 if (pathname.isFile() && pathname.getName().endsWith(".tar.xz")) {
1280 return true;
1281 }
1282 return false;
1283 }
1284 });
1285 for (File f : files) {
1286 if (f.getName().startsWith("ubuntu-")) {
1287 estimatedCheckCount += (f.length() / PROGRESS_UBUNTU_ADJUSTMENT);
1288 } else if (f.getName().startsWith("device-")) {
1289 estimatedCheckCount += (f.length() / PROGRESS_DEVICE_ADJUSTMENT);
1290 } else {
1291 estimatedCheckCount += (f.length() / PROGRESS_CUSTOM_ADJUSTMENT);
1292 }
1293 }
1294 }
1295 if (releaseType == ReleaseType.DELTA) {
1296 // set double checkpoints for removing files
1297 estimatedCheckCount *=2;
1298 }
1299 return (int)estimatedCheckCount;
1300 }
1301
1302 /**
1303 * Handle download error
1304 */
965 private Intent handleDownloadError(Intent i, int res, String reason) {1305 private Intent handleDownloadError(Intent i, int res, String reason) {
1306 mActionOutput += "\n" + reason;
1307 if ( res == -2) {
1308 // download canceled by user, dismiss progress notification
1309 dismissProgressNotification();
1310 } else if (isUpdate()) {
1311 showUbuntuNotification(R.string.notification_download_failed, LaunchActivity.class);
1312 } else {
1313 showUbuntuNotification(R.string.notification_download_failed, InstallActivity.class);
1314 }
966 i.putExtra(DOWNLOAD_RESULT_EXTRA_INT, res);1315 i.putExtra(DOWNLOAD_RESULT_EXTRA_INT, res);
967 i.putExtra(DOWNLOAD_RESULT_EXTRA_STR, reason);1316 i.putExtra(DOWNLOAD_RESULT_EXTRA_STR, reason);
968 return i;1317 return i;
969 }1318 }
9701319
971 private String doDownloadFile(JsonChannelParser.File file, File targetLocation) throws MalformedURLException,1320 private String doDownloadFile(String serverUrl, JsonChannelParser.File file, File targetLocation)
972 FileNotFoundException, IOException, ECancelException {1321 throws MalformedURLException, FileNotFoundException, IOException, ECancelException {
973 URL url = new URL(BASE_URL + file.path);1322 URL url = new URL(serverUrl + file.path);
974 return doDownloadUrl(url, targetLocation, true);1323 return doDownloadUrl(url, targetLocation, true);
975 }1324 }
9761325
977 private String doDownloadFileSignature(JsonChannelParser.File file, File targetLocation) throws MalformedURLException,
978 FileNotFoundException, IOException, ECancelException {
979 URL url = new URL(BASE_URL + file.signature);
980 return doDownloadUrl(url, targetLocation);
981 }
982
983 private String doDownloadUrl(URL url, File targertLocation) throws MalformedURLException,
984 FileNotFoundException, IOException, ECancelException {
985 return doDownloadUrl(url, targertLocation, false);
986 }
987
988 private String doDownloadUrl(URL url, File targertLocation, boolean resume) throws MalformedURLException,1326 private String doDownloadUrl(URL url, File targertLocation, boolean resume) throws MalformedURLException,
989 FileNotFoundException, IOException, ECancelException {1327 FileNotFoundException, IOException, ECancelException {
990 Log.v(TAG, "Downloading:" + url.toString());1328 Log.v(TAG, "Downloading:" + url.toString());
991 URLConnection conn = url.openConnection();1329 URLConnection conn = url.openConnection();
992 String fileName = URLUtil.guessFileName(url.toString(), null, null);1330 String fileName = URLUtil.guessFileName(url.toString(), null, null);
993 // TODO: update progress accordingly1331 broadcastProgress("Downloading: " + fileName);
994 broadcastProgress(mLastSignalledProgress, "Downloading: " + fileName);
995 File file = new File(targertLocation, fileName);1332 File file = new File(targertLocation, fileName);
996 if ((! resume) && file.exists() && file.isFile()) {1333 if ((! resume) && file.exists() && file.isFile()) {
997 file.delete();1334 file.delete();
@@ -1011,7 +1348,7 @@
1011 // resumePosition > 0 ==> append mode1348 // resumePosition > 0 ==> append mode
1012 FileOutputStream output = new FileOutputStream(file, resumePosition > 0);1349 FileOutputStream output = new FileOutputStream(file, resumePosition > 0);
10131350
1014 InputStream input = conn.getInputStream();1351 final InputStream input = conn.getInputStream();
10151352
1016 byte[] buffer = new byte[1024];1353 byte[] buffer = new byte[1024];
1017 int len = 0;1354 int len = 0;
@@ -1021,9 +1358,18 @@
1021 output.close();1358 output.close();
1022 conn = null;1359 conn = null;
1023 // input.close() need more time to close() as donwload large file.1360 // input.close() need more time to close() as donwload large file.
1024 input = null;1361 new Thread(new Runnable() {
1362 @Override
1363 public void run() {
1364 try {
1365 input.close();
1366 } catch (IOException e) {
1367 e.printStackTrace();
1368 }
1369 }
1370 }).start();
1025 long flen = file.length();1371 long flen = file.length();
1026 if (flen > 0) {1372 if (flen > 0 && !resume) {
1027 try {1373 try {
1028 file.delete();1374 file.delete();
1029 flen = 0;1375 flen = 0;
@@ -1041,7 +1387,7 @@
1041 if (mLastSignalledProgress < (mProgress * 100 / mTotalSize)) {1387 if (mLastSignalledProgress < (mProgress * 100 / mTotalSize)) {
1042 // update and signal new progress1388 // update and signal new progress
1043 mLastSignalledProgress = (int) (mProgress * 100 / mTotalSize);1389 mLastSignalledProgress = (int) (mProgress * 100 / mTotalSize);
1044 broadcastProgress(mLastSignalledProgress, null);1390 broadcastProgress(null);
1045 }1391 }
1046 }1392 }
1047 output.flush();1393 output.flush();
@@ -1066,52 +1412,42 @@
1066 }1412 }
10671413
1068 /**1414 /**
1069 * @return null if success or error1415 * Delete downloaded release
1070 */1416 */
1071 private String deleteRelease() {1417 private void doDeleteDownloadedRelease() {
1072 // First delete old release if it exists1418 // delete old release if it exists
1073 File rootFolder = new File(mRootOfWorkPath);1419 if (mReleaseFolder.exists()) {
1074 File release = new File(rootFolder, RELEASE_FOLDER);1420 deleteDirectory(mReleaseFolder);
1075 if (release.exists()) {
1076 deleteDirectory(release);
1077 // cleanup update command
1078 cleanUpdateCommand();
1079 // clean up version number.
1080 VersionInfo.storeEmptyVersion(getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE).edit(), PREF_KEY_DOWNLOADED_VERSION);
1081 }1421 }
1082 return null;1422 // cleanup update command
1423 cleanUpdateCommand();
1424 mSharedPreferences.edit()
1425 .remove(PREF_KEY_DOWNLOAD_CHANNEL)
1426 .remove(PREF_KEY_DOWNLOAD_SERVER)
1427 .remove(PREF_KEY_DOWNLOAD_BOOTSTRAP)
1428 .remove(PREF_KEY_DOWNLOAD_VERSION)
1429 .putBoolean(PREF_KEY_DOWNLOAD_ACTIVE, false)
1430 .putLong(PREF_KEY_DOWNLOAD_COMPLETED, 0)
1431 .remove(PREF_KEY_DOWNLOAD_TYPE)
1432 .commit();
1083 }1433 }
10841434
1085 private void broadcastInstallerState() {
1086 Intent i = new Intent(SERVICE_STATE);
1087 i.putExtra(SERVICE_STATE, mInstallerState.ordinal());
1088 sendBroadcast(i);
1089 }
1090
1091 private void updateInstallerState(InstallerState newState) {1435 private void updateInstallerState(InstallerState newState) {
1092 mInstallerState = newState;1436 mServiceState = newState;
1093 Intent i = new Intent(SERVICE_STATE);1437 Intent i = new Intent(SERVICE_STATE_CHANGED);
1094 i.putExtra(SERVICE_STATE, mInstallerState.ordinal());
1095 sendBroadcast(i); 1438 sendBroadcast(i);
1096 }1439 }
10971440
1098 /**1441 /**
1099 * Check whether storage free space is enough.1442 * Check whether storage free space is enough for install or update
1100 * @param downloadSize: download size from json. 0 means file already downloaded.1443 * @param downloadSize: download size from json. 0 means file already downloaded.
1101 * @return true if stoarge size is ok to go.1444 * @return true if storage size is ok to go.
1102 */1445 */
1103 private boolean isStorageSpaceEnoughBFDownload(long downloadSize) {1446 private boolean isStorageSpaceEnoughBFDownload(long downloadSize) {
1104 long dataSizeRequired = INSTALL_SIZE_REQUIRED;1447 long dataSizeRequired = downloadSize;
11051448 // if Ubuntu is already installed, we don't need that extra space, it will be freed
1106 if (workPathInCache) {1449 if (!mSharedPreferences.getBoolean(PREF_KEY_UBUNTU_INSTALLED, false)) {
1107 if (downloadSize > 0) {1450 dataSizeRequired += INSTALL_SIZE_REQUIRED;
1108 long cacheFreeSpace = Utils.getFreeSpaceInBytes("/cache");
1109 if (cacheFreeSpace < EXTRA_SIZE_REQUIRED + downloadSize) {
1110 return false;
1111 }
1112 }
1113 } else {
1114 dataSizeRequired += downloadSize;
1115 }1451 }
11161452
1117 long dataFreeSpace = Utils.getFreeSpaceInBytes("/data");1453 long dataFreeSpace = Utils.getFreeSpaceInBytes("/data");
@@ -1121,114 +1457,127 @@
1121 return true;1457 return true;
1122 }1458 }
11231459
1124 private static VersionInfo getVersionWithPrefKey(Context c, String prefKey) {1460
1125 SharedPreferences pref = c.getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE);1461 /**
11261462 * Check if recovery command exists on the system.
1127 if (VersionInfo.hasValidVersion(pref, prefKey)) {
1128 return new VersionInfo(pref, prefKey);
1129 }
1130 return null;
1131 }
1132
1133 /**
1134 * Internal helper function to get current DOWNLOAD_VERSION even download is partial
1135 * @param context
1136 * @return version info for download image.
1137 */
1138 private static VersionInfo getDownloadVersion(Context context) {
1139 return getVersionWithPrefKey(context, PREF_KEY_DOWNLOADED_VERSION);
1140 }
1141
1142 /**
1143 * To get current DOWNLOAD_VERSION for completed download.
1144 * @param context
1145 * @return Version info for download-ed image.
1146 */
1147 public static VersionInfo getDownloadedVersion(Context context) {
1148 VersionInfo v = getVersionWithPrefKey(context, PREF_KEY_DOWNLOADED_VERSION);
1149 if (v != null) {
1150 if (v.mDownloadedSize == 0) return v;
1151 }
1152 return null;
1153 }
1154
1155 public static VersionInfo getInstalledVersion(Context c) {
1156 return getVersionWithPrefKey(c, PREF_KEY_INSTALLED_VERSION);
1157 }
1158
1159 public static boolean isUbuntuInstalled(Context c) {
1160 SharedPreferences pref = c.getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE);
1161 if (VersionInfo.hasValidVersion(pref, PREF_KEY_INSTALLED_VERSION)) {
1162 // go to launch screen
1163 return true;
1164 }
1165 return false;
1166 }
1167
1168 /**
1169 * check if update_command available for upgrade.
1170 *
1171 * @param c
1172 * @return
1173 */
1174 public static boolean isUpgradeable(Context c) {
1175 String cmd = c.getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE).getString(PREF_KEY_UPDATE_COMMAND, "");
1176 return (cmd.startsWith("/cache/"));
1177 }
1178
1179 /**
1180 * check if recovery command is exist on the system.
1181 * system-image in Ubuntu Touch downloaded new version of image at /cache/recovery.1463 * system-image in Ubuntu Touch downloaded new version of image at /cache/recovery.
1182 * This function check if there is a ubuntu_command file in /cache/recovery.1464 * This function check if there is a ubuntu_command file in /cache/recovery.
1183 *1465 *
1184 * The ubuntu_command will be renamed or removed after installation.1466 * The ubuntu_command will be renamed or removed after installation.
1185 *1467 */
1186 * @return if there is upgradeable images stored in /cache.1468 public void findPendingUpdates () {
1187 */1469
1188 public boolean findInstallCommand () {1470 // check is there is update in linked upgrader folder
1189 String[] candidates = {1471 File linkedUpgrader = new File(getFilesDir(), LINKED_UPGRADER_COMMAND );
1190 "/cache/recovery/ubuntu_command",1472 File downloadedUpdate = new File(mReleaseFolder, UPDATE_COMMAND );
1191 "/cache/ubunturecovery/ubuntu_command",1473 boolean updateAvailable = false;
1192 };1474 if (linkedUpgrader.exists()) {
1193 boolean ret = false;1475 updateAvailable = true;
1194 for(String command: candidates) {1476 setUpdateCommand(linkedUpgrader.getAbsolutePath());
1195 if(new File("/cache").canRead()) {1477 // parse file, if it has "format system", it will full install
1196 // if we have permission, we can read /cache.1478 if (Utils.parseAndUpdateInstallCommand(this,linkedUpgrader)) {
1197 File cmd = new File(command);1479 // remove channel and server so it's parsed from new install
1198 if(cmd.exists() && cmd.isFile()) {1480 mSharedPreferences.edit()
1199 Log.d(TAG, "Found upgrade command - " + cmd.getAbsoluteFile().toString());1481 .remove(PREF_KEY_DOWNLOAD_CHANNEL)
1200 // find the upgradeable file, stored into pref.1482 .remove(PREF_KEY_DOWNLOAD_SERVER).commit();
1201 setUpdateCommand(cmd.getAbsolutePath());1483 }
1202 ret = true;1484 // if there is anything downloaded by this installer, we prefer updates from Ubuntu updater
1203 }1485 if (mReleaseFolder.exists()) {
1204 } else {1486 deleteDirectory(mReleaseFolder);
1205 // check the file with su1487 }
1206 File workingFolder = new File(mRootOfWorkPath + "/" + TEMP_FOLDER);1488 } else if (downloadedUpdate.exists()) {
1207 if (!workingFolder.exists() && !workingFolder.mkdir()) {1489 updateAvailable = true;
1208 Log.e(TAG, "can not create working folder");1490 setUpdateCommand(downloadedUpdate.getAbsolutePath());
1209 ret = false;1491 }
1210 }1492 if (updateAvailable) {
1211 try {1493 mSharedPreferences.edit().putBoolean(PREF_KEY_PENDING_UPDATE,true);
1212 int r = executeSUCommands(new String[] {1494 sendBroadcast(new Intent(UBUNTU_UPDATE_PENDING));
1213 String.format("%s %s\n", UPGRADECHECKER, command),1495 showUbuntuUpdateNotification(R.string.notification_update_available);
1214 });1496 }
1215 if(r == 1) {1497 // check if there is also Android update
1216 Log.d(TAG, "Found upgradeable file - " + command);1498 checkForPendingAndroidUpdate();
1217 setUpdateCommand(command);1499 File androidUpdate = new File(getFilesDir(), PENDING_ANDROID_UPDATE);
1218 ret = true;1500 if (androidUpdate.exists()) {
1219 }1501 // delete file, we don't need it anymore
1220 } catch (EShellExecException e) {1502 androidUpdate.delete();
1221 ret = false;1503 sendBroadcast(new Intent(ANDROID_UPDATE_PENDING));
1222 }1504 // show notification only if it is desired by user
1223 }1505 if (!mSharedPreferences.getBoolean(PREF_KEY_ANDROID_UPDATE_DISMISSED, false)) {
1224 }1506 showAndroidUpdateNotification();
1225 if(ret) {1507 }
1226 // FIXME we don't know what's the version in /cache.1508 }
1227 SharedPreferences pref = getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE);1509 }
1228 VersionInfo v = new VersionInfo(pref, PREF_KEY_INSTALLED_VERSION);1510
1229 v.storeVersion(pref.edit(), PREF_KEY_DOWNLOADED_VERSION);1511 /**
1230 }1512 * Check if there is pending android update zip package already downloaded
1231 return ret;1513 */
1514 private void checkForPendingAndroidUpdate() {
1515 try {
1516 executeSUCommands(new String[] {
1517 String.format("if [[ ! -z $(busybox find /cache/ -maxdepth 1 -iname '*%s*%s*.zip') ]]; then touch %s/%s; chmod 777 %s/%s; fi\n",
1518 Build.PRODUCT.toLowerCase(Locale.US),
1519 Build.ID,
1520 getFilesDir().toString(),
1521 PENDING_ANDROID_UPDATE,
1522 getFilesDir().toString(),
1523 PENDING_ANDROID_UPDATE)
1524 });
1525 } catch (EShellExecException e1) {
1526 // ignore error
1527 }
1528 }
1529
1530 /**
1531 * Check if there is available update to be downloaded
1532 */
1533 private void checkForAvailableUpdate() {
1534 String channel = mSharedPreferences.getString(PREF_KEY_DOWNLOAD_CHANNEL, null);
1535 String server = mSharedPreferences.getString(PREF_KEY_DOWNLOAD_SERVER, null);
1536 if (channel == null || server == null) {
1537 // no stored channel or server URL
1538 return;
1539 }
1540 String jsonStr = Utils.httpDownload(String.format("%s/%s", server, channel));
1541 if (jsonStr != null) {
1542 List<Image> releases = JsonChannelParser.getAvailableReleases(jsonStr, ReleaseType.DELTA);
1543 if (releases.size() == 0 || releases.get(0).files.length == 0 ) {
1544 // something is wrong, empty release
1545 Log.e(TAG, "Empty releas");
1546 return;
1547 }
1548 // look for version with right base
1549 String baseStr = mSharedPreferences.getString(PREF_KEY_VERSION_NUMBER, "0");
1550 int base = Integer.valueOf(baseStr);
1551 for(Image r : releases) {
1552 if (r.base == base) {
1553 Log.d(TAG, "Found update to version:" + r.version);
1554 mSharedPreferences.edit().putBoolean(PREF_KEY_PENDING_UPDATE, true).commit();
1555 Intent intent = new Intent(UBUNTU_UPDATE_AVAILABLE);
1556 sendBroadcast(intent);
1557 // show notification
1558 showUbuntuUpdateNotification(R.string.notification_update_available);
1559 return;
1560 }
1561 }
1562 }
1563 }
1564
1565 /**
1566 * Update used storage
1567 * @return broadcast about data being updated
1568 */
1569 private void doUpdateStorageUse() {
1570 try {
1571 executeSUCommands(
1572 new String[]{
1573 String.format("busybox du -sm %s || true\n", UBUNTU_ROOTFS),
1574 String.format("busybox du -sm %s || true\n", UBUNTU_SYSTEM_DATA),
1575 String.format("busybox du -sm %s || true\n", UBUNTU_USER_DATA),
1576 } );
1577 } catch (EShellExecException e) {
1578 // ignore error
1579 e.printStackTrace();
1580 }
1232 }1581 }
12331582
1234 /**1583 /**
@@ -1236,7 +1585,7 @@
1236 * @file absolute file path of Ubuntu Command file.1585 * @file absolute file path of Ubuntu Command file.
1237 */1586 */
1238 private String getUpdateCommand(){1587 private String getUpdateCommand(){
1239 return getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE).getString(PREF_KEY_UPDATE_COMMAND, "");1588 return mSharedPreferences.getString(PREF_KEY_UPDATE_COMMAND, "");
1240 }1589 }
12411590
1242 /**1591 /**
@@ -1244,27 +1593,60 @@
1244 * @file absolute file path of Ubuntu Command file.1593 * @file absolute file path of Ubuntu Command file.
1245 */1594 */
1246 private void setUpdateCommand(String file){1595 private void setUpdateCommand(String file){
1247 getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE).1596 mSharedPreferences.edit().putString(PREF_KEY_UPDATE_COMMAND, file).commit();
1248 edit().
1249 putString(PREF_KEY_UPDATE_COMMAND, file).
1250 commit();
1251 }1597 }
12521598
1253 /**1599 /**
1254 * clean update command string stored in shared preferences.1600 * clean update command string stored in shared preferences.
1255 */1601 */
1256 private void cleanUpdateCommand() {1602 private void cleanUpdateCommand() {
1257 this.setUpdateCommand("");1603 mSharedPreferences.edit()
1258 }1604 .remove(PREF_KEY_UPDATE_COMMAND)
1259 1605 .commit();
1260 private void broadcastProgress(int val, String progress) {1606 }
1261 Intent i = new Intent(PROGRESS);1607
1262 i.putExtra(PROGRESS_EXTRA_INT, val);1608 /**
1263 if (progress!= null) {1609 * Clean installed version info and all othe values
1264 i.putExtra(PROGRESS_EXTRA_TEXT, progress);1610 */
1611 private void setUbuntuUninstalled() {
1612 mSharedPreferences.edit()
1613 .remove(PREF_KEY_SIZE_ROOTFS)
1614 .remove(PREF_KEY_VERSION_NUMBER)
1615 .remove(PREF_KEY_VERSION_CHANNEL)
1616 .remove(PREF_KEY_VERSION_CHANNEL_TARGET)
1617 .remove(PREF_KEY_VERSION_DESCRIPTION)
1618 .remove(PREF_KEY_VERSION_BASE)
1619 .putBoolean(PREF_KEY_UBUNTU_INSTALLED, false)
1620 .putBoolean(PREF_KEY_PENDING_UPDATE, false)
1621 .commit();
1622 Utils.unregisterUpdateCheckAlarm(this);
1623 dismissUbuntuNotification();
1624 dismissProgressNotification();
1625 dismissUbuntuUpdateNotification();
1626 }
1627
1628 private void broadcastProgress(String progress) {
1629
1630 Intent i = null;
1631 if (progress == null) {
1632 i = new Intent(PROGRESS);
1633 // update notification
1634 showProgressNotification();
1635 } else {
1636 mActionOutput += "\n" + progress;
1637 i = new Intent(PROGRESS_OUPUT);
1265 }1638 }
1266 sendBroadcast(i);1639 sendBroadcast(i);
1267 }1640 }
1641
1642 private boolean isNetworkAvailable() {
1643 final ConnectivityManager conMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
1644 final NetworkInfo activeNetwork = conMgr.getActiveNetworkInfo();
1645 if (activeNetwork != null && activeNetwork.isConnected()) {
1646 return true;
1647 }
1648 return false;
1649 }
12681650
1269 /**1651 /**
1270 * Check if there is downloaded release ready to install.1652 * Check if there is downloaded release ready to install.
@@ -1272,25 +1654,157 @@
1272 * @param context1654 * @param context
1273 * @return true if there is downloaded release ready to install1655 * @return true if there is downloaded release ready to install
1274 */1656 */
1275 public static boolean checkifReadyToInstall(Context context) {1657 public static boolean isReadyToInstall(SharedPreferences sp) {
1276 SharedPreferences pref = context.getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE);1658 String command = sp.getString(PREF_KEY_UPDATE_COMMAND, "");
1277 VersionInfo versionInfo = getDownloadVersion(context);
1278 if (versionInfo == null) return false;
1279 if (versionInfo.getDownloadedSize() != 0) return false;
1280
1281 String command = pref.getString(PREF_KEY_UPDATE_COMMAND, "");
1282 Log.d(TAG, "checkifReadyToInstall");1659 Log.d(TAG, "checkifReadyToInstall");
1283 if (!command.equals("")) {1660 if (!command.equals("") && new File(command).exists() ) {
1284 if (new File(command).exists() || command.startsWith("/cache")) {1661 Log.d(TAG, "checkifReadyToInstall - found command file " + command);
1285 Log.d(TAG, "checkifReadyToInstall - found command file " + command);1662 return true;
1286 return true;1663 } else {
1664 sp.edit().remove(PREF_KEY_UPDATE_COMMAND).commit();
1665 return false;
1666 }
1667 }
1668
1669 public static boolean isDownloadActive(SharedPreferences sp) {
1670 return sp.getBoolean(UbuntuInstallService.PREF_KEY_DOWNLOAD_ACTIVE, false);
1671 }
1672
1673 public static void startInstallationIfPossible(Context c) {
1674 // continue only if battery charge if over 30%
1675 if ( MIN_INSTALL_BATTERY_CHARGE > getBatteryCharge(c) ) {
1676 Utils.showToast(c, R.string.not_enough_charge_warning);
1677 } else {
1678 c.startService(new Intent(UbuntuInstallService.INSTALL_UBUNTU));
1679 }
1680 }
1681
1682
1683 public static int getBatteryCharge(Context c) {
1684 IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
1685 Intent batteryStatus = c.registerReceiver(null, ifilter);
1686 int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
1687 int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
1688 return (level * 100 / scale);
1689 }
1690
1691 private void showUbuntuNotification(int textRsid, Class<?> act) {
1692 Log.d(TAG, "showUbuntuNotification:" + getString(textRsid));
1693 dismissProgressNotification();
1694 mUbuntuNotification = showNotification(textRsid,
1695 R.id.ubuntu_notification, act);
1696 }
1697
1698 private void showUbuntuUpdateNotification(int textRsid) {
1699 mUbuntuUpdateNotification = showNotification(textRsid,
1700 R.id.ubuntu_update_notification,
1701 LaunchActivity.class);
1702 }
1703
1704 private void showAndroidUpdateNotification() {
1705 mAndroidUpdateNotification = showNotification(
1706 R.string.notification_android_update,
1707 R.id.android_update_notification,
1708 LaunchActivity.class);
1709 }
1710
1711
1712 private Notification showNotification(int textrRsid, int notificationId, Class<?> act) {
1713 Intent updateActivity = new Intent(this, act);
1714 updateActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1715 PendingIntent pendingUpdate = PendingIntent.getActivity(
1716 this, 0, updateActivity, PendingIntent.FLAG_UPDATE_CURRENT);
1717
1718 Notification notification = new Notification.Builder(this)
1719 .setAutoCancel(true)
1720 .setSmallIcon(R.drawable.ic_stat_notify_ubuntu)
1721 .setContentTitle(getString(R.string.notification_title))
1722 .setContentText(getString(textrRsid))
1723 .setTicker(getString(textrRsid))
1724 .setContentIntent(pendingUpdate)
1725 .build();
1726
1727 mNotificationManager.notify(notificationId, notification);
1728 return notification;
1729 }
1730
1731 private void showProgressNotification() {
1732 // we are showing progress, no need for update notification
1733 dismissUbuntuUpdateNotification();
1734 // choose text based on state downloading/installing and type FULL/DELTA
1735 ReleaseType releaseType = ReleaseType.fromValue( // use delta as default for unknown updates
1736 mSharedPreferences.getInt(PREF_KEY_DOWNLOAD_TYPE, ReleaseType.DELTA.getValue()));
1737 int textRsid = 0;
1738 if (mServiceState == InstallerState.DOWNLOADING) {
1739 if (releaseType == ReleaseType.FULL) {
1740 textRsid = R.string.notification_downloading_release;
1287 } else {1741 } else {
1288 pref.edit().putString(PREF_KEY_UPDATE_COMMAND, "").commit();1742 textRsid = R.string.notification_downloading_update;
1289 VersionInfo.storeEmptyVersion(pref.edit(), PREF_KEY_DOWNLOADED_VERSION);
1290 return false;
1291 }1743 }
1744 } else if (mServiceState == InstallerState.INSTALLING) {
1745 if (releaseType == ReleaseType.FULL) {
1746 textRsid = R.string.notification_installing_release;
1747 } else {
1748 textRsid = R.string.notification_installing_update;
1749 }
1750 } else {
1751 // don't show any notification
1752 return;
1292 }1753 }
1293 VersionInfo.storeEmptyVersion(pref.edit(), PREF_KEY_DOWNLOADED_VERSION);1754 Intent updateActivity = new Intent(this, InstallActivity.class);
1294 return false;1755 updateActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1756 PendingIntent pendingUpdate = PendingIntent.getActivity(
1757 this, 0, updateActivity, PendingIntent.FLAG_UPDATE_CURRENT);
1758
1759 mUbuntuProgressNotification = new Notification.Builder(this)
1760 .setAutoCancel(true)
1761 .setSmallIcon(R.drawable.ic_stat_notify_ubuntu)
1762 .setContentTitle(getString(R.string.notification_title))
1763 .setContentText(getString(textRsid))
1764 .setTicker(getString(textRsid))
1765 .setContentIntent(pendingUpdate)
1766 .setProgress(100, mLastSignalledProgress, false)
1767 .build();
1768 mNotificationManager.notify(R.id.ubuntu_progress_notification, mUbuntuProgressNotification);
1295 }1769 }
1770
1771 /**
1772 * Dismiss progress notification
1773 */
1774 public void dismissProgressNotification() {
1775 if (mUbuntuProgressNotification != null) {
1776 mNotificationManager.cancel(R.id.ubuntu_progress_notification);
1777 mUbuntuProgressNotification = null;
1778 }
1779 }
1780
1781 /**
1782 * Dismiss Ubuntu notification
1783 */
1784 public void dismissUbuntuNotification() {
1785 if (mUbuntuNotification != null) {
1786 mUbuntuNotification = null;
1787 mNotificationManager.cancel(R.id.ubuntu_notification);
1788 }
1789 }
1790
1791 /**
1792 * Dismiss Ubuntu notification
1793 */
1794 public void dismissUbuntuUpdateNotification() {
1795 if (mUbuntuUpdateNotification != null) {
1796 mUbuntuUpdateNotification = null;
1797 mNotificationManager.cancel(R.id.ubuntu_update_notification);
1798 }
1799 }
1800
1801 /**
1802 * Dismiss Android notification
1803 */
1804 public void dismissAndroidNotification() {
1805 if (mAndroidUpdateNotification != null) {
1806 mAndroidUpdateNotification = null;
1807 mNotificationManager.cancel(R.id.android_update_notification);
1808 }
1809 }
1296}1810}
12971811
=== modified file 'src/com/canonical/ubuntu/installer/Utils.java'
--- src/com/canonical/ubuntu/installer/Utils.java 2014-01-09 08:54:46 +0000
+++ src/com/canonical/ubuntu/installer/Utils.java 2014-06-09 11:59:50 +0000
@@ -1,14 +1,36 @@
1/*
2 * This file is part of Ubuntu dualboot installer for Android.
3 * Copyright 2013 Canonical Ltd.
4 *
5 * Ubuntu dualboot installer is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation.
8 *
9 * Ubuntu dualboot installer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Ubuntu dualboot installer. If not, see <http://www.gnu.org/licenses/>.
16 */
17
1package com.canonical.ubuntu.installer;18package com.canonical.ubuntu.installer;
219
20import android.app.AlarmManager;
3import android.app.AlertDialog;21import android.app.AlertDialog;
22import android.app.PendingIntent;
4import android.content.Context;23import android.content.Context;
5import android.content.DialogInterface;24import android.content.DialogInterface;
6import android.content.Intent;25import android.content.Intent;
26import android.content.SharedPreferences;
7import android.content.res.AssetManager;27import android.content.res.AssetManager;
8import android.net.wifi.WifiManager;28import android.net.wifi.WifiManager;
9import android.os.Build;29import android.os.Build;
10import android.os.StatFs;30import android.os.StatFs;
11import android.util.Log;31import android.util.Log;
32import android.view.Gravity;
33import android.widget.TextView;
12import android.widget.Toast;34import android.widget.Toast;
1335
14import org.apache.http.HttpEntity;36import org.apache.http.HttpEntity;
@@ -22,6 +44,7 @@
22import java.io.File;44import java.io.File;
23import java.io.FileInputStream;45import java.io.FileInputStream;
24import java.io.FileOutputStream;46import java.io.FileOutputStream;
47import java.io.FileReader;
25import java.io.IOException;48import java.io.IOException;
26import java.io.InputStream;49import java.io.InputStream;
27import java.io.InputStreamReader;50import java.io.InputStreamReader;
@@ -30,6 +53,7 @@
30import java.io.StringWriter;53import java.io.StringWriter;
31import java.io.Writer;54import java.io.Writer;
32import java.security.MessageDigest;55import java.security.MessageDigest;
56import java.util.ArrayList;
33import java.util.List;57import java.util.List;
34import java.util.Locale;58import java.util.Locale;
3559
@@ -191,18 +215,43 @@
191 }215 }
192216
193 public static String getDeviceModel() {217 public static String getDeviceModel() {
194 return Build.DEVICE.toLowerCase(Locale.US);218 String deviceModel = Build.DEVICE.toLowerCase(Locale.US);
219 if (deviceModel.equals("deb") || deviceModel.equals("tilapia")) {
220 deviceModel = "flo";
221 }
222 if (isBringupMode()) {
223 deviceModel = "mako";
224 }
225 return deviceModel;
195 }226 }
196227
197 public static boolean isDeviceSupported() {228 public static boolean isDeviceSupported() {
198 String path = getBootPartitionPath();229 String path = getBootPartitionPath();
199 if ("".equals(path)) return false;230 if ("".equals(path)) {
231 return false;
232 } else {
233 return true;
234 }
235 }
236
237 /**
238 * Check if device is in the list of know test devices
239 * of if we are in bringup mode
240 */
241 public static boolean isBringupMode() {
242 if (!UbuntuInstallService.BRINGUP_MODE) {
243 String deviceModel = Build.DEVICE.toLowerCase(Locale.US);
244 if ("bq_aquaris5".equals(deviceModel)) {
245 return true;
246 }
247 return false;
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches