mirror of
https://github.com/syncthing/syncthing-android.git
synced 2024-12-22 10:51:28 +00:00
Target android sdk 29 (#1575)
This commit is contained in:
parent
b04cacd8b4
commit
b03d2465dc
8 changed files with 129 additions and 112 deletions
|
@ -25,8 +25,8 @@ dependencies {
|
|||
|
||||
android {
|
||||
// Changes to these values need to be reflected in `.travis.yml`
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion '28.0.3'
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion '29.0.3'
|
||||
|
||||
buildTypes.debug.applicationIdSuffix ".debug"
|
||||
dataBinding.enabled = true
|
||||
|
@ -39,7 +39,7 @@ android {
|
|||
defaultConfig {
|
||||
applicationId "com.nutomic.syncthingandroid"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 28
|
||||
targetSdkVersion 29
|
||||
versionCode 4253
|
||||
versionName "1.11.1"
|
||||
testApplicationId 'com.nutomic.syncthingandroid.test'
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
<!-- ACCESS_FINE_LOCATION is required to get WiFi's SSID on 10 "Q" -->
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<!-- ACCESS_BACKGROUND_LOCATION is required to get WiFi's SSID on 10 "Q" -->
|
||||
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
||||
<!-- CAMERA is required for the QR Code Scanner -->
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
|
||||
|
@ -34,6 +36,7 @@
|
|||
android:description="@string/app_description"
|
||||
android:supportsRtl="true"
|
||||
android:installLocation="internalOnly"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:name=".SyncthingApp">
|
||||
<activity
|
||||
android:name=".activities.FirstStartActivity"
|
||||
|
|
|
@ -39,8 +39,7 @@ import javax.inject.Inject;
|
|||
public class FirstStartActivity extends Activity {
|
||||
|
||||
private static String TAG = "FirstStartActivity";
|
||||
private static final int REQUEST_COARSE_LOCATION = 141;
|
||||
private static final int REQUEST_WRITE_STORAGE = 142;
|
||||
|
||||
private static final int SLIDE_POS_LOCATION_PERMISSION = 1;
|
||||
|
||||
private ViewPager mViewPager;
|
||||
|
@ -300,8 +299,8 @@ public class FirstStartActivity extends Activity {
|
|||
*/
|
||||
private void requestLocationPermission() {
|
||||
ActivityCompat.requestPermissions(this,
|
||||
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
|
||||
REQUEST_COARSE_LOCATION);
|
||||
Constants.getLocationPermissions(),
|
||||
Constants.PermissionRequestType.LOCATION.ordinal());
|
||||
}
|
||||
|
||||
private boolean haveStoragePermission() {
|
||||
|
@ -313,23 +312,32 @@ public class FirstStartActivity extends Activity {
|
|||
private void requestStoragePermission() {
|
||||
ActivityCompat.requestPermissions(this,
|
||||
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
||||
REQUEST_WRITE_STORAGE);
|
||||
Constants.PermissionRequestType.STORAGE.ordinal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
|
||||
@NonNull int[] grantResults) {
|
||||
switch (requestCode) {
|
||||
case REQUEST_COARSE_LOCATION:
|
||||
if (grantResults.length == 0 ||
|
||||
grantResults[0] != PackageManager.PERMISSION_GRANTED) {
|
||||
Log.i(TAG, "User denied ACCESS_COARSE_LOCATION permission.");
|
||||
} else {
|
||||
switch (Constants.PermissionRequestType.values()[requestCode]) {
|
||||
case LOCATION:
|
||||
boolean granted = grantResults.length != 0;
|
||||
if (!granted) {
|
||||
Log.i(TAG, "No location permission in request-result");
|
||||
break;
|
||||
}
|
||||
for (int i = 0; i < grantResults.length; i++) {
|
||||
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
|
||||
Log.i(TAG, "User granted permission: " + permissions[i]);
|
||||
} else {
|
||||
granted = false;
|
||||
Log.i(TAG, "User denied permission: " + permissions[i]);
|
||||
}
|
||||
}
|
||||
if (granted) {
|
||||
Toast.makeText(this, R.string.permission_granted, Toast.LENGTH_SHORT).show();
|
||||
Log.i(TAG, "User granted ACCESS_COARSE_LOCATION permission.");
|
||||
}
|
||||
break;
|
||||
case REQUEST_WRITE_STORAGE:
|
||||
case STORAGE:
|
||||
if (grantResults.length == 0 ||
|
||||
grantResults[0] != PackageManager.PERMISSION_GRANTED) {
|
||||
Log.i(TAG, "User denied WRITE_EXTERNAL_STORAGE permission.");
|
||||
|
|
|
@ -66,21 +66,23 @@ public class SettingsActivity extends SyncthingActivity {
|
|||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
// On Android 8.1, ACCESS_COARSE_LOCATION is required, see issue #999
|
||||
if (requestCode == Constants.PERM_REQ_ACCESS_COARSE_LOCATION) {
|
||||
for (int i = 0; i < permissions.length; i++) {
|
||||
if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permissions[i])) {
|
||||
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
|
||||
this.startService(new Intent(this, SyncthingService.class)
|
||||
.setAction(SyncthingService.ACTION_REFRESH_NETWORK_INFO));
|
||||
} else {
|
||||
Util.getAlertDialogBuilder(this)
|
||||
.setTitle(R.string.sync_only_wifi_ssids_location_permission_rejected_dialog_title)
|
||||
.setMessage(R.string.sync_only_wifi_ssids_location_permission_rejected_dialog_content)
|
||||
.setPositiveButton(android.R.string.ok, null).show();
|
||||
}
|
||||
if (requestCode == Constants.PermissionRequestType.LOCATION.ordinal()) {
|
||||
boolean granted = grantResults.length > 0;
|
||||
for (int i = 0; i < grantResults.length; i++) {
|
||||
if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
|
||||
granted = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (granted) {
|
||||
this.startService(new Intent(this, SyncthingService.class)
|
||||
.setAction(SyncthingService.ACTION_REFRESH_NETWORK_INFO));
|
||||
} else {
|
||||
Util.getAlertDialogBuilder(this)
|
||||
.setTitle(R.string.sync_only_wifi_ssids_location_permission_rejected_dialog_title)
|
||||
.setMessage(R.string.sync_only_wifi_ssids_location_permission_rejected_dialog_content)
|
||||
.setPositiveButton(android.R.string.ok, null).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.nutomic.syncthingandroid.service;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
|
@ -48,10 +49,33 @@ public class Constants {
|
|||
public static final String FOLDER_TYPE_RECEIVE_ONLY = "receiveonly";
|
||||
|
||||
/**
|
||||
* On Android 8.1, ACCESS_COARSE_LOCATION is required to access WiFi SSID.
|
||||
* This is the request code used when requesting the permission.
|
||||
* These are the request codes used when requesting the permissions.
|
||||
*/
|
||||
public static final int PERM_REQ_ACCESS_COARSE_LOCATION = 999; // for issue #999
|
||||
public enum PermissionRequestType {
|
||||
LOCATION, STORAGE
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the location permissions required to access wifi SSIDs depending
|
||||
* on the respective Android version.
|
||||
*/
|
||||
public static String[] getLocationPermissions() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { // before android 9
|
||||
return new String[]{
|
||||
Manifest.permission.ACCESS_COARSE_LOCATION,
|
||||
};
|
||||
}
|
||||
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P) { // android 9
|
||||
return new String[]{
|
||||
Manifest.permission.ACCESS_FINE_LOCATION,
|
||||
};
|
||||
}
|
||||
return new String[]{ // after android 9
|
||||
Manifest.permission.ACCESS_FINE_LOCATION,
|
||||
Manifest.permission.ACCESS_BACKGROUND_LOCATION,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Interval in ms at which the GUI is updated (eg {@link com.nutomic.syncthingandroid.fragments.DrawerFragment}).
|
||||
|
|
|
@ -5,6 +5,7 @@ import android.app.Activity;
|
|||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.wifi.WifiConfiguration;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
@ -18,6 +19,7 @@ import com.nutomic.syncthingandroid.R;
|
|||
import com.nutomic.syncthingandroid.service.Constants;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
@ -59,99 +61,76 @@ public class WifiSsidPreference extends MultiSelectListPreference {
|
|||
*/
|
||||
@Override
|
||||
protected void showDialog(Bundle state) {
|
||||
WifiConfiguration[] networks = loadConfiguredNetworksSorted();
|
||||
if (networks != null) {
|
||||
Set<String> selected = getSharedPreferences().getStringSet(getKey(), new HashSet<>());
|
||||
// from JavaDoc: Note that you must not modify the set instance returned by this call.
|
||||
// therefore required to make a defensive copy of the elements
|
||||
selected = new HashSet<>(selected);
|
||||
CharSequence[] all = extractSsid(networks, false);
|
||||
filterRemovedNetworks(selected, all);
|
||||
setEntries(extractSsid(networks, true)); // display without surrounding quotes
|
||||
setEntryValues(all); // the value of the entry is the SSID "as is"
|
||||
setValues(selected); // the currently selected values (without meanwhile deleted networks)
|
||||
super.showDialog(state);
|
||||
} else {
|
||||
Toast.makeText(getContext(), R.string.sync_only_wifi_ssids_wifi_turn_on_wifi, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
Context context = getContext();
|
||||
|
||||
// On Android 8.1, ACCESS_COARSE_LOCATION is required, see issue #999
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
||||
if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
|
||||
if (getContext() instanceof Activity) {
|
||||
Activity activity = (Activity) getContext();
|
||||
ActivityCompat.requestPermissions(activity, new String[] { Manifest.permission.ACCESS_COARSE_LOCATION }, Constants.PERM_REQ_ACCESS_COARSE_LOCATION);
|
||||
this.getDialog().dismiss(); // wait for result
|
||||
} else {
|
||||
Toast.makeText(getContext(), R.string.sync_only_wifi_ssids_need_to_grant_location_permission, Toast.LENGTH_LONG).show();
|
||||
Set<String> selected = getSharedPreferences().getStringSet(getKey(), new HashSet<>());
|
||||
// from JavaDoc: Note that you must not modify the set instance returned by this call.
|
||||
// therefore required to make a defensive copy of the elements
|
||||
selected = new HashSet<>(selected);
|
||||
List<String> all = new ArrayList<>(selected);
|
||||
|
||||
boolean connected = false;
|
||||
WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
|
||||
if (wifiManager != null) {
|
||||
WifiInfo info = wifiManager.getConnectionInfo();
|
||||
if (info != null) {
|
||||
String ssid = info.getSSID();
|
||||
// api lvl 30 will have WifiManager.UNKNOWN_SSID
|
||||
if (ssid != null && ssid != "" && !ssid.contains("unknown ssid")) {
|
||||
if (!selected.contains(ssid)) {
|
||||
all.add(ssid);
|
||||
}
|
||||
connected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasPerms = hasLocationPermissions();
|
||||
if (!connected) {
|
||||
if (!hasPerms) {
|
||||
Toast.makeText(context, R.string.sync_only_wifi_ssids_need_to_grant_location_permission, Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
Toast.makeText(context, R.string.sync_only_wifi_ssids_connect_to_wifi, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
if (all.size() > 0 ) {
|
||||
setEntries(stripQuotes(all)); // display without surrounding quotes
|
||||
setEntryValues(all.toArray(new CharSequence[all.size()])); // the value of the entry is the SSID "as is"
|
||||
setValues(selected); // the currently selected values (without meanwhile deleted networks)
|
||||
super.showDialog(state);
|
||||
}
|
||||
|
||||
if (!hasPerms && context instanceof Activity) {
|
||||
Activity activity = (Activity) context;
|
||||
ActivityCompat.requestPermissions(activity, Constants.getLocationPermissions(), Constants.PermissionRequestType.LOCATION.ordinal());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes any network that is no longer saved on the device. Otherwise it will never be
|
||||
* removed from the allowed set by MultiSelectListPreference.
|
||||
* Checks if the required location permissions to obtain WiFi SSID are granted.
|
||||
*/
|
||||
private void filterRemovedNetworks(Set<String> selected, CharSequence[] all) {
|
||||
HashSet<CharSequence> availableNetworks = new HashSet<>(Arrays.asList(all));
|
||||
selected.retainAll(availableNetworks);
|
||||
private boolean hasLocationPermissions() {
|
||||
String[] perms = Constants.getLocationPermissions();
|
||||
for (int i = 0; i < perms.length; i++) {
|
||||
if (ContextCompat.checkSelfPermission(getContext(), perms[i]) != PackageManager.PERMISSION_GRANTED) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts WiFi configuration to it's string representation, using the SSID.
|
||||
* Returns a copy of the given WiFi SSIDs with quotes stripped.
|
||||
*
|
||||
* It can also remove surrounding quotes which indicate that the SSID is an UTF-8
|
||||
* string and not a Hex-String, if the strings are intended to be displayed to the
|
||||
* user, who will not expect the quotes.
|
||||
*
|
||||
* @param configs the objects to convert
|
||||
* @param stripQuotes if to remove surrounding quotes
|
||||
* @return the formatted SSID of the wifi configurations
|
||||
* @param ssids the list of ssids to strip quotes from
|
||||
*/
|
||||
private CharSequence[] extractSsid(WifiConfiguration[] configs, boolean stripQuotes) {
|
||||
CharSequence[] result = new CharSequence[configs.length];
|
||||
for (int i = 0; i < configs.length; i++) {
|
||||
// See #620: there may be null-SSIDs
|
||||
String ssid = configs[i].SSID != null ? configs[i].SSID : "";
|
||||
// WiFi SSIDs can either be UTF-8 (encapsulated in '"') or hex-strings
|
||||
if (stripQuotes)
|
||||
result[i] = ssid.replaceFirst("^\"", "").replaceFirst("\"$", "");
|
||||
else
|
||||
result[i] = ssid;
|
||||
private CharSequence[] stripQuotes(List<String> ssids) {
|
||||
CharSequence[] result = new CharSequence[ssids.size()];
|
||||
for (int i = 0; i < ssids.size(); i++) {
|
||||
result[i] = ssids.get(i).replaceFirst("^\"", "").replaceFirst("\"$", "");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the configured WiFi networks, sort them by SSID.
|
||||
*
|
||||
* @return a sorted array of WifiConfiguration, or null, if data cannot be retrieved
|
||||
*/
|
||||
private WifiConfiguration[] loadConfiguredNetworksSorted() {
|
||||
WifiManager wifiManager = (WifiManager)
|
||||
getContext().getApplicationContext().getSystemService(Context.WIFI_SERVICE);
|
||||
if (wifiManager != null) {
|
||||
List<WifiConfiguration> configuredNetworks = null;
|
||||
try {
|
||||
configuredNetworks = wifiManager.getConfiguredNetworks();
|
||||
} catch (SecurityException e) {
|
||||
// See changes in Android Q, https://developer.android.com/reference/android/net/wifi/WifiManager.html#getConfiguredNetworks()
|
||||
}
|
||||
// if WiFi is turned off, getConfiguredNetworks returns null on many devices
|
||||
if (configuredNetworks != null) {
|
||||
WifiConfiguration[] result = configuredNetworks.toArray(new WifiConfiguration[configuredNetworks.size()]);
|
||||
Arrays.sort(result, (lhs, rhs) -> {
|
||||
// See #620: There may be null-SSIDs
|
||||
String l = lhs.SSID != null ? lhs.SSID : "";
|
||||
String r = rhs.SSID != null ? rhs.SSID : "";
|
||||
return l.compareToIgnoreCase(r);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// WiFi is turned off or device doesn't have WiFi
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -324,6 +324,7 @@ Please report any problems you encounter via Github.</string>
|
|||
<string name="run_on_all_wifi_networks">Run on all Wi-Fi networks.</string>
|
||||
|
||||
<string name="sync_only_wifi_ssids_wifi_turn_on_wifi">Please turn on Wi-Fi to select networks.</string>
|
||||
<string name="sync_only_wifi_ssids_connect_to_wifi">Please connect to a Wi-Fi to add it to the list.</string>
|
||||
|
||||
<string name="sync_only_wifi_ssids_need_to_grant_location_permission">You need to grant LOCATION permission to use this feature.</string>
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
FROM openjdk:8
|
||||
|
||||
ENV GO_VERSION 1.15.2
|
||||
ENV GO_VERSION 1.15.5
|
||||
ENV ANDROID_SDK_VERSION 3859397
|
||||
|
||||
WORKDIR /opt
|
||||
|
@ -23,7 +23,7 @@ ENV ANDROID_HOME /opt/android-sdk
|
|||
RUN yes | ${ANDROID_HOME}/tools/bin/sdkmanager --licenses
|
||||
|
||||
# Install other android packages, including NDK
|
||||
RUN ${ANDROID_HOME}/tools/bin/sdkmanager tools platform-tools "build-tools;27.0.2" "platforms;android-27" "extras;android;m2repository" ndk-bundle
|
||||
RUN ${ANDROID_HOME}/tools/bin/sdkmanager tools platform-tools "build-tools;29.0.3" "platforms;android-29" "extras;android;m2repository" ndk-bundle
|
||||
|
||||
# Accept licenses of newly installed packages
|
||||
RUN yes | ${ANDROID_HOME}/tools/bin/sdkmanager --licenses
|
||||
|
|
Loading…
Reference in a new issue