Merge branch '1.1-crash-fixes' into 'master'
1.1 crash fixes Closes #1325, #1305, and #1306 See merge request fdroid/fdroidclient!643
This commit is contained in:
commit
4766ed2868
@ -48,10 +48,8 @@ import android.view.Menu;
|
|||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.ViewTreeObserver;
|
import android.view.ViewTreeObserver;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
||||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||||
|
|
||||||
import org.fdroid.fdroid.data.Apk;
|
import org.fdroid.fdroid.data.Apk;
|
||||||
import org.fdroid.fdroid.data.ApkProvider;
|
import org.fdroid.fdroid.data.ApkProvider;
|
||||||
import org.fdroid.fdroid.data.App;
|
import org.fdroid.fdroid.data.App;
|
||||||
@ -69,8 +67,9 @@ import org.fdroid.fdroid.views.apps.FeatureImage;
|
|||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
@SuppressWarnings("LineLength")
|
public class AppDetails2 extends AppCompatActivity
|
||||||
public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog.ShareChooserDialogListener, AppDetailsRecyclerViewAdapter.AppDetailsRecyclerViewAdapterCallbacks {
|
implements ShareChooserDialog.ShareChooserDialogListener,
|
||||||
|
AppDetailsRecyclerViewAdapter.AppDetailsRecyclerViewAdapterCallbacks {
|
||||||
|
|
||||||
public static final String EXTRA_APPID = "appid";
|
public static final String EXTRA_APPID = "appid";
|
||||||
private static final String TAG = "AppDetails2";
|
private static final String TAG = "AppDetails2";
|
||||||
@ -121,7 +120,8 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
|
|||||||
appBarLayout = (AppBarLayout) coordinatorLayout.findViewById(R.id.app_bar);
|
appBarLayout = (AppBarLayout) coordinatorLayout.findViewById(R.id.app_bar);
|
||||||
recyclerView = (RecyclerView) findViewById(R.id.rvDetails);
|
recyclerView = (RecyclerView) findViewById(R.id.rvDetails);
|
||||||
adapter = new AppDetailsRecyclerViewAdapter(this, app, this);
|
adapter = new AppDetailsRecyclerViewAdapter(this, app, this);
|
||||||
OverscrollLinearLayoutManager lm = new OverscrollLinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
|
OverscrollLinearLayoutManager lm = new OverscrollLinearLayoutManager(this,
|
||||||
|
LinearLayoutManager.VERTICAL, false);
|
||||||
lm.setStackFromEnd(false);
|
lm.setStackFromEnd(false);
|
||||||
|
|
||||||
// Has to be invoked after AppDetailsRecyclerViewAdapter is created.
|
// Has to be invoked after AppDetailsRecyclerViewAdapter is created.
|
||||||
@ -146,10 +146,12 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
|
|||||||
public int onOverscrollY(int overscroll) {
|
public int onOverscrollY(int overscroll) {
|
||||||
int consumed = 0;
|
int consumed = 0;
|
||||||
if (overscroll < 0) {
|
if (overscroll < 0) {
|
||||||
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
|
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)
|
||||||
|
appBarLayout.getLayoutParams();
|
||||||
CoordinatorLayout.Behavior behavior = lp.getBehavior();
|
CoordinatorLayout.Behavior behavior = lp.getBehavior();
|
||||||
if (behavior != null && behavior instanceof AppBarLayout.Behavior) {
|
if (behavior != null && behavior instanceof AppBarLayout.Behavior) {
|
||||||
((AppBarLayout.Behavior) behavior).onNestedScroll(coordinatorLayout, appBarLayout, recyclerView, 0, 0, 0, overscroll);
|
((AppBarLayout.Behavior) behavior).onNestedScroll(
|
||||||
|
coordinatorLayout, appBarLayout, recyclerView, 0, 0, 0, overscroll);
|
||||||
consumed = overscroll; // Consume all of it!
|
consumed = overscroll; // Consume all of it!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,7 +175,8 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
|
|||||||
final FeatureImage featureImage = (FeatureImage) findViewById(R.id.feature_graphic);
|
final FeatureImage featureImage = (FeatureImage) findViewById(R.id.feature_graphic);
|
||||||
DisplayImageOptions displayImageOptions = Utils.getImageLoadingOptions().build();
|
DisplayImageOptions displayImageOptions = Utils.getImageLoadingOptions().build();
|
||||||
String featureGraphicUrl = app.getFeatureGraphicUrl(this);
|
String featureGraphicUrl = app.getFeatureGraphicUrl(this);
|
||||||
featureImage.loadImageAndDisplay(ImageLoader.getInstance(), displayImageOptions, featureGraphicUrl, app.iconUrl);
|
featureImage.loadImageAndDisplay(ImageLoader.getInstance(), displayImageOptions,
|
||||||
|
featureGraphicUrl, app.iconUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getPackageNameFromIntent(Intent intent) {
|
private String getPackageNameFromIntent(Intent intent) {
|
||||||
@ -197,26 +200,27 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
|
|||||||
app = newApp;
|
app = newApp;
|
||||||
|
|
||||||
// Remove all "installed" statuses for this app, since we are now viewing it.
|
// Remove all "installed" statuses for this app, since we are now viewing it.
|
||||||
AppUpdateStatusManager appUpdateStatusManager = AppUpdateStatusManager.getInstance(this);
|
AppUpdateStatusManager ausm = AppUpdateStatusManager.getInstance(this);
|
||||||
for (AppUpdateStatusManager.AppUpdateStatus status : appUpdateStatusManager.getByPackageName(app.packageName)) {
|
for (AppUpdateStatusManager.AppUpdateStatus status : ausm.getByPackageName(app.packageName)) {
|
||||||
if (status.status == AppUpdateStatusManager.Status.Installed) {
|
if (status.status == AppUpdateStatusManager.Status.Installed) {
|
||||||
appUpdateStatusManager.removeApk(status.getUniqueKey());
|
ausm.removeApk(status.getUniqueKey());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some notifications (like "downloading" and "installed") are not shown for this app if it is open in app details.
|
* Some notifications (like "downloading" and "installed") are not shown
|
||||||
* When closing, we need to refresh the notifications, so they are displayed again.
|
* for this app if it is open in app details. When closing, we need to
|
||||||
|
* refresh the notifications, so they are displayed again.
|
||||||
*/
|
*/
|
||||||
private void updateNotificationsForApp() {
|
private void updateNotificationsForApp() {
|
||||||
if (app != null) {
|
if (app != null) {
|
||||||
AppUpdateStatusManager appUpdateStatusManager = AppUpdateStatusManager.getInstance(this);
|
AppUpdateStatusManager ausm = AppUpdateStatusManager.getInstance(this);
|
||||||
for (AppUpdateStatusManager.AppUpdateStatus status : appUpdateStatusManager.getByPackageName(app.packageName)) {
|
for (AppUpdateStatusManager.AppUpdateStatus status : ausm.getByPackageName(app.packageName)) {
|
||||||
if (status.status == AppUpdateStatusManager.Status.Installed) {
|
if (status.status == AppUpdateStatusManager.Status.Installed) {
|
||||||
appUpdateStatusManager.removeApk(status.getUniqueKey());
|
ausm.removeApk(status.getUniqueKey());
|
||||||
} else {
|
} else {
|
||||||
appUpdateStatusManager.refreshApk(status.getUniqueKey());
|
ausm.refreshApk(status.getUniqueKey());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -245,7 +249,8 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
|
|||||||
* Then, asks the view to update itself to reflect this status.
|
* Then, asks the view to update itself to reflect this status.
|
||||||
*/
|
*/
|
||||||
private void refreshStatus() {
|
private void refreshStatus() {
|
||||||
Iterator<AppUpdateStatusManager.AppUpdateStatus> statuses = AppUpdateStatusManager.getInstance(this).getByPackageName(app.packageName).iterator();
|
AppUpdateStatusManager ausm = AppUpdateStatusManager.getInstance(this);
|
||||||
|
Iterator<AppUpdateStatusManager.AppUpdateStatus> statuses = ausm.getByPackageName(app.packageName).iterator();
|
||||||
if (statuses.hasNext()) {
|
if (statuses.hasNext()) {
|
||||||
AppUpdateStatusManager.AppUpdateStatus status = statuses.next();
|
AppUpdateStatusManager.AppUpdateStatus status = statuses.next();
|
||||||
updateAppStatus(status, false);
|
updateAppStatus(status, false);
|
||||||
@ -304,10 +309,12 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
|
|||||||
Intent shareIntent = new Intent(Intent.ACTION_SEND);
|
Intent shareIntent = new Intent(Intent.ACTION_SEND);
|
||||||
shareIntent.setType("text/plain");
|
shareIntent.setType("text/plain");
|
||||||
shareIntent.putExtra(Intent.EXTRA_SUBJECT, app.name);
|
shareIntent.putExtra(Intent.EXTRA_SUBJECT, app.name);
|
||||||
shareIntent.putExtra(Intent.EXTRA_TEXT, app.name + " (" + app.summary + ") - https://f-droid.org/app/" + app.packageName);
|
shareIntent.putExtra(Intent.EXTRA_TEXT, app.name + " (" + app.summary
|
||||||
|
+ ") - https://f-droid.org/app/" + app.packageName);
|
||||||
|
|
||||||
boolean showNearbyItem = app.isInstalled(getApplicationContext()) && fdroidApp.bluetoothAdapter != null;
|
boolean showNearbyItem = app.isInstalled(getApplicationContext()) && fdroidApp.bluetoothAdapter != null;
|
||||||
ShareChooserDialog.createChooser((CoordinatorLayout) findViewById(R.id.rootCoordinator), this, this, shareIntent, showNearbyItem);
|
CoordinatorLayout coordinatorLayout = (CoordinatorLayout) findViewById(R.id.rootCoordinator);
|
||||||
|
ShareChooserDialog.createChooser(coordinatorLayout, this, this, shareIntent, showNearbyItem);
|
||||||
return true;
|
return true;
|
||||||
} else if (item.getItemId() == R.id.action_ignore_all) {
|
} else if (item.getItemId() == R.id.action_ignore_all) {
|
||||||
app.getPrefs(this).ignoreAllUpdates ^= true;
|
app.getPrefs(this).ignoreAllUpdates ^= true;
|
||||||
@ -420,7 +427,8 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
|
|||||||
|
|
||||||
private void initiateInstall(Apk apk) {
|
private void initiateInstall(Apk apk) {
|
||||||
if (isAppDownloading()) {
|
if (isAppDownloading()) {
|
||||||
Log.i(TAG, "Ignoring request to install " + apk.packageName + " version " + apk.versionName + ", as we are already downloading (either that or a different version).");
|
Log.i(TAG, "Ignoring request to install " + apk.packageName + " version " + apk.versionName
|
||||||
|
+ ", as we are already downloading (either that or a different version).");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -489,7 +497,8 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
|
|||||||
case ReadyToInstall:
|
case ReadyToInstall:
|
||||||
if (justReceived) {
|
if (justReceived) {
|
||||||
adapter.clearProgress();
|
adapter.clearProgress();
|
||||||
localBroadcastManager.registerReceiver(installReceiver, Installer.getInstallIntentFilter(Uri.parse(newStatus.getUniqueKey())));
|
localBroadcastManager.registerReceiver(installReceiver,
|
||||||
|
Installer.getInstallIntentFilter(Uri.parse(newStatus.getUniqueKey())));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -520,13 +529,19 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
|
|||||||
private final BroadcastReceiver appStatusReceiver = new BroadcastReceiver() {
|
private final BroadcastReceiver appStatusReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
AppUpdateStatusManager.AppUpdateStatus status = intent.getParcelableExtra(AppUpdateStatusManager.EXTRA_STATUS);
|
AppUpdateStatusManager.AppUpdateStatus status = intent.getParcelableExtra(
|
||||||
|
AppUpdateStatusManager.EXTRA_STATUS);
|
||||||
|
|
||||||
boolean isRemoving = TextUtils.equals(intent.getAction(), AppUpdateStatusManager.BROADCAST_APPSTATUS_REMOVED);
|
boolean isRemoving = TextUtils.equals(intent.getAction(),
|
||||||
if (currentStatus != null && isRemoving && !TextUtils.equals(status.getUniqueKey(), currentStatus.getUniqueKey())) {
|
AppUpdateStatusManager.BROADCAST_APPSTATUS_REMOVED);
|
||||||
Utils.debugLog(TAG, "Ignoring app status change because it belongs to " + status.getUniqueKey() + " not " + currentStatus.getUniqueKey());
|
if (currentStatus != null
|
||||||
|
&& isRemoving
|
||||||
|
&& !TextUtils.equals(status.getUniqueKey(), currentStatus.getUniqueKey())) {
|
||||||
|
Utils.debugLog(TAG, "Ignoring app status change because it belongs to "
|
||||||
|
+ status.getUniqueKey() + " not " + currentStatus.getUniqueKey());
|
||||||
} else if (status != null && !TextUtils.equals(status.apk.packageName, app.packageName)) {
|
} else if (status != null && !TextUtils.equals(status.apk.packageName, app.packageName)) {
|
||||||
Utils.debugLog(TAG, "Ignoring app status change because it belongs to " + status.apk.packageName + " not " + app.packageName);
|
Utils.debugLog(TAG, "Ignoring app status change because it belongs to "
|
||||||
|
+ status.apk.packageName + " not " + app.packageName);
|
||||||
} else {
|
} else {
|
||||||
updateAppStatus(status, true);
|
updateAppStatus(status, true);
|
||||||
}
|
}
|
||||||
@ -583,15 +598,17 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
|
|||||||
case Installer.ACTION_INSTALL_USER_INTERACTION:
|
case Installer.ACTION_INSTALL_USER_INTERACTION:
|
||||||
Apk apk = intent.getParcelableExtra(Installer.EXTRA_APK);
|
Apk apk = intent.getParcelableExtra(Installer.EXTRA_APK);
|
||||||
if (!isAppVisible(apk.packageName)) {
|
if (!isAppVisible(apk.packageName)) {
|
||||||
Utils.debugLog(TAG, "Ignore request for user interaction from installer, because " + apk.packageName + " is no longer showing.");
|
Utils.debugLog(TAG, "Ignore request for user interaction from installer, because "
|
||||||
|
+ apk.packageName + " is no longer showing.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils.debugLog(TAG, "Automatically showing package manager for " + apk.packageName + " as it is being viewed by the user.");
|
Utils.debugLog(TAG, "Automatically showing package manager for " + apk.packageName
|
||||||
PendingIntent installPendingIntent = intent.getParcelableExtra(Installer.EXTRA_USER_INTERACTION_PI);
|
+ " as it is being viewed by the user.");
|
||||||
|
PendingIntent pendingIntent = intent.getParcelableExtra(Installer.EXTRA_USER_INTERACTION_PI);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
installPendingIntent.send();
|
pendingIntent.send();
|
||||||
} catch (PendingIntent.CanceledException e) {
|
} catch (PendingIntent.CanceledException e) {
|
||||||
Log.e(TAG, "PI canceled", e);
|
Log.e(TAG, "PI canceled", e);
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ import android.net.Uri;
|
|||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.fdroid.fdroid.data.Apk;
|
import org.fdroid.fdroid.data.Apk;
|
||||||
import org.fdroid.fdroid.data.ApkProvider;
|
import org.fdroid.fdroid.data.ApkProvider;
|
||||||
import org.fdroid.fdroid.data.InstalledAppProviderService;
|
import org.fdroid.fdroid.data.InstalledAppProviderService;
|
||||||
@ -109,7 +108,7 @@ public class AppUpdateStatusService extends IntentService {
|
|||||||
|
|
||||||
Utils.debugLog(TAG, "Found package for " + downloadedInfo.packageName + ", checking its hash to see if it downloaded correctly.");
|
Utils.debugLog(TAG, "Found package for " + downloadedInfo.packageName + ", checking its hash to see if it downloaded correctly.");
|
||||||
Apk downloadedApk = findApkMatchingHash(apkPath);
|
Apk downloadedApk = findApkMatchingHash(apkPath);
|
||||||
if (downloadedApk == null) {
|
if (downloadedApk == null) {
|
||||||
Log.i(TAG, "Either the apk wasn't downloaded fully, or the repo it came from has been disabled. Either way, not notifying the user about it.");
|
Log.i(TAG, "Either the apk wasn't downloaded fully, or the repo it came from has been disabled. Either way, not notifying the user about it.");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -129,7 +128,8 @@ public class AppUpdateStatusService extends IntentService {
|
|||||||
AppUpdateStatusManager.getInstance(this).markAsNoLongerPendingInstall(downloadedApk.getUrl());
|
AppUpdateStatusManager.getInstance(this).markAsNoLongerPendingInstall(downloadedApk.getUrl());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
} catch (PackageManager.NameNotFoundException ignored) { }
|
} catch (PackageManager.NameNotFoundException ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
Utils.debugLog(TAG, downloadedApk.packageName + " is pending install, so we need to notify the user about installing it.");
|
Utils.debugLog(TAG, downloadedApk.packageName + " is pending install, so we need to notify the user about installing it.");
|
||||||
return downloadedApk;
|
return downloadedApk;
|
||||||
@ -140,12 +140,16 @@ public class AppUpdateStatusService extends IntentService {
|
|||||||
* This method looks for all matching records in the database. It then asks each of these
|
* This method looks for all matching records in the database. It then asks each of these
|
||||||
* {@link Apk} instances where they expect to be downloaded. If they expect to be downloaded
|
* {@link Apk} instances where they expect to be downloaded. If they expect to be downloaded
|
||||||
* to {@param apkPath} then that instance is returned.
|
* to {@param apkPath} then that instance is returned.
|
||||||
*
|
* <p>
|
||||||
* If no files have a matching hash, or only those which don't belong to the correct repo, then
|
* If no files have a matching hash, or only those which don't belong to the correct repo, then
|
||||||
* this will return null.
|
* this will return null. This method needs to do its own check whether the file exists,
|
||||||
|
* since files can be deleted from the cache at any time without warning.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private Apk findApkMatchingHash(File apkPath) {
|
private Apk findApkMatchingHash(File apkPath) {
|
||||||
|
if (!apkPath.canRead()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: This presumes SHA256 is the only supported hash. It seems like that is an assumption
|
// NOTE: This presumes SHA256 is the only supported hash. It seems like that is an assumption
|
||||||
// in more than one place in the F-Droid client. If this becomes a problem in the future, we
|
// in more than one place in the F-Droid client. If this becomes a problem in the future, we
|
||||||
|
@ -14,6 +14,9 @@ import java.io.File;
|
|||||||
@TargetApi(21)
|
@TargetApi(21)
|
||||||
class CleanCacheService21 {
|
class CleanCacheService21 {
|
||||||
static void deleteIfOld(File file, long olderThan) {
|
static void deleteIfOld(File file, long olderThan) {
|
||||||
|
if (file == null || !file.exists()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
StructStat stat = Os.lstat(file.getAbsolutePath());
|
StructStat stat = Os.lstat(file.getAbsolutePath());
|
||||||
if ((stat.st_atime * 1000L) < olderThan) {
|
if ((stat.st_atime * 1000L) < olderThan) {
|
||||||
|
@ -285,7 +285,21 @@ public class FDroidApp extends Application {
|
|||||||
public void onConfigurationChanged(Configuration newConfig) {
|
public void onConfigurationChanged(Configuration newConfig) {
|
||||||
super.onConfigurationChanged(newConfig);
|
super.onConfigurationChanged(newConfig);
|
||||||
Languages.setLanguage(this);
|
Languages.setLanguage(this);
|
||||||
UpdateService.forceUpdateRepo(this);
|
|
||||||
|
// update the descriptions based on the new language preferences
|
||||||
|
SharedPreferences atStartTime = getAtStartTimeSharedPreferences();
|
||||||
|
final String lastLocaleKey = "lastLocale";
|
||||||
|
String lastLocale = atStartTime.getString(lastLocaleKey, null);
|
||||||
|
String currentLocale;
|
||||||
|
if (Build.VERSION.SDK_INT < 24) {
|
||||||
|
currentLocale = newConfig.locale.toString();
|
||||||
|
} else {
|
||||||
|
currentLocale = newConfig.getLocales().toString();
|
||||||
|
}
|
||||||
|
if (!TextUtils.equals(lastLocale, currentLocale)) {
|
||||||
|
UpdateService.forceUpdateRepo(this);
|
||||||
|
}
|
||||||
|
atStartTime.edit().putString(lastLocaleKey, currentLocale).apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -435,7 +449,7 @@ public class FDroidApp extends Application {
|
|||||||
Provisioner.scanAndProcess(getApplicationContext());
|
Provisioner.scanAndProcess(getApplicationContext());
|
||||||
|
|
||||||
// if the underlying OS version has changed, then fully rebuild the database
|
// if the underlying OS version has changed, then fully rebuild the database
|
||||||
SharedPreferences atStartTime = getSharedPreferences("at-start-time", Context.MODE_PRIVATE);
|
SharedPreferences atStartTime = getAtStartTimeSharedPreferences();
|
||||||
if (Build.VERSION.SDK_INT != atStartTime.getInt("build-version", Build.VERSION.SDK_INT)) {
|
if (Build.VERSION.SDK_INT != atStartTime.getInt("build-version", Build.VERSION.SDK_INT)) {
|
||||||
UpdateService.forceUpdateRepo(this);
|
UpdateService.forceUpdateRepo(this);
|
||||||
}
|
}
|
||||||
@ -483,6 +497,10 @@ public class FDroidApp extends Application {
|
|||||||
return ((BluetoothManager) getSystemService(BLUETOOTH_SERVICE)).getAdapter();
|
return ((BluetoothManager) getSystemService(BLUETOOTH_SERVICE)).getAdapter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SharedPreferences getAtStartTimeSharedPreferences() {
|
||||||
|
return getSharedPreferences("at-start-time", Context.MODE_PRIVATE);
|
||||||
|
}
|
||||||
|
|
||||||
public void sendViaBluetooth(Activity activity, int resultCode, String packageName) {
|
public void sendViaBluetooth(Activity activity, int resultCode, String packageName) {
|
||||||
if (resultCode == Activity.RESULT_CANCELED) {
|
if (resultCode == Activity.RESULT_CANCELED) {
|
||||||
return;
|
return;
|
||||||
|
@ -433,6 +433,12 @@ class NotificationHelper {
|
|||||||
intentDeleted.setClass(context, NotificationBroadcastReceiver.class);
|
intentDeleted.setClass(context, NotificationBroadcastReceiver.class);
|
||||||
PendingIntent piDeleted = PendingIntent.getBroadcast(context, 0, intentDeleted, PendingIntent.FLAG_UPDATE_CURRENT);
|
PendingIntent piDeleted = PendingIntent.getBroadcast(context, 0, intentDeleted, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
builder.setDeleteIntent(piDeleted);
|
builder.setDeleteIntent(piDeleted);
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT < 11) {
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
builder.setContentIntent(PendingIntent.getActivity(context, 0, intent, 0));
|
||||||
|
}
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -706,11 +706,19 @@ public class App extends ValueObject implements Comparable<App>, Parcelable {
|
|||||||
this.compatible = true;
|
this.compatible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes an {@link App} instances from an APK file. Since the file
|
||||||
|
* could in the cache, and files can disappear from the cache at any time,
|
||||||
|
* this needs to be quite defensive ensuring that {@code apkFile} still
|
||||||
|
* exists.
|
||||||
|
*/
|
||||||
private void initApkFromApkFile(Context context, Apk apk, PackageInfo packageInfo, SanitizedFile apkFile)
|
private void initApkFromApkFile(Context context, Apk apk, PackageInfo packageInfo, SanitizedFile apkFile)
|
||||||
throws IOException, CertificateEncodingException {
|
throws IOException, CertificateEncodingException {
|
||||||
// TODO include signature hash calculation here
|
// TODO include signature hash calculation here
|
||||||
apk.hashType = "sha256";
|
if (apkFile.canRead()) {
|
||||||
apk.hash = Utils.getBinaryHash(apkFile, apk.hashType);
|
apk.hashType = "sha256";
|
||||||
|
apk.hash = Utils.getBinaryHash(apkFile, apk.hashType);
|
||||||
|
}
|
||||||
initInstalledApk(context, apk, packageInfo, apkFile);
|
initInstalledApk(context, apk, packageInfo, apkFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -750,10 +758,22 @@ public class App extends ValueObject implements Comparable<App>, Parcelable {
|
|||||||
apk.packageName = this.packageName;
|
apk.packageName = this.packageName;
|
||||||
apk.requestedPermissions = packageInfo.requestedPermissions;
|
apk.requestedPermissions = packageInfo.requestedPermissions;
|
||||||
apk.apkName = apk.packageName + "_" + apk.versionCode + ".apk";
|
apk.apkName = apk.packageName + "_" + apk.versionCode + ".apk";
|
||||||
apk.installedFile = apkFile;
|
|
||||||
|
|
||||||
initInstalledObbFiles(apk);
|
initInstalledObbFiles(apk);
|
||||||
|
|
||||||
|
final FeatureInfo[] features = packageInfo.reqFeatures;
|
||||||
|
if (features != null && features.length > 0) {
|
||||||
|
apk.features = new String[features.length];
|
||||||
|
for (int i = 0; i < features.length; i++) {
|
||||||
|
apk.features[i] = features[i].name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!apkFile.canRead()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
apk.installedFile = apkFile;
|
||||||
JarFile apkJar = new JarFile(apkFile);
|
JarFile apkJar = new JarFile(apkFile);
|
||||||
HashSet<String> abis = new HashSet<>(3);
|
HashSet<String> abis = new HashSet<>(3);
|
||||||
Pattern pattern = Pattern.compile("^lib/([a-z0-9-]+)/.*");
|
Pattern pattern = Pattern.compile("^lib/([a-z0-9-]+)/.*");
|
||||||
@ -766,14 +786,6 @@ public class App extends ValueObject implements Comparable<App>, Parcelable {
|
|||||||
}
|
}
|
||||||
apk.nativecode = abis.toArray(new String[abis.size()]);
|
apk.nativecode = abis.toArray(new String[abis.size()]);
|
||||||
|
|
||||||
final FeatureInfo[] features = packageInfo.reqFeatures;
|
|
||||||
if (features != null && features.length > 0) {
|
|
||||||
apk.features = new String[features.length];
|
|
||||||
for (int i = 0; i < features.length; i++) {
|
|
||||||
apk.features[i] = features[i].name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final JarEntry aSignedEntry = (JarEntry) apkJar.getEntry("AndroidManifest.xml");
|
final JarEntry aSignedEntry = (JarEntry) apkJar.getEntry("AndroidManifest.xml");
|
||||||
|
|
||||||
if (aSignedEntry == null) {
|
if (aSignedEntry == null) {
|
||||||
|
@ -55,12 +55,11 @@ import java.util.HashMap;
|
|||||||
* <p/>
|
* <p/>
|
||||||
* This installer makes unattended installs/uninstalls possible.
|
* This installer makes unattended installs/uninstalls possible.
|
||||||
* Thus no PendingIntents are returned.
|
* Thus no PendingIntents are returned.
|
||||||
* <p/>
|
*
|
||||||
* Sources for Android 4.4 change:
|
* @see <a href="https://groups.google.com/forum/#!msg/android-security-discuss/r7uL_OEMU5c/LijNHvxeV80J">
|
||||||
* https://groups.google.com/forum/#!msg/android-
|
* Sources for Android 4.4 change</a>
|
||||||
* security-discuss/r7uL_OEMU5c/LijNHvxeV80J
|
* @see <a href="https://android.googlesource.com/platform/frameworks/base/+/ccbf84f44">
|
||||||
* https://android.googlesource.com/platform
|
* Commit that restricted "signatureOrSystem" permissions</a>
|
||||||
* /frameworks/base/+/ccbf84f44c9e6a5ed3c08673614826bb237afc54
|
|
||||||
*/
|
*/
|
||||||
public class PrivilegedInstaller extends Installer {
|
public class PrivilegedInstaller extends Installer {
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user