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