Initial files
This commit is contained in:
commit
0b71cb7e73
7
.classpath
Normal file
7
.classpath
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="gen"/>
|
||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
local.properties
|
||||
bin/*
|
||||
gen/*
|
||||
|
33
.project
Normal file
33
.project
Normal file
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>fdroid</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
22
AndroidManifest.xml
Normal file
22
AndroidManifest.xml
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.fdroid.fdroid" android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
<application android:label="@string/app_name">
|
||||
<activity android:name="FDroid">
|
||||
android:label="@string/app_name"
|
||||
android:icon="@drawable/icon">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="ManageRepo" />
|
||||
<activity android:name="Settings" />
|
||||
<activity android:name="AppDetails" />
|
||||
</application>
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
</manifest>
|
17
build.properties
Normal file
17
build.properties
Normal file
@ -0,0 +1,17 @@
|
||||
# This file is used to override default values used by the Ant build system.
|
||||
#
|
||||
# This file must be checked in Version Control Systems, as it is
|
||||
# integral to the build system of your project.
|
||||
|
||||
# This file is only used by the Ant script.
|
||||
|
||||
# You can use this to override default values such as
|
||||
# 'source.dir' for the location of your java source folder and
|
||||
# 'out.dir' for the location of your output folder.
|
||||
|
||||
# You can also use it define how the release builds are signed by declaring
|
||||
# the following properties:
|
||||
# 'key.store' for the location of your keystore and
|
||||
# 'key.alias' for the name of the key to use.
|
||||
# The password will be asked during the build when you use the 'release' target.
|
||||
|
67
build.xml
Normal file
67
build.xml
Normal file
@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="FDroid" default="help">
|
||||
|
||||
<!-- The local.properties file is created and updated by the 'android' tool.
|
||||
It contains the path to the SDK. It should *NOT* be checked in in Version
|
||||
Control Systems. -->
|
||||
<property file="local.properties" />
|
||||
|
||||
<!-- The build.properties file can be created by you and is never touched
|
||||
by the 'android' tool. This is the place to change some of the default property values
|
||||
used by the Ant rules.
|
||||
Here are some properties you may want to change/update:
|
||||
|
||||
application.package
|
||||
the name of your application package as defined in the manifest. Used by the
|
||||
'uninstall' rule.
|
||||
source.dir
|
||||
the name of the source directory. Default is 'src'.
|
||||
out.dir
|
||||
the name of the output directory. Default is 'bin'.
|
||||
|
||||
Properties related to the SDK location or the project target should be updated
|
||||
using the 'android' tool with the 'update' action.
|
||||
|
||||
This file is an integral part of the build system for your application and
|
||||
should be checked in in Version Control Systems.
|
||||
|
||||
-->
|
||||
<property file="build.properties" />
|
||||
|
||||
<!-- The default.properties file is created and updated by the 'android' tool, as well
|
||||
as ADT.
|
||||
This file is an integral part of the build system for your application and
|
||||
should be checked in in Version Control Systems. -->
|
||||
<property file="default.properties" />
|
||||
|
||||
<!-- Custom Android task to deal with the project target, and import the proper rules.
|
||||
This requires ant 1.6.0 or above. -->
|
||||
<path id="android.antlibs">
|
||||
<pathelement path="${sdk.dir}/tools/lib/anttasks.jar" />
|
||||
<pathelement path="${sdk.dir}/tools/lib/sdklib.jar" />
|
||||
<pathelement path="${sdk.dir}/tools/lib/androidprefs.jar" />
|
||||
<pathelement path="${sdk.dir}/tools/lib/apkbuilder.jar" />
|
||||
<pathelement path="${sdk.dir}/tools/lib/jarutils.jar" />
|
||||
</path>
|
||||
|
||||
<taskdef name="setup"
|
||||
classname="com.android.ant.SetupTask"
|
||||
classpathref="android.antlibs" />
|
||||
|
||||
<!-- Execute the Android Setup task that will setup some properties specific to the target,
|
||||
and import the build rules files.
|
||||
|
||||
The rules file is imported from
|
||||
<SDK>/platforms/<target_platform>/templates/android_rules.xml
|
||||
|
||||
To customize some build steps for your project:
|
||||
- copy the content of the main node <project> from android_rules.xml
|
||||
- paste it in this build.xml below the <setup /> task.
|
||||
- disable the import by changing the setup task below to <setup import="false" />
|
||||
|
||||
This will ensure that the properties are setup correctly but that your customized
|
||||
build steps are used.
|
||||
-->
|
||||
<setup />
|
||||
|
||||
</project>
|
13
default.properties
Normal file
13
default.properties
Normal file
@ -0,0 +1,13 @@
|
||||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
# To customize properties used by the Ant build system use,
|
||||
# "build.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
|
||||
# Indicates whether an apk should be generated for each density.
|
||||
split.density=false
|
||||
# Project target.
|
||||
target=android-4
|
BIN
res/drawable/btn_check_off.png
Normal file
BIN
res/drawable/btn_check_off.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
res/drawable/btn_check_on.png
Normal file
BIN
res/drawable/btn_check_on.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
BIN
res/drawable/icon.png
Normal file
BIN
res/drawable/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
38
res/layout/about.xml
Normal file
38
res/layout/about.xml
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent" android:layout_height="fill_parent"
|
||||
android:orientation="vertical" android:paddingLeft="5px">
|
||||
|
||||
<LinearLayout android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" android:orientation="horizontal">
|
||||
|
||||
<TextView android:id="@+id/site" android:text="@string/about_site"
|
||||
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||
android:textSize="16px" android:textColor="#ffffff" />
|
||||
|
||||
<TextView android:id="@+id/sitec" android:text="http://f-droid.org"
|
||||
android:layout_width="wrap_content" android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView android:id="@+id/not" android:text=" "
|
||||
android:layout_width="wrap_content" android:layout_height="wrap_content" />
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent" android:layout_height="fill_parent"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView android:id="@+id/mail" android:text="@string/about_mail"
|
||||
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||
android:textSize="16px" android:autoLink="email" android:textColor="#ffffff" />
|
||||
|
||||
<TextView android:id="@+id/mailc" android:text="admin@f-droid.org"
|
||||
android:layout_width="wrap_content" android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView android:id="@+id/about11" android:text="@string/about_desc"
|
||||
android:layout_width="fill_parent" android:layout_height="fill_parent"
|
||||
android:textSize="16px" />
|
||||
|
||||
</LinearLayout>
|
37
res/layout/addrepo.xml
Normal file
37
res/layout/addrepo.xml
Normal file
@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:ems="20"
|
||||
android:layout_height="wrap_content" android:text="@string/repo_add_url"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/edit_uri"
|
||||
android:maxLines="1"
|
||||
android:layout_width="wrap_content"
|
||||
android:ems="20"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="http://"/>
|
||||
</LinearLayout>
|
||||
<!--
|
||||
* Copyright (C) 2009 Roberto Jacinto
|
||||
* roberto.jacinto@caixamagica.pt
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
-->
|
20
res/layout/apklistitem.xml
Normal file
20
res/layout/apklistitem.xml
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/vw1" android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" android:orientation="horizontal">
|
||||
|
||||
<RelativeLayout android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" android:orientation="vertical">
|
||||
|
||||
<TextView android:id="@+id/version" android:textStyle="bold"
|
||||
android:singleLine="true" android:ellipsize="marquee"
|
||||
android:layout_width="fill_parent" android:layout_height="wrap_content"
|
||||
android:textSize="18sp" />
|
||||
|
||||
<TextView android:id="@+id/status" android:textSize="12sp"
|
||||
android:layout_below="@id/version" android:layout_alignParentRight="false"
|
||||
android:layout_height="wrap_content" android:layout_width="wrap_content" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
41
res/layout/appdetails.xml
Normal file
41
res/layout/appdetails.xml
Normal file
@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent" android:layout_height="fill_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout android:id="@+id/header"
|
||||
android:layout_width="fill_parent" android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView android:id="@+id/icon" android:cropToPadding="true"
|
||||
android:padding="4px" android:scaleType="centerInside"
|
||||
android:layout_height="50px" android:layout_width="50px" />
|
||||
|
||||
<RelativeLayout android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" android:orientation="vertical">
|
||||
|
||||
<TextView android:id="@+id/title" android:textStyle="bold"
|
||||
android:singleLine="true" android:ellipsize="marquee"
|
||||
android:layout_width="fill_parent" android:layout_height="wrap_content"
|
||||
android:textSize="18sp" />
|
||||
|
||||
<TextView android:id="@+id/license" android:textSize="12sp"
|
||||
android:layout_below="@id/title" android:layout_alignParentRight="true"
|
||||
android:layout_height="wrap_content" android:layout_width="wrap_content" />
|
||||
|
||||
<TextView android:id="@+id/status" android:layout_toLeftOf="@id/license"
|
||||
android:layout_below="@id/title" android:layout_alignParentLeft="true"
|
||||
android:textSize="12sp" android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView android:id="@+id/description" android:singleLine="false"
|
||||
android:layout_width="fill_parent" android:layout_height="wrap_content" />
|
||||
|
||||
<ListView android:id="@android:id/list" android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" />
|
||||
|
||||
</LinearLayout>
|
39
res/layout/applistitem.xml
Normal file
39
res/layout/applistitem.xml
Normal file
@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/vw1" android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" android:orientation="vertical">
|
||||
|
||||
<LinearLayout android:id="@+id/vw2" android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" android:orientation="horizontal">
|
||||
|
||||
<ImageView android:id="@+id/icon" android:cropToPadding="true"
|
||||
android:padding="4px" android:scaleType="centerInside"
|
||||
android:layout_height="50px" android:layout_width="50px" />
|
||||
|
||||
<RelativeLayout android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" android:orientation="vertical">
|
||||
|
||||
<TextView android:id="@+id/name" android:textStyle="bold"
|
||||
android:singleLine="true" android:ellipsize="marquee"
|
||||
android:layout_width="fill_parent" android:layout_height="wrap_content"
|
||||
android:textSize="18sp" />
|
||||
|
||||
<TextView android:id="@+id/license" android:textSize="12sp"
|
||||
android:layout_below="@id/name" android:layout_alignParentRight="true"
|
||||
android:layout_height="wrap_content" android:layout_width="wrap_content" />
|
||||
|
||||
<TextView android:id="@+id/status" android:layout_toLeftOf="@id/license"
|
||||
android:layout_below="@id/name" android:layout_alignParentLeft="true"
|
||||
android:textSize="12sp" android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent" />
|
||||
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView android:id="@+id/summary" android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent" />
|
||||
|
||||
</LinearLayout>
|
||||
|
16
res/layout/fdroid.xml
Normal file
16
res/layout/fdroid.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@android:id/tabhost" android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<TabWidget android:id="@android:id/tabs"
|
||||
android:layout_width="fill_parent" android:layout_height="wrap_content" />
|
||||
|
||||
<FrameLayout android:id="@android:id/tabcontent"
|
||||
android:layout_width="fill_parent" android:layout_height="fill_parent"
|
||||
android:paddingTop="65px">
|
||||
<ListView android:id="@android:id/list" android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" />
|
||||
</FrameLayout>
|
||||
|
||||
</TabHost>
|
36
res/layout/remrepo.xml
Normal file
36
res/layout/remrepo.xml
Normal file
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="6dip"
|
||||
android:paddingRight="6dip"
|
||||
android:paddingBottom="6dip">
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/rem_lst"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawSelectorOnTop="true"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
<!--
|
||||
* Copyright (C) 2009 Roberto Jacinto
|
||||
* roberto.jacinto@caixamagica.pt
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
-->
|
32
res/layout/repolist.xml
Normal file
32
res/layout/repolist.xml
Normal file
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<ListView android:id="@android:id/list"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"/>
|
||||
|
||||
<TextView android:id="@android:id/empty"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="200px"
|
||||
android:text="@string/no_repo"/>
|
||||
</LinearLayout>
|
||||
<!--
|
||||
* Copyright (C) 2009 Roberto Jacinto
|
||||
* roberto.jacinto@caixamagica.pt
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
-->
|
46
res/layout/repolisticons.xml
Normal file
46
res/layout/repolisticons.xml
Normal file
@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/vw1"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView android:id="@+id/img"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView android:id="@+id/uri"
|
||||
android:textSize="21sp"
|
||||
android:textStyle="bold"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
<!--
|
||||
* Copyright (C) 2009 Roberto Jacinto
|
||||
* roberto.jacinto@caixamagica.pt
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
-->
|
37
res/values/alertstr.xml
Normal file
37
res/values/alertstr.xml
Normal file
@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources>
|
||||
<string name="up_server">Servers: </string>
|
||||
<string name="lstver">Server version: </string>
|
||||
<string name="isinst">Installed: </string>
|
||||
<string name="instver">Installed version: </string>
|
||||
<string name="install">Install </string>
|
||||
<string name="rem">Uninstall </string>
|
||||
<string name="update">Update!</string>
|
||||
|
||||
<string name="update_alrt">There updates available for some installed applications.\nDo you wish to see them?</string>
|
||||
<string name="repo_alrt">The list of repositories in use has been changed.\nDo you wish to update them?</string>
|
||||
|
||||
<string name="error_download_alrt">Could not connect to server or apk file is corrupt!</string>
|
||||
<string name="download_alrt">Getting application from:\n </string>
|
||||
|
||||
|
||||
|
||||
</resources>
|
||||
<!--
|
||||
* Copyright (C) 2009 Roberto Jacinto
|
||||
* roberto.jacinto@caixamagica.pt
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
-->
|
37
res/values/menu.xml
Normal file
37
res/values/menu.xml
Normal file
@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources>
|
||||
|
||||
|
||||
|
||||
<string name="menu_update_repo">Update</string>
|
||||
<string name="menu_manage">Manage Repos</string>
|
||||
|
||||
|
||||
<string name="menu_about">About</string>
|
||||
|
||||
|
||||
|
||||
<string name="menu_add_repo">New Repository</string>
|
||||
<string name="menu_rem_repo">Remove Repository</string>
|
||||
|
||||
|
||||
|
||||
</resources>
|
||||
<!--
|
||||
* Copyright (C) 2009 Roberto Jacinto
|
||||
* roberto.jacinto@caixamagica.pt
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
-->
|
23
res/values/path.xml
Normal file
23
res/values/path.xml
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources>
|
||||
<string name="icons_path">/sdcard/.fdroid/icons/</string>
|
||||
|
||||
</resources>
|
||||
<!--
|
||||
* Copyright (C) 2009 Roberto Jacinto
|
||||
* roberto.jacinto@caixamagica.pt
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
-->
|
61
res/values/strings.xml
Normal file
61
res/values/strings.xml
Normal file
@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">FDroid</string>
|
||||
<string name="about_title">About FDroid</string>
|
||||
<string name="about_desc">Based on Aptoide.\nReleased under the GNU GPL v2 license.</string>
|
||||
<string name="about_site">Home: </string>
|
||||
<string name="about_mail">e-Mail: </string>
|
||||
<string name="about_website">Web Site</string>
|
||||
|
||||
<string name="no_found">No application found!</string>
|
||||
<string name="no_repo">You have no repositories configured!\n\nA repository is a source of applications. To add one, press the MENU button now and enter the URL.\n\nA repository URL looks something like this: http://f-droid.org/repo</string>
|
||||
|
||||
<string name="not_inst">Not Installed</string>
|
||||
<string name="installed">Installed - Ver.:</string>
|
||||
<string name="installed_update">Update possible - Ver.:</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="error">Error</string>
|
||||
<string name="ok">Ok</string>
|
||||
|
||||
<string name="yes">Yes</string>
|
||||
<string name="no">No</string>
|
||||
<string name="repo_add_title">Add new repository</string>
|
||||
<string name="repo_add_add">Add</string>
|
||||
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="repo_delete_title">Chose repository to remove</string>
|
||||
<string name="url_website">http://f-droid.org</string>
|
||||
<string name="server_connection_error">Could not connect to server!</string>
|
||||
|
||||
<string name="repo_update_title">Update repositories</string>
|
||||
<string name="tab_installed">Installed</string>
|
||||
<string name="tab_noninstalled">Available</string>
|
||||
<string name="tab_updates">Updates</string>
|
||||
<string name="update_available">Updates available</string>
|
||||
<string name="process_wait_title">Please Wait</string>
|
||||
<string name="process_update_msg">Updating application list...</string>
|
||||
<string name="connection_error">Could not connect to the network.</string>
|
||||
<string name="connection_timeout">Timeout</string>
|
||||
<string name="connection_error_msg">Could not connect to server!</string>
|
||||
<string name="download">Download</string>
|
||||
<string name="download_server">Getting application from</string>
|
||||
<string name="apk_market_view">Market</string>
|
||||
<string name="apk_version_new"> available v </string>
|
||||
<string name="settings_sort_title">Sort application list by:</string>
|
||||
<string name="settings_sort_abc">Alphabetically</string>
|
||||
<string name="settings_sort_installed">Installed / Not Installed</string>
|
||||
<string name="settings_sort_recent">Most recent first</string>
|
||||
<string name="settings_sort_rating">Rating</string>
|
||||
<string name="settings_filter_title">Show applications:</string>
|
||||
<string name="settings_filter_category">By category</string>
|
||||
<string name="settings_filter_all">All applications</string>
|
||||
<string name="settings_save">Save</string>
|
||||
<string name="repo_add_url">Repository URL</string>
|
||||
</resources>
|
354
src/org/fdroid/fdroid/AppDetails.java
Normal file
354
src/org/fdroid/fdroid/AppDetails.java
Normal file
@ -0,0 +1,354 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Ciaran Gultnieks, ciaran@ciarang.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package org.fdroid.fdroid;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.fdroid.fdroid.R;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.ListActivity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
|
||||
public class AppDetails extends ListActivity {
|
||||
|
||||
private String LOCAL_PATH = "/sdcard/.fdroid";
|
||||
|
||||
private static final int REQUEST_INSTALL = 0;
|
||||
private static final int REQUEST_UNINSTALL = 1;
|
||||
|
||||
private class ApkListAdapter extends BaseAdapter {
|
||||
|
||||
private List<DB.Apk> items = new ArrayList<DB.Apk>();
|
||||
|
||||
public ApkListAdapter(Context context) {
|
||||
}
|
||||
|
||||
public void addItem(DB.Apk apk) {
|
||||
items.add(apk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return items.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return items.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
View v = convertView;
|
||||
if (v == null) {
|
||||
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
v = vi.inflate(R.layout.apklistitem, null);
|
||||
}
|
||||
DB.Apk apk = items.get(position);
|
||||
TextView version = (TextView) v.findViewById(R.id.version);
|
||||
version.setText("Version " + apk.version);
|
||||
TextView status = (TextView) v.findViewById(R.id.status);
|
||||
if (apk.version.equals(app.installedVersion))
|
||||
status.setText("Installed");
|
||||
else
|
||||
status.setText("Not installed");
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
private DB db;
|
||||
private DB.App app;
|
||||
private DB.Apk curapk;
|
||||
private String appid;
|
||||
private PackageManager mPm;
|
||||
private ProgressDialog pd;
|
||||
|
||||
private Context mctx = this;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.appdetails);
|
||||
|
||||
db = new DB(this);
|
||||
mPm = getPackageManager();
|
||||
|
||||
Intent i = getIntent();
|
||||
appid = "";
|
||||
if (!i.hasExtra("appid")) {
|
||||
Log.d("FDroid", "No application ID in AppDetails!?");
|
||||
} else {
|
||||
appid = i.getStringExtra("appid");
|
||||
}
|
||||
|
||||
reset(false);
|
||||
|
||||
}
|
||||
|
||||
// Reset the display and list contents. Used when entering the activity, and
|
||||
// also when something has been installed/uninstalled. In the latter case,
|
||||
// 'update' is true to make the installed status get refreshed.
|
||||
private void reset(boolean update) {
|
||||
|
||||
Log.d("FDroid", "Getting application details for " + appid);
|
||||
app = db.getApps(appid, null, update).get(0);
|
||||
|
||||
// Set the icon...
|
||||
ImageView iv = (ImageView) findViewById(R.id.icon);
|
||||
String icon_path = this.getString(R.string.icons_path) + app.icon;
|
||||
File test_icon = new File(icon_path);
|
||||
if (test_icon.exists()) {
|
||||
iv.setImageDrawable(new BitmapDrawable(icon_path));
|
||||
} else {
|
||||
iv.setImageResource(android.R.drawable.sym_def_app_icon);
|
||||
}
|
||||
|
||||
// Set the title and other header details...
|
||||
TextView tv = (TextView) findViewById(R.id.title);
|
||||
tv.setText(app.name);
|
||||
tv = (TextView) findViewById(R.id.license);
|
||||
tv.setText(app.license);
|
||||
tv = (TextView) findViewById(R.id.status);
|
||||
int vnum = app.apks.size();
|
||||
String v = vnum == 1 ? "version" : "versions";
|
||||
tv.setText("" + vnum + " " + v + ", "
|
||||
+ (app.installedVersion == null ? "not" : "1") + " installed");
|
||||
tv = (TextView) findViewById(R.id.description);
|
||||
tv.setText(app.description);
|
||||
|
||||
// Set up the list...
|
||||
ApkListAdapter la = new ApkListAdapter(this);
|
||||
for (DB.Apk apk : app.apks)
|
||||
la.addItem(apk);
|
||||
setListAdapter(la);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onListItemClick(ListView l, View v, int position, long id) {
|
||||
// Create alert dialog...
|
||||
final AlertDialog p = new AlertDialog.Builder(this).create();
|
||||
|
||||
curapk = app.apks.get(position);
|
||||
|
||||
// Set the title and icon...
|
||||
String icon_path = this.getString(R.string.icons_path) + app.icon;
|
||||
File test_icon = new File(icon_path);
|
||||
if (test_icon.exists()) {
|
||||
p.setIcon(new BitmapDrawable(icon_path));
|
||||
} else {
|
||||
p.setIcon(android.R.drawable.sym_def_app_icon);
|
||||
}
|
||||
p.setTitle(app.name + " " + curapk.version);
|
||||
|
||||
boolean caninstall = true;
|
||||
String installed = getString(R.string.no);
|
||||
if (app.installedVersion != null) {
|
||||
if (app.installedVersion.equals(curapk.version)) {
|
||||
installed = getString(R.string.yes);
|
||||
caninstall = false;
|
||||
} else {
|
||||
installed += " - " + app.installedVersion;
|
||||
}
|
||||
}
|
||||
p.setMessage(getString(R.string.isinst) + " " + installed);
|
||||
|
||||
p.setButton(getString(R.string.ok),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
if (caninstall) {
|
||||
p.setButton2(getString(R.string.install),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
p.dismiss();
|
||||
new Thread() {
|
||||
public void run() {
|
||||
String apk_pkg = downloadFile(app, curapk);
|
||||
if (apk_pkg == null) {
|
||||
Message msg = new Message();
|
||||
msg.arg1 = 1;
|
||||
download_handler.sendMessage(msg);
|
||||
download_error_handler
|
||||
.sendEmptyMessage(0);
|
||||
} else {
|
||||
installApk(apk_pkg);
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
p.setButton3(getString(R.string.apk_market_view),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
startActivity(new Intent(Intent.ACTION_VIEW, Uri
|
||||
.parse("market://search?q=pname:" + app.id)));
|
||||
}
|
||||
});
|
||||
|
||||
if (!caninstall) {
|
||||
p.setButton2(getString(R.string.rem),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
removeApk(app.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
p.show();
|
||||
}
|
||||
|
||||
// Download the requested apk file, given the DB.App and DB.Apk
|
||||
// that refer to it. Returns the path to the downloaded file, or
|
||||
// null if the download was not successful.
|
||||
private String downloadFile(DB.App app, DB.Apk apk) {
|
||||
try {
|
||||
|
||||
String apkname = apk.apkName;
|
||||
String localfile = new String(LOCAL_PATH + "/" + apkname);
|
||||
String remotefile = apk.server + "/" + apkname.replace(" ", "%20");
|
||||
|
||||
Log.d("FDroid", "Downloading apk from " + remotefile);
|
||||
|
||||
Message msg = new Message();
|
||||
msg.arg1 = 0;
|
||||
msg.obj = new String(remotefile);
|
||||
download_handler.sendMessage(msg);
|
||||
|
||||
BufferedInputStream getit = new BufferedInputStream(new URL(
|
||||
remotefile).openStream());
|
||||
|
||||
FileOutputStream saveit = new FileOutputStream(localfile);
|
||||
BufferedOutputStream bout = new BufferedOutputStream(saveit, 1024);
|
||||
byte data[] = new byte[1024];
|
||||
|
||||
int readed = getit.read(data, 0, 1024);
|
||||
while (readed != -1) {
|
||||
bout.write(data, 0, readed);
|
||||
readed = getit.read(data, 0, 1024);
|
||||
}
|
||||
bout.close();
|
||||
getit.close();
|
||||
saveit.close();
|
||||
File f = new File(localfile);
|
||||
Md5Handler hash = new Md5Handler();
|
||||
|
||||
if (apk.hash.equalsIgnoreCase(hash.md5Calc(f))) {
|
||||
return localfile;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d("FDroid", "Download failed - " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Handler download_handler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
if (msg.arg1 == 0) {
|
||||
pd = ProgressDialog.show(mctx, getString(R.string.download),
|
||||
getString(R.string.download_server) + ":\n "
|
||||
+ msg.obj.toString(), true);
|
||||
} else {
|
||||
pd.dismiss();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private Handler download_error_handler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
Toast.makeText(mctx, getString(R.string.connection_error_msg),
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
};
|
||||
|
||||
private void removeApk(String id) {
|
||||
PackageInfo pkginfo;
|
||||
try {
|
||||
pkginfo = mPm.getPackageInfo(id, 0);
|
||||
} catch (NameNotFoundException e) {
|
||||
Log.d("FDroid", "Couldn't find package " + id + " to uninstall.");
|
||||
return;
|
||||
}
|
||||
Uri uri = Uri.fromParts("package", pkginfo.packageName, null);
|
||||
Intent intent = new Intent(Intent.ACTION_DELETE, uri);
|
||||
startActivityForResult(intent, REQUEST_UNINSTALL);
|
||||
}
|
||||
|
||||
private void installApk(String id) {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(android.content.Intent.ACTION_VIEW);
|
||||
intent.setDataAndType(Uri.parse("file://" + id),
|
||||
"application/vnd.android.package-archive");
|
||||
|
||||
Message msg = new Message();
|
||||
msg.arg1 = 1;
|
||||
download_handler.sendMessage(msg);
|
||||
|
||||
startActivityForResult(intent, REQUEST_INSTALL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
reset(true);
|
||||
}
|
||||
|
||||
}
|
445
src/org/fdroid/fdroid/DB.java
Normal file
445
src/org/fdroid/fdroid/DB.java
Normal file
@ -0,0 +1,445 @@
|
||||
/*
|
||||
a * Copyright (C) 2010 Ciaran Gultnieks, ciaran@ciarang.com
|
||||
* Copyright (C) 2009 Roberto Jacinto, roberto.jacinto@caixamagica.pt
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package org.fdroid.fdroid;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Vector;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.util.Log;
|
||||
|
||||
public class DB {
|
||||
|
||||
private static final String DATABASE_NAME = "fdroid_db";
|
||||
|
||||
private SQLiteDatabase db;
|
||||
|
||||
// The TABLE_APP table stores details of all the applications we know about.
|
||||
// This information is retrieved from the repositories.
|
||||
private static final String TABLE_APP = "fdroid_app";
|
||||
private static final String CREATE_TABLE_APP = "create table " + TABLE_APP
|
||||
+ "( " + "id text not null, " + "name text not null, "
|
||||
+ "summary text not null, " + "icon text, "
|
||||
+ "description text not null, " + "license text not null, "
|
||||
+ "webURL text, " + "trackerURL text, " + "sourceURL text, "
|
||||
+ "installedVersion text," + "hasUpdates int not null,"
|
||||
+ "primary key(id));";
|
||||
|
||||
public static class App {
|
||||
|
||||
public App() {
|
||||
name = "Unknown";
|
||||
summary = "Unknown application";
|
||||
icon = "noicon.png";
|
||||
id = "unknown";
|
||||
hasUpdates = false;
|
||||
updated = false;
|
||||
apks = new Vector<Apk>();
|
||||
}
|
||||
|
||||
public String id;
|
||||
public String name;
|
||||
public String summary;
|
||||
public String icon;
|
||||
public String description;
|
||||
public String license;
|
||||
public String webURL;
|
||||
public String trackerURL;
|
||||
public String sourceURL;
|
||||
public String installedVersion;
|
||||
|
||||
// True if there are new versions (apks) that the user hasn't
|
||||
// explicitly ignored.
|
||||
public boolean hasUpdates;
|
||||
|
||||
// Used internally for tracking during repo updates.
|
||||
public boolean updated;
|
||||
|
||||
public Vector<Apk> apks;
|
||||
}
|
||||
|
||||
// The TABLE_APK table stores details of all the application versions we
|
||||
// know
|
||||
// about. Each relates directly back to an entry in TABLE_APP.
|
||||
// This information is retrieved from the repositories.
|
||||
private static final String TABLE_APK = "fdroid_apk";
|
||||
private static final String CREATE_TABLE_APK = "create table " + TABLE_APK
|
||||
+ "( " + "id text not null, " + "version text not null, "
|
||||
+ "server text not null, " + "hash text not null, "
|
||||
+ "apkName text not null, " + "primary key(id,version));";
|
||||
|
||||
public static class Apk {
|
||||
|
||||
public Apk() {
|
||||
updated = false;
|
||||
}
|
||||
|
||||
public String id;
|
||||
public String version;
|
||||
public String server;
|
||||
public String hash;
|
||||
public String apkName;
|
||||
|
||||
// Used internally for tracking during repo updates.
|
||||
public boolean updated;
|
||||
|
||||
public String getURL() {
|
||||
String path = apkName.replace(" ", "%20");
|
||||
return server + "/" + path;
|
||||
}
|
||||
}
|
||||
|
||||
// The TABLE_REPO table stores the details of the repositories in use.
|
||||
private static final String TABLE_REPO = "fdroid_repo";
|
||||
private static final String CREATE_TABLE_REPO = "create table "
|
||||
+ TABLE_REPO + " (" + "address text primary key, "
|
||||
+ "inuse integer not null, " + "priority integer not null);";
|
||||
|
||||
public static class Repo {
|
||||
public String address;
|
||||
public boolean inuse;
|
||||
public int priority;
|
||||
}
|
||||
|
||||
private PackageManager mPm;
|
||||
|
||||
public DB(Context ctx) {
|
||||
db = ctx.openOrCreateDatabase(DATABASE_NAME, 0, null);
|
||||
|
||||
Cursor c = db.rawQuery(
|
||||
"SELECT name FROM sqlite_master WHERE type='table' AND name= '"
|
||||
+ TABLE_REPO + "'", null);
|
||||
if (c.getCount() == 0) {
|
||||
reset();
|
||||
}
|
||||
c.close();
|
||||
|
||||
mPm = ctx.getPackageManager();
|
||||
}
|
||||
|
||||
// Reset the database, i.e. (re-)create all the tables from scratch and
|
||||
// populate any initial data.
|
||||
public void reset() {
|
||||
db.execSQL("drop table if exists " + TABLE_REPO);
|
||||
db.execSQL("drop table if exists " + TABLE_APP);
|
||||
db.execSQL("drop table if exists " + TABLE_APK);
|
||||
db.execSQL(CREATE_TABLE_REPO);
|
||||
db.execSQL(CREATE_TABLE_APP);
|
||||
db.execSQL(CREATE_TABLE_APK);
|
||||
addServer("http://f-droid.org/repo", 10);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
db.close();
|
||||
db = null;
|
||||
}
|
||||
|
||||
// Return a list of apps matching the given criteria.
|
||||
// 'appid' - specific app id to retrieve, or null
|
||||
// 'filter' - search text to filter on.
|
||||
// 'update' - update installed version information from device, rather than
|
||||
// simply using values cached in the database. Slower.
|
||||
public Vector<App> getApps(String appid, String filter, boolean update) {
|
||||
Vector<App> result = new Vector<App>();
|
||||
Cursor c = null;
|
||||
Cursor c2 = null;
|
||||
try {
|
||||
|
||||
String query = "select * from " + TABLE_APP;
|
||||
if (appid != null) {
|
||||
query += " where id = '" + appid + "'";
|
||||
} else if (filter != null) {
|
||||
query += " where name like '%" + filter + "%'"
|
||||
+ " or description like '%" + filter + "%'";
|
||||
}
|
||||
query += " order by name collate nocase";
|
||||
|
||||
c = db.rawQuery(query, null);
|
||||
c.moveToFirst();
|
||||
while (!c.isAfterLast()) {
|
||||
|
||||
App app = new App();
|
||||
app.id = c.getString(c.getColumnIndex("id"));
|
||||
app.name = c.getString(c.getColumnIndex("name"));
|
||||
app.summary = c.getString(c.getColumnIndex("summary"));
|
||||
app.icon = c.getString(c.getColumnIndex("icon"));
|
||||
app.description = c.getString(c.getColumnIndex("description"));
|
||||
app.license = c.getString(c.getColumnIndex("license"));
|
||||
app.webURL = c.getString(c.getColumnIndex("webURL"));
|
||||
app.trackerURL = c.getString(c.getColumnIndex("trackerURL"));
|
||||
app.sourceURL = c.getString(c.getColumnIndex("sourceURL"));
|
||||
app.installedVersion = c.getString(c
|
||||
.getColumnIndex("installedVersion"));
|
||||
app.hasUpdates = c.getInt(c.getColumnIndex("hasUpdates")) == 1;
|
||||
|
||||
c2 = db.rawQuery("select * from " + TABLE_APK + " where "
|
||||
+ "id = '" + app.id + "'", null);
|
||||
c2.moveToFirst();
|
||||
while (!c2.isAfterLast()) {
|
||||
Apk apk = new Apk();
|
||||
apk.id = app.id;
|
||||
apk.version = c2.getString(c2.getColumnIndex("version"));
|
||||
apk.server = c2.getString(c2.getColumnIndex("server"));
|
||||
apk.hash = c2.getString(c2.getColumnIndex("hash"));
|
||||
apk.apkName = c2.getString(c2.getColumnIndex("apkName"));
|
||||
app.apks.add(apk);
|
||||
c2.moveToNext();
|
||||
}
|
||||
|
||||
result.add(app);
|
||||
c.moveToNext();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.d("FDroid", "Exception during database reading - "
|
||||
+ e.getMessage());
|
||||
} finally {
|
||||
if (c != null) {
|
||||
c.close();
|
||||
}
|
||||
if (c2 != null) {
|
||||
c2.close();
|
||||
}
|
||||
}
|
||||
|
||||
if (update) {
|
||||
getUpdates(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Verify installed status against the system's package list.
|
||||
private void getUpdates(Vector<DB.App> apps) {
|
||||
List<PackageInfo> installedPackages = mPm.getInstalledPackages(0);
|
||||
Map<String, PackageInfo> systemApks = new HashMap<String, PackageInfo>();
|
||||
for (PackageInfo appInfo : installedPackages) {
|
||||
systemApks.put(appInfo.packageName, appInfo);
|
||||
}
|
||||
|
||||
for (DB.App app : apps) {
|
||||
if (systemApks.containsKey(app.id)) {
|
||||
String version = systemApks.get(app.id).versionName;
|
||||
if (app.installedVersion == null
|
||||
|| !app.installedVersion.equals(version)) {
|
||||
setInstalledVersion(app.id, version);
|
||||
app.installedVersion = version;
|
||||
}
|
||||
} else {
|
||||
if (app.installedVersion != null) {
|
||||
setInstalledVersion(app.id, null);
|
||||
app.installedVersion = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Vector<App> updateApps = null;
|
||||
|
||||
// Called before a repo update starts.
|
||||
public void beginUpdate() {
|
||||
updateApps = getApps(null, null, true);
|
||||
Log.d("FDroid", "AppUpdate: " + updateApps.size()
|
||||
+ " apps before starting.");
|
||||
}
|
||||
|
||||
// Called when a repo update ends. Any applications that have not been
|
||||
// updated (by a call to updateApplication) are assumed to be no longer
|
||||
// in the repos.
|
||||
public void endUpdate() {
|
||||
for (App app : updateApps) {
|
||||
if (!app.updated) {
|
||||
// The application hasn't been updated, so it's no longer
|
||||
// in the repos.
|
||||
db.delete(TABLE_APP, "id = '" + app.id + "'", null);
|
||||
} else {
|
||||
for (Apk apk : app.apks) {
|
||||
if (!apk.updated) {
|
||||
// The package hasn't been updated, so this is a
|
||||
// version that's no longer available.
|
||||
db.delete(TABLE_APK, "id = '" + app.id
|
||||
+ " and version ='" + apk.version + "'", null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
updateApps = null;
|
||||
}
|
||||
|
||||
// Called during update to supply new details for an application (or
|
||||
// details of a completely new one).
|
||||
public void updateApplication(App upapp) {
|
||||
|
||||
if (updateApps == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean found = false;
|
||||
for (App app : updateApps) {
|
||||
if (app.id.equals(upapp.id)) {
|
||||
Log.d("FDroid", "AppUpdate: " + app.id
|
||||
+ " is already in the database.");
|
||||
updateAppIfDifferent(app, upapp);
|
||||
app.updated = true;
|
||||
found = true;
|
||||
for (Apk upapk : upapp.apks) {
|
||||
boolean afound = false;
|
||||
for (Apk apk : app.apks) {
|
||||
if (apk.version.equals(upapk.version)) {
|
||||
Log.d("FDroid", "AppUpdate: " + apk.version
|
||||
+ " is a known version.");
|
||||
updateApkIfDifferent(apk, upapk);
|
||||
apk.updated = true;
|
||||
afound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!afound) {
|
||||
// A new version of this application.
|
||||
Log.d("FDroid", "AppUpdate: " + upapk.version
|
||||
+ " is a new version.");
|
||||
updateApkIfDifferent(null, upapk);
|
||||
upapk.updated = true;
|
||||
app.apks.add(upapk);
|
||||
app.hasUpdates = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
// It's a brand new application...
|
||||
Log
|
||||
.d("FDroid", "AppUpdate: " + upapp.id
|
||||
+ " is a new application.");
|
||||
updateAppIfDifferent(null, upapp);
|
||||
for (Apk upapk : upapp.apks) {
|
||||
updateApkIfDifferent(null, upapk);
|
||||
}
|
||||
upapp.updated = true;
|
||||
updateApps.add(upapp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Update application details in the database, if different to the
|
||||
// previous ones.
|
||||
// 'oldapp' - previous details - i.e. what's in the database.
|
||||
// If null, this app is not in the database at all and
|
||||
// should be added.
|
||||
// 'upapp' - updated details
|
||||
private void updateAppIfDifferent(App oldapp, App upapp) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put("id", upapp.id);
|
||||
values.put("name", upapp.name);
|
||||
values.put("summary", upapp.summary);
|
||||
values.put("icon", upapp.icon);
|
||||
values.put("description", upapp.description);
|
||||
values.put("license", upapp.license);
|
||||
values.put("webURL", upapp.webURL);
|
||||
values.put("trackerURL", upapp.trackerURL);
|
||||
values.put("sourceURL", upapp.sourceURL);
|
||||
values.put("installedVersion", upapp.installedVersion);
|
||||
values.put("hasUpdates", upapp.hasUpdates ? 1 : 0);
|
||||
if (oldapp != null) {
|
||||
db.update(TABLE_APP, values, "id = '" + oldapp.id + "'", null);
|
||||
} else {
|
||||
db.insert(TABLE_APP, null, values);
|
||||
}
|
||||
}
|
||||
|
||||
// Update apk details in the database, if different to the
|
||||
// previous ones.
|
||||
// 'oldapk' - previous details - i.e. what's in the database.
|
||||
// If null, this apk is not in the database at all and
|
||||
// should be added.
|
||||
// 'upapk' - updated details
|
||||
private void updateApkIfDifferent(Apk oldapk, Apk upapk) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put("id", upapk.id);
|
||||
values.put("version", upapk.version);
|
||||
values.put("server", upapk.server);
|
||||
values.put("hash", upapk.hash);
|
||||
values.put("apkName", upapk.apkName);
|
||||
if (oldapk != null) {
|
||||
db.update(TABLE_APK, values, "id = '" + oldapk.id
|
||||
+ "' and version = '" + oldapk.version + "'", null);
|
||||
} else {
|
||||
db.insert(TABLE_APK, null, values);
|
||||
}
|
||||
}
|
||||
|
||||
public void setInstalledVersion(String id, String version) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put("installedVersion", version);
|
||||
db.update(TABLE_APP, values, "id = '" + id + "'", null);
|
||||
}
|
||||
|
||||
// Get a list of the configured repositories.
|
||||
public Vector<Repo> getRepos() {
|
||||
Vector<Repo> repos = new Vector<Repo>();
|
||||
Cursor c = null;
|
||||
try {
|
||||
c = db.rawQuery("select address, inuse, priority from "
|
||||
+ TABLE_REPO + " order by priority", null);
|
||||
c.moveToFirst();
|
||||
while(!c.isAfterLast()) {
|
||||
Repo repo = new Repo();
|
||||
repo.address = c.getString(0);
|
||||
repo.inuse = (c.getInt(1) == 1);
|
||||
repo.priority = c.getInt(2);
|
||||
repos.add(repo);
|
||||
c.moveToNext();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} finally {
|
||||
if (c != null) {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
return repos;
|
||||
}
|
||||
|
||||
public void changeServerStatus(String address) {
|
||||
db.rawQuery("update " + TABLE_REPO
|
||||
+ " set inuse=1-inuse where address='" + address + "'", null);
|
||||
}
|
||||
|
||||
public void addServer(String address, int priority) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put("address", address);
|
||||
values.put("inuse", 1);
|
||||
values.put("priority", priority);
|
||||
db.insert(TABLE_REPO, null, values);
|
||||
}
|
||||
|
||||
public void removeServers(Vector<String> addresses) {
|
||||
for (String address : addresses) {
|
||||
db.delete(TABLE_REPO, "address = '" + address + "'", null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
538
src/org/fdroid/fdroid/FDroid.java
Normal file
538
src/org/fdroid/fdroid/FDroid.java
Normal file
@ -0,0 +1,538 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Ciaran Gultnieks, ciaran@ciarang.com
|
||||
* Copyright (C) 2009 Roberto Jacinto, roberto.jacinto@caixamagica.pt
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package org.fdroid.fdroid;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
|
||||
import org.fdroid.fdroid.R;
|
||||
|
||||
import android.R.drawable;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.app.TabActivity;
|
||||
import android.app.AlertDialog.Builder;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TabHost;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.TabHost.TabSpec;
|
||||
|
||||
public class FDroid extends TabActivity implements OnItemClickListener {
|
||||
|
||||
private class AppListAdapter extends BaseAdapter {
|
||||
|
||||
private List<DB.App> items = new ArrayList<DB.App>();
|
||||
|
||||
public AppListAdapter(Context context) {
|
||||
}
|
||||
|
||||
public void addItem(DB.App app) {
|
||||
items.add(app);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
items.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return items.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return items.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
View v = convertView;
|
||||
if (v == null) {
|
||||
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
v = vi.inflate(R.layout.applistitem, null);
|
||||
}
|
||||
DB.App app = items.get(position);
|
||||
|
||||
TextView name = (TextView) v.findViewById(R.id.name);
|
||||
name.setText(app.name);
|
||||
|
||||
String vs = " versions available";
|
||||
int numav = app.apks.size();
|
||||
if (numav == 1)
|
||||
vs = " version available";
|
||||
TextView status = (TextView) v.findViewById(R.id.status);
|
||||
status.setText(numav + vs);
|
||||
|
||||
TextView license = (TextView) v.findViewById(R.id.license);
|
||||
license.setText(app.license);
|
||||
|
||||
TextView summary = (TextView) v.findViewById(R.id.summary);
|
||||
summary.setText(app.summary);
|
||||
|
||||
ImageView icon = (ImageView) v.findViewById(R.id.icon);
|
||||
String iconpath = new String(FDroid.this
|
||||
.getString(R.string.icons_path)
|
||||
+ app.icon);
|
||||
File icn = new File(iconpath);
|
||||
if (icn.exists() && icn.length() > 0) {
|
||||
new Uri.Builder().build();
|
||||
icon.setImageURI(Uri.parse(iconpath));
|
||||
} else {
|
||||
icon.setImageResource(android.R.drawable.sym_def_app_icon);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
private String LOCAL_PATH = "/sdcard/.fdroid";
|
||||
private String XML_PATH = LOCAL_PATH + "/remapklst.xml";
|
||||
|
||||
private static final int REQUEST_APPDETAILS = 0;
|
||||
private static final int REQUEST_MANAGEREPOS = 1;
|
||||
|
||||
private static final int UPDATE_REPO = Menu.FIRST;
|
||||
private static final int MANAGE_REPO = Menu.FIRST + 1;
|
||||
private static final int RESET_DB = Menu.FIRST + 2;
|
||||
private static final int ABOUT = Menu.FIRST + 3;
|
||||
|
||||
private DB db = null;
|
||||
|
||||
// Apps that are available to be installed
|
||||
private AppListAdapter apps_av = new AppListAdapter(this);
|
||||
|
||||
// Apps that are installed
|
||||
private AppListAdapter apps_in = new AppListAdapter(this);
|
||||
|
||||
// Apps that can be upgraded
|
||||
private AppListAdapter apps_up = new AppListAdapter(this);
|
||||
|
||||
private ProgressDialog pd;
|
||||
|
||||
private Context mctx = this;
|
||||
|
||||
private static final String TAB_IN = "INST";
|
||||
private static final String TAB_UN = "UNIN";
|
||||
private static final String TAB_UP = "UPDT";
|
||||
private TabHost tabHost;
|
||||
private TabSpec ts;
|
||||
private TabSpec ts1;
|
||||
private TabSpec tsUp;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.fdroid);
|
||||
|
||||
File local_path = new File(LOCAL_PATH);
|
||||
if (!local_path.exists())
|
||||
local_path.mkdir();
|
||||
|
||||
File icon_path = new File(this.getString(R.string.icons_path));
|
||||
if (!icon_path.exists())
|
||||
icon_path.mkdir();
|
||||
|
||||
db = new DB(this);
|
||||
|
||||
tabHost = getTabHost();
|
||||
createTabs();
|
||||
|
||||
Intent i = getIntent();
|
||||
if (i.hasExtra("uri")) {
|
||||
Intent call = new Intent(this, ManageRepo.class);
|
||||
call.putExtra("uri", i.getStringExtra("uri"));
|
||||
startActivityForResult(call, REQUEST_MANAGEREPOS);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
populateLists(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
|
||||
super.onCreateOptionsMenu(menu);
|
||||
menu.add(Menu.NONE, UPDATE_REPO, 1, R.string.menu_update_repo).setIcon(
|
||||
android.R.drawable.ic_menu_rotate);
|
||||
menu.add(Menu.NONE, MANAGE_REPO, 2, R.string.menu_manage).setIcon(
|
||||
android.R.drawable.ic_menu_agenda);
|
||||
menu.add(Menu.NONE, RESET_DB, 4, "Reset DB").setIcon(
|
||||
android.R.drawable.ic_menu_revert);
|
||||
menu.add(Menu.NONE, ABOUT, 5, R.string.menu_about).setIcon(
|
||||
android.R.drawable.ic_menu_help);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
|
||||
switch (item.getItemId()) {
|
||||
|
||||
case UPDATE_REPO:
|
||||
updateRepos();
|
||||
return true;
|
||||
|
||||
case MANAGE_REPO:
|
||||
Intent i = new Intent(this, ManageRepo.class);
|
||||
startActivityForResult(i, REQUEST_MANAGEREPOS);
|
||||
return true;
|
||||
|
||||
case RESET_DB:
|
||||
db.reset();
|
||||
populateLists(true);
|
||||
return true;
|
||||
|
||||
case ABOUT:
|
||||
LayoutInflater li = LayoutInflater.from(this);
|
||||
View view = li.inflate(R.layout.about, null);
|
||||
Builder p = new AlertDialog.Builder(this).setView(view);
|
||||
final AlertDialog alrt = p.create();
|
||||
alrt.setIcon(R.drawable.icon);
|
||||
alrt.setTitle(getString(R.string.about_title));
|
||||
alrt.setButton(AlertDialog.BUTTON_NEUTRAL,
|
||||
getString(R.string.about_website),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog,
|
||||
int whichButton) {
|
||||
Uri uri = Uri
|
||||
.parse(getString(R.string.url_website));
|
||||
startActivity(new Intent(Intent.ACTION_VIEW, uri));
|
||||
}
|
||||
});
|
||||
alrt.setButton(AlertDialog.BUTTON_NEGATIVE, "Ok",
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog,
|
||||
int whichButton) {
|
||||
}
|
||||
});
|
||||
alrt.show();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
|
||||
switch (requestCode) {
|
||||
case REQUEST_APPDETAILS:
|
||||
populateLists(false);
|
||||
break;
|
||||
case REQUEST_MANAGEREPOS:
|
||||
if (data.hasExtra("update")) {
|
||||
AlertDialog.Builder ask_alrt = new AlertDialog.Builder(this);
|
||||
ask_alrt.setTitle(getString(R.string.repo_update_title));
|
||||
ask_alrt.setIcon(android.R.drawable.ic_menu_rotate);
|
||||
ask_alrt.setMessage(getString(R.string.repo_alrt));
|
||||
ask_alrt.setPositiveButton(getString(R.string.yes),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog,
|
||||
int whichButton) {
|
||||
updateRepos();
|
||||
}
|
||||
});
|
||||
ask_alrt.setNegativeButton(getString(R.string.no),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog,
|
||||
int whichButton) {
|
||||
return;
|
||||
}
|
||||
});
|
||||
AlertDialog alert = ask_alrt.create();
|
||||
alert.show();
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void createTabs() {
|
||||
tabHost.clearAllTabs();
|
||||
|
||||
// TabContentFactory that can generate the appropriate list for each
|
||||
// tab...
|
||||
TabHost.TabContentFactory tf = new TabHost.TabContentFactory() {
|
||||
@Override
|
||||
public View createTabContent(String tag) {
|
||||
|
||||
AppListAdapter ad;
|
||||
if (tag.equals(TAB_IN))
|
||||
ad = apps_in;
|
||||
else if (tag.equals(TAB_UP))
|
||||
ad = apps_up;
|
||||
else
|
||||
ad = apps_av;
|
||||
|
||||
ListView lst = new ListView(FDroid.this);
|
||||
lst.setOnItemClickListener(FDroid.this);
|
||||
lst.setAdapter(ad);
|
||||
return lst;
|
||||
}
|
||||
};
|
||||
|
||||
// Create the tab of installed apps...
|
||||
ts = tabHost.newTabSpec(TAB_IN);
|
||||
ts.setIndicator(getString(R.string.tab_installed), getResources()
|
||||
.getDrawable(drawable.star_off));
|
||||
ts.setContent(tf);
|
||||
|
||||
// Create the tab of apps with updates...
|
||||
tsUp = tabHost.newTabSpec(TAB_UP);
|
||||
tsUp.setIndicator(getString(R.string.tab_updates), getResources()
|
||||
.getDrawable(drawable.star_on));
|
||||
tsUp.setContent(tf);
|
||||
|
||||
// Create the tab of available apps...
|
||||
ts1 = tabHost.newTabSpec(TAB_UN);
|
||||
ts1.setIndicator(getString(R.string.tab_noninstalled), getResources()
|
||||
.getDrawable(drawable.ic_input_add));
|
||||
ts1.setContent(tf);
|
||||
|
||||
tabHost.addTab(ts1);
|
||||
tabHost.addTab(ts);
|
||||
tabHost.addTab(tsUp);
|
||||
|
||||
}
|
||||
|
||||
// Populate the lists.
|
||||
// 'update' - true to update the installed status of the applications
|
||||
// by asking the system.
|
||||
private void populateLists(boolean update) {
|
||||
|
||||
Vector<DB.App> apps = db.getApps(null, null, update);
|
||||
Log.d("FDroid", "Updating lists - " + apps.size() + " apps in total");
|
||||
|
||||
apps_in.clear();
|
||||
apps_av.clear();
|
||||
apps_up.clear();
|
||||
for (DB.App app : apps) {
|
||||
if (app.installedVersion == null) {
|
||||
apps_av.addItem(app);
|
||||
} else {
|
||||
apps_in.addItem(app);
|
||||
if (app.hasUpdates)
|
||||
apps_up.addItem(app);
|
||||
}
|
||||
}
|
||||
|
||||
// Tell the lists that the data behind the adapter has changed, so
|
||||
// they can refresh...
|
||||
apps_av.notifyDataSetChanged();
|
||||
apps_in.notifyDataSetChanged();
|
||||
apps_up.notifyDataSetChanged();
|
||||
|
||||
}
|
||||
|
||||
public boolean updateRepos() {
|
||||
pd = ProgressDialog.show(this, getString(R.string.process_wait_title),
|
||||
getString(R.string.process_update_msg), true);
|
||||
pd.setIcon(android.R.drawable.ic_dialog_info);
|
||||
|
||||
// Check for connection first!
|
||||
ConnectivityManager netstate = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
if (netstate.getNetworkInfo(1).getState() == NetworkInfo.State.CONNECTED
|
||||
|| netstate.getNetworkInfo(0).getState() == NetworkInfo.State.CONNECTED) {
|
||||
new Thread() {
|
||||
public void run() {
|
||||
try {
|
||||
db.beginUpdate();
|
||||
Vector<DB.Repo> repos = db.getRepos();
|
||||
for (DB.Repo repo : repos) {
|
||||
if (repo.inuse) {
|
||||
downloadRepoIndex(repo.address);
|
||||
xmlPass(repo.address);
|
||||
}
|
||||
}
|
||||
db.endUpdate();
|
||||
} catch (Exception e) {
|
||||
Log.d("FDroid", "Exception while updating - "
|
||||
+ e.getMessage());
|
||||
}
|
||||
update_handler.sendEmptyMessage(0);
|
||||
}
|
||||
}.start();
|
||||
return true;
|
||||
} else {
|
||||
pd.dismiss();
|
||||
Toast.makeText(FDroid.this, getString(R.string.connection_error),
|
||||
Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Pass XML info to BD a xml file must exists...
|
||||
*/
|
||||
private void xmlPass(String srv) {
|
||||
SAXParserFactory spf = SAXParserFactory.newInstance();
|
||||
try {
|
||||
SAXParser sp = spf.newSAXParser();
|
||||
XMLReader xr = sp.getXMLReader();
|
||||
RepoXMLHandler handler = new RepoXMLHandler(this, srv);
|
||||
xr.setContentHandler(handler);
|
||||
|
||||
InputStreamReader isr = new FileReader(new File(XML_PATH));
|
||||
InputSource is = new InputSource(isr);
|
||||
xr.parse(is);
|
||||
File xml_file = new File(XML_PATH);
|
||||
xml_file.delete();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (SAXException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ParserConfigurationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// Download a repo index to a temporary file on the SD card.
|
||||
private void downloadRepoIndex(String srv) {
|
||||
try {
|
||||
BufferedInputStream getit = new BufferedInputStream(new URL(srv
|
||||
+ "/index.xml").openStream());
|
||||
|
||||
File file_teste = new File(XML_PATH);
|
||||
if (file_teste.exists())
|
||||
file_teste.delete();
|
||||
|
||||
FileOutputStream saveit = new FileOutputStream(XML_PATH);
|
||||
BufferedOutputStream bout = new BufferedOutputStream(saveit, 1024);
|
||||
byte data[] = new byte[1024];
|
||||
|
||||
int readed = getit.read(data, 0, 1024);
|
||||
while (readed != -1) {
|
||||
bout.write(data, 0, readed);
|
||||
readed = getit.read(data, 0, 1024);
|
||||
}
|
||||
bout.close();
|
||||
getit.close();
|
||||
saveit.close();
|
||||
} catch (UnknownHostException e) {
|
||||
Message msg = new Message();
|
||||
msg.obj = new String(srv);
|
||||
error_handler.sendMessage(msg);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Handlers for thread functions that need to access GUI
|
||||
*/
|
||||
private Handler update_handler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
populateLists(true);
|
||||
if (pd.isShowing())
|
||||
pd.dismiss();
|
||||
}
|
||||
};
|
||||
|
||||
private Handler error_handler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
if (pd.isShowing())
|
||||
pd.dismiss();
|
||||
AlertDialog p = new AlertDialog.Builder(mctx).create();
|
||||
p.setTitle(getString(R.string.connection_timeout));
|
||||
p.setIcon(android.R.drawable.ic_dialog_alert);
|
||||
p.setMessage(getString(R.string.connection_error_msg) + ": < "
|
||||
+ msg.obj.toString() + " >");
|
||||
p.setButton(getString(R.string.ok),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
return;
|
||||
}
|
||||
});
|
||||
p.show();
|
||||
}
|
||||
};
|
||||
|
||||
// Handler for a click on one of the items in an application list. Pops
|
||||
// up a dialog that shows the details of the application and all its
|
||||
// available versions, with buttons to allow installation etc.
|
||||
public void onItemClick(AdapterView<?> arg0, View arg1, final int arg2,
|
||||
long arg3) {
|
||||
|
||||
final DB.App app;
|
||||
String curtab = tabHost.getCurrentTabTag();
|
||||
if (curtab.equalsIgnoreCase(TAB_IN)) {
|
||||
app = (DB.App) apps_in.getItem(arg2);
|
||||
} else if (curtab.equalsIgnoreCase(TAB_UP)) {
|
||||
app = (DB.App) apps_up.getItem(arg2);
|
||||
} else {
|
||||
app = (DB.App) apps_av.getItem(arg2);
|
||||
}
|
||||
|
||||
Intent intent = new Intent(this, AppDetails.class);
|
||||
intent.putExtra("appid", app.id);
|
||||
startActivityForResult(intent, REQUEST_APPDETAILS);
|
||||
|
||||
}
|
||||
|
||||
}
|
205
src/org/fdroid/fdroid/ManageRepo.java
Normal file
205
src/org/fdroid/fdroid/ManageRepo.java
Normal file
@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Roberto Jacinto, roberto.jacinto@caixamagica.pt
|
||||
* Copyright (C) 2010 Ciaran Gultnieks, ciaran@ciarang.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package org.fdroid.fdroid;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.fdroid.fdroid.R;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.ListActivity;
|
||||
import android.app.AlertDialog.Builder;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ListView;
|
||||
import android.widget.SimpleAdapter;
|
||||
|
||||
public class ManageRepo extends ListActivity {
|
||||
|
||||
private DB db = null;
|
||||
|
||||
private final int ADD_REPO = 1;
|
||||
private final int REM_REPO = 2;
|
||||
|
||||
private boolean changed = false;
|
||||
|
||||
private Vector<DB.Repo> repos;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.repolist);
|
||||
|
||||
db = new DB(this);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
|
||||
super.onResume();
|
||||
redraw();
|
||||
}
|
||||
|
||||
private void redraw() {
|
||||
repos = db.getRepos();
|
||||
|
||||
List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
|
||||
Map<String, Object> server_line;
|
||||
|
||||
for (DB.Repo repo : repos) {
|
||||
server_line = new HashMap<String, Object>();
|
||||
server_line.put("address", repo.address);
|
||||
if (repo.inuse) {
|
||||
server_line.put("inuse", R.drawable.btn_check_on);
|
||||
} else {
|
||||
server_line.put("inuse", R.drawable.btn_check_off);
|
||||
}
|
||||
result.add(server_line);
|
||||
}
|
||||
SimpleAdapter show_out = new SimpleAdapter(this, result,
|
||||
R.layout.repolisticons, new String[] { "address", "inuse" },
|
||||
new int[] { R.id.uri, R.id.img });
|
||||
|
||||
setListAdapter(show_out);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onListItemClick(ListView l, View v, int position, long id) {
|
||||
|
||||
super.onListItemClick(l, v, position, id);
|
||||
db.changeServerStatus(repos.get(position).address);
|
||||
changed = true;
|
||||
redraw();
|
||||
}
|
||||
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
|
||||
super.onCreateOptionsMenu(menu);
|
||||
menu.add(Menu.NONE, ADD_REPO, 1, R.string.menu_add_repo).setIcon(
|
||||
android.R.drawable.ic_menu_add);
|
||||
menu.add(Menu.NONE, REM_REPO, 2, R.string.menu_rem_repo).setIcon(
|
||||
android.R.drawable.ic_menu_close_clear_cancel);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemSelected(int featureId, MenuItem item) {
|
||||
|
||||
super.onMenuItemSelected(featureId, item);
|
||||
LayoutInflater li = LayoutInflater.from(this);
|
||||
|
||||
switch (item.getItemId()) {
|
||||
case ADD_REPO:
|
||||
View view = li.inflate(R.layout.addrepo, null);
|
||||
Builder p = new AlertDialog.Builder(this).setView(view);
|
||||
final AlertDialog alrt = p.create();
|
||||
|
||||
alrt.setIcon(android.R.drawable.ic_menu_add);
|
||||
alrt.setTitle(getString(R.string.repo_add_title));
|
||||
alrt.setButton(getString(R.string.repo_add_add),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
EditText uri = (EditText) alrt
|
||||
.findViewById(R.id.edit_uri);
|
||||
String uri_str = uri.getText().toString();
|
||||
db.addServer(uri_str, 10);
|
||||
changed = true;
|
||||
redraw();
|
||||
}
|
||||
});
|
||||
|
||||
alrt.setButton2(getString(R.string.cancel),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
return;
|
||||
}
|
||||
});
|
||||
alrt.show();
|
||||
return true;
|
||||
|
||||
case REM_REPO:
|
||||
final Vector<String> rem_lst = new Vector<String>();
|
||||
CharSequence[] b = new CharSequence[repos.size()];
|
||||
for (int i = 0; i < repos.size(); i++) {
|
||||
b[i] = repos.get(i).address;
|
||||
}
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(getString(R.string.repo_delete_title));
|
||||
builder.setIcon(android.R.drawable.ic_menu_close_clear_cancel);
|
||||
builder.setMultiChoiceItems(b, null,
|
||||
new DialogInterface.OnMultiChoiceClickListener() {
|
||||
public void onClick(DialogInterface dialog,
|
||||
int whichButton, boolean isChecked) {
|
||||
if (isChecked) {
|
||||
rem_lst
|
||||
.addElement(repos.get(whichButton).address);
|
||||
} else {
|
||||
rem_lst
|
||||
.removeElement(repos.get(whichButton).address);
|
||||
}
|
||||
}
|
||||
});
|
||||
builder.setPositiveButton(getString(R.string.ok),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog,
|
||||
int whichButton) {
|
||||
db.removeServers(rem_lst);
|
||||
changed = true;
|
||||
redraw();
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(getString(R.string.cancel),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog,
|
||||
int whichButton) {
|
||||
return;
|
||||
}
|
||||
});
|
||||
AlertDialog alert = builder.create();
|
||||
alert.show();
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
Intent ret = new Intent();
|
||||
if (changed)
|
||||
ret.putExtra("update", true);
|
||||
this.setResult(RESULT_OK, ret);
|
||||
db.close();
|
||||
super.finish();
|
||||
}
|
||||
|
||||
}
|
41
src/org/fdroid/fdroid/Md5Handler.java
Normal file
41
src/org/fdroid/fdroid/Md5Handler.java
Normal file
@ -0,0 +1,41 @@
|
||||
package org.fdroid.fdroid;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
public class Md5Handler {
|
||||
|
||||
private MessageDigest digest;
|
||||
|
||||
public Md5Handler() {
|
||||
try {
|
||||
digest = MessageDigest.getInstance("MD5");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public String md5Calc(File f) {
|
||||
String md5hash = null;
|
||||
byte[] buffer = new byte[1024];
|
||||
int read = 0;
|
||||
|
||||
try {
|
||||
InputStream is = new FileInputStream(f);
|
||||
while ((read = is.read(buffer)) > 0) {
|
||||
digest.update(buffer, 0, read);
|
||||
}
|
||||
byte[] md5sum = digest.digest();
|
||||
BigInteger bigInt = new BigInteger(1, md5sum);
|
||||
md5hash = bigInt.toString(16);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
return md5hash;
|
||||
}
|
||||
|
||||
}
|
164
src/org/fdroid/fdroid/RepoXMLHandler.java
Normal file
164
src/org/fdroid/fdroid/RepoXMLHandler.java
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Ciaran Gultnieks, ciaran@ciarang.com
|
||||
* Copyright (C) 2009 Roberto Jacinto, roberto.jacinto@caixamagica.pt
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package org.fdroid.fdroid;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.net.URL;
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import org.fdroid.fdroid.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
public class RepoXMLHandler extends DefaultHandler {
|
||||
|
||||
Context mctx;
|
||||
String mserver;
|
||||
|
||||
private DB db = null;
|
||||
|
||||
private DB.App curapp = null;
|
||||
private DB.Apk curapk = null;
|
||||
private String curel = null;
|
||||
|
||||
public RepoXMLHandler(Context ctx, String srv) {
|
||||
mctx = ctx;
|
||||
mserver = srv;
|
||||
db = new DB(mctx);
|
||||
db.beginUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endDocument() throws SAXException {
|
||||
super.endDocument();
|
||||
db.endUpdate();
|
||||
db.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void characters(char[] ch, int start, int length)
|
||||
throws SAXException {
|
||||
|
||||
super.characters(ch, start, length);
|
||||
|
||||
String str = new String(ch).substring(start, start + length);
|
||||
if (curapk != null && curel != null) {
|
||||
if (curel == "version")
|
||||
curapk.version = str;
|
||||
else if (curel == "hash")
|
||||
curapk.hash = str;
|
||||
else if (curel == "apkname")
|
||||
curapk.apkName = str;
|
||||
} else if (curapp != null && curel != null) {
|
||||
if (curel == "id")
|
||||
curapp.id = str;
|
||||
else if (curel == "name")
|
||||
curapp.name = str;
|
||||
else if (curel == "icon")
|
||||
curapp.icon = str;
|
||||
else if (curel == "description")
|
||||
curapp.description = str;
|
||||
else if (curel == "summary")
|
||||
curapp.summary = str;
|
||||
else if (curel == "license")
|
||||
curapp.license = str;
|
||||
else if (curel == "source")
|
||||
curapp.sourceURL = str;
|
||||
else if (curel == "web")
|
||||
curapp.webURL = str;
|
||||
else if (curel == "tracker")
|
||||
curapp.trackerURL = str;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endElement(String uri, String localName, String qName)
|
||||
throws SAXException {
|
||||
|
||||
super.endElement(uri, localName, qName);
|
||||
|
||||
if (localName == "application" && curapp != null) {
|
||||
Log.d("FDroid", "Repo: Updating application " + curapp.id);
|
||||
db.updateApplication(curapp);
|
||||
getIcon(curapp);
|
||||
curapp = null;
|
||||
} else if (localName == "package" && curapk != null && curapp != null) {
|
||||
Log.d("FDroid", "Repo: Package added (" + curapk.version + ")");
|
||||
curapp.apks.add(curapk);
|
||||
curapk = null;
|
||||
} else {
|
||||
curel = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName,
|
||||
Attributes attributes) throws SAXException {
|
||||
|
||||
super.startElement(uri, localName, qName, attributes);
|
||||
if (localName == "application" && curapp == null) {
|
||||
Log.d("FDroid", "Repo: Found application at " + mserver);
|
||||
curapp = new DB.App();
|
||||
} else if (localName == "package" && curapp != null && curapk == null) {
|
||||
Log.d("FDroid", "Repo: Found package for " + curapp.id);
|
||||
curapk = new DB.Apk();
|
||||
curapk.id = curapp.id;
|
||||
curapk.server = mserver;
|
||||
} else {
|
||||
curel = localName;
|
||||
}
|
||||
}
|
||||
|
||||
private void getIcon(DB.App app) {
|
||||
try {
|
||||
|
||||
String destpath = mctx.getString(R.string.icons_path) + app.icon;
|
||||
BufferedInputStream getit = new BufferedInputStream(new URL(mserver
|
||||
+ "/icons/" + app.icon).openStream());
|
||||
File f = new File(destpath);
|
||||
if (f.exists())
|
||||
f.delete();
|
||||
|
||||
FileOutputStream saveit = new FileOutputStream(destpath);
|
||||
BufferedOutputStream bout = new BufferedOutputStream(saveit, 1024);
|
||||
byte data[] = new byte[1024];
|
||||
|
||||
int readed = getit.read(data, 0, 1024);
|
||||
while (readed != -1) {
|
||||
bout.write(data, 0, readed);
|
||||
readed = getit.read(data, 0, 1024);
|
||||
}
|
||||
bout.close();
|
||||
getit.close();
|
||||
saveit.close();
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user