Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0ba6299990 | ||
![]() |
bc6c4fbc80 | ||
![]() |
377b57f985 | ||
![]() |
aab60aec4e | ||
![]() |
4eb37b0d33 | ||
![]() |
6b26eb661f | ||
![]() |
46fc6dbbfd | ||
![]() |
4f420c55d0 | ||
![]() |
9ded5eb974 | ||
![]() |
2a7a8ac38b | ||
![]() |
f5065c93a8 | ||
![]() |
7b802eaf2f | ||
![]() |
4090132d84 | ||
![]() |
242cdb5dd4 | ||
![]() |
1fdb573774 | ||
![]() |
88ee9849f7 | ||
![]() |
94403d1d7e | ||
![]() |
ff6a60ae26 |
@ -1,4 +1,4 @@
|
|||||||
image: fdroid/ci:client-20161023
|
image: registry.gitlab.com/fdroid/ci-images:client
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
paths:
|
paths:
|
||||||
@ -7,13 +7,21 @@ cache:
|
|||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- export GRADLE_USER_HOME=$PWD/.gradle
|
- export GRADLE_USER_HOME=$PWD/.gradle
|
||||||
|
- export ANDROID_COMPILE_SDK=`sed -n 's,.*compileSdkVersion\s*\([0-9][0-9]*\).*,\1,p' app/build.gradle`
|
||||||
|
- echo y | android --silent update sdk --no-ui --filter android-${ANDROID_COMPILE_SDK}
|
||||||
|
|
||||||
test:
|
test:
|
||||||
script:
|
script:
|
||||||
|
- cd app
|
||||||
|
- ./tools/langs-list-check.py
|
||||||
|
- ./tools/check-string-format.py
|
||||||
|
- cd ..
|
||||||
- ./gradlew assemble -PdisablePreDex
|
- ./gradlew assemble -PdisablePreDex
|
||||||
# always report on lint errors to the build log
|
# always report on lint errors to the build log
|
||||||
- sed -i -e 's,textReport .*,textReport true,' app/build.gradle
|
- sed -i -e 's,textReport .*,textReport true,' app/build.gradle
|
||||||
- ./gradlew lint -PdisablePreDex
|
- ./gradlew lint -PdisablePreDex
|
||||||
|
- ./gradlew pmd -PdisablePreDex
|
||||||
|
- ./gradlew checkstyle -PdisablePreDex
|
||||||
- ./gradlew test -PdisablePreDex || {
|
- ./gradlew test -PdisablePreDex || {
|
||||||
for log in app/build/reports/*ests/*/*ml; do
|
for log in app/build/reports/*ests/*/*ml; do
|
||||||
echo "read $log here:";
|
echo "read $log here:";
|
||||||
@ -26,6 +34,7 @@ connected10:
|
|||||||
variables:
|
variables:
|
||||||
AVD_SDK: "10"
|
AVD_SDK: "10"
|
||||||
script:
|
script:
|
||||||
|
- ./gradlew assembleDebug -PdisablePreDex
|
||||||
- emulator64-arm -avd fcl-test-$AVD_SDK -no-skin -no-audio -no-window &
|
- emulator64-arm -avd fcl-test-$AVD_SDK -no-skin -no-audio -no-window &
|
||||||
- ./tools/wait-for-emulator
|
- ./tools/wait-for-emulator
|
||||||
- adb shell input keyevent 82 &
|
- adb shell input keyevent 82 &
|
||||||
@ -47,7 +56,8 @@ connected24:
|
|||||||
variables:
|
variables:
|
||||||
AVD_SDK: "24"
|
AVD_SDK: "24"
|
||||||
script:
|
script:
|
||||||
- emulator64-x86 -avd fcl-test-$AVD_SDK -no-skin -no-audio -no-window &
|
- ./gradlew assembleDebug -PdisablePreDex
|
||||||
|
- emulator64-arm -avd fcl-test-$AVD_SDK -no-audio -no-window &
|
||||||
- ./tools/wait-for-emulator
|
- ./tools/wait-for-emulator
|
||||||
- adb shell input keyevent 82 &
|
- adb shell input keyevent 82 &
|
||||||
- export EXITVALUE=0
|
- export EXITVALUE=0
|
||||||
@ -64,24 +74,6 @@ connected24:
|
|||||||
done
|
done
|
||||||
- exit $EXITVALUE
|
- exit $EXITVALUE
|
||||||
|
|
||||||
pmd:
|
|
||||||
script:
|
|
||||||
- ./gradlew pmd -PdisablePreDex
|
|
||||||
|
|
||||||
checkstyle:
|
|
||||||
script:
|
|
||||||
- ./gradlew checkstyle -PdisablePreDex
|
|
||||||
|
|
||||||
tools:
|
|
||||||
before_script:
|
|
||||||
- echo "ignored, no gradle needed"
|
|
||||||
script:
|
|
||||||
- cd app
|
|
||||||
- ./tools/langs-list-check.py
|
|
||||||
- ./tools/check-string-format.py
|
|
||||||
after_script:
|
|
||||||
- echo "ignored, no gradle needed"
|
|
||||||
|
|
||||||
after_script:
|
after_script:
|
||||||
# this file changes every time but should not be cached
|
# this file changes every time but should not be cached
|
||||||
- rm -f $GRADLE_USER_HOME/caches/modules-2/modules-2.lock
|
- rm -f $GRADLE_USER_HOME/caches/modules-2/modules-2.lock
|
||||||
|
@ -170,7 +170,7 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
versionCode 102050
|
versionCode 102350
|
||||||
versionName getVersionName()
|
versionName getVersionName()
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* *
|
||||||
|
* * This file is part of QuickLyric
|
||||||
|
* * Created by geecko
|
||||||
|
* *
|
||||||
|
* * QuickLyric 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.
|
||||||
|
* *
|
||||||
|
* * QuickLyric 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 QuickLyric. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.geecko.QuickLyric.view;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.preference.ListPreference;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import android.support.v7.app.AlertDialog;
|
||||||
|
import android.support.v7.app.AppCompatDialog;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
public class AppCompatListPreference extends ListPreference {
|
||||||
|
|
||||||
|
private AppCompatDialog mDialog;
|
||||||
|
|
||||||
|
public AppCompatListPreference(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppCompatListPreference(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AppCompatDialog getDialog() {
|
||||||
|
return mDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void showDialog(Bundle state) {
|
||||||
|
if (getEntries() == null || getEntryValues() == null) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"ListPreference requires an entries array and an entryValues array.");
|
||||||
|
}
|
||||||
|
|
||||||
|
int preselect = findIndexOfValue(getValue());
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(getContext())
|
||||||
|
.setTitle(getDialogTitle())
|
||||||
|
.setIcon(getDialogIcon())
|
||||||
|
.setSingleChoiceItems(getEntries(), preselect, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
if (which >= 0 && getEntryValues() != null) {
|
||||||
|
String value = getEntryValues()[which].toString();
|
||||||
|
if (callChangeListener(value) && isPersistent()) {
|
||||||
|
setValue(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dialog.dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
PreferenceManager pm = getPreferenceManager();
|
||||||
|
try {
|
||||||
|
Method method = pm.getClass().getDeclaredMethod(
|
||||||
|
"registerOnActivityDestroyListener",
|
||||||
|
PreferenceManager.OnActivityDestroyListener.class);
|
||||||
|
method.setAccessible(true);
|
||||||
|
method.invoke(pm, this);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
mDialog = builder.create();
|
||||||
|
if (state != null) {
|
||||||
|
mDialog.onRestoreInstanceState(state);
|
||||||
|
}
|
||||||
|
mDialog.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityDestroy() {
|
||||||
|
super.onActivityDestroy();
|
||||||
|
if (mDialog != null && mDialog.isShowing() &&
|
||||||
|
mDialog.getWindow() != null && mDialog.getWindow().getWindowManager() != null) {
|
||||||
|
mDialog.dismiss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -432,6 +432,15 @@ public class AppDetails extends AppCompatActivity {
|
|||||||
myAppObserver);
|
myAppObserver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
App newApp = AppProvider.Helper.findHighestPriorityMetadata(getContentResolver(), app.packageName);
|
||||||
|
if (newApp.isInstalled() != app.isInstalled()) {
|
||||||
|
setApp(newApp);
|
||||||
|
}
|
||||||
|
super.onResume();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onResumeFragments() {
|
protected void onResumeFragments() {
|
||||||
// Must be called before super.onResumeFragments(), as the fragments depend on the active
|
// Must be called before super.onResumeFragments(), as the fragments depend on the active
|
||||||
@ -993,7 +1002,7 @@ public class AppDetails extends AppCompatActivity {
|
|||||||
return apk;
|
return apk;
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
throw new IllegalStateException("Couldn't find app while installing");
|
throw new IllegalStateException("Couldn't find installed apk for " + app.packageName, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,13 +22,13 @@ import android.os.Build;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.FragmentManager;
|
import android.support.v4.app.FragmentManager;
|
||||||
import android.support.v4.app.NavUtils;
|
import android.support.v4.app.NavUtils;
|
||||||
import android.support.v7.app.ActionBarActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
import org.fdroid.fdroid.views.fragments.PreferencesFragment;
|
import org.fdroid.fdroid.views.fragments.PreferencesFragment;
|
||||||
|
|
||||||
public class PreferencesActivity extends ActionBarActivity {
|
public class PreferencesActivity extends AppCompatActivity {
|
||||||
|
|
||||||
public static final int RESULT_RESTART = 4;
|
public static final int RESULT_RESTART = 4;
|
||||||
|
|
||||||
|
@ -408,13 +408,29 @@ public final class Utils {
|
|||||||
|
|
||||||
byte[] mdbytes = md.digest();
|
byte[] mdbytes = md.digest();
|
||||||
return toHexString(mdbytes).toLowerCase(Locale.ENGLISH);
|
return toHexString(mdbytes).toLowerCase(Locale.ENGLISH);
|
||||||
} catch (IOException | NoSuchAlgorithmException e) {
|
} catch (IOException e) {
|
||||||
|
// The annoyance (potentially) caused by miscellaneous filesystem corruption results in
|
||||||
|
// F-Droid constantly popping up crash reports when F-Droid isn't even open. As such this
|
||||||
|
// exception-message-parsing-and-throwing-a-new-ignorable-exception-hackery is probably
|
||||||
|
// warranted. See https://www.gitlab.com/fdroid/fdroidclient/issues/855 for more detail.
|
||||||
|
if (e.getMessage().contains("read failed: EIO (I/O error)")) {
|
||||||
|
throw new PotentialFilesystemCorruptionException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException(e);
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
throw new IllegalArgumentException(e);
|
throw new IllegalArgumentException(e);
|
||||||
} finally {
|
} finally {
|
||||||
closeQuietly(fis);
|
closeQuietly(fis);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class PotentialFilesystemCorruptionException extends IllegalArgumentException {
|
||||||
|
public PotentialFilesystemCorruptionException(IOException e) {
|
||||||
|
super(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes the base 16 representation of the byte array argument.
|
* Computes the base 16 representation of the byte array argument.
|
||||||
*
|
*
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
package org.fdroid.fdroid.compat;
|
package org.fdroid.fdroid.compat;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.fdroid.fdroid.installer.PrivilegedInstaller;
|
||||||
import org.fdroid.fdroid.Utils;
|
import org.fdroid.fdroid.Utils;
|
||||||
|
|
||||||
public class PackageManagerCompat {
|
public class PackageManagerCompat {
|
||||||
@ -12,10 +14,20 @@ public class PackageManagerCompat {
|
|||||||
private static final String TAG = "PackageManagerCompat";
|
private static final String TAG = "PackageManagerCompat";
|
||||||
|
|
||||||
@TargetApi(11)
|
@TargetApi(11)
|
||||||
public static void setInstaller(PackageManager mPm, String packageName) {
|
public static void setInstaller(Context context, PackageManager mPm, String packageName) {
|
||||||
if (Build.VERSION.SDK_INT < 11) return;
|
if (Build.VERSION.SDK_INT < 11) return;
|
||||||
try {
|
try {
|
||||||
mPm.setInstallerPackageName(packageName, "org.fdroid.fdroid");
|
/*
|
||||||
|
* Starting with 7.0 (API 24), we're using PackageInstaller APIs
|
||||||
|
* to install and uninstall apps via the privileged extension.
|
||||||
|
* That enforces the uninstaller being the same as the installer,
|
||||||
|
* so set the package name to that.
|
||||||
|
*/
|
||||||
|
if (Build.VERSION.SDK_INT >= 24 && PrivilegedInstaller.isDefault(context)) {
|
||||||
|
mPm.setInstallerPackageName(packageName, "org.fdroid.fdroid.privileged");
|
||||||
|
} else {
|
||||||
|
mPm.setInstallerPackageName(packageName, "org.fdroid.fdroid");
|
||||||
|
}
|
||||||
Utils.debugLog(TAG, "Installer package name for " + packageName + " set successfully");
|
Utils.debugLog(TAG, "Installer package name for " + packageName + " set successfully");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// Many problems can occur:
|
// Many problems can occur:
|
||||||
|
@ -8,13 +8,19 @@ import android.content.pm.PackageInfo;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.Signature;
|
import android.content.pm.Signature;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
import org.acra.ACRA;
|
import org.acra.ACRA;
|
||||||
import org.fdroid.fdroid.Hasher;
|
import org.fdroid.fdroid.Hasher;
|
||||||
import org.fdroid.fdroid.Utils;
|
import org.fdroid.fdroid.Utils;
|
||||||
import org.fdroid.fdroid.data.Schema.InstalledAppTable;
|
import org.fdroid.fdroid.data.Schema.InstalledAppTable;
|
||||||
|
import rx.functions.Action1;
|
||||||
|
import rx.schedulers.Schedulers;
|
||||||
|
import rx.subjects.PublishSubject;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FilenameFilter;
|
import java.io.FilenameFilter;
|
||||||
@ -23,10 +29,6 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import rx.functions.Action1;
|
|
||||||
import rx.schedulers.Schedulers;
|
|
||||||
import rx.subjects.PublishSubject;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles all updates to {@link InstalledAppProvider}, whether checking the contents
|
* Handles all updates to {@link InstalledAppProvider}, whether checking the contents
|
||||||
* versus what Android says is installed, or processing {@link Intent}s that come
|
* versus what Android says is installed, or processing {@link Intent}s that come
|
||||||
@ -124,13 +126,21 @@ public class InstalledAppProviderService extends IntentService {
|
|||||||
* is in sync with what the {@link PackageManager} tells us is installed. Once
|
* is in sync with what the {@link PackageManager} tells us is installed. Once
|
||||||
* completed, the relevant {@link android.content.ContentProvider}s will be
|
* completed, the relevant {@link android.content.ContentProvider}s will be
|
||||||
* notified of any changes to installed statuses.
|
* notified of any changes to installed statuses.
|
||||||
* <p/>
|
* <p>
|
||||||
* The installed app cache could get out of sync, e.g. if F-Droid crashed/ or
|
* The installed app cache could get out of sync, e.g. if F-Droid crashed/ or
|
||||||
* ran out of battery half way through responding to {@link Intent#ACTION_PACKAGE_ADDED}.
|
* ran out of battery half way through responding to {@link Intent#ACTION_PACKAGE_ADDED}.
|
||||||
* This method returns immediately, and will continue to work in an
|
* This method returns immediately, and will continue to work in an
|
||||||
* {@link IntentService}. It doesn't really matter where we put this in the
|
* {@link IntentService}. It doesn't really matter where we put this in the
|
||||||
* bootstrap process, because it runs in its own thread, at the lowest priority:
|
* bootstrap process, because it runs in its own thread, at the lowest priority:
|
||||||
* {@link Process#THREAD_PRIORITY_LOWEST}.
|
* {@link Process#THREAD_PRIORITY_LOWEST}.
|
||||||
|
* <p>
|
||||||
|
* APKs installed in {@code /system} will often have zeroed out timestamps, like
|
||||||
|
* 2008-01-01 (ziptime) or 2009-01-01. So instead anything older than 2010 every
|
||||||
|
* time since we have no way to know whether an APK wasn't changed as part of an
|
||||||
|
* OTA update. An OTA update could change the APK without changing the
|
||||||
|
* {@link PackageInfo#versionCode} or {@link PackageInfo#lastUpdateTime}.
|
||||||
|
*
|
||||||
|
* @see <a href="https://gitlab.com/fdroid/fdroidclient/issues/819>issue #819</a>
|
||||||
*/
|
*/
|
||||||
public static void compareToPackageManager(Context context) {
|
public static void compareToPackageManager(Context context) {
|
||||||
Map<String, Long> cachedInfo = InstalledAppProvider.Helper.all(context);
|
Map<String, Long> cachedInfo = InstalledAppProvider.Helper.all(context);
|
||||||
@ -139,7 +149,8 @@ public class InstalledAppProviderService extends IntentService {
|
|||||||
.getInstalledPackages(PackageManager.GET_SIGNATURES);
|
.getInstalledPackages(PackageManager.GET_SIGNATURES);
|
||||||
for (PackageInfo packageInfo : packageInfoList) {
|
for (PackageInfo packageInfo : packageInfoList) {
|
||||||
if (cachedInfo.containsKey(packageInfo.packageName)) {
|
if (cachedInfo.containsKey(packageInfo.packageName)) {
|
||||||
if (packageInfo.lastUpdateTime > cachedInfo.get(packageInfo.packageName)) {
|
if (packageInfo.lastUpdateTime < 1262300400000L // 2010-01-01 00:00
|
||||||
|
|| packageInfo.lastUpdateTime > cachedInfo.get(packageInfo.packageName)) {
|
||||||
insert(context, packageInfo);
|
insert(context, packageInfo);
|
||||||
}
|
}
|
||||||
cachedInfo.remove(packageInfo.packageName);
|
cachedInfo.remove(packageInfo.packageName);
|
||||||
@ -188,6 +199,22 @@ public class InstalledAppProviderService extends IntentService {
|
|||||||
String hashType = "sha256";
|
String hashType = "sha256";
|
||||||
String hash = Utils.getBinaryHash(apk, hashType);
|
String hash = Utils.getBinaryHash(apk, hashType);
|
||||||
insertAppIntoDb(this, packageInfo, hashType, hash);
|
insertAppIntoDb(this, packageInfo, hashType, hash);
|
||||||
|
} catch (final Utils.PotentialFilesystemCorruptionException e) {
|
||||||
|
Log.e(TAG, "Encountered potential filesystem corruption, or other unknown " +
|
||||||
|
"problem when calculating hash of " + apk.getAbsolutePath() + ". " +
|
||||||
|
"It is unlikely F-Droid can do anything about this, and this " +
|
||||||
|
"likely happened in the background. As such, we will continue without " +
|
||||||
|
"interrupting the user by asking them to send a crash report.");
|
||||||
|
Handler handler = new Handler(Looper.getMainLooper());
|
||||||
|
handler.post(new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Context context = getApplicationContext();
|
||||||
|
Toast.makeText(context, e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
Utils.debugLog(TAG, e.getMessage());
|
Utils.debugLog(TAG, e.getMessage());
|
||||||
ACRA.getErrorReporter().handleException(e, false);
|
ACRA.getErrorReporter().handleException(e, false);
|
||||||
@ -207,7 +234,7 @@ public class InstalledAppProviderService extends IntentService {
|
|||||||
* broadcast. In the first case, it will already have a {@link PackageInfo} for us. However if
|
* broadcast. In the first case, it will already have a {@link PackageInfo} for us. However if
|
||||||
* it is from the later case, we'll need to query the {@link PackageManager} ourselves to get
|
* it is from the later case, we'll need to query the {@link PackageManager} ourselves to get
|
||||||
* this info.
|
* this info.
|
||||||
*
|
* <p>
|
||||||
* Can still return null, as there is potentially race conditions to do with uninstalling apps
|
* Can still return null, as there is potentially race conditions to do with uninstalling apps
|
||||||
* such that querying the {@link PackageManager} for a given package may throw an exception.
|
* such that querying the {@link PackageManager} for a given package may throw an exception.
|
||||||
*/
|
*/
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
package org.fdroid.fdroid.installer;
|
package org.fdroid.fdroid.installer;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.support.v4.content.FileProvider;
|
import android.support.v4.content.FileProvider;
|
||||||
|
|
||||||
@ -59,8 +60,9 @@ public class ApkFileProvider extends FileProvider {
|
|||||||
|
|
||||||
if (useContentUri) {
|
if (useContentUri) {
|
||||||
// return a content Uri using support libs FileProvider
|
// return a content Uri using support libs FileProvider
|
||||||
|
Uri apkUri = getUriForFile(context, AUTHORITY, sanitizedApkFile);
|
||||||
return getUriForFile(context, AUTHORITY, sanitizedApkFile);
|
context.grantUriPermission("org.fdroid.fdroid.privileged", apkUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
|
return apkUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need the apk to be world readable, so that the installer is able to read it.
|
// Need the apk to be world readable, so that the installer is able to read it.
|
||||||
|
@ -334,7 +334,10 @@ public class InstallManagerService extends Service {
|
|||||||
case Installer.ACTION_INSTALL_COMPLETE:
|
case Installer.ACTION_INSTALL_COMPLETE:
|
||||||
Apk apkComplete = removeFromActive(downloadUrl);
|
Apk apkComplete = removeFromActive(downloadUrl);
|
||||||
|
|
||||||
PackageManagerCompat.setInstaller(getPackageManager(), apkComplete.packageName);
|
PackageManagerCompat.setInstaller(context, getPackageManager(), apkComplete.packageName);
|
||||||
|
if (PrivilegedInstaller.isDefault(context)) {
|
||||||
|
cancelNotification(downloadUrl);
|
||||||
|
}
|
||||||
|
|
||||||
localBroadcastManager.unregisterReceiver(this);
|
localBroadcastManager.unregisterReceiver(this);
|
||||||
break;
|
break;
|
||||||
|
@ -45,12 +45,12 @@ public class InstallerFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Installer installer;
|
Installer installer;
|
||||||
if (apk.packageName.equals(PrivilegedInstaller.PRIVILEGED_EXTENSION_PACKAGE_NAME)) {
|
if (PrivilegedInstaller.isDefault(context)) {
|
||||||
// special case for installing "Privileged Extension" with root
|
|
||||||
installer = new ExtensionInstaller(context, apk);
|
|
||||||
} else if (PrivilegedInstaller.isDefault(context)) {
|
|
||||||
Utils.debugLog(TAG, "privileged extension correctly installed -> PrivilegedInstaller");
|
Utils.debugLog(TAG, "privileged extension correctly installed -> PrivilegedInstaller");
|
||||||
installer = new PrivilegedInstaller(context, apk);
|
installer = new PrivilegedInstaller(context, apk);
|
||||||
|
} else if (apk.packageName.equals(PrivilegedInstaller.PRIVILEGED_EXTENSION_PACKAGE_NAME)) {
|
||||||
|
// special case for installing "Privileged Extension" with root
|
||||||
|
installer = new ExtensionInstaller(context, apk);
|
||||||
} else {
|
} else {
|
||||||
installer = new DefaultInstaller(context, apk);
|
installer = new DefaultInstaller(context, apk);
|
||||||
}
|
}
|
||||||
|
@ -27,12 +27,14 @@ import android.content.Intent;
|
|||||||
import android.content.ServiceConnection;
|
import android.content.ServiceConnection;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.fdroid.fdroid.Preferences;
|
import org.fdroid.fdroid.Preferences;
|
||||||
import org.fdroid.fdroid.R;
|
import org.fdroid.fdroid.R;
|
||||||
|
import org.fdroid.fdroid.compat.PackageManagerCompat;
|
||||||
import org.fdroid.fdroid.data.Apk;
|
import org.fdroid.fdroid.data.Apk;
|
||||||
import org.fdroid.fdroid.privileged.IPrivilegedCallback;
|
import org.fdroid.fdroid.privileged.IPrivilegedCallback;
|
||||||
import org.fdroid.fdroid.privileged.IPrivilegedService;
|
import org.fdroid.fdroid.privileged.IPrivilegedService;
|
||||||
@ -393,6 +395,10 @@ public class PrivilegedInstaller extends Installer {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set installer to the privileged extension
|
||||||
|
*/
|
||||||
|
PackageManagerCompat.setInstaller(context, context.getPackageManager(), apk.packageName);
|
||||||
Intent serviceIntent = new Intent(PRIVILEGED_EXTENSION_SERVICE_INTENT);
|
Intent serviceIntent = new Intent(PRIVILEGED_EXTENSION_SERVICE_INTENT);
|
||||||
serviceIntent.setPackage(PRIVILEGED_EXTENSION_PACKAGE_NAME);
|
serviceIntent.setPackage(PRIVILEGED_EXTENSION_PACKAGE_NAME);
|
||||||
context.getApplicationContext().bindService(serviceIntent, mServiceConnection,
|
context.getApplicationContext().bindService(serviceIntent, mServiceConnection,
|
||||||
@ -406,7 +412,6 @@ public class PrivilegedInstaller extends Installer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean supportsContentUri() {
|
protected boolean supportsContentUri() {
|
||||||
// TODO: correct?
|
return Build.VERSION.SDK_INT >= 24;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<PreferenceCategory android:title="@string/updates">
|
<PreferenceCategory android:title="@string/updates">
|
||||||
<ListPreference android:title="@string/update_interval"
|
<com.geecko.QuickLyric.view.AppCompatListPreference android:title="@string/update_interval"
|
||||||
android:key="updateInterval"
|
android:key="updateInterval"
|
||||||
android:defaultValue="24"
|
android:defaultValue="24"
|
||||||
android:entries="@array/updateIntervalNames"
|
android:entries="@array/updateIntervalNames"
|
||||||
@ -24,12 +24,12 @@
|
|||||||
android:title="@string/update_history" />
|
android:title="@string/update_history" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
<PreferenceCategory android:title="@string/display">
|
<PreferenceCategory android:title="@string/display">
|
||||||
<ListPreference android:title="@string/pref_language"
|
<com.geecko.QuickLyric.view.AppCompatListPreference android:title="@string/pref_language"
|
||||||
android:key="language"
|
android:key="language"
|
||||||
android:defaultValue=""
|
android:defaultValue=""
|
||||||
android:entries="@array/languageNames"
|
android:entries="@array/languageNames"
|
||||||
android:entryValues="@array/languageValues" />
|
android:entryValues="@array/languageValues" />
|
||||||
<ListPreference android:title="@string/theme"
|
<com.geecko.QuickLyric.view.AppCompatListPreference android:title="@string/theme"
|
||||||
android:key="theme"
|
android:key="theme"
|
||||||
android:defaultValue="light"
|
android:defaultValue="light"
|
||||||
android:entries="@array/themeNames"
|
android:entries="@array/themeNames"
|
||||||
@ -77,7 +77,7 @@
|
|||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
<PreferenceCategory android:title="@string/other"
|
<PreferenceCategory android:title="@string/other"
|
||||||
android:key="pref_category_other">
|
android:key="pref_category_other">
|
||||||
<ListPreference android:title="@string/cache_downloaded"
|
<com.geecko.QuickLyric.view.AppCompatListPreference android:title="@string/cache_downloaded"
|
||||||
android:key="keepCacheFor"
|
android:key="keepCacheFor"
|
||||||
android:defaultValue="86400000"
|
android:defaultValue="86400000"
|
||||||
android:entries="@array/keepCacheNames"
|
android:entries="@array/keepCacheNames"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user