Compare commits

..

No commits in common. "master" and "1.12-alpha2" have entirely different histories.

594 changed files with 7657 additions and 10857 deletions

View File

@ -11,7 +11,7 @@ stages:
- echo y | sdkmanager "platforms;android-${ANDROID_COMPILE_SDK}" > /dev/null
# limit RAM usage for all gradle runs
- export maxmem=$(expr $(sed -n 's,^MemAvailable:[^0-9]*\([0-9][0-9]*\)[^0-9]*$,\1,p' /proc/meminfo) / 1024 / 2 / 1024 \* 1024)
- printf "\norg.gradle.jvmargs=-Xmx${maxmem}m -XX:MaxPermSize=${maxmem}m\norg.gradle.daemon=false\norg.gradle.parallel=false\n" >> gradle.properties
- printf '\norg.gradle.jvmargs=-Xmx${maxmem}m -XX:MaxPermSize=${maxmem}m\norg.gradle.daemon=false\norg.gradle.parallel=false\n' >> local.properties
after_script:
# this file changes every time but should not be cached
- rm -f $GRADLE_USER_HOME/caches/modules-2/modules-2.lock

View File

@ -1,31 +1,3 @@
### 1.13-alpha1 (2021-06-02)
* Stop repeated updates of Trichrome Library
* More changes to follow Material Design (@proletarius101)
* Improve OpenCollective badge (@ConnyDuck)
### 1.13-alpha0 (2021-04-22)
* Theme support tied to built-in Android themes (@proletarius101)
* New top banner notifications: "No Internet" and "No Data or WiFi enabled"
* Improved handling of USB-OTG and SD Card repos and mirrors
### 1.12.1 (2021-04-12)
* Fix trove4j verification error
### 1.12 (2021-04-06)
* Sync translations
### 1.12-alpha3 (2021-03-10)
* Opt-in F-Droid Metrics
### 1.12-alpha2 (2021-03-03)
* Overhaul clean up of cached files

View File

@ -1,6 +1,6 @@
# F-Droid Client
[![build status](https://gitlab.com/fdroid/fdroidclient/badges/master/pipeline.svg)](https://gitlab.com/fdroid/fdroidclient/-/jobs)
[![build status](https://gitlab.com/fdroid/fdroidclient/badges/master/build.svg)](https://gitlab.com/fdroid/fdroidclient/builds)
[![Translation status](https://hosted.weblate.org/widgets/f-droid/-/svg-badge.svg)](https://hosted.weblate.org/engage/f-droid/)
Client for [F-Droid](https://f-droid.org), the Free Software repository system

View File

@ -21,16 +21,16 @@ def basicApplicationId = "org.fdroid.basic"
def privilegedExtensionApplicationId = '"org.fdroid.fdroid.privileged"'
android {
compileSdkVersion 30
compileSdkVersion 29
defaultConfig {
versionCode 1013001
versionCode 1012002
versionName getVersionName()
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
minSdkVersion 24
minSdkVersion 14
//noinspection ExpiredTargetSdkVersion
targetSdkVersion 28
targetSdkVersion 25
/*
The Android Testing Support Library collects analytics to continuously improve the testing
experience. More specifically, it uploads a hash of the package name of the application
@ -38,7 +38,6 @@ android {
passing the following argument to the test runner: disableAnalytics "true".
*/
testInstrumentationRunnerArguments disableAnalytics: 'true'
vectorDrawables.useSupportLibrary = true
}
buildTypes {
@ -142,9 +141,10 @@ android {
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.preference:preference:1.1.1'
implementation 'androidx.gridlayout:gridlayout:1.0.0'
implementation 'androidx.annotation:annotation:1.1.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.vectordrawable:vectordrawable:1.1.0'
@ -152,19 +152,18 @@ dependencies {
implementation 'androidx.palette:palette:1.0.0'
implementation 'androidx.work:work-runtime:2.4.0'
implementation 'com.google.android.material:material:1.3.0'
implementation 'com.google.android.material:material:1.1.0'
implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
implementation 'com.google.zxing:core:3.3.3'
implementation 'info.guardianproject.netcipher:netcipher:2.2.0-alpha'
implementation 'info.guardianproject.netcipher:netcipher:2.0.0-beta1'
implementation 'info.guardianproject.panic:panic:1.0'
implementation 'commons-io:commons-io:2.6'
implementation 'commons-net:commons-net:3.6'
implementation 'ch.acra:acra:4.9.1'
implementation 'io.reactivex:rxjava:1.1.0'
implementation 'com.hannesdorfmann:adapterdelegates3:3.0.1'
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
implementation 'io.reactivex.rxjava3:rxjava:3.0.9'
implementation 'com.ashokvarma.android:bottom-navigation-bar:2.0.5'
implementation 'com.fasterxml.jackson.core:jackson-core:2.11.1'
implementation 'com.fasterxml.jackson.core:jackson-annotations:2.11.1'

View File

@ -31,6 +31,13 @@
public *;
}
# The rxjava library depends on sun.misc.Unsafe, which is unavailable on Android
# The rxjava team is aware of this, and mention in the docs that they only use
# the unsafe functionality if the platform supports it.
# - https://github.com/ReactiveX/RxJava/issues/1415#issuecomment-48390883
# - https://github.com/ReactiveX/RxJava/blob/1.x/src/main/java/rx/internal/util/unsafe/UnsafeAccess.java#L23
-dontwarn rx.internal.util.**
-keepattributes *Annotation*,EnclosingMethod,Signature
-keepnames class com.fasterxml.jackson.** { *; }
-dontwarn com.fasterxml.jackson.databind.ext.**

View File

@ -1,24 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="org.fdroid.fdroid.tests"
android:versionCode="1"
android:versionName="1.0">
xmlns:tools="http://schemas.android.com/tools"
package="org.fdroid.fdroid.tests"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk tools:overrideLibrary="android_libs.ub_uiautomator" />
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
which is needed when building test cases. -->
<application>
<uses-library
android:name="android.test.runner"
<uses-library android:name="android.test.runner"
android:required="false" />
</application>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
</manifest>

View File

@ -21,7 +21,7 @@ import androidx.test.uiautomator.UiObjectNotFoundException;
import androidx.test.uiautomator.UiSelector;
import android.util.Log;
import android.view.View;
import org.fdroid.fdroid.views.StatusBanner;
import org.fdroid.fdroid.views.BannerUpdatingRepos;
import org.fdroid.fdroid.views.main.MainActivity;
import org.hamcrest.Matchers;
import org.junit.After;
@ -267,7 +267,7 @@ public class MainActivityEspressoTest {
if (!BuildConfig.FLAVOR.startsWith("full")) {
return;
}
onView(Matchers.<View>instanceOf(StatusBanner.class)).check(matches(not(isDisplayed())));
onView(Matchers.<View>instanceOf(BannerUpdatingRepos.class)).check(matches(not(isDisplayed())));
onView(allOf(withText(R.string.menu_settings), isDisplayed())).perform(click());
onView(allOf(withText(R.string.main_menu__latest_apps), isDisplayed())).perform(click());
onView(allOf(withId(R.id.swipe_to_refresh), isDisplayed()))

View File

@ -1,72 +0,0 @@
/*
* Copyright (C) 2021 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.
*/
package org.fdroid.fdroid.work;
import androidx.arch.core.executor.testing.InstantTaskExecutorRule;
import androidx.test.filters.LargeTest;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkInfo;
import com.google.common.util.concurrent.ListenableFuture;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import static org.junit.Assert.assertEquals;
/**
* This actually runs {@link FDroidMetricsWorker} on a device/emulator and
* submits a report to https://metrics.cleaninsights.org
* <p>
* This is marked with {@link LargeTest} to exclude it from running on GitLab CI
* because it always fails on the emulator tests there. Also, it actually submits
* a report.
*/
@LargeTest
public class FDroidMetricsWorkerTest {
public static final String TAG = "FDroidMetricsWorkerTest";
@Rule
public InstantTaskExecutorRule instantTaskExecutorRule = new InstantTaskExecutorRule();
@Rule
public WorkManagerTestRule workManagerTestRule = new WorkManagerTestRule();
/**
* A test for easy manual testing.
*/
@Ignore
@Test
public void testGenerateReport() throws IOException {
String json = FDroidMetricsWorker.generateReport(
InstrumentationRegistry.getInstrumentation().getTargetContext());
System.out.println(json);
}
@Test
public void testWorkRequest() throws ExecutionException, InterruptedException {
OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(FDroidMetricsWorker.class).build();
workManagerTestRule.workManager.enqueue(request).getResult();
ListenableFuture<WorkInfo> workInfo = workManagerTestRule.workManager.getWorkInfoById(request.getId());
assertEquals(WorkInfo.State.SUCCEEDED, workInfo.get().getState());
}
}

View File

@ -1,7 +1,3 @@
-dontoptimize
-dontwarn
-dontobfuscate
-dontwarn android.test.**
-dontwarn android.support.test.**
-dontnote junit.framework.**
@ -18,8 +14,3 @@
-keep class junit.** { *; }
-dontwarn junit.**
# This is necessary so that RemoteWorkManager can be initialized (also marked with @Keep)
-keep class androidx.work.multiprocess.RemoteWorkManagerClient {
public <init>(...);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -1,8 +1,13 @@
<?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">
<PreferenceScreen android:title="@string/about_title"
android:key="pref_about" />
<PreferenceScreen android:title="@string/about_title">
<intent
android:action="android.intent.action.MAIN"
android:targetPackage="@string/applicationId"
android:targetClass="org.fdroid.fdroid.AboutActivity"/>
</PreferenceScreen>
<PreferenceCategory android:title="@string/preference_category__my_apps">
<PreferenceScreen android:title="@string/preference_manage_installed_apps">
@ -42,7 +47,7 @@
android:title="@string/over_data"
android:defaultValue="@integer/defaultOverData"
android:layout="@layout/preference_seekbar"/>
<SwitchPreferenceCompat
<SwitchPreference
android:title="@string/update_auto_download"
android:summary="@string/update_auto_download_summary"
android:key="updateAutoDownload"/>
@ -51,7 +56,7 @@
android:title="@string/update_interval"
android:defaultValue="@integer/defaultUpdateInterval"
android:layout="@layout/preference_seekbar"/>
<SwitchPreferenceCompat
<SwitchPreference
android:title="@string/notify"
android:defaultValue="true"
android:key="updateNotify"/>
@ -72,26 +77,26 @@
<PreferenceCategory android:title="@string/appcompatibility"
android:key="pref_category_appcompatibility">
<SwitchPreferenceCompat
<SwitchPreference
android:title="@string/show_incompat_versions"
android:defaultValue="false"
android:key="incompatibleVersions"/>
<SwitchPreferenceCompat
<SwitchPreference
android:title="@string/show_anti_feature_apps"
android:defaultValue="false"
android:key="showAntiFeatureApps"/>
<SwitchPreferenceCompat
<SwitchPreference
android:title="@string/force_touch_apps"
android:defaultValue="false"
android:key="ignoreTouchscreen"/>
</PreferenceCategory>
<PreferenceCategory android:title="@string/proxy">
<SwitchPreferenceCompat
<SwitchPreference
android:key="useTor"
android:summary="@string/useTorSummary"
android:title="@string/useTor"/>
<SwitchPreferenceCompat
<SwitchPreference
android:defaultValue="false"
android:key="enableProxy"
android:title="@string/enable_proxy_title"
@ -111,12 +116,12 @@
<PreferenceCategory
android:key="pref_category_privacy"
android:title="@string/privacy">
<SwitchPreferenceCompat
<SwitchPreference
android:key="promptToSendCrashReports"
android:title="@string/prompt_to_send_crash_reports"
android:summary="@string/prompt_to_send_crash_reports_summary"
android:defaultValue="true"/>
<SwitchPreferenceCompat
<SwitchPreference
android:defaultValue="false"
android:key="preventScreenshots"
android:summary="@string/preventScreenshots_summary"
@ -132,7 +137,7 @@
android:defaultValue="86400000"
android:entries="@array/keepCacheNames"
android:entryValues="@array/keepCacheValues"/>
<SwitchPreferenceCompat
<SwitchPreference
android:title="@string/expert"
android:defaultValue="false"
android:key="expert"/>
@ -148,12 +153,6 @@
android:summary="@string/keep_install_history_summary"
android:defaultValue="false"
android:dependency="expert"/>
<CheckBoxPreference
android:key="sendToFdroidMetrics"
android:title="@string/send_to_fdroid_metrics"
android:summary="@string/send_to_fdroid_metrics_summary"
android:defaultValue="false"
android:dependency="expert"/>
<CheckBoxPreference
android:key="hideAllNotifications"
android:title="@string/hide_all_notifications"

View File

@ -1,8 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This file should be outside of release manifest (in this case app/src/mock/Manifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!--required to enable/disable system animations from the app itself during Espresso test runs-->
<uses-permission android:name="android.permission.SET_ANIMATION_SCALE" />
<uses-permission android:name="android.permission.SET_ANIMATION_SCALE"/>
</manifest>

View File

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
* Copyright (C) 2010-2012 Ciaran Gultnieks
* Copyright (C) 2013-2017 Peter Serwylo
@ -24,128 +23,91 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.fdroid.fdroid"
android:installLocation="auto">
package="org.fdroid.fdroid"
android:installLocation="auto">
<uses-feature
android:name="android.hardware.nfc"
android:required="false" />
<uses-feature
android:name="android.hardware.bluetooth"
android:required="false" />
<uses-feature android:name="android.hardware.nfc" android:required="false"/>
<uses-feature android:name="android.hardware.bluetooth" android:required="false"/>
<uses-feature android:name="android.hardware.usb.host" android:required="false"/>
<uses-feature
android:name="android.hardware.usb.host"
android:required="false" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.NFC"/>
<uses-permission android:name="android.permission.USB_PERMISSION"
android:maxSdkVersion="22"/> <!-- maybe unnecessary -->
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.NFC" />
<uses-permission
android:name="android.permission.USB_PERMISSION"
android:maxSdkVersion="22" /><!-- maybe unnecessary -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<application>
<activity
android:name=".nearby.SwapWorkflowActivity"
android:configChanges="orientation|keyboardHidden"
android:label="@string/swap"
android:launchMode="singleTask"
android:parentActivityName=".views.main.MainActivity"
android:screenOrientation="portrait">
android:label="@string/swap"
android:name=".nearby.SwapWorkflowActivity"
android:parentActivityName=".views.main.MainActivity"
android:launchMode="singleTask"
android:theme="@style/SwapTheme.Wizard"
android:screenOrientation="portrait"
android:configChanges="orientation|keyboardHidden">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".views.main.MainActivity" />
android:name="android.support.PARENT_ACTIVITY"
android:value=".views.main.MainActivity"/>
</activity>
<activity
android:name=".panic.PanicPreferencesActivity"
android:label="@string/panic_settings"
android:parentActivityName=".views.main.MainActivity">
<intent-filter>
<action android:name="info.guardianproject.panic.action.CONNECT" />
<action android:name="info.guardianproject.panic.action.DISCONNECT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".views.main.MainActivity" />
</activity>
<activity
android:name=".panic.SelectInstalledAppsActivity"
android:parentActivityName=".panic.PanicPreferencesActivity" />
<activity
android:name=".panic.PanicResponderActivity"
android:noHistory="true"
android:theme="@android:style/Theme.NoDisplay">
<!-- this can never have launchMode singleTask or singleInstance! -->
<intent-filter>
<action android:name="info.guardianproject.panic.action.TRIGGER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".panic.ExitActivity"
android:theme="@android:style/Theme.NoDisplay" />
<activity
android:name=".panic.CalculatorActivity"
android:enabled="false"
android:icon="@mipmap/ic_calculator_launcher"
android:label="@string/hiding_calculator">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".nearby.WifiStateChangeReceiver">
<intent-filter>
<action android:name="android.net.wifi.STATE_CHANGE" />
</intent-filter>
</receiver>
<receiver android:name=".receiver.DeviceStorageReceiver">
<intent-filter>
<action android:name="android.intent.action.DEVICE_STORAGE_LOW" />
<action android:name="android.net.wifi.STATE_CHANGE"/>
</intent-filter>
</receiver>
<receiver android:name=".nearby.UsbDeviceAttachedReceiver">
<receiver android:name=".receiver.DeviceStorageReceiver">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
<action android:name="android.intent.action.DEVICE_STORAGE_LOW"/>
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
</receiver>
<receiver android:name=".nearby.UsbDeviceDetachedReceiver">
<service
android:name=".nearby.WifiStateChangeService"
android:exported="false"/>
<service android:name=".nearby.SwapService"/>
<service
android:name=".nearby.LocalRepoService"
android:exported="false"/>
<service
android:name=".nearby.TreeUriScannerIntentService"
android:exported="false"/>
<service
android:name=".nearby.SDCardScannerService"
android:exported="false"/>
<receiver
android:name=".nearby.UsbDeviceAttachedReceiver">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_DETACHED"
android:resource="@xml/device_filter" />
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter"/>
</receiver>
<receiver
android:name=".nearby.UsbDeviceDetachedReceiver">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED"/>
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_DETACHED"
android:resource="@xml/device_filter"/>
</receiver>
<receiver android:name=".nearby.UsbDeviceMediaMountedReceiver">
<intent-filter>
@ -159,20 +121,52 @@
</intent-filter>
</receiver>
<service
android:name=".nearby.WifiStateChangeService"
android:exported="false" />
<service android:name=".nearby.SwapService" />
<activity
android:name=".panic.PanicPreferencesActivity"
android:label="@string/panic_settings"
android:parentActivityName=".views.main.MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".views.main.MainActivity"/>
<service
android:name=".nearby.LocalRepoService"
android:exported="false" />
<service
android:name=".nearby.TreeUriScannerIntentService"
android:exported="false" />
<service
android:name=".nearby.SDCardScannerService"
android:exported="false" />
<intent-filter>
<action android:name="info.guardianproject.panic.action.CONNECT"/>
<action android:name="info.guardianproject.panic.action.DISCONNECT"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity
android:name=".panic.SelectInstalledAppsActivity"
android:parentActivityName=".panic.PanicPreferencesActivity"/>
<activity
android:name=".panic.PanicResponderActivity"
android:noHistory="true"
android:theme="@android:style/Theme.NoDisplay">
<!-- this can never have launchMode singleTask or singleInstance! -->
<intent-filter>
<action android:name="info.guardianproject.panic.action.TRIGGER"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity
android:name=".panic.ExitActivity"
android:theme="@android:style/Theme.NoDisplay"/>
<activity
android:name=".panic.CalculatorActivity"
android:enabled="false"
android:icon="@mipmap/ic_calculator_launcher"
android:label="@string/hiding_calculator"
android:theme="@style/AppThemeLight">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>

View File

@ -4,13 +4,12 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import javax.jmdns.ServiceInfo;
import javax.jmdns.impl.util.ByteWrangler;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.UnknownHostException;
import javax.jmdns.ServiceInfo;
import javax.jmdns.impl.util.ByteWrangler;
/**
* The ServiceInfo class needs to be serialized in order to be sent as an Android broadcast.
* In order to make it Parcelable (or Serializable for that matter), there are some package-scope

View File

@ -10,17 +10,15 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.os.Process;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import android.text.TextUtils;
import android.util.Log;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.nearby.peers.BluetoothPeer;
import java.lang.ref.WeakReference;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
/**
* Manage the {@link android.bluetooth.BluetoothAdapter}in a {@link HandlerThread}.
* The start process is in {@link HandlerThread#onLooperPrepared()} so that it is

View File

@ -5,7 +5,7 @@ import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.util.Log;
import android.webkit.MimeTypeMap;
import fi.iki.elonen.NanoHTTPD;
import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.nearby.httpish.Request;
import org.fdroid.fdroid.nearby.httpish.Response;
@ -20,8 +20,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import fi.iki.elonen.NanoHTTPD;
/**
* Act as a layer on top of LocalHTTPD server, by forwarding requests served
* over bluetooth to that server.

View File

@ -10,6 +10,9 @@ import android.os.Process;
import android.text.TextUtils;
import android.util.Log;
import androidx.core.content.ContextCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.Utils;
@ -25,9 +28,6 @@ import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceInfo;
import javax.jmdns.ServiceListener;
import androidx.core.content.ContextCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
/**
* Manage {@link JmDNS} in a {@link HandlerThread}. The start process is in
* {@link HandlerThread#onLooperPrepared()} so that it is always started before

View File

@ -35,9 +35,11 @@ package org.fdroid.fdroid.nearby;
import android.content.Context;
import android.net.Uri;
import fi.iki.elonen.NanoHTTPD;
import fi.iki.elonen.NanoHTTPD.Response.IStatus;
import org.fdroid.fdroid.BuildConfig;
import javax.net.ssl.SSLServerSocketFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@ -60,11 +62,6 @@ import java.util.Map;
import java.util.StringTokenizer;
import java.util.TimeZone;
import javax.net.ssl.SSLServerSocketFactory;
import fi.iki.elonen.NanoHTTPD;
import fi.iki.elonen.NanoHTTPD.Response.IStatus;
/**
* A HTTP server for serving the files that are being swapped via WiFi, etc.
* The only changes were to remove unneeded extras like {@code main()}, the

View File

@ -6,8 +6,8 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.os.Process;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import android.util.Log;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.Preferences;
@ -15,8 +15,6 @@ import java.io.IOException;
import java.net.BindException;
import java.util.Random;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
/**
* Manage {@link LocalHTTPD} in a {@link HandlerThread};
*/

View File

@ -2,7 +2,7 @@ package org.fdroid.fdroid.nearby;
import android.content.Context;
import android.util.Log;
import kellinwood.security.zipsigner.ZipSigner;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.GeneralName;
@ -19,6 +19,9 @@ import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.Utils;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.X509KeyManager;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@ -46,12 +49,6 @@ import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.X509KeyManager;
import kellinwood.security.zipsigner.ZipSigner;
// TODO Address exception handling in a uniform way throughout
@SuppressWarnings("LineLength")

View File

@ -12,7 +12,8 @@ import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.Hasher;
import org.fdroid.fdroid.IndexUpdater;
@ -49,9 +50,6 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
/**
* The {@link SwapService} deals with managing the entire workflow from selecting apps to
* swap, to invoking this class to prepare the webroot, to enabling various communication protocols.

View File

@ -4,7 +4,7 @@ import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.os.Process;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils;
@ -15,8 +15,6 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
/**
* Handles setting up and generating the local repo used to swap apps, including
* the {@code index.jar}, the symlinks to the shared APKs, etc.

View File

@ -29,7 +29,7 @@ import android.os.Build;
import android.os.Environment;
import android.os.Process;
import android.util.Log;
import androidx.core.content.ContextCompat;
import org.fdroid.fdroid.IndexUpdater;
import org.fdroid.fdroid.IndexV1Updater;
import org.fdroid.fdroid.Utils;
@ -44,8 +44,6 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import androidx.core.content.ContextCompat;
/**
* An {@link IntentService} subclass for scanning removable "external storage"
* for F-Droid package repos, e.g. SD Cards. This is intended to support

View File

@ -4,6 +4,7 @@ import android.annotation.TargetApi;
import android.content.Context;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
@ -20,10 +21,6 @@ import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.data.InstalledAppProvider;
import org.fdroid.fdroid.data.Schema.InstalledAppTable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
@ -32,6 +29,10 @@ import androidx.loader.app.LoaderManager;
import androidx.loader.content.CursorLoader;
import androidx.loader.content.Loader;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.data.InstalledAppProvider;
import org.fdroid.fdroid.data.Schema.InstalledAppTable;
public class SelectAppsView extends SwapView implements LoaderManager.LoaderCallbacks<Cursor> {
public SelectAppsView(Context context) {
@ -199,6 +200,8 @@ public class SelectAppsView extends SwapView implements LoaderManager.LoaderCall
}
});
}
updateCheckedIndicatorView(view, listView.isItemChecked(listPosition));
}
public void updateCheckedIndicatorView(int position, boolean checked) {
@ -207,6 +210,24 @@ public class SelectAppsView extends SwapView implements LoaderManager.LoaderCall
if (position >= firstListItemPosition && position <= lastListItemPosition) {
final int childIndex = position - firstListItemPosition;
updateCheckedIndicatorView(listView.getChildAt(childIndex), checked);
}
}
private void updateCheckedIndicatorView(View view, boolean checked) {
ImageView imageView = (ImageView) view.findViewById(R.id.checked);
if (imageView != null) {
int resource;
int colour;
if (checked) {
resource = R.drawable.ic_check_circle;
colour = ContextCompat.getColor(getContext(), R.color.swap_bright_blue);
} else {
resource = R.drawable.ic_add_circle_outline;
colour = 0xFFD0D0D4;
}
imageView.setImageDrawable(ContextCompat.getDrawable(getContext(), resource));
imageView.setColorFilter(colour, PorterDuff.Mode.MULTIPLY);
}
}
}

View File

@ -20,6 +20,11 @@ import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.SwitchCompat;
import androidx.core.content.ContextCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils;
@ -27,10 +32,6 @@ import org.fdroid.fdroid.nearby.peers.Peer;
import java.util.ArrayList;
import androidx.annotation.Nullable;
import com.google.android.material.switchmaterial.SwitchMaterial;
import androidx.core.content.ContextCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import cc.mvdan.accesspoint.WifiApControl;
@SuppressWarnings("LineLength")
@ -79,7 +80,7 @@ public class StartSwapView extends SwapView {
@Nullable /* Emulators typically don't have bluetooth adapters */
private final BluetoothAdapter bluetooth = BluetoothAdapter.getDefaultAdapter();
private SwitchMaterial bluetoothSwitch;
private SwitchCompat bluetoothSwitch;
private TextView viewBluetoothId;
private TextView textBluetoothVisible;
private TextView viewWifiId;
@ -175,7 +176,7 @@ public class StartSwapView extends SwapView {
textBluetoothVisible = findViewById(R.id.bluetooth_visible);
bluetoothSwitch = (SwitchMaterial) findViewById(R.id.switch_bluetooth);
bluetoothSwitch = (SwitchCompat) findViewById(R.id.switch_bluetooth);
bluetoothSwitch.setOnCheckedChangeListener(onBluetoothSwitchToggled);
bluetoothSwitch.setChecked(SwapService.getBluetoothVisibleUserPreference());
bluetoothSwitch.setEnabled(true);

View File

@ -1,5 +1,6 @@
package org.fdroid.fdroid.nearby;
import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
@ -12,17 +13,17 @@ import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.IBinder;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.core.app.ServiceCompat;
import androidx.core.content.ContextCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import cc.mvdan.accesspoint.WifiApControl;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.NotificationHelper;
import org.fdroid.fdroid.Preferences;
@ -35,6 +36,7 @@ import org.fdroid.fdroid.data.Schema;
import org.fdroid.fdroid.nearby.peers.Peer;
import org.fdroid.fdroid.net.Downloader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
@ -45,12 +47,6 @@ import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import cc.mvdan.accesspoint.WifiApControl;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Completable;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
/**
* Central service which manages all of the different moving parts of swap which are required
* to enable p2p swapping of apps.
@ -111,6 +107,46 @@ public class SwapService extends Service {
UpdateService.updateRepoNow(this, peer.getRepoAddress());
}
@SuppressLint("StaticFieldLeak")
private void askServerToSwapWithUs(final Repo repo) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... args) {
String swapBackUri = Utils.getLocalRepoUri(FDroidApp.repo).toString();
HttpURLConnection conn = null;
try {
URL url = new URL(repo.address.replace("/fdroid/repo", "/request-swap"));
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
OutputStream outputStream = conn.getOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(outputStream);
writer.write("repo=" + swapBackUri);
writer.flush();
writer.close();
outputStream.close();
int responseCode = conn.getResponseCode();
Utils.debugLog(TAG, "Asking server at " + repo.address + " to swap with us in return (by " +
"POSTing to \"/request-swap\" with repo \"" + swapBackUri + "\"): " + responseCode);
} catch (IOException e) {
Log.e(TAG, "Error while asking server to swap with us", e);
Intent intent = new Intent(Downloader.ACTION_INTERRUPTED);
intent.setData(Uri.parse(repo.address));
intent.putExtra(Downloader.EXTRA_ERROR_MESSAGE, e.getLocalizedMessage());
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
} finally {
if (conn != null) {
conn.disconnect();
}
}
return null;
}
}.execute();
}
private Repo ensureRepoExists(@NonNull Peer peer) {
// TODO: newRepoConfig.getParsedUri() will include a fingerprint, which may not match with
// the repos address in the database. Not sure on best behaviour in this situation.
@ -304,15 +340,12 @@ public class SwapService extends Service {
@Nullable
private Timer timer;
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
public class Binder extends android.os.Binder {
public SwapService getService() {
return SwapService.this;
}
}
@Override
public void onCreate() {
super.onCreate();
startForeground(NOTIFICATION, createNotification());
@ -362,45 +395,6 @@ public class SwapService extends Service {
BonjourManager.setVisible(this, getWifiVisibleUserPreference() || getHotspotActivatedUserPreference());
}
private void askServerToSwapWithUs(final Repo repo) {
compositeDisposable.add(
Completable.fromAction(() -> {
String swapBackUri = Utils.getLocalRepoUri(FDroidApp.repo).toString();
HttpURLConnection conn = null;
try {
URL url = new URL(repo.address.replace("/fdroid/repo", "/request-swap"));
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
try (OutputStream outputStream = conn.getOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(outputStream)) {
writer.write("repo=" + swapBackUri);
writer.flush();
}
int responseCode = conn.getResponseCode();
Utils.debugLog(TAG, "Asking server at " + repo.address + " to swap with us in return (by " +
"POSTing to \"/request-swap\" with repo \"" + swapBackUri + "\"): " + responseCode);
} finally {
if (conn != null) {
conn.disconnect();
}
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnError(e -> {
Intent intent = new Intent(Downloader.ACTION_INTERRUPTED);
intent.setData(Uri.parse(repo.address));
intent.putExtra(Downloader.EXTRA_ERROR_MESSAGE, e.getLocalizedMessage());
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
})
.subscribe()
);
}
/**
* This is for setting things up for when the {@code SwapService} was
* started by the user clicking on the initial start button. The things
@ -424,8 +418,6 @@ public class SwapService extends Service {
@Override
public void onDestroy() {
compositeDisposable.dispose();
Utils.debugLog(TAG, "Destroying service, will disable swapping if required, and unregister listeners.");
Preferences.get().unregisterLocalRepoHttpsListeners(httpsEnabledListener);
localBroadcastManager.unregisterReceiver(onWifiChange);

View File

@ -1,6 +1,7 @@
package org.fdroid.fdroid.nearby;
import android.annotation.TargetApi;
import androidx.appcompat.app.AppCompatActivity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
@ -11,6 +12,14 @@ import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.CursorLoader;
import androidx.loader.content.Loader;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.cursoradapter.widget.CursorAdapter;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
@ -23,9 +32,7 @@ import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.nostra13.universalimageloader.core.ImageLoader;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.UpdateService;
import org.fdroid.fdroid.Utils;
@ -42,16 +49,6 @@ import org.fdroid.fdroid.net.DownloaderService;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.cursoradapter.widget.CursorAdapter;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.CursorLoader;
import androidx.loader.content.Loader;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
/**
* This is a view that shows a listing of all apps in the swap repo that this
* just connected to. The app listing and search should be replaced by

View File

@ -6,12 +6,12 @@ import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
import org.fdroid.fdroid.R;
import androidx.annotation.ColorInt;
import androidx.annotation.LayoutRes;
import androidx.core.content.ContextCompat;
import org.fdroid.fdroid.R;
/**
* A {@link android.view.View} that registers to handle the swap events from
* {@link SwapService}.

View File

@ -1,6 +1,7 @@
package org.fdroid.fdroid.nearby;
import android.annotation.TargetApi;
import androidx.appcompat.app.AppCompatActivity;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@ -41,11 +42,11 @@ import androidx.annotation.StringRes;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.SwitchCompat;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.google.android.material.appbar.MaterialToolbar;
import com.google.android.material.switchmaterial.SwitchMaterial;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
@ -65,6 +66,7 @@ import org.fdroid.fdroid.net.BluetoothDownloader;
import org.fdroid.fdroid.net.Downloader;
import org.fdroid.fdroid.net.HttpDownloader;
import org.fdroid.fdroid.qr.CameraCharacteristicsChecker;
import org.fdroid.fdroid.qr.QrGenAsyncTask;
import org.fdroid.fdroid.views.main.MainActivity;
import java.util.Date;
@ -76,7 +78,6 @@ import java.util.Timer;
import java.util.TimerTask;
import cc.mvdan.accesspoint.WifiApControl;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import static org.fdroid.fdroid.views.main.MainActivity.ACTION_REQUEST_SWAP;
@ -106,7 +107,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
private static final int REQUEST_WRITE_SETTINGS_PERMISSION = 5;
private static final int STEP_INTRO = 1; // TODO remove this special case, only use layoutResIds
private MaterialToolbar toolbar;
private Toolbar toolbar;
private SwapView currentView;
private boolean hasPreparedLocalRepo;
private boolean newIntent;
@ -119,8 +120,6 @@ public class SwapWorkflowActivity extends AppCompatActivity {
@LayoutRes
private int currentSwapViewLayoutRes = STEP_INTRO;
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
public static void requestSwap(Context context, String repo) {
requestSwap(context, Uri.parse(repo));
}
@ -202,11 +201,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
FDroidApp fdroidApp = (FDroidApp) getApplication();
fdroidApp.setSecureWindow(this);
fdroidApp.applyPureBlackBackgroundInDarkTheme(this);
((FDroidApp) getApplication()).setSecureWindow(this);
super.onCreate(savedInstanceState);
currentView = new SwapView(this); // dummy placeholder to avoid NullPointerExceptions;
@ -219,8 +214,10 @@ public class SwapWorkflowActivity extends AppCompatActivity {
setContentView(R.layout.swap_activity);
toolbar = findViewById(R.id.toolbar);
toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitleTextAppearance(getApplicationContext(), R.style.SwapTheme_Wizard_Text_Toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
container = (ViewGroup) findViewById(R.id.container);
@ -238,7 +235,6 @@ public class SwapWorkflowActivity extends AppCompatActivity {
@Override
protected void onDestroy() {
compositeDisposable.dispose();
localBroadcastManager.unregisterReceiver(downloaderInterruptedReceiver);
unbindService(serviceConnection);
super.onDestroy();
@ -499,6 +495,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
currentView.setLayoutResId(viewRes);
currentSwapViewLayoutRes = viewRes;
toolbar.setBackgroundColor(currentView.getToolbarColour());
toolbar.setTitle(currentView.getToolbarTitle());
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
@ -779,7 +776,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
private final BroadcastReceiver bluetoothScanModeChanged = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
SwitchMaterial bluetoothSwitch = container.findViewById(R.id.switch_bluetooth);
SwitchCompat bluetoothSwitch = container.findViewById(R.id.switch_bluetooth);
TextView textBluetoothVisible = container.findViewById(R.id.bluetooth_visible);
if (bluetoothSwitch == null || textBluetoothVisible == null
|| !BluetoothManager.ACTION_STATUS.equals(intent.getAction())) {
@ -933,23 +930,18 @@ public class SwapWorkflowActivity extends AppCompatActivity {
ImageView qrImage = container.findViewById(R.id.wifi_qr_code);
if (qrUriString != null && qrImage != null) {
Utils.debugLog(TAG, "Encoded swap URI in QR Code: " + qrUriString);
new QrGenAsyncTask(SwapWorkflowActivity.this, R.id.wifi_qr_code).execute(qrUriString);
compositeDisposable.add(Utils.generateQrBitmap(this, qrUriString)
.subscribe(qrBitmap -> {
qrImage.setImageBitmap(qrBitmap);
// Replace all blacks with the background blue.
qrImage.setColorFilter(new LightingColorFilter(0xffffffff, ContextCompat.getColor(this,
R.color.swap_blue)));
// Replace all blacks with the background blue.
qrImage.setColorFilter(new LightingColorFilter(0xffffffff,
ContextCompat.getColor(this, R.color.swap_blue)));
final View qrWarningMessage = container.findViewById(R.id.warning_qr_scanner);
if (CameraCharacteristicsChecker.getInstance(this).hasAutofocus()) {
qrWarningMessage.setVisibility(View.GONE);
} else {
qrWarningMessage.setVisibility(View.VISIBLE);
}
})
);
final View qrWarningMessage = container.findViewById(R.id.warning_qr_scanner);
if (CameraCharacteristicsChecker.getInstance(this).hasAutofocus()) {
qrWarningMessage.setVisibility(View.GONE);
} else {
qrWarningMessage.setVisibility(View.VISIBLE);
}
}
}
@ -996,7 +988,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
}
});
SwitchMaterial wifiSwitch = findViewById(R.id.switch_wifi);
SwitchCompat wifiSwitch = findViewById(R.id.switch_wifi);
wifiSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
@ -1120,7 +1112,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
private final BroadcastReceiver bluetoothStatus = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
SwitchMaterial bluetoothSwitch = container.findViewById(R.id.switch_bluetooth);
SwitchCompat bluetoothSwitch = container.findViewById(R.id.switch_bluetooth);
TextView textBluetoothVisible = container.findViewById(R.id.bluetooth_visible);
TextView textDeviceIdBluetooth = container.findViewById(R.id.device_id_bluetooth);
TextView peopleNearbyText = container.findViewById(R.id.text_people_nearby);

View File

@ -29,7 +29,7 @@ import android.os.Build;
import android.os.Process;
import android.util.Log;
import android.widget.Toast;
import androidx.documentfile.provider.DocumentFile;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.fdroid.fdroid.AddRepoIntentService;
@ -49,8 +49,6 @@ import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import androidx.documentfile.provider.DocumentFile;
/**
* An {@link IntentService} subclass for handling asynchronous scanning of a
* removable storage device like an SD Card or USB OTG thumb drive using the

View File

@ -8,13 +8,13 @@ import android.os.Build;
import android.os.storage.StorageManager;
import android.provider.DocumentsContract;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import java.io.File;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
/**
* @see <a href="https://stackoverflow.com/a/36162691">Android 5.0 DocumentFile from tree URI</a>

View File

@ -31,10 +31,8 @@ import android.os.Build;
import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;
import org.fdroid.fdroid.views.main.NearbyViewBinder;
import androidx.annotation.RequiresApi;
import org.fdroid.fdroid.views.main.NearbyViewBinder;
/**

View File

@ -29,13 +29,11 @@ import android.net.Uri;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.RequiresApi;
import org.fdroid.fdroid.views.main.NearbyViewBinder;
import java.util.HashMap;
import androidx.annotation.RequiresApi;
/**
* This is just a shim to receive {@link UsbManager#ACTION_USB_DEVICE_DETACHED}
* events.

View File

@ -4,7 +4,6 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Environment;
import org.fdroid.fdroid.views.main.NearbyViewBinder;
public class UsbDeviceMediaMountedReceiver extends BroadcastReceiver {

View File

@ -4,7 +4,6 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.WifiManager;
import org.fdroid.fdroid.Utils;
public class WifiStateChangeReceiver extends BroadcastReceiver {

View File

@ -10,13 +10,12 @@ import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import android.text.TextUtils;
import android.util.Log;
import cc.mvdan.accesspoint.WifiApControl;
import org.apache.commons.net.util.SubnetUtils;
import org.fdroid.fdroid.BuildConfig;
import org.fdroid.fdroid.FDroidApp;
@ -35,9 +34,6 @@ import java.security.cert.Certificate;
import java.util.Enumeration;
import java.util.Locale;
import cc.mvdan.accesspoint.WifiApControl;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
/**
* Handle state changes to the device's wifi, storing the required bits.
* The {@link Intent} that starts it either has no extras included,
@ -72,8 +68,6 @@ public class WifiStateChangeService extends IntentService {
private static int previousWifiState = Integer.MIN_VALUE;
private static int wifiState;
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
public WifiStateChangeService() {
super("WifiStateChangeService");
}
@ -86,12 +80,6 @@ public class WifiStateChangeService extends IntentService {
context.startService(intent);
}
@Override
public void onDestroy() {
compositeDisposable.dispose();
super.onDestroy();
}
@Override
protected void onHandleIntent(Intent intent) {
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_LOWEST);
@ -119,7 +107,7 @@ public class WifiStateChangeService extends IntentService {
}
if (Build.VERSION.SDK_INT < 21 && wifiState == WifiManager.WIFI_STATE_ENABLED) {
compositeDisposable.add(UpdateService.scheduleIfStillOnWifi(this).subscribe());
UpdateService.scheduleIfStillOnWifi(this);
}
}
}

View File

@ -5,10 +5,10 @@ import android.bluetooth.BluetoothDevice;
import android.os.Parcel;
import android.text.TextUtils;
import org.fdroid.fdroid.R;
import androidx.annotation.Nullable;
import org.fdroid.fdroid.R;
public class BluetoothPeer implements Peer {
private static final String BLUETOOTH_NAME_TAG = "FDroid:";

View File

@ -2,15 +2,13 @@ package org.fdroid.fdroid.nearby.peers;
import android.net.Uri;
import android.os.Parcel;
import androidx.annotation.Nullable;
import android.text.TextUtils;
import org.fdroid.fdroid.FDroidApp;
import javax.jmdns.ServiceInfo;
import javax.jmdns.impl.FDroidServiceInfo;
import androidx.annotation.Nullable;
public class BonjourPeer extends WifiPeer {
private static final String TAG = "BonjourPeer";

View File

@ -1,7 +1,6 @@
package org.fdroid.fdroid.nearby.peers;
import android.os.Parcelable;
import androidx.annotation.DrawableRes;
/**

View File

@ -1,21 +1,17 @@
package org.fdroid.fdroid.panic;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.appbar.MaterialToolbar;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.R;
import java.util.regex.Pattern;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
/**
* A very hacky calculator which is barely functional.
* It is just meant to pass a very casual inspection.
@ -39,13 +35,10 @@ public class CalculatorActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
FDroidApp fdroidApp = (FDroidApp) getApplication();
fdroidApp.applyPureBlackBackgroundInDarkTheme(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_calculator);
MaterialToolbar toolbar = findViewById(R.id.toolbar);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
textView = (TextView) findViewById(R.id.textView);

View File

@ -3,13 +3,13 @@ package org.fdroid.fdroid.panic;
import android.content.Context;
import android.util.AttributeSet;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.R;
import androidx.core.content.ContextCompat;
import androidx.preference.CheckBoxPreference;
import androidx.preference.PreferenceViewHolder;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.R;
public class DestructiveCheckBoxPreference extends CheckBoxPreference {
public DestructiveCheckBoxPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);

View File

@ -3,13 +3,13 @@ package org.fdroid.fdroid.panic;
import android.content.Context;
import android.util.AttributeSet;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.R;
import androidx.core.content.ContextCompat;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.R;
public class DestructivePreference extends Preference {
public DestructivePreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);

View File

@ -3,7 +3,6 @@ package org.fdroid.fdroid.panic;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
public class ExitActivity extends AppCompatActivity {

View File

@ -7,14 +7,12 @@ import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import androidx.core.app.NotificationManagerCompat;
import androidx.appcompat.app.AlertDialog;
import org.fdroid.fdroid.BuildConfig;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.views.main.MainActivity;
import androidx.appcompat.app.AlertDialog;
import androidx.core.app.NotificationManagerCompat;
/**
* This class is encapsulating all methods related to hiding the app from the launcher
* and restoring it.

View File

@ -1,32 +1,37 @@
package org.fdroid.fdroid.panic;
import android.os.Bundle;
import android.view.View;
import com.google.android.material.appbar.MaterialToolbar;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.view.MenuItem;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.R;
import androidx.appcompat.app.AppCompatActivity;
public class PanicPreferencesActivity extends AppCompatActivity {
@Override
public void onCreate(Bundle bundle) {
FDroidApp fdroidApp = (FDroidApp) getApplication();
fdroidApp.applyPureBlackBackgroundInDarkTheme(this);
((FDroidApp) getApplication()).applyTheme(this);
super.onCreate(bundle);
setContentView(R.layout.activity_panic_settings);
MaterialToolbar toolbar = findViewById(R.id.toolbar);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// Handle navigation icon press
onBackPressed();
}
});
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar ab = getSupportActionBar();
if (ab != null) {
ab.setDisplayShowHomeEnabled(true);
ab.setDisplayHomeAsUpEnabled(true);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
}

View File

@ -1,5 +1,6 @@
package org.fdroid.fdroid.panic;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ComponentName;
import android.content.DialogInterface;
import android.content.Intent;
@ -15,6 +16,16 @@ import android.os.Bundle;
import android.text.TextUtils;
import android.util.TypedValue;
import androidx.annotation.ColorInt;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.preference.CheckBoxPreference;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceFragmentCompat;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.installer.PrivilegedInstaller;
@ -22,16 +33,6 @@ import org.fdroid.fdroid.installer.PrivilegedInstaller;
import java.util.ArrayList;
import java.util.Set;
import androidx.annotation.ColorInt;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.preference.CheckBoxPreference;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceFragmentCompat;
import info.guardianproject.panic.Panic;
import info.guardianproject.panic.PanicResponder;

View File

@ -1,13 +1,17 @@
package org.fdroid.fdroid.panic;
import androidx.appcompat.app.AppCompatActivity;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import info.guardianproject.panic.Panic;
import info.guardianproject.panic.PanicResponder;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.data.DBHelper;
@ -27,11 +31,6 @@ import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import androidx.appcompat.app.AppCompatActivity;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import info.guardianproject.panic.Panic;
import info.guardianproject.panic.PanicResponder;
/**
* This {@link AppCompatActivity} is purely to run events in response to a panic trigger.
* It needs to be an {@code AppCompatActivity} rather than a {@link android.app.Service}

View File

@ -1,8 +1,9 @@
package org.fdroid.fdroid.panic;
import androidx.appcompat.app.AppCompatActivity;
import androidx.annotation.NonNull;
import android.view.View;
import android.view.ViewGroup;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.views.installed.InstalledAppListAdapter;
@ -10,9 +11,6 @@ import org.fdroid.fdroid.views.installed.InstalledAppListItemController;
import java.util.Set;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
public class SelectInstalledAppListAdapter extends InstalledAppListAdapter {
private final Set<String> selectedApps;

View File

@ -1,7 +1,9 @@
package org.fdroid.fdroid.panic;
import androidx.appcompat.app.AppCompatActivity;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.view.View;
import org.fdroid.fdroid.AppUpdateStatusManager;
import org.fdroid.fdroid.data.App;
import org.fdroid.fdroid.views.apps.AppListItemState;
@ -9,10 +11,6 @@ import org.fdroid.fdroid.views.installed.InstalledAppListItemController;
import java.util.Set;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
/**
* Shows the currently installed apps as a selectable list.
*/

View File

@ -27,7 +27,15 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import com.google.android.material.appbar.MaterialToolbar;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.CursorLoader;
import androidx.loader.content.Loader;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.Preferences;
@ -35,14 +43,6 @@ import org.fdroid.fdroid.R;
import org.fdroid.fdroid.data.InstalledAppProvider;
import org.fdroid.fdroid.views.installed.InstalledAppListAdapter;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.CursorLoader;
import androidx.loader.content.Loader;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class SelectInstalledAppsActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> {
private InstalledAppListAdapter adapter;
@ -54,14 +54,13 @@ public class SelectInstalledAppsActivity extends AppCompatActivity implements Lo
@Override
protected void onCreate(Bundle savedInstanceState) {
FDroidApp fdroidApp = (FDroidApp) getApplication();
fdroidApp.applyPureBlackBackgroundInDarkTheme(this);
((FDroidApp) getApplication()).applyTheme(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.installed_apps_layout);
MaterialToolbar toolbar = findViewById(R.id.toolbar);
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setTitle(getString(R.string.panic_add_apps_to_uninstall));
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);

View File

@ -6,9 +6,15 @@ import android.os.Bundle;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.CursorLoader;
import androidx.loader.content.Loader;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.UpdateService;
@ -25,15 +31,6 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.CursorLoader;
import androidx.loader.content.Loader;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
/**
* Responsible for ensuring that the categories view is inflated and then populated correctly.
* Will start a loader to get the list of categories from the database and populate a recycler

View File

@ -2,15 +2,15 @@ package org.fdroid.fdroid.views.main;
import android.widget.FrameLayout;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.views.PreferencesFragment;
import org.fdroid.fdroid.views.updates.UpdatesViewBinder;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.views.PreferencesFragment;
import org.fdroid.fdroid.views.updates.UpdatesViewBinder;
/**
* Decides which view on the main screen to attach to a given {@link FrameLayout}. This class
* doesn't know which view it will be rendering at the time it is constructed. Rather, at some

View File

@ -1,6 +1,7 @@
package org.fdroid.fdroid.views.main;
import android.Manifest;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.Intent;
import android.content.UriPermission;
@ -21,7 +22,9 @@ import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.RequiresApi;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.nearby.SDCardScannerService;
@ -31,11 +34,6 @@ import org.fdroid.fdroid.nearby.TreeUriScannerIntentService;
import java.io.File;
import java.util.List;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
/**
* A splash screen encouraging people to start the swap process. The swap
* process is quite heavy duty in that it fires up Bluetooth and/or WiFi

View File

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal"
tools:ignore="VectorRaster">
<path
android:fillColor="#FFFFFF"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM9.29,16.29L5.7,12.7c-0.39,-0.39 -0.39,-1.02 0,-1.41 0.39,-0.39 1.02,-0.39 1.41,0L10,14.17l6.88,-6.88c0.39,-0.39 1.02,-0.39 1.41,0 0.39,0.39 0.39,1.02 0,1.41l-7.59,7.59c-0.38,0.39 -1.02,0.39 -1.41,0z"/>
</vector>

View File

@ -1,8 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="130dp"
@ -13,7 +12,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
app:srcCompat="@drawable/swap_start_header"/>
android:src="@drawable/swap_start_header"/>
<TextView
android:layout_width="wrap_content"

View File

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2010 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingBottom="2dip"
android:paddingTop="2dip">
<ImageView
android:id="@android:id/icon"
android:layout_width="48dip"
android:layout_height="48dip"
android:layout_marginLeft="?attr/listPreferredItemPaddingLeft"
android:layout_marginStart="?android:attr/listPreferredItemPaddingStart"
android:layout_marginTop="6dip"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
tools:src="@drawable/ic_launcher"
tools:ignore="ContentDescription" />
<!-- Suppress InconsistentLayout because the lower API levels use a checkbox rather than this -->
<ImageView
android:id="@+id/checked"
android:layout_width="32dip"
android:layout_height="32dip"
android:layout_marginRight="?attr/listPreferredItemPaddingLeft"
android:layout_marginEnd="?android:attr/listPreferredItemPaddingStart"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
tools:suppress="InconsistentLayout"
android:src="@drawable/ic_add_circle_outline" />
<TwoLineListItem
android:layout_toRightOf="@android:id/icon"
android:layout_toEndOf="@android:id/icon"
android:layout_toLeftOf="@id/checked"
android:layout_toStartOf="@id/checked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:mode="twoLine" >
<TextView
android:id="@+id/application_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="?attr/listPreferredItemPaddingLeft"
android:layout_marginStart="?android:attr/listPreferredItemPaddingStart"
android:layout_marginTop="6dip"
android:textAppearance="?android:attr/textAppearanceMedium"
tools:text="F-Droid" />
<TextView
android:id="@+id/package_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="@+id/application_label"
android:layout_alignLeft="@+id/application_label"
android:layout_below="@+id/application_label"
android:textAppearance="?android:attr/textAppearanceSmall"
tools:text="Application Manager" />
</TwoLineListItem>
</RelativeLayout>

View File

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2010 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingBottom="2dip"
android:paddingTop="2dip">
<ImageView
android:id="@android:id/icon"
android:layout_width="48dip"
android:layout_height="48dip"
android:layout_marginStart="?android:attr/listPreferredItemPaddingStart"
android:layout_marginTop="6dip"
android:layout_alignParentStart="true"
tools:src="@drawable/ic_launcher"
tools:ignore="ContentDescription" />
<!-- Suppress InconsistentLayout because the lower API levels use a checkbox rather than this -->
<ImageView
android:id="@+id/checked"
android:layout_width="32dip"
android:layout_height="32dip"
android:layout_marginEnd="?android:attr/listPreferredItemPaddingStart"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
tools:suppress="InconsistentLayout"
android:src="@drawable/ic_add_circle_outline" />
<TwoLineListItem
android:layout_toEndOf="@android:id/icon"
android:layout_toStartOf="@id/checked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:mode="twoLine" >
<TextView
android:id="@+id/application_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="?android:attr/listPreferredItemPaddingStart"
android:layout_marginTop="6dip"
android:textAppearance="?android:attr/textAppearanceMedium"
tools:text="F-Droid" />
<TextView
android:id="@+id/package_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="@+id/application_label"
android:layout_below="@+id/application_label"
android:textAppearance="?android:attr/textAppearanceSmall"
tools:text="Application Manager" />
</TwoLineListItem>
</RelativeLayout>

View File

@ -1,302 +1,291 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".panic.CalculatorActivity">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".panic.CalculatorActivity"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/topAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:liftOnScroll="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="@drawable/ic_back"
style="@style/Widget.MaterialComponents.Toolbar.PrimarySurface" />
</com.google.android.material.appbar.AppBarLayout>
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:theme="?attr/actionBarTheme" />
<TextView
android:id="@+id/textView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:gravity="bottom|end"
android:padding="5dp"
android:textAlignment="textEnd"
android:textSize="22sp"
android:typeface="monospace"
app:layout_constraintBottom_toTopOf="@+id/ce"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/topAppBarLayout"
tools:text="1337+42" />
android:id="@+id/textView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:gravity="bottom|end"
android:padding="5dp"
android:textAlignment="textEnd"
android:textSize="22sp"
android:typeface="monospace"
app:layout_constraintBottom_toTopOf="@+id/ce"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar"
tools:text="1337+42" />
<Button
android:id="@+id/times"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="op"
android:text="×"
app:layout_constraintBottom_toTopOf="@+id/seven"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="HardcodedText" />
android:id="@+id/times"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="op"
android:text="×"
app:layout_constraintBottom_toTopOf="@+id/seven"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="HardcodedText" />
<Button
android:id="@+id/divided"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="op"
android:text="÷"
app:layout_constraintBottom_toTopOf="@+id/eight"
app:layout_constraintStart_toEndOf="@+id/times"
tools:ignore="HardcodedText" />
android:id="@+id/divided"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="op"
android:text="÷"
app:layout_constraintBottom_toTopOf="@+id/eight"
app:layout_constraintStart_toEndOf="@+id/times"
tools:ignore="HardcodedText" />
<Button
android:id="@+id/c"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="c"
android:text="C"
app:layout_constraintBottom_toTopOf="@+id/nine"
app:layout_constraintStart_toEndOf="@+id/divided"
tools:ignore="HardcodedText" />
android:id="@+id/c"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="c"
android:text="C"
app:layout_constraintBottom_toTopOf="@+id/nine"
app:layout_constraintStart_toEndOf="@+id/divided"
tools:ignore="HardcodedText" />
<Button
android:id="@+id/seven"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="number"
android:text="7"
app:layout_constraintBottom_toTopOf="@+id/four"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="HardcodedText" />
android:id="@+id/seven"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="number"
android:text="7"
app:layout_constraintBottom_toTopOf="@+id/four"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="HardcodedText" />
<Button
android:id="@+id/eight"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="number"
android:text="8"
app:layout_constraintBottom_toTopOf="@+id/five"
app:layout_constraintStart_toEndOf="@+id/seven"
tools:ignore="HardcodedText" />
android:id="@+id/eight"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="number"
android:text="8"
app:layout_constraintBottom_toTopOf="@+id/five"
app:layout_constraintStart_toEndOf="@+id/seven"
tools:ignore="HardcodedText" />
<Button
android:id="@+id/nine"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="number"
android:text="9"
app:layout_constraintBottom_toTopOf="@+id/six"
app:layout_constraintStart_toEndOf="@+id/eight"
tools:ignore="HardcodedText" />
android:id="@+id/nine"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="number"
android:text="9"
app:layout_constraintBottom_toTopOf="@+id/six"
app:layout_constraintStart_toEndOf="@+id/eight"
tools:ignore="HardcodedText" />
<Button
android:id="@+id/ce"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:onClick="ce"
android:text="CE"
app:layout_constraintBottom_toTopOf="@+id/plus"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/nine"
tools:ignore="HardcodedText" />
android:id="@+id/ce"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:onClick="ce"
android:text="CE"
app:layout_constraintBottom_toTopOf="@+id/plus"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/nine"
tools:ignore="HardcodedText" />
<Button
android:id="@+id/four"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="number"
android:text="4"
app:layout_constraintBottom_toTopOf="@+id/one"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="HardcodedText" />
android:id="@+id/four"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="number"
android:text="4"
app:layout_constraintBottom_toTopOf="@+id/one"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="HardcodedText" />
<Button
android:id="@+id/five"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="number"
android:text="5"
app:layout_constraintBottom_toTopOf="@+id/two"
app:layout_constraintStart_toEndOf="@+id/four"
tools:ignore="HardcodedText" />
android:id="@+id/five"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="number"
android:text="5"
app:layout_constraintBottom_toTopOf="@+id/two"
app:layout_constraintStart_toEndOf="@+id/four"
tools:ignore="HardcodedText" />
<Button
android:id="@+id/six"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="number"
android:text="6"
app:layout_constraintBottom_toTopOf="@+id/three"
app:layout_constraintStart_toEndOf="@+id/five"
tools:ignore="HardcodedText" />
android:id="@+id/six"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="number"
android:text="6"
app:layout_constraintBottom_toTopOf="@+id/three"
app:layout_constraintStart_toEndOf="@+id/five"
tools:ignore="HardcodedText" />
<Button
android:id="@+id/plus"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:onClick="op"
android:text="+"
app:layout_constraintBottom_toTopOf="@+id/minus"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/six"
tools:ignore="HardcodedText" />
android:id="@+id/plus"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:onClick="op"
android:text="+"
app:layout_constraintBottom_toTopOf="@+id/minus"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/six"
tools:ignore="HardcodedText" />
<Button
android:id="@+id/minus"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:onClick="op"
android:text="-"
app:layout_constraintBottom_toTopOf="@+id/equals"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/three"
tools:ignore="HardcodedText" />
android:id="@+id/minus"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:onClick="op"
android:text="-"
app:layout_constraintBottom_toTopOf="@+id/equals"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/three"
tools:ignore="HardcodedText" />
<Button
android:id="@+id/one"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="number"
android:text="1"
app:layout_constraintBottom_toTopOf="@+id/zero"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="HardcodedText" />
android:id="@+id/one"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="number"
android:text="1"
app:layout_constraintBottom_toTopOf="@+id/zero"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="HardcodedText" />
<Button
android:id="@+id/two"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="number"
android:text="2"
app:layout_constraintBottom_toTopOf="@+id/comma"
app:layout_constraintStart_toEndOf="@+id/one"
tools:ignore="HardcodedText" />
android:id="@+id/two"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="number"
android:text="2"
app:layout_constraintBottom_toTopOf="@+id/comma"
app:layout_constraintStart_toEndOf="@+id/one"
tools:ignore="HardcodedText" />
<Button
android:id="@+id/three"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="number"
android:text="3"
app:layout_constraintBottom_toTopOf="@+id/percent"
app:layout_constraintStart_toEndOf="@+id/two"
tools:ignore="HardcodedText" />
android:id="@+id/three"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="number"
android:text="3"
app:layout_constraintBottom_toTopOf="@+id/percent"
app:layout_constraintStart_toEndOf="@+id/two"
tools:ignore="HardcodedText" />
<Button
android:id="@+id/zero"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="number"
android:text="0"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="HardcodedText" />
android:id="@+id/zero"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="number"
android:text="0"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="HardcodedText" />
<Button
android:id="@+id/comma"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="number"
android:text="."
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/zero"
tools:ignore="HardcodedText" />
android:id="@+id/comma"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="number"
android:text="."
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/zero"
tools:ignore="HardcodedText" />
<Button
android:id="@+id/percent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="op"
android:text="%"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/comma"
tools:ignore="HardcodedText" />
android:id="@+id/percent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:onClick="op"
android:text="%"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/comma"
tools:ignore="HardcodedText" />
<Button
android:id="@+id/equals"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:onClick="op"
android:text="="
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@+id/three"
app:layout_constraintTop_toTopOf="@+id/three"
tools:ignore="HardcodedText" />
android:id="@+id/equals"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:onClick="op"
android:text="="
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@+id/three"
app:layout_constraintTop_toTopOf="@+id/three"
tools:ignore="HardcodedText" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,32 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:fitsSystemWindows="true">
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
app:theme="?attr/actionBarTheme" />
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:liftOnScroll="true">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:title="@string/panic_settings"
app:navigationIcon="@drawable/ic_back"
style="@style/Widget.MaterialComponents.Toolbar.PrimarySurface" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment_container"
class="org.fdroid.fdroid.panic.PanicPreferencesFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container"
class="org.fdroid.fdroid.panic.PanicPreferencesFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

View File

@ -5,8 +5,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
android:layout_height="match_parent">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:layout_width="match_parent"
@ -17,7 +16,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<org.fdroid.fdroid.views.StatusBanner
<org.fdroid.fdroid.views.BannerUpdatingRepos
android:id="@+id/banner_updating_repos"
android:layout_width="0dp"
android:layout_height="wrap_content"

View File

@ -11,7 +11,7 @@
android:id="@+id/image"
android:layout_width="0dp"
android:layout_height="0dp"
app:srcCompat="@drawable/nearby_splash"
android:src="@drawable/nearby_splash"
android:importantForAccessibility="no"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"

View File

@ -16,7 +16,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/listPreferredItemHeight"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingBottom="2dip"
android:paddingTop="2dip">
@ -25,9 +25,10 @@
android:layout_width="48dip"
android:layout_height="48dip"
android:layout_marginLeft="?attr/listPreferredItemPaddingLeft"
android:layout_marginStart="?attr/listPreferredItemPaddingStart"
android:layout_marginStart="?android:attr/listPreferredItemPaddingStart"
android:layout_marginTop="6dip"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
tools:src="@drawable/ic_launcher"
tools:ignore="ContentDescription" />
@ -36,13 +37,15 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="?attr/listPreferredItemPaddingLeft"
android:layout_marginStart="?attr/listPreferredItemPaddingStart"
android:layout_marginStart="?android:attr/listPreferredItemPaddingStart"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true" />
<TwoLineListItem
android:layout_toRightOf="@android:id/icon"
android:layout_toEndOf="@android:id/icon"
android:layout_toLeftOf="@id/checkbox"
android:layout_toStartOf="@id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@ -53,7 +56,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="?attr/listPreferredItemPaddingLeft"
android:layout_marginStart="?attr/listPreferredItemPaddingStart"
android:layout_marginStart="?android:attr/listPreferredItemPaddingStart"
android:layout_marginTop="6dip"
android:textAppearance="?android:attr/textAppearanceMedium"
tools:text="F-Droid" />
@ -63,6 +66,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="@+id/application_label"
android:layout_alignLeft="@+id/application_label"
android:layout_below="@+id/application_label"
android:textAppearance="?android:attr/textAppearanceSmall"
tools:text="Application Manager" />

View File

@ -1,29 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:liftOnScroll="true">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="@drawable/ic_back"
style="@style/Widget.MaterialComponents.Toolbar.PrimarySurface" />
</com.google.android.material.appbar.AppBarLayout>
android:layout_width="match_parent"
android:titleTextAppearance="@style/SwapTheme.Wizard.Text"
titleTextAppearance="@style/SwapTheme.Wizard.Text"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
tools:ignore="UnusedAttribute"/>
<FrameLayout
android:id="@+id/container"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
android:layout_height="fill_parent"/>
</LinearLayout>

View File

@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/listPreferredItemHeight"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingBottom="2dip"
android:paddingTop="2dip">
@ -12,7 +12,7 @@
android:id="@android:id/icon"
android:layout_width="48dip"
android:layout_height="48dip"
android:layout_marginStart="?attr/listPreferredItemPaddingStart"
android:layout_marginStart="?android:attr/listPreferredItemPaddingStart"
android:layout_marginLeft="10dp"
android:layout_marginTop="6dip"
android:layout_alignParentStart="true"
@ -28,7 +28,7 @@
android:layout_centerInParent="true"
android:orientation="vertical"
android:gravity="end"
android:layout_marginEnd="?attr/listPreferredItemPaddingEnd"
android:layout_marginEnd="?android:attr/listPreferredItemPaddingEnd"
android:layout_marginRight="10dp">
<Button
@ -68,7 +68,7 @@
android:layout_toLeftOf="@+id/button_or_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="?attr/listPreferredItemPaddingStart"
android:layout_marginStart="?android:attr/listPreferredItemPaddingStart"
android:layout_marginLeft="10dp"
android:layout_marginTop="6dip"
android:layout_marginBottom="6dip"

View File

@ -14,7 +14,7 @@
<ImageView
android:id="@+id/icon"
swap:srcCompat="@drawable/ic_launcher"
android:src="@drawable/ic_launcher"
android:contentDescription="@string/icon"
android:layout_alignParentTop="true"
android:layout_width="117.6dp"

View File

@ -25,7 +25,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/wifi_icon"
swap:srcCompat="@drawable/ic_wifi"
android:src="@drawable/ic_wifi"
android:layout_below="@+id/text_description"
android:layout_centerHorizontal="true"/>

View File

@ -14,7 +14,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/icon_nfc"
swap:srcCompat="@drawable/nfc_touch"
android:src="@drawable/nfc_touch"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"/>

View File

@ -14,13 +14,13 @@
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginLeft="?attr/listPreferredItemPaddingLeft"
android:layout_marginStart="?attr/listPreferredItemPaddingStart"
android:layout_marginStart="?android:attr/listPreferredItemPaddingStart"
android:layout_gravity="center_vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:srcCompat="@drawable/circle"
android:src="@drawable/circle"
app:tint="@color/swap_light_grey_icon"/>
<ImageView
@ -38,7 +38,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="?attr/listPreferredItemPaddingLeft"
android:layout_marginStart="?attr/listPreferredItemPaddingStart"
android:layout_marginStart="?android:attr/listPreferredItemPaddingStart"
android:textSize="20sp"
android:textAppearance="?android:attr/textAppearanceMedium"
tools:text="Nexus 4"/>

View File

@ -26,7 +26,7 @@
android:layout_width="24dp"
android:layout_height="24dp"
android:contentDescription="@string/use_bluetooth"
swap:srcCompat="@drawable/ic_bluetooth_searching"/>
android:src="@drawable/ic_bluetooth_searching"/>
<LinearLayout
android:layout_width="0dp"
@ -53,7 +53,7 @@
</LinearLayout>
<com.google.android.material.switchmaterial.SwitchMaterial
<androidx.appcompat.widget.SwitchCompat
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:enabled="false"
@ -74,7 +74,7 @@
android:layout_width="24dp"
android:layout_height="24dp"
android:contentDescription="@string/wifi"
swap:srcCompat="@drawable/ic_wifi"/>
android:src="@drawable/ic_wifi"/>
<LinearLayout
android:layout_width="0dp"
@ -110,7 +110,7 @@
</LinearLayout>
<com.google.android.material.switchmaterial.SwitchMaterial
<androidx.appcompat.widget.SwitchCompat
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/switch_wifi"/>
@ -155,7 +155,7 @@
<Button
android:id="@+id/btn_send_fdroid"
style="@style/Widget.App.Button.TextButton"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
swap:icon="@drawable/ic_fdroid_grey"
android:layout_height="wrap_content"
@ -163,7 +163,7 @@
<Button
android:id="@+id/btn_scan_qr"
style="@style/Widget.App.Button.TextButton"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/swap_scan_qr"

View File

@ -1,42 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="MenuTitle">
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="MenuTitle">
<!-- android:title and android:icon are set dynamically in MainActivity -->
<item
android:id="@+id/latest"
android:enabled="true"
android:icon="@drawable/ic_latest"
android:orderInCategory="0"
android:title="@string/main_menu__latest_apps"
app:showAsAction="ifRoom|withText" />
app:showAsAction="ifRoom|withText"
android:id="@+id/latest"/>
<item
android:id="@+id/categories"
android:enabled="true"
android:icon="@drawable/ic_categories"
android:orderInCategory="1"
android:title="@string/main_menu__categories"
app:showAsAction="ifRoom|withText" />
app:showAsAction="ifRoom|withText"
android:id="@+id/categories"/>
<item
android:id="@+id/nearby"
android:enabled="true"
android:icon="@drawable/ic_nearby"
android:orderInCategory="2"
android:title="@string/main_menu__swap_nearby"
app:showAsAction="ifRoom|withText" />
app:showAsAction="ifRoom|withText"
android:id="@+id/nearby"/>
<item
android:id="@+id/updates"
android:enabled="true"
android:icon="@drawable/ic_updates"
android:orderInCategory="3"
android:title="@string/main_menu__updates"
app:showAsAction="ifRoom|withText" />
app:showAsAction="ifRoom|withText"
android:id="@+id/updates"/>
<item
android:id="@+id/settings"
android:enabled="true"
android:icon="@drawable/ic_settings"
android:orderInCategory="4"
android:title="@string/menu_settings"
app:showAsAction="ifRoom|withText" />
app:showAsAction="ifRoom|withText"
android:id="@+id/settings"/>
</menu>

View File

@ -4,7 +4,7 @@
<style name="SwapTheme.AppList.SwapSuccess" parent="SwapTheme.AppList.SwapSuccessBase">
<item name="android:textAlignment">center</item>
<item name="android:gravity">center</item>
<item name="fontFamily">sans-serif-light</item>
<item name="android:fontFamily">sans-serif-light</item>
</style>
<style name="SwapTheme.AppList.SwapSuccessDetails" parent="SwapTheme.AppList.SwapSuccessDetailsBase">
@ -23,7 +23,7 @@
</style>
<style name="SwapTheme.Wizard.MainText" parent="SwapTheme.Wizard.MainTextBase">
<item name="fontFamily">sans-serif-light</item>
<item name="android:fontFamily">sans-serif-light</item>
</style>
</resources>

View File

@ -2,7 +2,7 @@
<resources>
<style name="SwapTheme.Wizard" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorButtonNormal">#04b9e6</item>
<item name="android:colorButtonNormal">#04b9e6</item>
</style>
</resources>

View File

@ -3,9 +3,13 @@
<style name="SwapTheme.Wizard" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorButtonNormal">@color/swap_bright_blue</item>
<item name="actionButtonStyle">@style/SwapTheme.Wizard.ActionButton</item>
<item name="actionBarStyle">@style/Widget.AppCompat.ActionBar.Solid</item>
</style>
<style name="SwapTheme.StartSwap" parent="Theme.App"/>
<style name="SwapTheme.StartSwap" parent="AppThemeLight">
<item name="android:background">@android:color/white</item>
</style>
<style name="SwapTheme.StartSwap.Text" parent="@style/SwapTheme.StartSwap">
</style>
@ -13,10 +17,10 @@
<style name="SwapTheme.BluetoothDeviceList" parent="@style/SwapTheme.Wizard">
</style>
<style name="SwapTheme.AppList" parent="Base.Theme.App">
<style name="SwapTheme.AppList" parent="AppThemeLight">
</style>
<style name="SwapTheme.AppList.ListItem" parent="Theme.App">
<style name="SwapTheme.AppList.ListItem" parent="AppThemeLight">
</style>
<style name="SwapTheme.AppList.SwapSuccessBase">

View File

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
* Copyright (C) 2010-2012 Ciaran Gultnieks
* Copyright (C) 2013-2017 Peter Serwylo
@ -23,328 +22,397 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="org.fdroid.fdroid"
android:installLocation="auto">
xmlns:tools="http://schemas.android.com/tools"
package="org.fdroid.fdroid"
android:installLocation="auto">
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="true"
android:resizeable="true"
android:smallScreens="true"
android:xlargeScreens="true" />
android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="true"
android:resizeable="true"
android:smallScreens="true"
android:xlargeScreens="true"
/>
<uses-feature
android:name="android.hardware.telephony"
android:required="false" />
android:name="android.hardware.telephony"
android:required="false"/>
<uses-feature
android:name="android.hardware.wifi"
android:required="false" />
android:name="android.hardware.wifi"
android:required="false"/>
<uses-feature
android:name="android.hardware.touchscreen"
android:required="false" />
android:name="android.hardware.touchscreen"
android:required="false"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.NFC"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<application
android:name=".FDroidApp"
android:allowBackup="true"
android:description="@string/app_description"
android:fullBackupContent="@xml/backup_rules"
android:icon="@drawable/ic_launcher"
android:label="BobStore"
android:networkSecurityConfig="@xml/network_security_config"
android:supportsRtl="true"
android:theme="@style/Theme.App">
android:name=".FDroidApp"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:description="@string/app_description"
android:allowBackup="true"
android:fullBackupContent="@xml/backup_rules"
android:networkSecurityConfig="@xml/network_security_config"
android:theme="@style/AppThemeLight"
android:supportsRtl="true">
<provider
android:authorities="${applicationId}.data.AppProvider"
android:name="org.fdroid.fdroid.data.AppProvider"
android:exported="false"/>
<provider
android:authorities="${applicationId}.data.RepoProvider"
android:name="org.fdroid.fdroid.data.RepoProvider"
android:exported="false"/>
<provider
android:authorities="${applicationId}.data.ApkProvider"
android:name="org.fdroid.fdroid.data.ApkProvider"
android:exported="false"/>
<provider
android:authorities="${applicationId}.data.TempApkProvider"
android:name="org.fdroid.fdroid.data.TempApkProvider"
android:exported="false"/>
<provider
android:authorities="${applicationId}.data.TempAppProvider"
android:name="org.fdroid.fdroid.data.TempAppProvider"
android:exported="false"/>
<provider
android:authorities="${applicationId}.data.InstalledAppProvider"
android:name="org.fdroid.fdroid.data.InstalledAppProvider"
android:exported="false"/>
<provider
android:authorities="${applicationId}.data.AppPrefsProvider"
android:name="org.fdroid.fdroid.data.AppPrefsProvider"
android:exported="false"/>
<provider
android:authorities="${applicationId}.data.PackageIdProvider"
android:name="org.fdroid.fdroid.data.PackageIdProvider"
android:exported="false"/>
<provider
android:authorities="${applicationId}.data.CategoryProvider"
android:name="org.fdroid.fdroid.data.CategoryProvider"
android:exported="false"/>
<provider
android:name="org.fdroid.fdroid.installer.ApkFileProvider"
android:authorities="${applicationId}.installer.ApkFileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/apk_file_provider"/>
</provider>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.installer"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/installer_file_provider"/>
</provider>
<activity
android:name=".privileged.views.InstallConfirmActivity"
android:configChanges="layoutDirection|locale"
android:excludeFromRecents="true"
android:label="@string/menu_install"
android:parentActivityName=".views.main.MainActivity">
android:name=".privileged.views.InstallConfirmActivity"
android:label="@string/menu_install"
android:theme="@style/MinWithDialogBaseThemeLight"
android:excludeFromRecents="true"
android:parentActivityName=".views.main.MainActivity"
android:configChanges="layoutDirection|locale">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".views.main.MainActivity" />
android:name="android.support.PARENT_ACTIVITY"
android:value=".views.main.MainActivity"/>
</activity>
<activity
android:name=".privileged.views.UninstallDialogActivity"
android:excludeFromRecents="true"
android:theme="@style/AppThemeTransparent"/>
<activity
android:name=".views.ManageReposActivity"
android:label="@string/menu_manage"
android:launchMode="singleTask"
android:parentActivityName=".views.main.MainActivity"
android:configChanges="layoutDirection|locale">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".views.main.MainActivity"/>
</activity>
<activity
android:name=".NfcNotEnabledActivity"
android:noHistory="true"
android:configChanges="layoutDirection|locale"/>
<activity
android:name=".views.RepoDetailsActivity"
android:label="@string/repo_details"
android:parentActivityName=".views.ManageReposActivity"
android:windowSoftInputMode="stateHidden"
android:configChanges="layoutDirection|locale">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".views.ManageReposActivity"/>
</activity>
<activity
android:name=".privileged.views.UninstallDialogActivity"
android:excludeFromRecents="true" />
<activity
android:name=".views.ManageReposActivity"
android:configChanges="layoutDirection|locale"
android:label="@string/menu_manage"
android:launchMode="singleTask"
android:parentActivityName=".views.main.MainActivity">
android:name=".views.AppDetailsActivity"
android:label="@string/app_details"
android:exported="true"
android:parentActivityName=".views.main.MainActivity"
android:configChanges="layoutDirection|locale">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".views.main.MainActivity" />
android:name="android.support.PARENT_ACTIVITY"
android:value=".views.main.MainActivity"/>
</activity>
<activity
android:name=".NfcNotEnabledActivity"
android:configChanges="layoutDirection|locale"
android:noHistory="true" />
android:name=".acra.CrashReportActivity"
android:theme="@style/AppThemeDark"
android:process=":error_report"
android:launchMode="singleInstance"
android:excludeFromRecents="true"
android:finishOnTaskLaunch="true"/>
<activity android:name=".views.ScreenShotsActivity"/>
<!-- Note: AppThemeTransparent, this activity shows dialogs only -->
<activity android:name=".data.ObbUrlActivity"
android:theme="@android:style/Theme.NoDisplay"/>
<!-- Note: AppThemeTransparent, this activity shows dialogs only -->
<activity
android:name=".views.RepoDetailsActivity"
android:configChanges="layoutDirection|locale"
android:label="@string/repo_details"
android:parentActivityName=".views.ManageReposActivity"
android:windowSoftInputMode="stateHidden">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".views.ManageReposActivity" />
</activity>
android:name=".installer.DefaultInstallerActivity"
android:theme="@style/AppThemeTransparent"/>
<!-- Note: AppThemeTransparent, this activity shows dialogs only -->
<activity
android:name=".views.AppDetailsActivity"
android:configChanges="layoutDirection|locale"
android:exported="true"
android:label="@string/app_details"
android:parentActivityName=".views.main.MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".views.main.MainActivity" />
</activity>
android:name=".installer.ErrorDialogActivity"
android:theme="@style/AppThemeTransparent"/>
<activity
android:name=".acra.CrashReportActivity"
android:excludeFromRecents="true"
android:finishOnTaskLaunch="true"
android:launchMode="singleInstance"
android:process=":error_report" />
<activity android:name=".views.ScreenShotsActivity" />
<activity
android:name=".data.ObbUrlActivity"
android:theme="@android:style/Theme.NoDisplay" />
<activity
android:name=".installer.DefaultInstallerActivity"
android:theme="@style/AppThemeTransparent" />
<activity
android:name=".installer.ErrorDialogActivity"
android:theme="@style/AppThemeTransparent" />
<activity
android:name=".views.main.MainActivity"
android:launchMode="singleTop"
android:windowSoftInputMode="adjustResize">
<receiver android:name=".receiver.StartupReceiver">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.HOME"/>
</intent-filter>
</receiver>
<receiver android:name=".receiver.PackageManagerReceiver">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED"/>
<action android:name="android.intent.action.PACKAGE_CHANGED"/>
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
<data android:scheme="package"/>
</intent-filter>
</receiver>
<receiver android:name=".NotificationBroadcastReceiver" android:exported="false">
<!-- Doesn't require an intent-filter because it is explicitly invoked via Intent.setClass() -->
</receiver>
<receiver android:name=".receiver.DeviceStorageReceiver">
<intent-filter>
<action android:name="android.intent.action.DEVICE_STORAGE_LOW"/>
</intent-filter>
</receiver>
<service
android:name=".UpdateService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="false"/>
<service
android:name=".UpdateJobService"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE"/>
<service
android:name=".net.DownloaderService"
android:exported="false"/>
<service
android:name=".installer.InstallerService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="false"/>
<service
android:name=".DeleteCacheService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="false"/>
<service
android:name=".net.ConnectivityMonitorService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="false"/>
<service
android:name=".installer.InstallManagerService"
android:exported="false"/>
<service
android:name=".installer.InstallHistoryService"
android:exported="false"/>
<service
android:name=".installer.ObfInstallerService"
android:exported="false"/>
<service
android:name=".data.InstalledAppProviderService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="false"/>
<service
android:name=".AddRepoIntentService"
android:exported="false"/>
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
android:exported="false"
tools:node="remove" />
<activity
android:name=".views.main.MainActivity"
android:launchMode="singleTop"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<!-- App URLs -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="fdroid.app" />
<data android:scheme="fdroid.app"/>
</intent-filter>
<intent-filter android:autoVerify="false">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="https" />
<data android:host="f-droid.org" />
<data android:host="www.f-droid.org" />
<data android:host="staging.f-droid.org" />
<data android:pathPrefix="/app/" />
<data android:pathPrefix="/packages/" />
<data android:pathPrefix="/repository/browse" />
<data android:scheme="https"/>
<data android:host="f-droid.org"/>
<data android:host="www.f-droid.org"/>
<data android:host="staging.f-droid.org"/>
<data android:pathPrefix="/app/"/>
<data android:pathPrefix="/packages/"/>
<data android:pathPrefix="/repository/browse"/>
<!-- support localized URLs -->
<data android:pathPattern="/.*/packages/.*" />
<data android:pathPattern="/.*/packages/.*/" />
<data android:pathPattern="/.*/packages/.*"/>
<data android:pathPattern="/.*/packages/.*/"/>
</intent-filter>
<intent-filter android:autoVerify="false">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="http" />
<data android:host="f-droid.org" />
<data android:host="www.f-droid.org" />
<data android:host="staging.f-droid.org" />
<data android:pathPrefix="/app/" />
<data android:pathPrefix="/packages/" />
<data android:pathPrefix="/repository/browse" />
<data android:scheme="http"/>
<data android:host="f-droid.org"/>
<data android:host="www.f-droid.org"/>
<data android:host="staging.f-droid.org"/>
<data android:pathPrefix="/app/"/>
<data android:pathPrefix="/packages/"/>
<data android:pathPrefix="/repository/browse"/>
<!-- support localized URLs -->
<data android:pathPattern="/.*/packages/.*" />
<data android:pathPattern="/.*/packages/.*/" />
<data android:pathPattern="/.*/packages/.*"/>
<data android:pathPattern="/.*/packages/.*/"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data
android:host="details"
android:scheme="market" />
<data android:scheme="market" android:host="details"/>
</intent-filter>
<intent-filter android:autoVerify="false">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="play.google.com" /> <!-- they don't do www. -->
<data android:path="/store/apps/details" />
<data android:scheme="http"/>
<data android:scheme="https"/>
<data android:host="play.google.com"/> <!-- they don't do www. -->
<data android:path="/store/apps/details"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data
android:host="apps"
android:path="/android"
android:scheme="amzn" />
<data android:scheme="amzn" android:host="apps" android:path="/android"/>
</intent-filter>
<intent-filter android:autoVerify="false">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="amazon.com" />
<data android:host="www.amazon.com" />
<data android:path="/gp/mas/dl/android" />
<data android:scheme="http"/>
<data android:scheme="https"/>
<data android:host="amazon.com"/>
<data android:host="www.amazon.com"/>
<data android:path="/gp/mas/dl/android"/>
</intent-filter>
<!-- Search URLs -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="fdroid.search" />
<data android:scheme="fdroid.search"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data
android:host="search"
android:scheme="market" />
<data android:scheme="market" android:host="search"/>
</intent-filter>
<intent-filter android:autoVerify="false">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="play.google.com" /> <!-- they don't do www. -->
<data android:path="/store/search" />
<data android:scheme="http"/>
<data android:scheme="https"/>
<data android:host="play.google.com"/> <!-- they don't do www. -->
<data android:path="/store/search"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
<action android:name="android.intent.action.SEARCH"/>
</intent-filter>
<intent-filter android:autoVerify="false">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<!--
Android's scheme matcher is case-sensitive, so include
ALL CAPS versions to support ALL CAPS URLs in QR Codes.
QR Codes have a special ALL CAPS mode that uses a reduced
character set, making for more compact QR Codes.
-->
<data android:scheme="http" />
<data
android:scheme="HTTP"
tools:ignore="AppLinkUrlError" />
<data android:scheme="https" />
<data
android:scheme="HTTPS"
tools:ignore="AppLinkUrlError" />
<data android:host="*" />
<!--
The pattern matcher here is poorly implemented, in particular the * is
non-greedy, so you have to do stupid tricks to match patterns that have
repeat characters in them. http://stackoverflow.com/a/8599921/306864
-->
<data android:path="/fdroid/repo" />
<data android:pathPattern="/fdroid/repo/*" />
<data android:pathPattern="/.*/fdroid/repo" />
<data android:pathPattern="/.*/fdroid/repo/*" />
<data android:pathPattern="/.*/.*/fdroid/repo" />
<data android:pathPattern="/.*/.*/fdroid/repo/*" />
<data android:pathPattern="/.*/.*/.*/fdroid/repo" />
<data android:pathPattern="/.*/.*/.*/fdroid/repo/*" />
<data android:pathPattern="/.*/.*/.*/.*/fdroid/repo" />
<data android:pathPattern="/.*/.*/.*/.*/fdroid/repo/*" />
<data android:pathPattern="/.*/.*/.*/.*/.*/fdroid/repo" />
<data android:pathPattern="/.*/.*/.*/.*/.*/fdroid/repo/*" />
<data android:pathPattern="/.*/.*/.*/.*/.*/.*/fdroid/repo" />
<data android:pathPattern="/.*/.*/.*/.*/.*/.*/fdroid/repo/*" />
<data android:path="/fdroid/archive" />
<data android:pathPattern="/fdroid/archive/*" />
<data android:pathPattern="/.*/fdroid/archive" />
<data android:pathPattern="/.*/fdroid/archive/*" />
<data android:pathPattern="/.*/.*/fdroid/archive" />
<data android:pathPattern="/.*/.*/fdroid/archive/*" />
<data android:pathPattern="/.*/.*/.*/fdroid/archive" />
<data android:pathPattern="/.*/.*/.*/fdroid/archive/*" />
<data android:pathPattern="/.*/.*/.*/.*/fdroid/archive" />
<data android:pathPattern="/.*/.*/.*/.*/fdroid/archive/*" />
<!--
Some QR Code scanners don't respect custom schemes like fdroidrepo://,
so this is a workaround, since the local repo URL is all uppercase in
the QR Code for sending the local repo to another device.
-->
<data android:path="/FDROID/REPO" />
<data android:pathPattern="/.*/FDROID/REPO" />
<data android:pathPattern="/.*/.*/FDROID/REPO" />
<data android:pathPattern="/.*/.*/.*/FDROID/REPO" />
</intent-filter>
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable"/>
<!-- Repo URLs -->
@ -364,11 +432,11 @@
This filter supports HTTP and HTTPS schemes. There is an additional filter for
fdroidrepo:// and fdroidrepos://
-->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<intent-filter android:autoVerify="false">
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<!--
Android's scheme matcher is case-sensitive, so include
@ -376,14 +444,51 @@
QR Codes have a special ALL CAPS mode that uses a reduced
character set, making for more compact QR Codes.
-->
<data android:scheme="fdroidrepo" />
<data
android:scheme="FDROIDREPO"
tools:ignore="AppLinkUrlError" />
<data android:scheme="fdroidrepos" />
<data
android:scheme="FDROIDREPOS"
tools:ignore="AppLinkUrlError" />
<data android:scheme="http"/>
<data android:scheme="HTTP" tools:ignore="AppLinkUrlError"/>
<data android:scheme="https"/>
<data android:scheme="HTTPS" tools:ignore="AppLinkUrlError"/>
<data android:host="*"/>
<!--
The pattern matcher here is poorly implemented, in particular the * is
non-greedy, so you have to do stupid tricks to match patterns that have
repeat characters in them. http://stackoverflow.com/a/8599921/306864
-->
<data android:path="/fdroid/repo"/>
<data android:pathPattern="/fdroid/repo/*"/>
<data android:pathPattern="/.*/fdroid/repo"/>
<data android:pathPattern="/.*/fdroid/repo/*"/>
<data android:pathPattern="/.*/.*/fdroid/repo"/>
<data android:pathPattern="/.*/.*/fdroid/repo/*"/>
<data android:pathPattern="/.*/.*/.*/fdroid/repo"/>
<data android:pathPattern="/.*/.*/.*/fdroid/repo/*"/>
<data android:pathPattern="/.*/.*/.*/.*/fdroid/repo"/>
<data android:pathPattern="/.*/.*/.*/.*/fdroid/repo/*"/>
<data android:pathPattern="/.*/.*/.*/.*/.*/fdroid/repo"/>
<data android:pathPattern="/.*/.*/.*/.*/.*/fdroid/repo/*"/>
<data android:pathPattern="/.*/.*/.*/.*/.*/.*/fdroid/repo"/>
<data android:pathPattern="/.*/.*/.*/.*/.*/.*/fdroid/repo/*"/>
<data android:path="/fdroid/archive"/>
<data android:pathPattern="/fdroid/archive/*"/>
<data android:pathPattern="/.*/fdroid/archive"/>
<data android:pathPattern="/.*/fdroid/archive/*"/>
<data android:pathPattern="/.*/.*/fdroid/archive"/>
<data android:pathPattern="/.*/.*/fdroid/archive/*"/>
<data android:pathPattern="/.*/.*/.*/fdroid/archive"/>
<data android:pathPattern="/.*/.*/.*/fdroid/archive/*"/>
<data android:pathPattern="/.*/.*/.*/.*/fdroid/archive"/>
<data android:pathPattern="/.*/.*/.*/.*/fdroid/archive/*"/>
<!--
Some QR Code scanners don't respect custom schemes like fdroidrepo://,
so this is a workaround, since the local repo URL is all uppercase in
the QR Code for sending the local repo to another device.
-->
<data android:path="/FDROID/REPO"/>
<data android:pathPattern="/.*/FDROID/REPO"/>
<data android:pathPattern="/.*/.*/FDROID/REPO"/>
<data android:pathPattern="/.*/.*/.*/FDROID/REPO"/>
</intent-filter>
<!--
@ -391,186 +496,58 @@
looks for fdroidrepos://* and doesn't care what the path is.
-->
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<!--
URIs that come in via NFC have scheme/host normalized to all lower case
https://developer.android.com/reference/android/nfc/NfcAdapter.html#ACTION_NDEF_DISCOVERED
Android's scheme matcher is case-sensitive, so include
ALL CAPS versions to support ALL CAPS URLs in QR Codes.
QR Codes have a special ALL CAPS mode that uses a reduced
character set, making for more compact QR Codes.
-->
<data android:scheme="fdroidrepo" />
<data android:scheme="fdroidrepos" />
<data android:scheme="fdroidrepo"/>
<data android:scheme="FDROIDREPO" tools:ignore="AppLinkUrlError"/>
<data android:scheme="fdroidrepos"/>
<data android:scheme="FDROIDREPOS" tools:ignore="AppLinkUrlError"/>
</intent-filter>
<!-- Handle NFC tags detected from outside our application -->
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<!--
URIs that come in via NFC have scheme/host normalized to all lower case
https://developer.android.com/reference/android/nfc/NfcAdapter.html#ACTION_NDEF_DISCOVERED
-->
<data android:scheme="fdroidrepo"/>
<data android:scheme="fdroidrepos"/>
</intent-filter>
</activity>
<activity android:name=".views.apps.AppListActivity" />
<activity
android:name=".views.installed.InstalledAppsActivity"
android:parentActivityName=".views.main.MainActivity">
<activity android:name=".views.apps.AppListActivity"/>
<activity android:name=".views.installed.InstalledAppsActivity"
android:parentActivityName=".views.main.MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".views.main.MainActivity" />
android:name="android.support.PARENT_ACTIVITY"
android:value=".views.main.MainActivity"/>
</activity>
<activity
android:name=".views.InstallHistoryActivity"
android:parentActivityName=".views.main.MainActivity">
<activity android:name=".views.InstallHistoryActivity"
android:parentActivityName=".views.main.MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".views.main.MainActivity" />
android:name="android.support.PARENT_ACTIVITY"
android:value=".views.main.MainActivity"/>
</activity>
<activity android:name=".AboutActivity" />
<activity
android:name=".installer.FileInstallerActivity"
android:theme="@style/AppThemeTransparent" />
<provider
android:name="org.fdroid.fdroid.data.AppProvider"
android:authorities="${applicationId}.data.AppProvider"
android:exported="false" />
<provider
android:name="org.fdroid.fdroid.data.RepoProvider"
android:authorities="${applicationId}.data.RepoProvider"
android:exported="false" />
<!-- Note: AppThemeTransparent, this activity shows dialogs only -->
<provider
android:name="org.fdroid.fdroid.data.ApkProvider"
android:authorities="${applicationId}.data.ApkProvider"
android:exported="false" />
<!-- Note: AppThemeTransparent, this activity shows dialogs only -->
<provider
android:name="org.fdroid.fdroid.data.TempApkProvider"
android:authorities="${applicationId}.data.TempApkProvider"
android:exported="false" />
<!-- Note: AppThemeTransparent, this activity shows dialogs only -->
<provider
android:name="org.fdroid.fdroid.data.TempAppProvider"
android:authorities="${applicationId}.data.TempAppProvider"
android:exported="false" />
<provider
android:name="org.fdroid.fdroid.data.InstalledAppProvider"
android:authorities="${applicationId}.data.InstalledAppProvider"
android:exported="false" />
<provider
android:name="org.fdroid.fdroid.data.AppPrefsProvider"
android:authorities="${applicationId}.data.AppPrefsProvider"
android:exported="false" />
<provider
android:name="org.fdroid.fdroid.data.PackageIdProvider"
android:authorities="${applicationId}.data.PackageIdProvider"
android:exported="false" />
<provider
android:name="org.fdroid.fdroid.data.CategoryProvider"
android:authorities="${applicationId}.data.CategoryProvider"
android:exported="false" />
<provider
android:name="org.fdroid.fdroid.installer.ApkFileProvider"
android:authorities="${applicationId}.installer.ApkFileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/apk_file_provider" />
</provider>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.installer"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/installer_file_provider" />
</provider>
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
android:exported="false"
tools:node="remove" />
<receiver android:name=".receiver.StartupReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.HOME" />
</intent-filter>
</receiver>
<receiver android:name=".receiver.PackageManagerReceiver">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED" />
<action android:name="android.intent.action.PACKAGE_CHANGED" />
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<data android:scheme="package" />
</intent-filter>
</receiver>
<receiver
android:name=".NotificationBroadcastReceiver"
android:exported="false">
<!-- Doesn't require an intent-filter because it is explicitly invoked via Intent.setClass() -->
</receiver>
<receiver android:name=".receiver.DeviceStorageReceiver">
<intent-filter>
<action android:name="android.intent.action.DEVICE_STORAGE_LOW" />
</intent-filter>
</receiver>
<service
android:name=".UpdateService"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE" />
<service
android:name=".UpdateJobService"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE" />
<service
android:name=".net.DownloaderService"
android:exported="false" />
<service
android:name=".installer.InstallerService"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE" />
<service
android:name=".DeleteCacheService"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE" />
<service
android:name=".net.ConnectivityMonitorService"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE" />
<service
android:name=".installer.InstallManagerService"
android:exported="false" />
<service
android:name=".installer.InstallHistoryService"
android:exported="false" />
<service
android:name=".installer.ObfInstallerService"
android:exported="false" />
<service
android:name=".data.InstalledAppProviderService"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE" />
<service
android:name=".AddRepoIntentService"
android:exported="false" />
<activity android:name=".AboutActivity" android:theme="@style/Theme.AppCompat.Light.Dialog"/>
<activity android:name=".installer.FileInstallerActivity" android:theme="@style/AppThemeTransparent"/>
</application>

View File

@ -16,6 +16,7 @@
package com.google.zxing.integration.android;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
@ -25,7 +26,6 @@ import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
@ -336,7 +336,7 @@ public class IntentIntegrator {
* @param intent Intent to start.
* @param code Request code for the activity
* @see android.app.AppCompatActivity#startActivityForResult(Intent, int)
* @see Fragment#startActivityForResult(Intent, int)
* @see android.app.Fragment#startActivityForResult(Intent, int)
*/
protected void startActivityForResult(Intent intent, int code) {
if (fragment == null) {

View File

@ -0,0 +1,32 @@
package org.fdroid.fdroid;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
public class AboutActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
FDroidApp fdroidApp = (FDroidApp) getApplication();
fdroidApp.applyDialogTheme(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.about);
String versionName = Utils.getVersionName(this);
if (versionName != null) {
((TextView) findViewById(R.id.version)).setText(versionName);
}
findViewById(R.id.ok_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
}

View File

@ -5,9 +5,10 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
import org.fdroid.fdroid.data.Repo;
import org.fdroid.fdroid.data.RepoProvider;
import org.fdroid.fdroid.views.ManageReposActivity;
@ -17,9 +18,6 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.util.Locale;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
/**
* Handles requests to add new repos via URLs. This is an {@code IntentService}
* so that requests are queued, which is necessary when either

View File

@ -9,7 +9,10 @@ import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.TaskStackBuilder;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.data.App;
import org.fdroid.fdroid.data.AppProvider;
@ -25,11 +28,6 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.TaskStackBuilder;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
/**
* Manages the state of APKs that are being installed or that have updates available.
* This also ensures the state is saved across F-Droid restarts, and repopulates

View File

@ -4,7 +4,7 @@ import android.content.Context;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import androidx.annotation.Nullable;
import org.fdroid.fdroid.compat.SupportedArchitectures;
import org.fdroid.fdroid.data.Apk;
@ -14,8 +14,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import androidx.annotation.Nullable;
// Call getIncompatibleReasons(apk) on an instance of this class to
// find reasons why an apk may be incompatible with the user's device.
public class CompatibilityChecker {

View File

@ -3,15 +3,13 @@ package org.fdroid.fdroid;
import android.content.Context;
import android.content.Intent;
import android.os.Process;
import android.util.Log;
import org.apache.commons.io.FileUtils;
import java.io.File;
import androidx.annotation.NonNull;
import androidx.core.app.JobIntentService;
import androidx.core.content.ContextCompat;
import android.util.Log;
import org.apache.commons.io.FileUtils;
import java.io.File;
/**
* An {@link JobIntentService} subclass for deleting the full cache for this app.

View File

@ -24,6 +24,7 @@
package org.fdroid.fdroid;
import android.annotation.TargetApi;
import androidx.appcompat.app.AppCompatActivity;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.Application;
@ -45,7 +46,10 @@ import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.collection.LongSparseArray;
import androidx.core.content.ContextCompat;
import com.nostra13.universalimageloader.cache.disc.DiskCache;
import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache;
import com.nostra13.universalimageloader.cache.disc.impl.ext.LruDiskCache;
@ -53,7 +57,8 @@ import com.nostra13.universalimageloader.core.DefaultConfigurationFactory;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.process.BitmapProcessor;
import info.guardianproject.netcipher.NetCipher;
import info.guardianproject.netcipher.proxy.OrbotHelper;
import org.acra.ACRA;
import org.acra.ReportField;
import org.acra.ReportingInteractionMode;
@ -77,23 +82,13 @@ import org.fdroid.fdroid.net.ImageLoaderForUIL;
import org.fdroid.fdroid.panic.HidingManager;
import org.fdroid.fdroid.work.CleanCacheWorker;
import javax.microedition.khronos.opengles.GL10;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.security.Security;
import java.util.List;
import java.util.UUID;
import javax.microedition.khronos.opengles.GL10;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.collection.LongSparseArray;
import androidx.core.content.ContextCompat;
import info.guardianproject.netcipher.NetCipher;
import info.guardianproject.netcipher.proxy.OrbotHelper;
@ReportsCrashes(mailTo = BuildConfig.ACRA_REPORT_EMAIL,
mode = ReportingInteractionMode.DIALOG,
reportDialogClass = org.fdroid.fdroid.acra.CrashReportActivity.class,
@ -157,47 +152,30 @@ public class FDroidApp extends Application implements androidx.work.Configuratio
private static Theme curTheme = Theme.light;
/**
* Apply pure black background in dark theme setting. Must be called in every activity's
* {@link AppCompatActivity#onCreate()}, before super.onCreate().
*
* @param activity The activity to apply the setting.
*/
public void applyPureBlackBackgroundInDarkTheme(AppCompatActivity activity) {
final boolean isPureBlack = Preferences.get().isPureBlack();
if (isPureBlack) {
activity.setTheme(R.style.Theme_App_Black);
}
}
public void applyTheme() {
public void reloadTheme() {
curTheme = Preferences.get().getTheme();
switch (curTheme) {
case dark:
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
break;
case light:
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
break;
default:
// `Set by Battery Saver` for Q above (inclusive), `Use system default` for Q below
// https://medium.com/androiddevelopers/appcompat-v23-2-daynight-d10f90c83e94
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
}
break;
}
}
// TODO: ResId no longer exists.
public void applyTheme(AppCompatActivity activity) {
activity.setTheme(getCurThemeResId());
setSecureWindow(activity);
}
public static int getCurThemeResId() {
return R.style.Theme_App;
switch (curTheme) {
case light:
return R.style.AppThemeLight;
case dark:
return R.style.AppThemeDark;
case night:
return R.style.AppThemeNight;
default:
return R.style.AppThemeLight;
}
}
public static boolean isAppThemeLight() {
return AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_NO;
return curTheme == Theme.light;
}
public void applyDialogTheme(AppCompatActivity activity) {
@ -213,7 +191,10 @@ public class FDroidApp extends Application implements androidx.work.Configuratio
private static int getCurDialogThemeResId() {
switch (curTheme) {
case light:
return R.style.MinWithDialogBaseThemeLight;
case dark:
return R.style.MinWithDialogBaseThemeDark;
case night:
return R.style.MinWithDialogBaseThemeDark;
default:
@ -221,6 +202,24 @@ public class FDroidApp extends Application implements androidx.work.Configuratio
}
}
/**
* Force reload the {@link AppCompatActivity to make theme changes take effect.}
* Same as {@link Languages#forceChangeLanguage(AppCompatActivity)}
*
* @param activity the {@code AppCompatActivity} to force reload
*/
public static void forceChangeTheme(AppCompatActivity activity) {
Intent intent = activity.getIntent();
if (intent == null) { // when launched as LAUNCHER
return;
}
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
activity.finish();
activity.overridePendingTransition(0, 0);
activity.startActivity(intent);
activity.overridePendingTransition(0, 0);
}
public static void enableBouncyCastle() {
Security.addProvider(BOUNCYCASTLE_PROVIDER);
}
@ -269,7 +268,7 @@ public class FDroidApp extends Application implements androidx.work.Configuratio
* @see #getTimeout()
* @see Repo#getRandomMirror(String)
*/
public static synchronized String getNewMirrorOnError(@Nullable String urlString, Repo repo2) throws IOException {
public static String getNewMirrorOnError(@Nullable String urlString, Repo repo2) throws IOException {
if (repo2.hasMirrors()) {
if (numTries <= 0) {
if (timeout == Downloader.DEFAULT_TIMEOUT) {
@ -394,8 +393,7 @@ public class FDroidApp extends Application implements androidx.work.Configuratio
PRNGFixes.apply();
applyTheme();
curTheme = preferences.getTheme();
configureProxy(preferences);
@ -679,7 +677,7 @@ public class FDroidApp extends Application implements androidx.work.Configuratio
* Set up WorkManager on demand to avoid slowing down starts.
*
* @see CleanCacheWorker
* @see org.fdroid.fdroid.work.FDroidMetricsWorker
* @see org.fdroid.fdroid.work.PopularityContestWorker
* @see org.fdroid.fdroid.work.UpdateWorker
* @see <a href="https://developer.android.com/codelabs/android-adv-workmanager#3">example</a>
*/

View File

@ -27,9 +27,9 @@ import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageInfo;
import androidx.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.data.ApkProvider;
import org.fdroid.fdroid.data.App;
@ -48,6 +48,9 @@ import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@ -61,12 +64,6 @@ import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import androidx.annotation.NonNull;
// TODO move to org.fdroid.fdroid.updater
// TODO reduce visibility of methods once in .updater package (.e.g tests need it public now)

View File

@ -25,9 +25,9 @@ package org.fdroid.fdroid;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageInfo;
import androidx.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonFactory;
@ -36,7 +36,6 @@ import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.InjectableValues;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.io.FileUtils;
import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.data.App;
@ -48,6 +47,10 @@ import org.fdroid.fdroid.data.Schema;
import org.fdroid.fdroid.net.Downloader;
import org.fdroid.fdroid.net.DownloaderFactory;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLKeyException;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLProtocolException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@ -68,13 +71,6 @@ import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLKeyException;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLProtocolException;
import androidx.annotation.NonNull;
/**
* Receives the index data about all available apps and packages via the V1
* JSON data {@link #DATA_FILE_NAME}, embedded in a signed jar

View File

@ -8,6 +8,8 @@ import android.content.res.Resources;
import android.os.Build;
import android.text.TextUtils;
import androidx.appcompat.app.AppCompatActivity;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
@ -16,8 +18,6 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import androidx.appcompat.app.AppCompatActivity;
public final class Languages {
public static final String TAG = "Languages";

View File

@ -1,6 +1,7 @@
package org.fdroid.fdroid;
import android.annotation.TargetApi;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@ -11,8 +12,6 @@ import android.nfc.NfcAdapter;
import android.os.Build;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
public class NfcHelper {
private static final String TAG = "NfcHelper";

View File

@ -6,7 +6,6 @@ import android.nfc.NfcAdapter;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import androidx.appcompat.app.AppCompatActivity;
// aka Android 4.0 aka Ice Cream Sandwich
@ -40,9 +39,8 @@ public class NfcNotEnabledActivity extends AppCompatActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
FDroidApp fdroidApp = (FDroidApp) getApplication();
fdroidApp.applyPureBlackBackgroundInDarkTheme(this);
((FDroidApp) getApplication()).applyTheme(this);
super.onCreate(savedInstanceState);
final Intent intent = new Intent();

View File

@ -20,6 +20,11 @@ import android.text.TextUtils;
import android.text.style.StyleSpan;
import android.view.View;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.content.ContextCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.assist.ImageSize;
@ -33,11 +38,6 @@ import org.fdroid.fdroid.views.main.MainActivity;
import java.util.ArrayList;
import java.util.Arrays;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.content.ContextCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
@SuppressWarnings("LineLength")
public class NotificationHelper {
public static final String CHANNEL_SWAPS = "swap-channel";

View File

@ -28,9 +28,11 @@ import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import androidx.core.content.ContextCompat;
import androidx.preference.PreferenceManager;
import android.text.format.DateUtils;
import android.util.Log;
import org.fdroid.fdroid.installer.PrivilegedInstaller;
import org.fdroid.fdroid.net.ConnectivityMonitorService;
@ -43,9 +45,6 @@ import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import androidx.core.content.ContextCompat;
import androidx.preference.PreferenceManager;
/**
* Handles shared preferences for FDroid, looking after the names of
* preferences, default values and caching. Needs to be setup in the FDroidApp
@ -89,7 +88,6 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh
public static final String PREF_AUTO_DOWNLOAD_INSTALL_UPDATES = "updateAutoDownload";
public static final String PREF_UPDATE_NOTIFICATION_ENABLED = "updateNotify";
public static final String PREF_THEME = "theme";
public static final String PREF_USE_PURE_BLACK_DARK_THEME = "usePureBlackDarkTheme";
public static final String PREF_SHOW_INCOMPAT_VERSIONS = "incompatibleVersions";
public static final String PREF_SHOW_ANTI_FEATURE_APPS = "showAntiFeatureApps";
public static final String PREF_FORCE_TOUCH_APPS = "ignoreTouchscreen";
@ -97,7 +95,6 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh
public static final String PREF_KEEP_CACHE_TIME = "keepCacheFor";
public static final String PREF_UNSTABLE_UPDATES = "unstableUpdates";
public static final String PREF_KEEP_INSTALL_HISTORY = "keepInstallHistory";
public static final String PREF_SEND_TO_FDROID_METRICS = "sendToFdroidMetrics";
public static final String PREF_EXPERT = "expert";
public static final String PREF_FORCE_OLD_INDEX = "forceOldIndex";
public static final String PREF_PRIVILEGED_INSTALLER = "privilegedInstaller";
@ -154,8 +151,7 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh
public enum Theme {
light,
dark,
followSystem,
night, // Obsolete
night,
lightWithDarkActionBar, // Obsolete
}
@ -367,10 +363,6 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh
return preferences.getBoolean(PREF_KEEP_INSTALL_HISTORY, IGNORED_B);
}
public boolean isSendingToFDroidMetrics() {
return isKeepingInstallHistory() && preferences.getBoolean(PREF_SEND_TO_FDROID_METRICS, IGNORED_B);
}
public boolean showIncompatibleVersions() {
return preferences.getBoolean(PREF_SHOW_INCOMPAT_VERSIONS, IGNORED_B);
}
@ -399,10 +391,6 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh
return Theme.valueOf(preferences.getString(Preferences.PREF_THEME, null));
}
public boolean isPureBlack() {
return preferences.getBoolean(Preferences.PREF_USE_PURE_BLACK_DARK_THEME, false);
}
public boolean isLocalRepoHttpsEnabled() {
return false; // disabled until it works well
}

View File

@ -1,11 +1,11 @@
package org.fdroid.fdroid;
import androidx.annotation.NonNull;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import androidx.annotation.NonNull;
class ProgressBufferedInputStream extends BufferedInputStream {
private final ProgressListener progressListener;
@ -24,7 +24,7 @@ class ProgressBufferedInputStream extends BufferedInputStream {
}
@Override
public synchronized int read(@NonNull byte[] buffer, int byteOffset, int byteCount) throws IOException {
public int read(@NonNull byte[] buffer, int byteOffset, int byteCount) throws IOException {
if (progressListener != null) {
currentBytes += byteCount;
/* don't send every change to keep things efficient. 333333 bytes to keep all

View File

@ -4,9 +4,7 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.util.Base64;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.io.IOUtils;
import org.fdroid.fdroid.data.Repo;
import org.fdroid.fdroid.data.RepoProvider;

View File

@ -30,6 +30,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Process;
import android.os.SystemClock;
@ -37,6 +38,12 @@ import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.core.app.JobIntentService;
import androidx.core.app.NotificationCompat;
import androidx.core.content.ContextCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.data.ApkProvider;
import org.fdroid.fdroid.data.App;
@ -50,18 +57,9 @@ import org.fdroid.fdroid.installer.InstallManagerService;
import org.fdroid.fdroid.net.BluetoothDownloader;
import org.fdroid.fdroid.net.ConnectivityMonitorService;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import androidx.annotation.NonNull;
import androidx.core.app.JobIntentService;
import androidx.core.app.NotificationCompat;
import androidx.core.content.ContextCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Completable;
import io.reactivex.rxjava3.schedulers.Schedulers;
public class UpdateService extends JobIntentService {
@ -83,13 +81,6 @@ public class UpdateService extends JobIntentService {
public static final int STATUS_ERROR_LOCAL_SMALL = 4;
public static final int STATUS_INFO = 5;
/**
* This number should never change, it is used by ROMs to trigger
* the first background update of F-Droid during setup.
*
* @see <a href="https://gitlab.com/fdroid/fdroidclient/-/issues/2147">Add a way to trigger an index update externally</a>
* @see <a href="https://review.calyxos.org/c/CalyxOS/platform_packages_apps_SetupWizard/+/3461"/>Schedule F-Droid index update on initialization and network connection</a>
*/
private static final int JOB_ID = 0xfedcba;
private static final int NOTIFY_ID_UPDATING = 0;
@ -217,30 +208,42 @@ public class UpdateService extends JobIntentService {
* unlimited networks over metered networks for index updates and auto
* downloads of app updates. Starting with {@code android-21}, this uses
* {@link android.app.job.JobScheduler} instead.
*
* @return a {@link Completable} that schedules the update. If this process is already running,
* a {@code Completable} that completes immediately is returned.
*/
@NonNull
public static Completable scheduleIfStillOnWifi(Context context) {
public static void scheduleIfStillOnWifi(Context context) {
if (Build.VERSION.SDK_INT >= 21) {
throw new IllegalStateException("This should never be used on android-21 or newer!");
}
if (isScheduleIfStillOnWifiRunning || !Preferences.get().isBackgroundDownloadAllowed()) {
return Completable.complete();
return;
}
isScheduleIfStillOnWifiRunning = true;
new StillOnWifiAsyncTask(context).execute();
}
private static final class StillOnWifiAsyncTask extends AsyncTask<Void, Void, Void> {
private final WeakReference<Context> contextWeakReference;
private StillOnWifiAsyncTask(Context context) {
this.contextWeakReference = new WeakReference<>(context);
}
@Override
protected Void doInBackground(Void... voids) {
Context context = contextWeakReference.get();
try {
Thread.sleep(120000);
if (Preferences.get().isBackgroundDownloadAllowed()) {
Utils.debugLog(TAG, "scheduling update because there is good internet");
schedule(context);
}
} catch (Throwable e) { // NOPMD
Utils.debugLog(TAG, e.getMessage());
}
isScheduleIfStillOnWifiRunning = false;
return null;
}
return Completable.timer(2, TimeUnit.MINUTES)
.andThen(Completable.fromAction(() -> {
if (Preferences.get().isBackgroundDownloadAllowed()) {
Utils.debugLog(TAG, "scheduling update because there is good internet");
schedule(context);
}
isScheduleIfStillOnWifiRunning = false;
}))
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread());
}
public static void stopNow(Context context) {
@ -250,37 +253,6 @@ public class UpdateService extends JobIntentService {
}
}
/**
* Return a {@link List} of all {@link Repo}s that have either a local
* canonical URL or a local mirror URL. These are repos that can be
* updated and used without using the Internet.
*/
public static List<Repo> getLocalRepos(Context context) {
return getLocalRepos(RepoProvider.Helper.all(context));
}
/**
* Return the repos in the {@code repos} {@link List} that have either a
* local canonical URL or a local mirror URL. These are repos that can be
* updated and used without using the Internet.
*/
public static List<Repo> getLocalRepos(List<Repo> repos) {
ArrayList<Repo> localRepos = new ArrayList<>();
for (Repo repo : repos) {
if (isLocalRepoAddress(repo.address)) {
localRepos.add(repo);
} else {
for (String mirrorAddress : repo.getMirrorList()) {
if (isLocalRepoAddress(mirrorAddress)) {
localRepos.add(repo);
break;
}
}
}
}
return localRepos;
}
@Override
public void onCreate() {
super.onCreate();
@ -292,7 +264,7 @@ public class UpdateService extends JobIntentService {
.setSmallIcon(R.drawable.ic_refresh)
.setOngoing(true)
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.setContentTitle(getString(R.string.banner_updating_repositories));
.setContentTitle(getString(R.string.update_notification_title));
appUpdateStatusManager = AppUpdateStatusManager.getInstance(this);
}
@ -432,11 +404,22 @@ public class UpdateService extends JobIntentService {
if (isLocalRepoAddress(address)) {
Utils.debugLog(TAG, "skipping internet check, this is local: " + address);
} else if (netState == ConnectivityMonitorService.FLAG_NET_UNAVAILABLE) {
// keep track of repos that have a local copy in case internet is not available
List<Repo> localRepos = getLocalRepos(repos);
if (localRepos.size() > 0) {
repos = localRepos;
} else {
boolean foundLocalRepo = false;
for (Repo repo : repos) {
if (isLocalRepoAddress(repo.address)) {
foundLocalRepo = true;
} else {
for (String mirrorAddress : repo.getMirrorList()) {
if (isLocalRepoAddress(mirrorAddress)) {
foundLocalRepo = true;
//localRepos.add(repo);
//FDroidApp.setLastWorkingMirror(repo.getId(), mirrorAddress);
break;
}
}
}
}
if (!foundLocalRepo) {
Utils.debugLog(TAG, "No internet, cannot update");
if (manualUpdate) {
Utils.showToastFromService(this, getString(R.string.warning_no_internet), Toast.LENGTH_SHORT);

View File

@ -27,7 +27,6 @@ import android.content.pm.Signature;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
@ -45,21 +44,19 @@ import android.text.style.TypefaceSpan;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.Display;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.Toast;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.encode.Contents;
import com.google.zxing.encode.QRCodeEncoder;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer;
import com.nostra13.universalimageloader.utils.StorageUtils;
import org.fdroid.fdroid.compat.FileCompat;
import org.fdroid.fdroid.data.App;
import org.fdroid.fdroid.data.Repo;
@ -97,15 +94,6 @@ import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.schedulers.Schedulers;
public final class Utils {
private static final String TAG = "Utils";
@ -492,7 +480,12 @@ public final class Utils {
*/
public static DisplayImageOptions.Builder getDefaultDisplayImageOptionsBuilder() {
if (defaultDisplayImageOptionsBuilder == null) {
defaultDisplayImageOptionsBuilder = createDefaultDisplayImageOptionsBuilder();
defaultDisplayImageOptionsBuilder = new DisplayImageOptions.Builder()
.cacheInMemory(true)
.cacheOnDisk(true)
.considerExifParams(false)
.bitmapConfig(Bitmap.Config.RGB_565)
.imageScaleType(ImageScaleType.EXACTLY);
}
return defaultDisplayImageOptionsBuilder;
}
@ -504,7 +497,7 @@ public final class Utils {
*/
public static DisplayImageOptions getRepoAppDisplayImageOptions() {
if (repoAppDisplayImageOptions == null) {
repoAppDisplayImageOptions = createDefaultDisplayImageOptionsBuilder()
repoAppDisplayImageOptions = getDefaultDisplayImageOptionsBuilder()
.showImageOnLoading(R.drawable.ic_repo_app_default)
.showImageForEmptyUri(R.drawable.ic_repo_app_default)
.showImageOnFail(R.drawable.ic_repo_app_default)
@ -514,15 +507,6 @@ public final class Utils {
return repoAppDisplayImageOptions;
}
private static DisplayImageOptions.Builder createDefaultDisplayImageOptionsBuilder() {
return new DisplayImageOptions.Builder()
.cacheInMemory(true)
.cacheOnDisk(true)
.considerExifParams(false)
.bitmapConfig(Bitmap.Config.RGB_565)
.imageScaleType(ImageScaleType.EXACTLY);
}
/**
* If app has an iconUrl we feed that to UIL, otherwise we ask the PackageManager which will
* return the app's icon directly when the app is installed.
@ -827,10 +811,6 @@ public final class Utils {
return versionName;
}
public static String getUserAgent() {
return "F-Droid " + BuildConfig.VERSION_NAME;
}
/**
* Try to get the {@link PackageInfo} for the {@code packageName} provided.
*
@ -995,27 +975,6 @@ public final class Utils {
}
}
@NonNull
public static Single<Bitmap> generateQrBitmap(@NonNull final AppCompatActivity activity,
@NonNull final String qrData) {
return Single.fromCallable(() -> {
Display display = activity.getWindowManager().getDefaultDisplay();
Point outSize = new Point();
display.getSize(outSize);
final int x = outSize.x;
final int y = outSize.y;
final int qrCodeDimension = Math.min(x, y);
debugLog(TAG, "generating QRCode Bitmap of " + qrCodeDimension + "x" + qrCodeDimension);
QRCodeEncoder qrCodeEncoder = new QRCodeEncoder(qrData, null,
Contents.Type.TEXT, BarcodeFormat.QR_CODE.toString(), qrCodeDimension);
return qrCodeEncoder.encodeAsBitmap();
})
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.doOnError(throwable -> Log.e(TAG, "Could not encode QR as bitmap", throwable));
}
/**
* Keep an instance of this class as an field in an AppCompatActivity for figuring out whether the on
* screen keyboard is currently visible or not.

View File

@ -2,15 +2,12 @@ package org.fdroid.fdroid.acra;
import android.content.DialogInterface;
import android.os.Bundle;
import androidx.appcompat.app.AlertDialog;
import android.widget.EditText;
import org.acra.dialog.BaseCrashReportDialog;
import org.fdroid.fdroid.R;
import androidx.appcompat.app.AlertDialog;
import com.google.android.material.textfield.TextInputLayout;
public class CrashReportActivity extends BaseCrashReportDialog
implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener {
@ -32,8 +29,7 @@ public class CrashReportActivity extends BaseCrashReportDialog
dialog.setOnDismissListener(this);
dialog.show();
TextInputLayout commentLayout = dialog.findViewById(android.R.id.input);
comment = commentLayout.getEditText();
comment = (EditText) dialog.findViewById(android.R.id.input);
if (savedInstanceState != null) {
comment.setText(savedInstanceState.getString(STATE_COMMENT));
}

View File

@ -4,15 +4,13 @@ package org.fdroid.fdroid.acra;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import androidx.annotation.NonNull;
import org.acra.ReportField;
import org.acra.collections.ImmutableSet;
import org.acra.collector.CrashReportData;
import org.acra.config.ACRAConfiguration;
import org.acra.sender.ReportSender;
import androidx.annotation.NonNull;
public class CrashReportSender implements ReportSender {
private final ACRAConfiguration config;

View File

@ -1,13 +1,12 @@
package org.fdroid.fdroid.acra;
import android.content.Context;
import androidx.annotation.NonNull;
import org.acra.config.ACRAConfiguration;
import org.acra.sender.ReportSender;
import org.acra.sender.ReportSenderFactory;
import androidx.annotation.NonNull;
public class CrashReportSenderFactory implements ReportSenderFactory {
@NonNull
@Override

Some files were not shown because too many files have changed in this diff Show More