parent
a7843af306
commit
fa90b746b2
@ -1,5 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.qr;
|
|
||||||
|
|
||||||
public interface ScanListener {
|
|
||||||
public void onQrDataFound(String data);
|
|
||||||
}
|
|
@ -1,125 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.qr;
|
|
||||||
|
|
||||||
import android.content.res.Configuration;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.google.zxing.BinaryBitmap;
|
|
||||||
import com.google.zxing.ChecksumException;
|
|
||||||
import com.google.zxing.DecodeHintType;
|
|
||||||
import com.google.zxing.FormatException;
|
|
||||||
import com.google.zxing.NotFoundException;
|
|
||||||
import com.google.zxing.PlanarYUVLuminanceSource;
|
|
||||||
import com.google.zxing.Result;
|
|
||||||
import com.google.zxing.common.HybridBinarizer;
|
|
||||||
import com.google.zxing.qrcode.QRCodeReader;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.components.camera.CameraView;
|
|
||||||
import org.thoughtcrime.securesms.components.camera.CameraView.PreviewFrame;
|
|
||||||
import org.session.libsignal.utilities.Log;
|
|
||||||
import org.session.libsession.utilities.Util;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
|
|
||||||
public class ScanningThread extends Thread implements CameraView.PreviewCallback {
|
|
||||||
|
|
||||||
private static final String TAG = ScanningThread.class.getSimpleName();
|
|
||||||
|
|
||||||
private final QRCodeReader reader = new QRCodeReader();
|
|
||||||
private final AtomicReference<ScanListener> scanListener = new AtomicReference<>();
|
|
||||||
private final Map<DecodeHintType, String> hints = new HashMap<>();
|
|
||||||
|
|
||||||
private boolean scanning = true;
|
|
||||||
private PreviewFrame previewFrame;
|
|
||||||
|
|
||||||
public void setCharacterSet(String characterSet) {
|
|
||||||
hints.put(DecodeHintType.CHARACTER_SET, characterSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setScanListener(ScanListener scanListener) {
|
|
||||||
this.scanListener.set(scanListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPreviewFrame(@NonNull PreviewFrame previewFrame) {
|
|
||||||
try {
|
|
||||||
synchronized (this) {
|
|
||||||
this.previewFrame = previewFrame;
|
|
||||||
this.notify();
|
|
||||||
}
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
while (true) {
|
|
||||||
PreviewFrame ourFrame;
|
|
||||||
|
|
||||||
synchronized (this) {
|
|
||||||
while (scanning && previewFrame == null) {
|
|
||||||
Util.wait(this, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!scanning) return;
|
|
||||||
else ourFrame = previewFrame;
|
|
||||||
|
|
||||||
previewFrame = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
String data = getScannedData(ourFrame.getData(), ourFrame.getWidth(), ourFrame.getHeight(), ourFrame.getOrientation());
|
|
||||||
ScanListener scanListener = this.scanListener.get();
|
|
||||||
|
|
||||||
if (data != null && scanListener != null) {
|
|
||||||
scanListener.onQrDataFound(data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stopScanning() {
|
|
||||||
synchronized (this) {
|
|
||||||
scanning = false;
|
|
||||||
notify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private @Nullable String getScannedData(byte[] data, int width, int height, int orientation) {
|
|
||||||
try {
|
|
||||||
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
|
|
||||||
byte[] rotatedData = new byte[data.length];
|
|
||||||
|
|
||||||
for (int y = 0; y < height; y++) {
|
|
||||||
for (int x = 0; x < width; x++) {
|
|
||||||
rotatedData[x * height + height - y - 1] = data[x + y * width];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int tmp = width;
|
|
||||||
width = height;
|
|
||||||
height = tmp;
|
|
||||||
data = rotatedData;
|
|
||||||
}
|
|
||||||
|
|
||||||
PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(data, width, height,
|
|
||||||
0, 0, width, height,
|
|
||||||
false);
|
|
||||||
|
|
||||||
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
|
|
||||||
Result result = reader.decode(bitmap, hints);
|
|
||||||
|
|
||||||
if (result != null) return result.getText();
|
|
||||||
|
|
||||||
} catch (NullPointerException | ChecksumException | FormatException | IndexOutOfBoundsException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
} catch (NotFoundException e) {
|
|
||||||
// Thanks ZXing...
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.util
|
|
||||||
|
|
||||||
import android.content.res.Configuration
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.LinearLayout
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import network.loki.messenger.databinding.FragmentScanQrCodeBinding
|
|
||||||
import org.thoughtcrime.securesms.qr.ScanListener
|
|
||||||
import org.thoughtcrime.securesms.qr.ScanningThread
|
|
||||||
|
|
||||||
class ScanQRCodeFragment : Fragment() {
|
|
||||||
private lateinit var binding: FragmentScanQrCodeBinding
|
|
||||||
private val scanningThread = ScanningThread()
|
|
||||||
var scanListener: ScanListener? = null
|
|
||||||
set(value) { field = value; scanningThread.setScanListener(scanListener) }
|
|
||||||
var message: CharSequence = ""
|
|
||||||
|
|
||||||
override fun onCreateView(layoutInflater: LayoutInflater, viewGroup: ViewGroup?, bundle: Bundle?): View {
|
|
||||||
binding = FragmentScanQrCodeBinding.inflate(layoutInflater, viewGroup, false)
|
|
||||||
return binding.root
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, bundle: Bundle?) {
|
|
||||||
super.onViewCreated(view, bundle)
|
|
||||||
when (resources.configuration.orientation) {
|
|
||||||
Configuration.ORIENTATION_LANDSCAPE -> binding.overlayView.orientation = LinearLayout.HORIZONTAL
|
|
||||||
else -> binding.overlayView.orientation = LinearLayout.VERTICAL
|
|
||||||
}
|
|
||||||
binding.messageTextView.text = message
|
|
||||||
binding.messageTextView.isVisible = message.isNotEmpty()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
binding.cameraView.onResume()
|
|
||||||
binding.cameraView.setPreviewCallback(scanningThread)
|
|
||||||
try {
|
|
||||||
scanningThread.start()
|
|
||||||
} catch (exception: Exception) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
scanningThread.setScanListener(scanListener)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onConfigurationChanged(newConfiguration: Configuration) {
|
|
||||||
super.onConfigurationChanged(newConfiguration)
|
|
||||||
binding.cameraView.onPause()
|
|
||||||
when (newConfiguration.orientation) {
|
|
||||||
Configuration.ORIENTATION_LANDSCAPE -> binding.overlayView.orientation = LinearLayout.HORIZONTAL
|
|
||||||
else -> binding.overlayView.orientation = LinearLayout.VERTICAL
|
|
||||||
}
|
|
||||||
binding.cameraView.onResume()
|
|
||||||
binding.cameraView.setPreviewCallback(scanningThread)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPause() {
|
|
||||||
super.onPause()
|
|
||||||
this.binding.cameraView.onPause()
|
|
||||||
this.scanningThread.stopScanning()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.util
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import com.squareup.phrase.Phrase
|
|
||||||
import network.loki.messenger.R
|
|
||||||
import network.loki.messenger.databinding.FragmentScanQrCodePlaceholderBinding
|
|
||||||
import org.session.libsession.utilities.StringSubstitutionConstants.APP_NAME_KEY
|
|
||||||
|
|
||||||
class ScanQRCodePlaceholderFragment: Fragment() {
|
|
||||||
private lateinit var binding: FragmentScanQrCodePlaceholderBinding
|
|
||||||
var delegate: ScanQRCodePlaceholderFragmentDelegate? = null
|
|
||||||
|
|
||||||
override fun onCreateView(layoutInflater: LayoutInflater, viewGroup: ViewGroup?, bundle: Bundle?): View {
|
|
||||||
binding = FragmentScanQrCodePlaceholderBinding.inflate(layoutInflater, viewGroup, false)
|
|
||||||
return binding.root
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
binding.grantCameraAccessButton.setOnClickListener { delegate?.requestCameraAccess() }
|
|
||||||
|
|
||||||
binding.needCameraPermissionsTV.text = Phrase.from(context, R.string.cameraGrantAccessQr)
|
|
||||||
.put(APP_NAME_KEY, getString(R.string.app_name))
|
|
||||||
.format()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ScanQRCodePlaceholderFragmentDelegate {
|
|
||||||
fun requestCameraAccess()
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<FrameLayout
|
|
||||||
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">
|
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.components.camera.CameraView
|
|
||||||
android:id="@+id/cameraView"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
app:camera="0" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/overlayView"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:weightSum="3" >
|
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.components.ShapeScrim
|
|
||||||
android:layout_weight="2"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/messageTextView"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:padding="@dimen/very_large_spacing"
|
|
||||||
android:gravity="center"
|
|
||||||
android:text="@string/messageNewDescriptionMobile"
|
|
||||||
android:background="?android:windowBackground"
|
|
||||||
android:textSize="@dimen/small_font_size"
|
|
||||||
android:textColor="?android:textColorTertiary" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
@ -1,36 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<RelativeLayout
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:gravity="center_horizontal"
|
|
||||||
android:layout_centerInParent="true">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/needCameraPermissionsTV"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginLeft="@dimen/very_large_spacing"
|
|
||||||
android:layout_marginRight="@dimen/very_large_spacing"
|
|
||||||
android:textSize="@dimen/small_font_size"
|
|
||||||
android:textAlignment="center"
|
|
||||||
android:text="@string/cameraGrantAccessQr" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
style="@style/Widget.Session.Button.Common.ProminentOutline"
|
|
||||||
android:id="@+id/grantCameraAccessButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="@dimen/medium_button_height"
|
|
||||||
android:layout_marginTop="@dimen/medium_spacing"
|
|
||||||
android:paddingLeft="@dimen/medium_spacing"
|
|
||||||
android:paddingRight="@dimen/medium_spacing"
|
|
||||||
android:text="@string/cameraGrantAccess" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<FrameLayout
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/fragmentContainer"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent" />
|
|
Loading…
Reference in New Issue