diff --git a/mastodon/build.gradle b/mastodon/build.gradle
index c50342df49..133af60a49 100644
--- a/mastodon/build.gradle
+++ b/mastodon/build.gradle
@@ -96,6 +96,7 @@ dependencies {
implementation 'com.squareup:otto:1.3.8'
implementation 'de.psdev:async-otto:1.0.3'
implementation 'com.google.zxing:core:3.5.3'
+ implementation 'com.github.markusfisch:BarcodeScannerView:1.6.0'
implementation 'org.microg:safe-parcel:1.5.0'
implementation 'org.parceler:parceler-api:1.1.12'
annotationProcessor 'org.parceler:parceler:1.1.12'
diff --git a/mastodon/src/main/AndroidManifest.xml b/mastodon/src/main/AndroidManifest.xml
index 7a97cfcee7..fb661ca008 100644
--- a/mastodon/src/main/AndroidManifest.xml
+++ b/mastodon/src/main/AndroidManifest.xml
@@ -9,6 +9,9 @@
+
+
+
@@ -79,6 +82,7 @@
+
diff --git a/mastodon/src/main/java/org/joinmastodon/android/QrCodeScanActivity.java b/mastodon/src/main/java/org/joinmastodon/android/QrCodeScanActivity.java
new file mode 100644
index 0000000000..271b84cf19
--- /dev/null
+++ b/mastodon/src/main/java/org/joinmastodon/android/QrCodeScanActivity.java
@@ -0,0 +1,98 @@
+package org.joinmastodon.android;
+
+import android.Manifest;
+import android.app.Activity;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
+import android.provider.Settings;
+import android.view.HapticFeedbackConstants;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+
+import org.joinmastodon.android.ui.M3AlertDialogBuilder;
+import org.joinmastodon.android.ui.utils.UiUtils;
+
+import de.markusfisch.android.barcodescannerview.widget.BarcodeScannerView;
+
+public class QrCodeScanActivity extends Activity{
+ private static final int PERMISSION_RESULT=65537;
+ private BarcodeScannerView scannerView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState){
+ super.onCreate(savedInstanceState);
+ UiUtils.setUserPreferredTheme(this);
+ setContentView(R.layout.activity_qr_scan);
+
+ if(this.checkSelfPermission(Manifest.permission.CAMERA)!=PackageManager.PERMISSION_GRANTED){
+ requestPermissions(new String[]{Manifest.permission.CAMERA}, PERMISSION_RESULT);
+ }
+
+ findViewById(R.id.dismiss).setOnClickListener(view -> finish());
+ scannerView=findViewById(R.id.scanner);
+ scannerView.setCropRatio(.75f);
+ scannerView.setOnBarcodeListener(barcode -> {
+ vibrate(scannerView);
+ Intent result=new Intent();
+ result.putExtra("barcode", barcode.getText());
+ setResult(RESULT_OK, result);
+ finish();
+ return false;
+ });
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults){
+ if(requestCode==PERMISSION_RESULT){
+ if(grantResults[0]==PackageManager.PERMISSION_GRANTED){
+ scannerView.openAsync();
+ }else if(!this.shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)){
+ new M3AlertDialogBuilder(this)
+ .setTitle(R.string.permission_required)
+ .setMessage(R.string.storage_permission_to_download)
+ .setPositiveButton(R.string.open_settings, (dialog, which)->this.startActivity(new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", this.getPackageName(), null))))
+ .setNegativeButton(R.string.cancel, (dialogInterface, i) -> finish())
+ .setOnCancelListener(dialogInterface -> finish())
+ .show();
+ }
+ }
+ }
+
+
+ private static void vibrate(View v) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ v.performHapticFeedback(HapticFeedbackConstants.CONFIRM);
+ return;
+ }
+
+ Vibrator vibrator=v.getContext().getSystemService(Vibrator.class);
+
+ if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
+ vibrator.vibrate(VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ VibrationEffect effect=VibrationEffect.createOneShot(75L, 128);
+ vibrator.vibrate(effect);
+ } else {
+ vibrator.vibrate(75L);
+ }
+ }
+
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ scannerView.openAsync();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ scannerView.close();
+ }
+}
diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileQrCodeFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileQrCodeFragment.java
index 32094a6410..124f6f12c3 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileQrCodeFragment.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileQrCodeFragment.java
@@ -53,7 +53,6 @@
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
-import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedDispatcher;
import com.google.zxing.BarcodeFormat;
@@ -64,6 +63,7 @@
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.joinmastodon.android.MainActivity;
+import org.joinmastodon.android.QrCodeScanActivity;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.MastodonAPIController;
import org.joinmastodon.android.api.session.AccountSessionManager;
@@ -127,7 +127,11 @@ public void onCreate(Bundle savedInstanceState){
accountID=getArguments().getString("account");
account=Parcels.unwrap(getArguments().getParcelable("targetAccount"));
setCancelable(false);
- scannerIntent=BarcodeScanner.createIntent(Barcode.FORMAT_QR_CODE, false, true);
+
+ scannerIntent=GmsClient.isGooglePlayServicesAvailable(getActivity())
+ ? BarcodeScanner.createIntent(Barcode.FORMAT_QR_CODE, false, true)
+ : new Intent(getActivity(), QrCodeScanActivity.class);
+
}
@Override
@@ -265,11 +269,9 @@ public void dismiss(){
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
- if(GmsClient.isGooglePlayServicesAvailable(getActivity())){
- MenuItem item=menu.add(0, 0, 0, R.string.scan_qr_code);
- item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
- item.setIcon(R.drawable.ic_qr_code_scanner_24px);
- }
+ MenuItem item=menu.add(0, 0, 0, R.string.scan_qr_code);
+ item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+ item.setIcon(R.drawable.ic_qr_code_scanner_24px);
}
@Override
@@ -330,11 +332,15 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data){
- if(requestCode==SCAN_RESULT && resultCode==Activity.RESULT_OK && BarcodeScanner.isValidResult(data)){
- Barcode code=BarcodeScanner.getResult(data);
+ if(requestCode==SCAN_RESULT && resultCode==Activity.RESULT_OK){
+ String code=data.getStringExtra("barcode");
+ if(BarcodeScanner.isValidResult(data)){
+ Barcode barcode=BarcodeScanner.getResult(data);
+ code=barcode.rawValue;
+ }
if(code!=null){
- if(code.rawValue.startsWith("https:") || code.rawValue.startsWith("http:")){
- ((MainActivity)getActivity()).handleURL(Uri.parse(code.rawValue), accountID);
+ if(code.startsWith("https:") || code.startsWith("http:")){
+ ((MainActivity)getActivity()).handleURL(Uri.parse(code), accountID);
dismiss();
}else{
Toast.makeText(themeWrapper, R.string.link_not_supported, Toast.LENGTH_SHORT).show();
diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/DiscoverFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/DiscoverFragment.java
index ca93bdd45d..f093672af2 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/DiscoverFragment.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/DiscoverFragment.java
@@ -17,6 +17,7 @@
import android.widget.Toast;
import org.joinmastodon.android.MainActivity;
+import org.joinmastodon.android.QrCodeScanActivity;
import org.joinmastodon.android.R;
import org.joinmastodon.android.fragments.ScrollableToTop;
import org.joinmastodon.android.googleservices.GmsClient;
@@ -70,7 +71,9 @@ public void onCreate(Bundle savedInstanceState){
setRetainInstance(true);
accountID=getArguments().getString("account");
- scannerIntent=BarcodeScanner.createIntent(Barcode.FORMAT_QR_CODE, false, true);
+ scannerIntent=GmsClient.isGooglePlayServicesAvailable(getActivity())
+ ? BarcodeScanner.createIntent(Barcode.FORMAT_QR_CODE, false, true)
+ : new Intent(getActivity(), QrCodeScanActivity.class);
}
@Nullable
@@ -186,11 +189,7 @@ public void onTabReselected(TabLayout.Tab tab){
searchView.setVisibility(View.VISIBLE);
}
searchScanQR=view.findViewById(R.id.search_scan_qr);
- if(!GmsClient.isGooglePlayServicesAvailable(getActivity())){
- searchScanQR.setVisibility(View.GONE);
- }else{
- searchScanQR.setOnClickListener(v->openQrScanner());
- }
+ searchScanQR.setOnClickListener(v->openQrScanner());
View searchWrap=view.findViewById(R.id.search_wrap);
searchWrap.setOutlineProvider(OutlineProviders.roundedRect(28));
@@ -280,11 +279,15 @@ public void onFragmentResult(int reqCode, boolean success, Bundle result){
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data){
- if(requestCode==SCAN_RESULT && resultCode==Activity.RESULT_OK && BarcodeScanner.isValidResult(data)){
- Barcode code=BarcodeScanner.getResult(data);
+ if(requestCode==SCAN_RESULT && resultCode==Activity.RESULT_OK){
+ String code=data.getStringExtra("barcode");
+ if(BarcodeScanner.isValidResult(data)){
+ Barcode barcode=BarcodeScanner.getResult(data);
+ code=barcode.rawValue;
+ }
if(code!=null){
- if(code.rawValue.startsWith("https:") || code.rawValue.startsWith("http:")){
- ((MainActivity)getActivity()).handleURL(Uri.parse(code.rawValue), accountID);
+ if(code.startsWith("https:") || code.startsWith("http:")){
+ ((MainActivity)getActivity()).handleURL(Uri.parse(code), accountID);
}else{
Toast.makeText(getActivity(), R.string.link_not_supported, Toast.LENGTH_SHORT).show();
}
diff --git a/mastodon/src/main/res/layout/activity_qr_scan.xml b/mastodon/src/main/res/layout/activity_qr_scan.xml
new file mode 100644
index 0000000000..6fc27c3acd
--- /dev/null
+++ b/mastodon/src/main/res/layout/activity_qr_scan.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
diff --git a/mastodon/src/main/res/values/strings.xml b/mastodon/src/main/res/values/strings.xml
index a7967c8861..6cd316464a 100644
--- a/mastodon/src/main/res/values/strings.xml
+++ b/mastodon/src/main/res/values/strings.xml
@@ -233,6 +233,7 @@
Download
Permission required
The app needs access to your storage to save this file.
+ The app needs access to your camera to scan.
Open settings
Error saving file
File saved
diff --git a/settings.gradle b/settings.gradle
index ff7f3f3b60..c8ea317756 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -4,6 +4,7 @@ dependencyResolutionManagement {
google()
mavenCentral()
mavenLocal()
+ maven { url 'https://jitpack.io' }
}
}
rootProject.name = "Mastodon"