mirror of https://github.com/nextcloud/android
Compare commits
21 Commits
5961a721ce
...
2a24af7e0d
Author | SHA1 | Date |
---|---|---|
alperozturk | 2a24af7e0d | |
alperozturk | 2b7d76273b | |
alperozturk | 1afb9ca582 | |
alperozturk | 2d878ff788 | |
alperozturk | 408502b8e7 | |
alperozturk | 8010a23dc6 | |
alperozturk | 4e34fdab13 | |
alperozturk | d3ec6694a3 | |
alperozturk | ce61fc5f47 | |
alperozturk | a531f8f294 | |
Alper Öztürk | 20cabd4aab | |
Unpublished | e7badaec39 | |
Unpublished | 724115de3e | |
Andy Scherzinger | f2cb841854 | |
Nextcloud bot | 3644710cc6 | |
nextcloud-android-bot | 8567928d16 | |
Andy Scherzinger | f58e7fc75a | |
Andy Scherzinger | bbe218a265 | |
Andy Scherzinger | e3a729c2cf | |
Andy Scherzinger | 92392d49a7 | |
tobiasKaminsky | 0334871f64 |
|
@ -44,7 +44,7 @@ jobs:
|
|||
echo "repo=${{ github.event.pull_request.head.repo.full_name }}"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
- uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
with:
|
||||
repository: ${{ steps.get-vars.outputs.repo }}
|
||||
ref: ${{ steps.get-vars.outputs.branch }}
|
||||
|
|
|
@ -33,13 +33,13 @@ jobs:
|
|||
language: [ 'java' ]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
- name: Set Swap Space
|
||||
uses: pierotofy/set-swap-space@49819abfb41bd9b44fb781159c033dba90353a7c # v1.0
|
||||
with:
|
||||
swap-size-gb: 10
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@8f596b4ae3cb3c588a5c46780b86dd53fef16c52 # v3.25.2
|
||||
uses: github/codeql-action/init@d39d31e687223d841ef683f52467bd88e9b21c14 # v3.25.3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Set up JDK 17
|
||||
|
@ -53,4 +53,4 @@ jobs:
|
|||
echo "org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError" > "$HOME/.gradle/gradle.properties"
|
||||
./gradlew assembleDebug
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@8f596b4ae3cb3c588a5c46780b86dd53fef16c52 # v3.25.2
|
||||
uses: github/codeql-action/analyze@d39d31e687223d841ef683f52467bd88e9b21c14 # v3.25.3
|
||||
|
|
|
@ -25,5 +25,5 @@ jobs:
|
|||
name: "Validation"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
|
||||
- uses: gradle/wrapper-validation-action@5188e9b5527a0a094cee21e2fe9a8ca44b4629af # v3.3.1
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
- uses: gradle/wrapper-validation-action@216d1ad2b3710bf005dc39237337b9673fd8fcd5 # v3.3.2
|
||||
|
|
|
@ -29,7 +29,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
@ -42,6 +42,6 @@ jobs:
|
|||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@8f596b4ae3cb3c588a5c46780b86dd53fef16c52 # v3.25.2
|
||||
uses: github/codeql-action/upload-sarif@d39d31e687223d841ef683f52467bd88e9b21c14 # v3.25.3
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
|
|
@ -17,7 +17,7 @@ concurrency:
|
|||
|
||||
jobs:
|
||||
screenshot:
|
||||
runs-on: macOS-latest
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
@ -48,6 +48,12 @@ jobs:
|
|||
distribution: "temurin"
|
||||
java-version: 17
|
||||
|
||||
- name: Enable KVM group perms
|
||||
run: |
|
||||
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger --name-match=kvm
|
||||
|
||||
- name: create AVD and generate snapshot for caching
|
||||
if: steps.avd-cache.outputs.cache-hit != 'true'
|
||||
uses: reactivecircus/android-emulator-runner@6b0df4b0efb23bb0ec63d881db79aefbc976e4b2 # v2.30.1
|
||||
|
|
|
@ -20,8 +20,8 @@ Copyright: 2015-2016 ownCloud Inc.
|
|||
License: GPL-2.0-only
|
||||
|
||||
Files: app/src/*/res/mipmap-*dpi/ic_launcher.png app/src/*/ic_launcher-web.png src/generic/fastlane/metadata/android/en-US/images/icon.png src/versionDev/fastlane/metadata/android/en-US/images/icon.png app/src/main/ic_launcher-web-round.png
|
||||
Copyright: 2017-2024 Nextcloud GmbH. All rights reserved. Trademarks apply, see https://nextcloud.com/trademarks/
|
||||
License: AGPL-3.0-or-later
|
||||
Copyright: 2017-2024 Nextcloud GmbH <https://nextcloud.com/trademarks/>
|
||||
License: LicenseRef-NextcloudTrademarks
|
||||
|
||||
Files: .idea/* app/schemas/com.nextcloud.client.database.NextcloudDatabase/*.json app/screenshots/gplay/debug/*.png app/src/main/res/values-*/strings.xml src/*/fastlane/metadata/android/*/*.txt src/versionDev/fastlane/metadata/android/*/changelogs/*.txt app/src/androidTest/assets/* app/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker app/src/*/google-services.json app/src/main/res/drawable-*dpi/checker_16_16.png app/src/main/res/raw/encryption_key_words.txt app/src/main/resources/ical4j.properties app/src/main/res/drawable-*dpi/apk.png app/src/main/res/drawable-*dpi/fdroid.png app/src/main/res/drawable-*dpi/playstore.png app/src/main/res/drawable-*dpi/background.png app/src/main/res/drawable-*dpi/background_nc18.png
|
||||
Copyright: 2016-2024 Nextcloud GmbH and Nextcloud contributors
|
||||
|
|
25
CHANGELOG.md
25
CHANGELOG.md
|
@ -1,17 +1,29 @@
|
|||
<!--
|
||||
~ SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
|
||||
~ SPDX-FileCopyrightText: 2016-2024 Tobias Kaminsky <tobias@kaminsky.me>
|
||||
~ SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-->
|
||||
|
||||
## 3.29.0 (April 24, 2024)
|
||||
|
||||
- NC Assistant
|
||||
- Client certificates
|
||||
- Personal files view
|
||||
- REUSE compliance
|
||||
- Bugfixes
|
||||
|
||||
Minimum: NC 16 Server, Android 7.0 Nougat
|
||||
|
||||
For a full list, please see https://github.com/nextcloud/android/milestone/89
|
||||
|
||||
## 3.28.2 (April 4th, 2024)
|
||||
|
||||
- Bugfixes
|
||||
|
||||
|
||||
Minimum: NC 16 Server, Android 7.0 Nougat
|
||||
|
||||
For a full list, please see https://github.com/nextcloud/android/milestone/90
|
||||
|
||||
<!--
|
||||
~ SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
|
||||
~ SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-->
|
||||
|
||||
## 3.28.1 (March 25th, 2024)
|
||||
|
||||
- Bugfixes
|
||||
|
@ -25,7 +37,6 @@ For a full list, please see https://github.com/nextcloud/android/milestone/90
|
|||
- E2E sharing
|
||||
- Bugfixes
|
||||
|
||||
|
||||
Minimum: NC 16 Server, Android 7.0 Nougat
|
||||
|
||||
For a full list, please see https://github.com/nextcloud/android/milestone/88
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
The Nextcloud marks
|
||||
Nextcloud and the Nextcloud logo is a registered trademark of Nextcloud GmbH in Germany and/or other countries.
|
||||
These guidelines cover the following marks pertaining both to the product names and the logo: “Nextcloud”
|
||||
and the blue/white cloud logo with or without the word Nextcloud; the service “Nextcloud Enterprise”;
|
||||
and our products: “Nextcloud Files”; “Nextcloud Groupware” and “Nextcloud Talk”.
|
||||
This set of marks is collectively referred to as the “Nextcloud marks.”
|
||||
|
||||
Use of Nextcloud logos and other marks is only permitted under the guidelines provided by the Nextcloud GmbH.
|
||||
A copy can be found at https://nextcloud.com/trademarks/
|
Binary file not shown.
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 31 KiB |
Binary file not shown.
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
@ -17,6 +17,7 @@ import android.Manifest;
|
|||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
@ -47,15 +48,20 @@ import android.widget.Toast;
|
|||
|
||||
import com.blikoon.qrcodescanner.QrCodeActivity;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.nextcloud.android.common.ui.color.ColorUtil;
|
||||
import com.nextcloud.android.common.ui.theme.utils.ColorRole;
|
||||
import com.nextcloud.client.account.User;
|
||||
import com.nextcloud.client.account.UserAccountManager;
|
||||
import com.nextcloud.client.device.DeviceInfo;
|
||||
import com.nextcloud.client.di.Injectable;
|
||||
import com.nextcloud.client.network.ClientFactory;
|
||||
import com.nextcloud.client.onboarding.FirstRunActivity;
|
||||
import com.nextcloud.client.onboarding.OnboardingService;
|
||||
import com.nextcloud.client.preferences.AppPreferences;
|
||||
import com.nextcloud.common.PlainClient;
|
||||
import com.nextcloud.operations.PostMethod;
|
||||
import com.nextcloud.utils.extensions.BundleExtensionsKt;
|
||||
import com.owncloud.android.MainApp;
|
||||
import com.owncloud.android.R;
|
||||
|
@ -100,6 +106,8 @@ import com.owncloud.android.utils.WebViewUtil;
|
|||
import com.owncloud.android.utils.theme.CapabilityUtils;
|
||||
import com.owncloud.android.utils.theme.ViewThemeUtils;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.HashMap;
|
||||
|
@ -107,9 +115,13 @@ import java.util.Locale;
|
|||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
@ -125,6 +137,8 @@ import de.cotech.hw.fido.ui.FidoDialogOptions;
|
|||
import de.cotech.hw.fido2.WebViewWebauthnBridge;
|
||||
import de.cotech.hw.fido2.ui.WebauthnDialogOptions;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import okhttp3.FormBody;
|
||||
import okhttp3.RequestBody;
|
||||
|
||||
import static com.owncloud.android.utils.PermissionUtil.PERMISSIONS_CAMERA;
|
||||
|
||||
|
@ -162,7 +176,17 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
private static final String KEY_USERNAME = "USERNAME";
|
||||
private static final String KEY_PASSWORD = "PASSWORD";
|
||||
private static final String KEY_ASYNC_TASK_IN_PROGRESS = "AUTH_IN_PROGRESS";
|
||||
public static final String WEB_LOGIN = "/index.php/login/flow";
|
||||
|
||||
/**
|
||||
* Login Flow v1
|
||||
*/
|
||||
// public static final String WEB_LOGIN = "/index.php/login/flow";
|
||||
|
||||
/**
|
||||
* Login Flow v2
|
||||
*/
|
||||
public static final String WEB_LOGIN = "/index.php/login/v2";
|
||||
|
||||
public static final String PROTOCOL_SUFFIX = "://";
|
||||
public static final String LOGIN_URL_DATA_KEY_VALUE_SEPARATOR = ":";
|
||||
public static final String HTTPS_PROTOCOL = "https://";
|
||||
|
@ -171,7 +195,6 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
public static final int NO_ICON = 0;
|
||||
public static final String EMPTY_STRING = "";
|
||||
|
||||
private static final int REQUEST_CODE_QR_SCAN = 101;
|
||||
public static final int REQUEST_CODE_FIRST_RUN = 102;
|
||||
|
||||
/// parameters from EXTRAs in starter Intent
|
||||
|
@ -218,6 +241,9 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
@Inject PassCodeManager passCodeManager;
|
||||
@Inject ViewThemeUtils.Factory viewThemeUtilsFactory;
|
||||
@Inject ColorUtil colorUtil;
|
||||
@Inject ClientFactory clientFactory;
|
||||
|
||||
private String token;
|
||||
|
||||
private boolean onlyAdd = false;
|
||||
@SuppressLint("ResourceAsColor") @ColorInt
|
||||
|
@ -242,7 +268,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
viewThemeUtils = viewThemeUtilsFactory.withPrimaryAsBackground();
|
||||
viewThemeUtils.platform.themeStatusBar(this, ColorRole.PRIMARY);
|
||||
|
||||
WebViewUtil webViewUtil = new WebViewUtil(this);
|
||||
// WebViewUtil webViewUtil = new WebViewUtil(this);
|
||||
|
||||
Uri data = getIntent().getData();
|
||||
boolean directLogin = data != null && data.toString().startsWith(getString(R.string.login_data_own_scheme));
|
||||
|
@ -298,7 +324,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
if (webViewLoginMethod) {
|
||||
accountSetupWebviewBinding = AccountSetupWebviewBinding.inflate(getLayoutInflater());
|
||||
setContentView(accountSetupWebviewBinding.getRoot());
|
||||
initWebViewLogin(webloginUrl, false);
|
||||
anonymouslyPostLoginRequest(webloginUrl);
|
||||
// initWebViewLogin(webloginUrl, false);
|
||||
} else {
|
||||
accountSetupBinding = AccountSetupBinding.inflate(getLayoutInflater());
|
||||
setContentView(accountSetupBinding.getRoot());
|
||||
|
@ -314,7 +341,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
|
||||
initServerPreFragment(savedInstanceState);
|
||||
|
||||
webViewUtil.checkWebViewVersion();
|
||||
// webViewUtil.checkWebViewVersion();
|
||||
}
|
||||
|
||||
private void deleteCookies() {
|
||||
|
@ -326,11 +353,57 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
}
|
||||
}
|
||||
|
||||
private String baseUrl;
|
||||
|
||||
/**
|
||||
* This function facilitates the login process by anonymously posting a login request to a specified URL.
|
||||
* After posting the request, it retrieves the login URL for completing the login flow.
|
||||
* The login flow version used is v2.
|
||||
*
|
||||
* @param url The URL where the login request is to be anonymously posted.
|
||||
* This URL should handle the login request and return the login URL.
|
||||
* It's typically the entry point for the login process.
|
||||
* Example: "https://example.com/index.php/login/v2"
|
||||
*/
|
||||
private void anonymouslyPostLoginRequest(String url) {
|
||||
baseUrl = url;
|
||||
|
||||
Thread thread = new Thread(() -> {
|
||||
PostMethod post = new PostMethod(baseUrl, false, new FormBody.Builder().build());
|
||||
|
||||
PlainClient client = clientFactory.createPlainClient();
|
||||
post.execute(client);
|
||||
String response = post.getResponseBodyAsString();
|
||||
JsonObject jsonObject = JsonParser.parseString(response).getAsJsonObject();
|
||||
String login = jsonObject.get("login").getAsString();
|
||||
if (login == null) {
|
||||
login = getResources().getString(R.string.webview_login_url);
|
||||
}
|
||||
|
||||
String loginUrl = login;
|
||||
runOnUiThread(() -> {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(loginUrl));
|
||||
loginFlowResultLauncher.launch(intent);
|
||||
});
|
||||
|
||||
token = jsonObject.getAsJsonObject("poll").get("token").getAsString();
|
||||
});
|
||||
|
||||
thread.start();
|
||||
}
|
||||
|
||||
private final ActivityResultLauncher<Intent> loginFlowResultLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(), result -> poolLogin(clientFactory.createPlainClient()));
|
||||
|
||||
private static String getWebLoginUserAgent() {
|
||||
return Build.MANUFACTURER.substring(0, 1).toUpperCase(Locale.getDefault()) +
|
||||
Build.MANUFACTURER.substring(1).toLowerCase(Locale.getDefault()) + " " + Build.MODEL + " (Android)";
|
||||
}
|
||||
|
||||
/**
|
||||
* @Deprecated This function is deprecated. Please use the {@link #anonymouslyPostLoginRequest(String)} method instead, which utilizes the improved login flow v2.
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressFBWarnings("ANDROID_WEB_VIEW_JAVASCRIPT")
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
private void initWebViewLogin(String baseURL, boolean useGenericUserAgent) {
|
||||
|
@ -680,7 +753,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
if (intent.getBooleanExtra(EXTRA_USE_PROVIDER_AS_WEBLOGIN, false)) {
|
||||
accountSetupWebviewBinding = AccountSetupWebviewBinding.inflate(getLayoutInflater());
|
||||
setContentView(accountSetupWebviewBinding.getRoot());
|
||||
initWebViewLogin(getString(R.string.provider_registration_server), true);
|
||||
anonymouslyPostLoginRequest(getString(R.string.provider_registration_server));
|
||||
// initWebViewLogin(getString(R.string.provider_registration_server), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -915,7 +989,11 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
|
||||
accountSetupWebviewBinding = AccountSetupWebviewBinding.inflate(getLayoutInflater());
|
||||
setContentView(accountSetupWebviewBinding.getRoot());
|
||||
initWebViewLogin(mServerInfo.mBaseUrl + WEB_LOGIN, false);
|
||||
|
||||
if (!isLoginProcessCompleted) {
|
||||
anonymouslyPostLoginRequest(mServerInfo.mBaseUrl + WEB_LOGIN);
|
||||
// initWebViewLogin(mServerInfo.mBaseUrl + WEB_LOGIN, false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
updateServerStatusIconAndText(result);
|
||||
|
@ -1169,7 +1247,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
|
||||
} else { // authorization fail due to client side - probably wrong credentials
|
||||
if (accountSetupWebviewBinding != null) {
|
||||
initWebViewLogin(mServerInfo.mBaseUrl + WEB_LOGIN, false);
|
||||
anonymouslyPostLoginRequest(mServerInfo.mBaseUrl + WEB_LOGIN);
|
||||
// initWebViewLogin(mServerInfo.mBaseUrl + WEB_LOGIN, false);
|
||||
DisplayUtils.showSnackMessage(this,
|
||||
accountSetupWebviewBinding.loginWebview, R.string.auth_access_failed,
|
||||
result.getLogMessage());
|
||||
|
@ -1340,9 +1419,37 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
|
||||
private void startQRScanner() {
|
||||
Intent intent = new Intent(this, QrCodeActivity.class);
|
||||
startActivityForResult(intent, REQUEST_CODE_QR_SCAN);
|
||||
qrScanResultLauncher.launch(intent);
|
||||
}
|
||||
|
||||
private final ActivityResultLauncher<Intent> qrScanResultLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {
|
||||
if (result.getResultCode() == Activity.RESULT_OK) {
|
||||
Intent data = result.getData();
|
||||
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String resultData = data.getStringExtra("com.blikoon.qrcodescanner.got_qr_scan_relult");
|
||||
|
||||
if (resultData == null || !resultData.startsWith(getString(R.string.login_data_own_scheme))) {
|
||||
mServerStatusIcon = R.drawable.ic_alert;
|
||||
mServerStatusText = "QR Code could not be read!";
|
||||
showServerStatus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!getResources().getBoolean(R.bool.multiaccount_support) &&
|
||||
accountManager.getAccounts().length == 1) {
|
||||
Toast.makeText(this, R.string.no_mutliple_accounts_allowed, Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
parseAndLoginFromWebView(resultData);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode,
|
||||
@NonNull String[] permissions,
|
||||
|
@ -1362,7 +1469,9 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
* server.
|
||||
*/
|
||||
private void showServerStatus() {
|
||||
if (accountSetupBinding == null) return;
|
||||
if (accountSetupBinding == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mServerStatusIcon == NO_ICON && EMPTY_STRING.equals(mServerStatusText)) {
|
||||
accountSetupBinding.serverStatusText.setVisibility(View.INVISIBLE);
|
||||
|
@ -1486,32 +1595,67 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (requestCode == REQUEST_CODE_QR_SCAN) {
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
private final ScheduledExecutorService loginFlowExecutorService = Executors.newSingleThreadScheduledExecutor();
|
||||
private boolean isLoginProcessCompleted = false;
|
||||
|
||||
String result = data.getStringExtra("com.blikoon.qrcodescanner.got_qr_scan_relult");
|
||||
|
||||
if (result == null || !result.startsWith(getString(R.string.login_data_own_scheme))) {
|
||||
mServerStatusIcon = R.drawable.ic_alert;
|
||||
mServerStatusText = "QR Code could not be read!";
|
||||
showServerStatus();
|
||||
return;
|
||||
private void poolLogin(PlainClient client) {
|
||||
loginFlowExecutorService.scheduleAtFixedRate(() -> {
|
||||
if (!isLoginProcessCompleted) {
|
||||
performLoginFlowV2(client);
|
||||
}
|
||||
}, 0, 30, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
if (!getResources().getBoolean(R.bool.multiaccount_support) &&
|
||||
accountManager.getAccounts().length == 1) {
|
||||
Toast.makeText(this, R.string.no_mutliple_accounts_allowed, Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
parseAndLoginFromWebView(result);
|
||||
}
|
||||
private void performLoginFlowV2(PlainClient client) {
|
||||
String postRequestUrl = baseUrl + "/poll";
|
||||
|
||||
RequestBody requestBody = new FormBody.Builder()
|
||||
.add("token", token)
|
||||
.build();
|
||||
|
||||
PostMethod post = new PostMethod(postRequestUrl, false, requestBody);
|
||||
int status = post.execute(client);
|
||||
String response = post.getResponseBodyAsString();
|
||||
|
||||
Log_OC.d(TAG, "performLoginFlowV2 status: " + status);
|
||||
Log_OC.d(TAG, "performLoginFlowV2 response: " + response);
|
||||
|
||||
if (!response.isEmpty()) {
|
||||
runOnUiThread(() -> completeLoginFlow(response, status));
|
||||
}
|
||||
}
|
||||
|
||||
private void completeLoginFlow(String response, int status) {
|
||||
try {
|
||||
JSONObject jsonObject = new JSONObject(response);
|
||||
|
||||
String server = jsonObject.getString("server");
|
||||
String loginName = jsonObject.getString("loginName");
|
||||
String appPassword = jsonObject.getString("appPassword");
|
||||
|
||||
LoginUrlInfo loginUrlInfo = new LoginUrlInfo();
|
||||
loginUrlInfo.serverAddress = server;
|
||||
loginUrlInfo.username = loginName;
|
||||
loginUrlInfo.password = appPassword;
|
||||
|
||||
isLoginProcessCompleted = (status == 200 && !server.isEmpty() && !loginName.isEmpty() && !appPassword.isEmpty());
|
||||
|
||||
if (accountSetupBinding != null) {
|
||||
accountSetupBinding.hostUrlInput.setText("");
|
||||
}
|
||||
mServerInfo.mBaseUrl = AuthenticatorUrlUtils.INSTANCE.normalizeUrlSuffix(loginUrlInfo.serverAddress);
|
||||
webViewUser = loginUrlInfo.username;
|
||||
webViewPassword = loginUrlInfo.password;
|
||||
} catch (Exception e) {
|
||||
Log_OC.d(TAG, "Error caught at completeLoginFlow: " + e);
|
||||
mServerStatusIcon = R.drawable.ic_alert;
|
||||
mServerStatusText = getString(R.string.qr_could_not_be_read);
|
||||
showServerStatus();
|
||||
}
|
||||
|
||||
checkOcServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from SslValidatorDialog when a new server certificate was correctly saved.
|
||||
*/
|
||||
|
|
|
@ -650,10 +650,22 @@ public final class DisplayUtils {
|
|||
*/
|
||||
public static Snackbar showSnackMessage(Activity activity, String message) {
|
||||
final Snackbar snackbar = Snackbar.make(activity.findViewById(android.R.id.content), message, Snackbar.LENGTH_LONG);
|
||||
var fab = findFABView(activity);
|
||||
if (fab != null && fab.getVisibility() == View.VISIBLE) {
|
||||
snackbar.setAnchorView(fab);
|
||||
}
|
||||
snackbar.show();
|
||||
return snackbar;
|
||||
}
|
||||
|
||||
private static View findFABView(Activity activity) {
|
||||
return activity.findViewById(R.id.fab_main);
|
||||
}
|
||||
|
||||
private static View findFABView(View view) {
|
||||
return view.findViewById(R.id.fab_main);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a temporary message in a {@link Snackbar} bound to the given view.
|
||||
*
|
||||
|
@ -663,6 +675,10 @@ public final class DisplayUtils {
|
|||
*/
|
||||
public static Snackbar showSnackMessage(View view, @StringRes int messageResource) {
|
||||
final Snackbar snackbar = Snackbar.make(view, messageResource, Snackbar.LENGTH_LONG);
|
||||
var fab = findFABView(view.getRootView());
|
||||
if (fab != null && fab.getVisibility() == View.VISIBLE) {
|
||||
snackbar.setAnchorView(fab);
|
||||
}
|
||||
snackbar.show();
|
||||
return snackbar;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
<!--
|
||||
~ Nextcloud - Android Client
|
||||
~
|
||||
~ SPDX-FileCopyrightText: 2023-2024 Nextcloud GmbH, all rights reserved
|
||||
~ SPDX-FileCopyrightText: 2023-2024 Tobias Kaminsky <tobias@kaminsky.me>
|
||||
~ SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
~ SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH <https://nextcloud.com/trademarks/>
|
||||
~ SPDX-License-Identifier: LicenseRef-NextcloudTrademarks
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
<!--
|
||||
~ Nextcloud - Android Client
|
||||
~
|
||||
~ SPDX-FileCopyrightText: 2023-2024 Nextcloud GmbH, all rights reserved
|
||||
~ SPDX-FileCopyrightText: 2021 Tobias Kaminsky <tobias@kaminsky.me>
|
||||
~ SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
~ SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH <https://nextcloud.com/trademarks/>
|
||||
~ SPDX-License-Identifier: LicenseRef-NextcloudTrademarks
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="200dp"
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
<string name="assistant_screen_top_bar_title">Yardımcı</string>
|
||||
<string name="assistant_screen_unknown_task_status_text">Bilinmiyor</string>
|
||||
<string name="assistant_task_detail_screen_input_button_title">Giriş</string>
|
||||
<string name="assistant_task_detail_screen_output_button_title">Çıktı</string>
|
||||
<string name="assistant_task_detail_screen_output_button_title">Çıkış</string>
|
||||
<string name="associated_account_not_found">İlişkili hesap bulunamadı!</string>
|
||||
<string name="auth_access_failed">Erişilemedi: %1$s</string>
|
||||
<string name="auth_account_does_not_exist">Aygıt üzerinde henüz bu hesap açılmamış</string>
|
||||
|
@ -172,6 +172,7 @@
|
|||
<string name="confirmation_remove_folder_alert">%1$s klasörünü ve içindekileri silmek istediğinize emin misiniz?</string>
|
||||
<string name="confirmation_remove_folders_alert">Seçilmiş ögeleri ve içindekileri silmek istediğinize emin misiniz?</string>
|
||||
<string name="confirmation_remove_local">Yalnızca yerel</string>
|
||||
<string name="conflict_dialog_error">Çakışma çözümleme penceresi oluşturulamadı</string>
|
||||
<string name="conflict_file_headline">%1$s dosyası çakışıyor</string>
|
||||
<string name="conflict_local_file">Yerel dosya</string>
|
||||
<string name="conflict_message_description">İki sürümü de saklamayı seçerseniz, yerel dosyanın adına bir numara eklenecek.</string>
|
||||
|
|
|
@ -254,7 +254,7 @@
|
|||
<string name="drawer_community">Спільнота</string>
|
||||
<string name="drawer_header_background">Зображення тла верхньої панелі</string>
|
||||
<string name="drawer_item_activities">Події</string>
|
||||
<string name="drawer_item_all_files">Усі файли</string>
|
||||
<string name="drawer_item_all_files">Усі документи</string>
|
||||
<string name="drawer_item_assistant">Помічник</string>
|
||||
<string name="drawer_item_favorites">Із зірочкою</string>
|
||||
<string name="drawer_item_gallery">Зображення та відео</string>
|
||||
|
@ -354,7 +354,7 @@
|
|||
<string name="file_list_empty_favorite_headline">Поки що ви нічого не позначили зірочкою</string>
|
||||
<string name="file_list_empty_favorites_filter_list">Тут можна буде знайти файли та каталоги, які ви позначити зірочкою.</string>
|
||||
<string name="file_list_empty_gallery">Не знайдено ані зображень, ані відео</string>
|
||||
<string name="file_list_empty_headline">Тут немає файлів</string>
|
||||
<string name="file_list_empty_headline">Тут відсутні файли</string>
|
||||
<string name="file_list_empty_headline_search">Жодного збігу у цьому каталозі</string>
|
||||
<string name="file_list_empty_headline_server_search">Жодного збігу</string>
|
||||
<string name="file_list_empty_moving">Тут нічого немає. Ви можете створити каталог.</string>
|
||||
|
|
Loading…
Reference in New Issue