Merge branch 'random-improvements' into 'master'
Random improvements See merge request !262
This commit is contained in:
commit
d902612f41
@ -65,7 +65,7 @@ In order to run the F-Droid test suite, you will need to have either a real devi
|
||||
connected via `adb`, or an emulator running. Then, execute the following from the
|
||||
command line:
|
||||
|
||||
./gradlew connectedCheck
|
||||
./gradlew check
|
||||
|
||||
Note that the CI already runs the tests on an emulator, so you don't
|
||||
necessarily have to do this yourself if you open a merge request as the tests
|
||||
|
@ -210,7 +210,7 @@ pmd {
|
||||
task pmd(type: Pmd, dependsOn: assembleDebug) {
|
||||
ruleSets = [
|
||||
//'java-basic',
|
||||
//'java-unusedcode',
|
||||
'java-unusedcode',
|
||||
'java-android',
|
||||
'java-clone',
|
||||
'java-finalizers',
|
||||
@ -218,7 +218,7 @@ task pmd(type: Pmd, dependsOn: assembleDebug) {
|
||||
'java-migrating',
|
||||
//'java-unnecessary', // too nitpicky with parenthesis
|
||||
]
|
||||
source 'src/main/java'
|
||||
source 'src/main/java', 'src/test/java', 'src/androidTest/java'
|
||||
include '**/*.java'
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,9 @@ import android.os.Build;
|
||||
import android.test.mock.MockContentResolver;
|
||||
import android.test.mock.MockContext;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
@ -132,6 +135,7 @@ public abstract class ProviderTestCase2MockContext<T extends ContentProvider> ex
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
@Before
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
@ -165,6 +169,7 @@ public abstract class ProviderTestCase2MockContext<T extends ContentProvider> ex
|
||||
* {@link android.content.ContentProvider} represented by mProvider.
|
||||
*/
|
||||
@Override
|
||||
@After
|
||||
protected void tearDown() throws Exception {
|
||||
shutdownProvider();
|
||||
super.tearDown();
|
||||
|
@ -18,7 +18,6 @@ import static org.junit.Assert.fail;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class RepoUpdaterTest {
|
||||
private static final String TAG = "RepoUpdaterTest";
|
||||
|
||||
private Context context;
|
||||
private RepoUpdater repoUpdater;
|
||||
|
@ -1,177 +1,175 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Hans-Christoph Steiner <hans@eds.org>
|
||||
*
|
||||
* 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 3
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2016, Liu Dong
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of apk-parser nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.fdroid.fdroid;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
/**
|
||||
* Parse the 'compressed' binary form of Android XML docs such as for
|
||||
* {@code AndroidManifest.xml} in APK files. This is a very truncated
|
||||
* version of apk-parser since currently, we only need the header from
|
||||
* the binary XML AndroidManifest.xml. apk-parser provides full APK
|
||||
* parsing, which is a lot more than what is needed.
|
||||
*
|
||||
* @see <a href="https://github.com/caoqianli/apk-parser">apk-parser</a>
|
||||
* @see <a href="https://justanapplication.wordpress.com/category/android/android-binary-xml">Android Internals: Binary XML</a>
|
||||
* @see <a href="https://stackoverflow.com/a/4761689">a binary XML parser</a>
|
||||
*/
|
||||
public class AndroidXMLDecompress {
|
||||
public static int startTag = 0x00100102;
|
||||
|
||||
/**
|
||||
* Just get the XML attributes from the {@code <manifest>} element.
|
||||
*
|
||||
* @return A key value map of the attributes, with values as {@link Object}s
|
||||
*/
|
||||
public static Map<String, Object> getManifestHeaderAttributes(String filename) throws IOException {
|
||||
byte[] binaryXml = getManifestFromFilename(filename);
|
||||
int numbStrings = littleEndianWord(binaryXml, 4 * 4);
|
||||
int stringIndexTableOffset = 0x24;
|
||||
int stringTableOffset = stringIndexTableOffset + numbStrings * 4;
|
||||
int xmlTagOffset = littleEndianWord(binaryXml, 3 * 4);
|
||||
for (int i = xmlTagOffset; i < binaryXml.length - 4; i += 4) {
|
||||
if (littleEndianWord(binaryXml, i) == startTag) {
|
||||
xmlTagOffset = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int offset = xmlTagOffset;
|
||||
|
||||
while (offset < binaryXml.length) {
|
||||
int tag0 = littleEndianWord(binaryXml, offset);
|
||||
int nameStringIndex = littleEndianWord(binaryXml, offset + 5 * 4);
|
||||
|
||||
if (tag0 == startTag) {
|
||||
int numbAttrs = littleEndianWord(binaryXml, offset + 7 * 4);
|
||||
offset += 9 * 4;
|
||||
|
||||
HashMap<String, Object> attributes = new HashMap<String, Object>(3);
|
||||
for (int i = 0; i < numbAttrs; i++) {
|
||||
int attributeNameStringIndex = littleEndianWord(binaryXml, offset + 1 * 4);
|
||||
int attributeValueStringIndex = littleEndianWord(binaryXml, offset + 2 * 4);
|
||||
int attributeResourceId = littleEndianWord(binaryXml, offset + 4 * 4);
|
||||
offset += 5 * 4;
|
||||
|
||||
String attributeName = getString(binaryXml, stringIndexTableOffset, stringTableOffset, attributeNameStringIndex);
|
||||
Object attributeValue;
|
||||
if (attributeValueStringIndex != -1) {
|
||||
attributeValue = getString(binaryXml, stringIndexTableOffset, stringTableOffset, attributeValueStringIndex);
|
||||
} else {
|
||||
attributeValue = attributeResourceId;
|
||||
}
|
||||
attributes.put(attributeName, attributeValue);
|
||||
}
|
||||
return attributes;
|
||||
} else {
|
||||
// we only need the first <manifest> start tag
|
||||
break;
|
||||
}
|
||||
}
|
||||
return new HashMap<String, Object>(0);
|
||||
}
|
||||
|
||||
public static byte[] getManifestFromFilename(String filename) throws IOException {
|
||||
InputStream is = null;
|
||||
ZipFile zip = null;
|
||||
int size = 0;
|
||||
|
||||
if (filename.endsWith(".apk")) {
|
||||
zip = new ZipFile(filename);
|
||||
ZipEntry ze = zip.getEntry("AndroidManifest.xml");
|
||||
is = zip.getInputStream(ze);
|
||||
size = (int) ze.getSize();
|
||||
} else {
|
||||
throw new RuntimeException("This only works on APK files!");
|
||||
}
|
||||
byte[] buf = new byte[size];
|
||||
is.read(buf);
|
||||
|
||||
is.close();
|
||||
if (zip != null) {
|
||||
zip.close();
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
public static String getString(byte[] bytes, int stringIndexTableOffset, int stringTableOffset, int stringIndex) {
|
||||
if (stringIndex < 0) {
|
||||
return null;
|
||||
}
|
||||
int stringOffset = stringTableOffset + littleEndianWord(bytes, stringIndexTableOffset + stringIndex * 4);
|
||||
return getStringAt(bytes, stringOffset);
|
||||
}
|
||||
|
||||
public static String getStringAt(byte[] bytes, int stringOffset) {
|
||||
int length = bytes[stringOffset + 1] << 8 & 0xff00 | bytes[stringOffset] & 0xff;
|
||||
byte[] chars = new byte[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
chars[i] = bytes[stringOffset + 2 + i * 2];
|
||||
}
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the little endian 32-bit word from the byte array at offset
|
||||
*/
|
||||
public static int littleEndianWord(byte[] bytes, int offset) {
|
||||
return bytes[offset + 3]
|
||||
<< 24 & 0xff000000
|
||||
| bytes[offset + 2]
|
||||
<< 16 & 0xff0000
|
||||
| bytes[offset + 1]
|
||||
<< 8 & 0xff00
|
||||
| bytes[offset] & 0xFF;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2016 Hans-Christoph Steiner <hans@eds.org>
|
||||
*
|
||||
* 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 3
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2016, Liu Dong
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of apk-parser nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.fdroid.fdroid;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
/**
|
||||
* Parse the 'compressed' binary form of Android XML docs such as for
|
||||
* {@code AndroidManifest.xml} in APK files. This is a very truncated
|
||||
* version of apk-parser since currently, we only need the header from
|
||||
* the binary XML AndroidManifest.xml. apk-parser provides full APK
|
||||
* parsing, which is a lot more than what is needed.
|
||||
*
|
||||
* @see <a href="https://github.com/caoqianli/apk-parser">apk-parser</a>
|
||||
* @see <a href="https://justanapplication.wordpress.com/category/android/android-binary-xml">Android Internals: Binary XML</a>
|
||||
* @see <a href="https://stackoverflow.com/a/4761689">a binary XML parser</a>
|
||||
*/
|
||||
public class AndroidXMLDecompress {
|
||||
public static int startTag = 0x00100102;
|
||||
|
||||
/**
|
||||
* Just get the XML attributes from the {@code <manifest>} element.
|
||||
*
|
||||
* @return A key value map of the attributes, with values as {@link Object}s
|
||||
*/
|
||||
public static Map<String, Object> getManifestHeaderAttributes(String filename) throws IOException {
|
||||
byte[] binaryXml = getManifestFromFilename(filename);
|
||||
int numbStrings = littleEndianWord(binaryXml, 4 * 4);
|
||||
int stringIndexTableOffset = 0x24;
|
||||
int stringTableOffset = stringIndexTableOffset + numbStrings * 4;
|
||||
int xmlTagOffset = littleEndianWord(binaryXml, 3 * 4);
|
||||
for (int i = xmlTagOffset; i < binaryXml.length - 4; i += 4) {
|
||||
if (littleEndianWord(binaryXml, i) == startTag) {
|
||||
xmlTagOffset = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int offset = xmlTagOffset;
|
||||
|
||||
while (offset < binaryXml.length) {
|
||||
int tag0 = littleEndianWord(binaryXml, offset);
|
||||
|
||||
if (tag0 == startTag) {
|
||||
int numbAttrs = littleEndianWord(binaryXml, offset + 7 * 4);
|
||||
offset += 9 * 4;
|
||||
|
||||
HashMap<String, Object> attributes = new HashMap<String, Object>(3);
|
||||
for (int i = 0; i < numbAttrs; i++) {
|
||||
int attributeNameStringIndex = littleEndianWord(binaryXml, offset + 1 * 4);
|
||||
int attributeValueStringIndex = littleEndianWord(binaryXml, offset + 2 * 4);
|
||||
int attributeResourceId = littleEndianWord(binaryXml, offset + 4 * 4);
|
||||
offset += 5 * 4;
|
||||
|
||||
String attributeName = getString(binaryXml, stringIndexTableOffset, stringTableOffset, attributeNameStringIndex);
|
||||
Object attributeValue;
|
||||
if (attributeValueStringIndex != -1) {
|
||||
attributeValue = getString(binaryXml, stringIndexTableOffset, stringTableOffset, attributeValueStringIndex);
|
||||
} else {
|
||||
attributeValue = attributeResourceId;
|
||||
}
|
||||
attributes.put(attributeName, attributeValue);
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
// we only need the first <manifest> start tag
|
||||
break;
|
||||
}
|
||||
return new HashMap<String, Object>(0);
|
||||
}
|
||||
|
||||
public static byte[] getManifestFromFilename(String filename) throws IOException {
|
||||
InputStream is = null;
|
||||
ZipFile zip = null;
|
||||
int size = 0;
|
||||
|
||||
if (filename.endsWith(".apk")) {
|
||||
zip = new ZipFile(filename);
|
||||
ZipEntry ze = zip.getEntry("AndroidManifest.xml");
|
||||
is = zip.getInputStream(ze);
|
||||
size = (int) ze.getSize();
|
||||
} else {
|
||||
throw new RuntimeException("This only works on APK files!");
|
||||
}
|
||||
byte[] buf = new byte[size];
|
||||
is.read(buf);
|
||||
|
||||
is.close();
|
||||
if (zip != null) {
|
||||
zip.close();
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
public static String getString(byte[] bytes, int stringIndexTableOffset, int stringTableOffset, int stringIndex) {
|
||||
if (stringIndex < 0) {
|
||||
return null;
|
||||
}
|
||||
int stringOffset = stringTableOffset + littleEndianWord(bytes, stringIndexTableOffset + stringIndex * 4);
|
||||
return getStringAt(bytes, stringOffset);
|
||||
}
|
||||
|
||||
public static String getStringAt(byte[] bytes, int stringOffset) {
|
||||
int length = bytes[stringOffset + 1] << 8 & 0xff00 | bytes[stringOffset] & 0xff;
|
||||
byte[] chars = new byte[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
chars[i] = bytes[stringOffset + 2 + i * 2];
|
||||
}
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the little endian 32-bit word from the byte array at offset
|
||||
*/
|
||||
public static int littleEndianWord(byte[] bytes, int offset) {
|
||||
return bytes[offset + 3]
|
||||
<< 24 & 0xff000000
|
||||
| bytes[offset + 2]
|
||||
<< 16 & 0xff0000
|
||||
| bytes[offset + 1]
|
||||
<< 8 & 0xff00
|
||||
| bytes[offset] & 0xFF;
|
||||
}
|
||||
}
|
||||
|
@ -79,6 +79,7 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh
|
||||
private static final boolean DEFAULT_EXPERT = false;
|
||||
private static final boolean DEFAULT_ENABLE_PROXY = false;
|
||||
public static final String DEFAULT_THEME = "light";
|
||||
@SuppressWarnings("PMD.AvoidUsingHardCodedIP")
|
||||
public static final String DEFAULT_PROXY_HOST = "127.0.0.1";
|
||||
public static final int DEFAULT_PROXY_PORT = 8118;
|
||||
private static final boolean DEFAULT_SHOW_NFC_DURING_SWAP = true;
|
||||
|
@ -92,6 +92,15 @@ public class RepoUpdater {
|
||||
return hasChanged;
|
||||
}
|
||||
|
||||
private static void cleanupDownloader(Downloader d) {
|
||||
if (d == null || d.outputFile == null) {
|
||||
return;
|
||||
}
|
||||
if (!d.outputFile.delete()) {
|
||||
Log.w(TAG, "Couldn't delete file: " + d.outputFile.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
private Downloader downloadIndex() throws UpdateException {
|
||||
Downloader downloader = null;
|
||||
try {
|
||||
@ -106,11 +115,7 @@ public class RepoUpdater {
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
if (downloader != null && downloader.outputFile != null) {
|
||||
if (!downloader.outputFile.delete()) {
|
||||
Log.w(TAG, "Couldn't delete file: " + downloader.outputFile.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
cleanupDownloader(downloader);
|
||||
|
||||
throw new UpdateException(repo, "Error getting index file", e);
|
||||
} catch (InterruptedException e) {
|
||||
@ -197,10 +202,8 @@ public class RepoUpdater {
|
||||
} finally {
|
||||
FDroidApp.enableSpongyCastleOnLollipop();
|
||||
Utils.closeQuietly(indexInputStream);
|
||||
if (downloadedFile != null) {
|
||||
if (!downloadedFile.delete()) {
|
||||
Log.w(TAG, "Couldn't delete file: " + downloadedFile.getAbsolutePath());
|
||||
}
|
||||
if (downloadedFile != null && !downloadedFile.delete()) {
|
||||
Log.w(TAG, "Couldn't delete file: " + downloadedFile.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -359,7 +362,7 @@ public class RepoUpdater {
|
||||
if (repo.signingCertificate.equals(certFromJar)
|
||||
&& repo.signingCertificate.equals(certFromIndexXml)
|
||||
&& certFromIndexXml.equals(certFromJar)) {
|
||||
return; // we have a match!
|
||||
return; // we have a match!
|
||||
}
|
||||
throw new SigningException(repo, "Signing certificate does not match!");
|
||||
}
|
||||
|
@ -275,7 +275,7 @@ public final class Utils {
|
||||
// return a fingerprint formatted for display
|
||||
public static String formatFingerprint(Context context, String fingerprint) {
|
||||
if (TextUtils.isEmpty(fingerprint)
|
||||
|| fingerprint.length() != 64 // SHA-256 is 64 hex chars
|
||||
|| fingerprint.length() != 64 // SHA-256 is 64 hex chars
|
||||
|| fingerprint.matches(".*[^0-9a-fA-F].*")) { // its a hex string
|
||||
return context.getString(R.string.bad_fingerprint);
|
||||
}
|
||||
@ -673,11 +673,10 @@ public final class Utils {
|
||||
}
|
||||
|
||||
for (File f : files) {
|
||||
if ((startsWith != null && f.getName().startsWith(startsWith))
|
||||
|| (endsWith != null && f.getName().endsWith(endsWith))) {
|
||||
if (!f.delete()) {
|
||||
Log.w(TAG, "Couldn't delete cache file " + f);
|
||||
}
|
||||
if (((startsWith != null && f.getName().startsWith(startsWith))
|
||||
|| (endsWith != null && f.getName().endsWith(endsWith)))
|
||||
&& !f.delete()) {
|
||||
Log.w(TAG, "Couldn't delete cache file " + f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -178,10 +178,8 @@ public abstract class Installer {
|
||||
Map<String, Object> attributes = AndroidXMLDecompress.getManifestHeaderAttributes(apkFile.getAbsolutePath());
|
||||
|
||||
/* This isn't really needed, but might as well since we have the data already */
|
||||
if (attributes.containsKey("packageName")) {
|
||||
if (!TextUtils.equals(packageName, (String) attributes.get("packageName"))) {
|
||||
throw new InstallFailedException(apkFile + " has packageName that clashes with " + packageName);
|
||||
}
|
||||
if (attributes.containsKey("packageName") && !TextUtils.equals(packageName, (String) attributes.get("packageName"))) {
|
||||
throw new InstallFailedException(apkFile + " has packageName that clashes with " + packageName);
|
||||
}
|
||||
|
||||
if (!attributes.containsKey("versionCode")) {
|
||||
|
@ -119,22 +119,16 @@ public final class LocalRepoManager {
|
||||
xmlIndexJar = new SanitizedFile(repoDir, "index.jar");
|
||||
xmlIndexJarUnsigned = new SanitizedFile(repoDir, "index.unsigned.jar");
|
||||
|
||||
if (!fdroidDir.exists()) {
|
||||
if (!fdroidDir.mkdir()) {
|
||||
Log.e(TAG, "Unable to create empty base: " + fdroidDir);
|
||||
}
|
||||
if (!fdroidDir.exists() && !fdroidDir.mkdir()) {
|
||||
Log.e(TAG, "Unable to create empty base: " + fdroidDir);
|
||||
}
|
||||
|
||||
if (!repoDir.exists()) {
|
||||
if (!repoDir.mkdir()) {
|
||||
Log.e(TAG, "Unable to create empty repo: " + repoDir);
|
||||
}
|
||||
if (!repoDir.exists() && !repoDir.mkdir()) {
|
||||
Log.e(TAG, "Unable to create empty repo: " + repoDir);
|
||||
}
|
||||
|
||||
if (!iconsDir.exists()) {
|
||||
if (!iconsDir.mkdir()) {
|
||||
Log.e(TAG, "Unable to create icons folder: " + iconsDir);
|
||||
}
|
||||
if (!iconsDir.exists() && !iconsDir.mkdir()) {
|
||||
Log.e(TAG, "Unable to create icons folder: " + iconsDir);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -228,17 +228,15 @@ public class LocalHTTPD extends NanoHTTPD {
|
||||
long startFrom = 0;
|
||||
long endAt = -1;
|
||||
String range = header.get("range");
|
||||
if (range != null) {
|
||||
if (range.startsWith("bytes=")) {
|
||||
range = range.substring("bytes=".length());
|
||||
int minus = range.indexOf('-');
|
||||
try {
|
||||
if (minus > 0) {
|
||||
startFrom = Long.parseLong(range.substring(0, minus));
|
||||
endAt = Long.parseLong(range.substring(minus + 1));
|
||||
}
|
||||
} catch (NumberFormatException ignored) {
|
||||
if (range != null && range.startsWith("bytes=")) {
|
||||
range = range.substring("bytes=".length());
|
||||
int minus = range.indexOf('-');
|
||||
try {
|
||||
if (minus > 0) {
|
||||
startFrom = Long.parseLong(range.substring(0, minus));
|
||||
endAt = Long.parseLong(range.substring(minus + 1));
|
||||
}
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ public class WifiStateChangeService extends Service {
|
||||
NetworkInfo is only passed via WifiStateChangeReceiver */
|
||||
Utils.debugLog(TAG, "ni == " + ni + " wifiState == " + printWifiState(wifiState));
|
||||
if (wifiState == WifiManager.WIFI_STATE_ENABLED
|
||||
|| wifiState == WifiManager.WIFI_STATE_DISABLING // might be switching to hotspot
|
||||
|| wifiState == WifiManager.WIFI_STATE_DISABLING // might be switching to hotspot
|
||||
|| wifiState == WifiManager.WIFI_STATE_DISABLED // might be hotspot
|
||||
|| wifiState == WifiManager.WIFI_STATE_UNKNOWN) { // might be hotspot
|
||||
if (asyncTask != null) {
|
||||
@ -100,7 +100,7 @@ public class WifiStateChangeService extends Service {
|
||||
if (FDroidApp.ipAddressString == null) {
|
||||
return null;
|
||||
}
|
||||
} else { // a hotspot can be active during WIFI_STATE_UNKNOWN
|
||||
} else { // a hotspot can be active during WIFI_STATE_UNKNOWN
|
||||
setIpInfoFromNetworkInterface();
|
||||
}
|
||||
|
||||
|
@ -266,17 +266,15 @@ public class BluetoothServer extends Thread {
|
||||
long startFrom = 0;
|
||||
long endAt = -1;
|
||||
String range = header.get("range");
|
||||
if (range != null) {
|
||||
if (range.startsWith("bytes=")) {
|
||||
range = range.substring("bytes=".length());
|
||||
int minus = range.indexOf('-');
|
||||
try {
|
||||
if (minus > 0) {
|
||||
startFrom = Long.parseLong(range.substring(0, minus));
|
||||
endAt = Long.parseLong(range.substring(minus + 1));
|
||||
}
|
||||
} catch (NumberFormatException ignored) {
|
||||
if (range != null && range.startsWith("bytes=")) {
|
||||
range = range.substring("bytes=".length());
|
||||
int minus = range.indexOf('-');
|
||||
try {
|
||||
if (minus > 0) {
|
||||
startFrom = Long.parseLong(range.substring(0, minus));
|
||||
endAt = Long.parseLong(range.substring(minus + 1));
|
||||
}
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,12 +0,0 @@
|
||||
package org.fdroid.fdroid.net.bluetooth;
|
||||
|
||||
class UnexpectedResponseException extends Exception {
|
||||
|
||||
UnexpectedResponseException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
UnexpectedResponseException(String message, Throwable cause) {
|
||||
super("Unexpected response from Bluetooth server: '" + message + "'", cause);
|
||||
}
|
||||
}
|
@ -29,15 +29,13 @@ public class InstallExtensionBootReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
|
||||
if (Preferences.get().isPostPrivilegedInstall()) {
|
||||
Preferences.get().setPostPrivilegedInstall(false);
|
||||
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED) && Preferences.get().isPostPrivilegedInstall()) {
|
||||
Preferences.get().setPostPrivilegedInstall(false);
|
||||
|
||||
Intent postInstall = new Intent(context.getApplicationContext(), InstallExtensionDialogActivity.class);
|
||||
postInstall.setAction(InstallExtensionDialogActivity.ACTION_POST_INSTALL);
|
||||
postInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(postInstall);
|
||||
}
|
||||
Intent postInstall = new Intent(context.getApplicationContext(), InstallExtensionDialogActivity.class);
|
||||
postInstall.setAction(InstallExtensionDialogActivity.ACTION_POST_INSTALL);
|
||||
postInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(postInstall);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -269,10 +269,8 @@ public class AppSecurityPermissions {
|
||||
String permName = strList[i];
|
||||
// If we are only looking at an existing app, then we only
|
||||
// care about permissions that have actually been granted to it.
|
||||
if (installedPkgInfo != null && info == installedPkgInfo) {
|
||||
if ((flagsList[i] & PackageInfo.REQUESTED_PERMISSION_GRANTED) == 0) {
|
||||
continue;
|
||||
}
|
||||
if (installedPkgInfo != null && info == installedPkgInfo && (flagsList[i] & PackageInfo.REQUESTED_PERMISSION_GRANTED) == 0) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
PermissionInfo tmpPermInfo = mPm.getPermissionInfo(permName, 0);
|
||||
|
@ -6,12 +6,11 @@ import android.os.Build;
|
||||
|
||||
public class AvailableAppListAdapter extends AppListAdapter {
|
||||
|
||||
public static AvailableAppListAdapter create(Context context, Cursor cursor, int flags) {
|
||||
public static AvailableAppListAdapter create(Context context, Cursor cursor, int flags) {
|
||||
if (Build.VERSION.SDK_INT >= 11) {
|
||||
return new AvailableAppListAdapter(context, cursor, flags);
|
||||
} else {
|
||||
return new AvailableAppListAdapter(context, cursor);
|
||||
}
|
||||
return new AvailableAppListAdapter(context, cursor);
|
||||
}
|
||||
|
||||
private AvailableAppListAdapter(Context context, Cursor c) {
|
||||
|
@ -9,9 +9,8 @@ public class CanUpdateAppListAdapter extends AppListAdapter {
|
||||
public static CanUpdateAppListAdapter create(Context context, Cursor cursor, int flags) {
|
||||
if (Build.VERSION.SDK_INT >= 11) {
|
||||
return new CanUpdateAppListAdapter(context, cursor, flags);
|
||||
} else {
|
||||
return new CanUpdateAppListAdapter(context, cursor);
|
||||
}
|
||||
return new CanUpdateAppListAdapter(context, cursor);
|
||||
}
|
||||
|
||||
private CanUpdateAppListAdapter(Context context, Cursor c) {
|
||||
|
@ -6,12 +6,11 @@ import android.os.Build;
|
||||
|
||||
public class InstalledAppListAdapter extends AppListAdapter {
|
||||
|
||||
public static InstalledAppListAdapter create(Context context, Cursor cursor, int flags) {
|
||||
public static InstalledAppListAdapter create(Context context, Cursor cursor, int flags) {
|
||||
if (Build.VERSION.SDK_INT >= 11) {
|
||||
return new InstalledAppListAdapter(context, cursor, flags);
|
||||
} else {
|
||||
return new InstalledAppListAdapter(context, cursor);
|
||||
}
|
||||
return new InstalledAppListAdapter(context, cursor);
|
||||
}
|
||||
|
||||
private InstalledAppListAdapter(Context context, Cursor c) {
|
||||
|
@ -23,12 +23,11 @@ public class RepoAdapter extends CursorAdapter {
|
||||
|
||||
private EnabledListener enabledListener;
|
||||
|
||||
public static RepoAdapter create(Context context, Cursor cursor, int flags) {
|
||||
public static RepoAdapter create(Context context, Cursor cursor, int flags) {
|
||||
if (Build.VERSION.SDK_INT >= 11) {
|
||||
return new RepoAdapter(context, cursor, flags);
|
||||
} else {
|
||||
return new RepoAdapter(context, cursor);
|
||||
}
|
||||
return new RepoAdapter(context, cursor);
|
||||
}
|
||||
|
||||
private RepoAdapter(Context context, Cursor c, int flags) {
|
||||
|
@ -290,11 +290,9 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!forceReload) {
|
||||
if (container.getVisibility() == View.GONE || currentView != null && currentView.getStep() == service.getStep()) {
|
||||
// Already showing the correct step, so don't bother changing anything.
|
||||
return;
|
||||
}
|
||||
if (!forceReload && (container.getVisibility() == View.GONE || currentView != null && currentView.getStep() == service.getStep())) {
|
||||
// Already showing the correct step, so don't bother changing anything.
|
||||
return;
|
||||
}
|
||||
|
||||
switch (service.getStep()) {
|
||||
|
@ -7,7 +7,3 @@ buildscript {
|
||||
classpath files('libs/gradle-witness.jar')
|
||||
}
|
||||
}
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
gradleVersion = '2.11'
|
||||
}
|
||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
5
gradle/wrapper/gradle-wrapper.properties
vendored
5
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,7 +1,6 @@
|
||||
#Mon Feb 15 16:30:29 GMT 2016
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.11-bin.zip
|
||||
distributionSha256Sum=8d7437082356c9fd6309a4479c8db307673965546daea445c6c72759cd6b1ed6
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.12-bin.zip
|
||||
distributionSha256Sum=e77064981906cd0476ff1e0de3e6fef747bd18e140960f1915cca8ff6c33ab5c
|
||||
|
Loading…
x
Reference in New Issue
Block a user