aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/de/pixart/messenger/ui
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/de/pixart/messenger/ui')
-rw-r--r--src/main/java/de/pixart/messenger/ui/ConversationActivity.java20
-rw-r--r--src/main/java/de/pixart/messenger/ui/ConversationsOverviewFragment.java5
-rw-r--r--src/main/java/de/pixart/messenger/ui/OmemoActivity.java9
-rw-r--r--src/main/java/de/pixart/messenger/ui/ScanActivity.java292
-rw-r--r--src/main/java/de/pixart/messenger/ui/TrustKeysActivity.java4
-rw-r--r--src/main/java/de/pixart/messenger/ui/UriHandlerActivity.java82
-rw-r--r--src/main/java/de/pixart/messenger/ui/VerifyOTRActivity.java12
-rw-r--r--src/main/java/de/pixart/messenger/ui/service/CameraManager.java305
-rw-r--r--src/main/java/de/pixart/messenger/ui/widget/ScannerView.java158
9 files changed, 849 insertions, 38 deletions
diff --git a/src/main/java/de/pixart/messenger/ui/ConversationActivity.java b/src/main/java/de/pixart/messenger/ui/ConversationActivity.java
index b80469649..2783a4b1f 100644
--- a/src/main/java/de/pixart/messenger/ui/ConversationActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/ConversationActivity.java
@@ -312,6 +312,7 @@ public class ConversationActivity extends XmppActivity implements OnConversation
}
private boolean processViewIntent(Intent intent) {
+ Log.d(Config.LOGTAG,"process view intent");
String uuid = intent.getStringExtra(EXTRA_CONVERSATION);
Conversation conversation = uuid != null ? xmppConnectionService.findConversationByUuid(uuid) : null;
if (conversation == null) {
@@ -323,8 +324,12 @@ public class ConversationActivity extends XmppActivity implements OnConversation
}
@Override
+ public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
+ UriHandlerActivity.onRequestPermissionResult(this, requestCode, grantResults);
+ }
+
+ @Override
public void onActivityResult(int requestCode, int resultCode, final Intent data) {
- Log.d(Config.LOGTAG, "on activity result");
if (resultCode == RESULT_OK) {
handlePositiveActivityResult(requestCode, data);
} else {
@@ -368,7 +373,12 @@ public class ConversationActivity extends XmppActivity implements OnConversation
this.getFragmentManager().addOnBackStackChangedListener(this::showDialogsIfMainIsOverview);
this.initializeFragments();
this.invalidateActionBarTitle();
- final Intent intent = getIntent();
+ final Intent intent;
+ if (savedInstanceState == null) {
+ intent = getIntent();
+ } else {
+ intent = savedInstanceState.getParcelable("intent");
+ }
if (isViewIntent(intent)) {
pendingViewIntent.push(intent);
setIntent(createLauncherIntent(this));
@@ -451,6 +461,12 @@ public class ConversationActivity extends XmppActivity implements OnConversation
}
@Override
+ public void onSaveInstanceState(Bundle savedInstanceState) {
+ savedInstanceState.putParcelable("intent", getIntent());
+ super.onSaveInstanceState(savedInstanceState);
+ }
+
+ @Override
protected void onStart() {
final int theme = findTheme();
if (this.mTheme != theme) {
diff --git a/src/main/java/de/pixart/messenger/ui/ConversationsOverviewFragment.java b/src/main/java/de/pixart/messenger/ui/ConversationsOverviewFragment.java
index 35e1e02b7..476cc267d 100644
--- a/src/main/java/de/pixart/messenger/ui/ConversationsOverviewFragment.java
+++ b/src/main/java/de/pixart/messenger/ui/ConversationsOverviewFragment.java
@@ -144,7 +144,10 @@ public class ConversationsOverviewFragment extends XmppFragment {
@Override
public void onSaveInstanceState(Bundle bundle) {
super.onSaveInstanceState(bundle);
- bundle.putParcelable(STATE_SCROLL_POSITION, getScrollState());
+ ScrollState scrollState = getScrollState();
+ if (scrollState != null) {
+ bundle.putParcelable(STATE_SCROLL_POSITION, scrollState);
+ }
}
private ScrollState getScrollState() {
diff --git a/src/main/java/de/pixart/messenger/ui/OmemoActivity.java b/src/main/java/de/pixart/messenger/ui/OmemoActivity.java
index a549c76e3..3406d0c46 100644
--- a/src/main/java/de/pixart/messenger/ui/OmemoActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/OmemoActivity.java
@@ -15,7 +15,6 @@ import android.widget.TextView;
import android.widget.Toast;
import java.security.cert.X509Certificate;
-import java.util.Arrays;
import de.pixart.messenger.Config;
import de.pixart.messenger.R;
@@ -25,8 +24,6 @@ import de.pixart.messenger.databinding.ContactKeyBinding;
import de.pixart.messenger.entities.Account;
import de.pixart.messenger.utils.CryptoHelper;
import de.pixart.messenger.utils.XmppUri;
-import de.pixart.messenger.utils.zxing.IntentIntegrator;
-import de.pixart.messenger.utils.zxing.IntentResult;
public abstract class OmemoActivity extends XmppActivity {
@@ -74,7 +71,7 @@ public abstract class OmemoActivity extends XmppActivity {
copyOmemoFingerprint(mSelectedFingerprint);
break;
case R.id.verify_scan:
- new IntentIntegrator(this).initiateScan(Arrays.asList("AZTEC","QR_CODE"));
+ //new IntentIntegrator(this).initiateScan(Arrays.asList("AZTEC","QR_CODE"));
break;
}
return true;
@@ -82,7 +79,7 @@ public abstract class OmemoActivity extends XmppActivity {
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
- IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
+ /*IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
if (scanResult != null && scanResult.getFormatName() != null) {
String data = scanResult.getContents();
XmppUri uri = new XmppUri(data);
@@ -91,7 +88,7 @@ public abstract class OmemoActivity extends XmppActivity {
} else {
this.mPendingFingerprintVerificationUri =uri;
}
- }
+ }*/
}
protected abstract void processFingerprintVerification(XmppUri uri);
diff --git a/src/main/java/de/pixart/messenger/ui/ScanActivity.java b/src/main/java/de/pixart/messenger/ui/ScanActivity.java
new file mode 100644
index 000000000..d44f50512
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/ui/ScanActivity.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2012-2015 the original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package de.pixart.messenger.ui;
+
+import android.Manifest;
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.SurfaceTexture;
+import android.hardware.Camera;
+import android.hardware.Camera.CameraInfo;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
+import android.os.Vibrator;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.content.ContextCompat;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Surface;
+import android.view.TextureView;
+import android.view.TextureView.SurfaceTextureListener;
+import android.view.View;
+import android.view.WindowManager;
+
+import com.google.zxing.BinaryBitmap;
+import com.google.zxing.DecodeHintType;
+import com.google.zxing.PlanarYUVLuminanceSource;
+import com.google.zxing.ReaderException;
+import com.google.zxing.Result;
+import com.google.zxing.ResultPointCallback;
+import com.google.zxing.common.HybridBinarizer;
+import com.google.zxing.qrcode.QRCodeReader;
+
+import java.util.EnumMap;
+import java.util.Map;
+
+import de.pixart.messenger.Config;
+import de.pixart.messenger.R;
+import de.pixart.messenger.ui.service.CameraManager;
+import de.pixart.messenger.ui.widget.ScannerView;
+
+/**
+ * @author Andreas Schildbach
+ */
+@SuppressWarnings("deprecation")
+public final class ScanActivity extends Activity implements SurfaceTextureListener, ActivityCompat.OnRequestPermissionsResultCallback {
+ public static final String INTENT_EXTRA_RESULT = "result";
+
+ private static final long VIBRATE_DURATION = 50L;
+ private static final long AUTO_FOCUS_INTERVAL_MS = 2500L;
+ private static boolean DISABLE_CONTINUOUS_AUTOFOCUS = Build.MODEL.equals("GT-I9100") // Galaxy S2
+ || Build.MODEL.equals("SGH-T989") // Galaxy S2
+ || Build.MODEL.equals("SGH-T989D") // Galaxy S2 X
+ || Build.MODEL.equals("SAMSUNG-SGH-I727") // Galaxy S2 Skyrocket
+ || Build.MODEL.equals("GT-I9300") // Galaxy S3
+ || Build.MODEL.equals("GT-N7000"); // Galaxy Note
+ private final CameraManager cameraManager = new CameraManager();
+ private ScannerView scannerView;
+ private TextureView previewView;
+ private volatile boolean surfaceCreated = false;
+ private Vibrator vibrator;
+ private HandlerThread cameraThread;
+ private volatile Handler cameraHandler;
+ private final Runnable closeRunnable = new Runnable() {
+ @Override
+ public void run() {
+ cameraHandler.removeCallbacksAndMessages(null);
+ cameraManager.close();
+ }
+ };
+ private final Runnable fetchAndDecodeRunnable = new Runnable() {
+ private final QRCodeReader reader = new QRCodeReader();
+ private final Map<DecodeHintType, Object> hints = new EnumMap<DecodeHintType, Object>(DecodeHintType.class);
+
+ @Override
+ public void run() {
+ cameraManager.requestPreviewFrame((data, camera) -> decode(data));
+ }
+
+ private void decode(final byte[] data) {
+ final PlanarYUVLuminanceSource source = cameraManager.buildLuminanceSource(data);
+ final BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
+
+ try {
+ hints.put(DecodeHintType.NEED_RESULT_POINT_CALLBACK, (ResultPointCallback) dot -> runOnUiThread(() -> scannerView.addDot(dot)));
+ final Result scanResult = reader.decode(bitmap, hints);
+
+ runOnUiThread(() -> handleResult(scanResult));
+ } catch (final ReaderException x) {
+ // retry
+ cameraHandler.post(fetchAndDecodeRunnable);
+ } finally {
+ reader.reset();
+ }
+ }
+ };
+ private final Runnable openRunnable = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ final Camera camera = cameraManager.open(previewView, displayRotation(), !DISABLE_CONTINUOUS_AUTOFOCUS);
+
+ final Rect framingRect = cameraManager.getFrame();
+ final RectF framingRectInPreview = new RectF(cameraManager.getFramePreview());
+ framingRectInPreview.offsetTo(0, 0);
+ final boolean cameraFlip = cameraManager.getFacing() == CameraInfo.CAMERA_FACING_FRONT;
+ final int cameraRotation = cameraManager.getOrientation();
+
+ runOnUiThread(() -> scannerView.setFraming(framingRect, framingRectInPreview, displayRotation(), cameraRotation, cameraFlip));
+
+ final String focusMode = camera.getParameters().getFocusMode();
+ final boolean nonContinuousAutoFocus = Camera.Parameters.FOCUS_MODE_AUTO.equals(focusMode)
+ || Camera.Parameters.FOCUS_MODE_MACRO.equals(focusMode);
+
+ if (nonContinuousAutoFocus)
+ cameraHandler.post(new AutoFocusRunnable(camera));
+
+ cameraHandler.post(fetchAndDecodeRunnable);
+ } catch (final Exception x) {
+ Log.d(Config.LOGTAG, "problem opening camera", x);
+ }
+ }
+
+ private int displayRotation() {
+ final int rotation = getWindowManager().getDefaultDisplay().getRotation();
+ if (rotation == Surface.ROTATION_0)
+ return 0;
+ else if (rotation == Surface.ROTATION_90)
+ return 90;
+ else if (rotation == Surface.ROTATION_180)
+ return 180;
+ else if (rotation == Surface.ROTATION_270)
+ return 270;
+ else
+ throw new IllegalStateException("rotation: " + rotation);
+ }
+ };
+
+ @Override
+ public void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
+
+ setContentView(R.layout.activity_scan);
+ scannerView = findViewById(R.id.scan_activity_mask);
+ previewView = findViewById(R.id.scan_activity_preview);
+ previewView.setSurfaceTextureListener(this);
+
+ cameraThread = new HandlerThread("cameraThread", Process.THREAD_PRIORITY_BACKGROUND);
+ cameraThread.start();
+ cameraHandler = new Handler(cameraThread.getLooper());
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ maybeOpenCamera();
+ }
+
+ @Override
+ protected void onPause() {
+ cameraHandler.post(closeRunnable);
+
+ super.onPause();
+ }
+
+ @Override
+ protected void onDestroy() {
+ // cancel background thread
+ cameraHandler.removeCallbacksAndMessages(null);
+ cameraThread.quit();
+
+ previewView.setSurfaceTextureListener(null);
+
+ super.onDestroy();
+ }
+
+ private void maybeOpenCamera() {
+ if (surfaceCreated && ContextCompat.checkSelfPermission(this,
+ Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED)
+ cameraHandler.post(openRunnable);
+ }
+
+ @Override
+ public void onSurfaceTextureAvailable(final SurfaceTexture surface, final int width, final int height) {
+ surfaceCreated = true;
+ maybeOpenCamera();
+ }
+
+ @Override
+ public boolean onSurfaceTextureDestroyed(final SurfaceTexture surface) {
+ surfaceCreated = false;
+ return true;
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(final SurfaceTexture surface, final int width, final int height) {
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(final SurfaceTexture surface) {
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+ }
+
+ @Override
+ public void onBackPressed() {
+ scannerView.setVisibility(View.GONE);
+ setResult(RESULT_CANCELED);
+ postFinish();
+ }
+
+ @Override
+ public boolean onKeyDown(final int keyCode, final KeyEvent event) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_FOCUS:
+ case KeyEvent.KEYCODE_CAMERA:
+ // don't launch camera app
+ return true;
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ cameraHandler.post(() -> cameraManager.setTorch(keyCode == KeyEvent.KEYCODE_VOLUME_UP));
+ return true;
+ }
+
+ return super.onKeyDown(keyCode, event);
+ }
+
+ public void handleResult(final Result scanResult) {
+ vibrator.vibrate(VIBRATE_DURATION);
+
+ scannerView.setIsResult(true);
+
+ final Intent result = new Intent();
+ result.putExtra(INTENT_EXTRA_RESULT, scanResult.getText());
+ setResult(RESULT_OK, result);
+ postFinish();
+ }
+
+ private void postFinish() {
+ new Handler().postDelayed(() -> finish(), 50);
+ }
+
+ private final class AutoFocusRunnable implements Runnable {
+ private final Camera camera;
+ private final Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {
+ @Override
+ public void onAutoFocus(final boolean success, final Camera camera) {
+ // schedule again
+ cameraHandler.postDelayed(AutoFocusRunnable.this, AUTO_FOCUS_INTERVAL_MS);
+ }
+ };
+
+ public AutoFocusRunnable(final Camera camera) {
+ this.camera = camera;
+ }
+
+ @Override
+ public void run() {
+ try {
+ camera.autoFocus(autoFocusCallback);
+ } catch (final Exception x) {
+ Log.d(Config.LOGTAG, "problem with auto-focus, will not schedule again", x);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/ui/TrustKeysActivity.java b/src/main/java/de/pixart/messenger/ui/TrustKeysActivity.java
index 385d0a68f..3499b8f00 100644
--- a/src/main/java/de/pixart/messenger/ui/TrustKeysActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/TrustKeysActivity.java
@@ -16,7 +16,6 @@ import android.widget.Toast;
import org.whispersystems.libsignal.IdentityKey;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -33,7 +32,6 @@ import de.pixart.messenger.entities.Account;
import de.pixart.messenger.entities.Conversation;
import de.pixart.messenger.utils.CryptoHelper;
import de.pixart.messenger.utils.XmppUri;
-import de.pixart.messenger.utils.zxing.IntentIntegrator;
import de.pixart.messenger.xmpp.OnKeyStatusUpdated;
import de.pixart.messenger.xmpp.jid.InvalidJidException;
import de.pixart.messenger.xmpp.jid.Jid;
@@ -130,7 +128,7 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
if (hasPendingKeyFetches()) {
Toast.makeText(this, R.string.please_wait_for_keys_to_be_fetched, Toast.LENGTH_SHORT).show();
} else {
- new IntentIntegrator(this).initiateScan(Arrays.asList("AZTEC","QR_CODE"));
+ //new IntentIntegrator(this).initiateScan(Arrays.asList("AZTEC","QR_CODE"));
return true;
}
}
diff --git a/src/main/java/de/pixart/messenger/ui/UriHandlerActivity.java b/src/main/java/de/pixart/messenger/ui/UriHandlerActivity.java
index c4374df33..d71feb3f7 100644
--- a/src/main/java/de/pixart/messenger/ui/UriHandlerActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/UriHandlerActivity.java
@@ -1,21 +1,60 @@
package de.pixart.messenger.ui;
+import android.Manifest;
import android.app.Activity;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.net.Uri;
+import android.os.Bundle;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
+import android.widget.Toast;
-import java.util.Arrays;
import java.util.List;
+import de.pixart.messenger.R;
import de.pixart.messenger.persistance.DatabaseBackend;
import de.pixart.messenger.utils.XmppUri;
-import de.pixart.messenger.utils.zxing.IntentIntegrator;
-import de.pixart.messenger.utils.zxing.IntentResult;
import de.pixart.messenger.xmpp.jid.Jid;
public class UriHandlerActivity extends AppCompatActivity {
+
public static final String ACTION_SCAN_QR_CODE = "scan_qr_code";
+ private static final int REQUEST_SCAN_QR_CODE = 0x1234;
+ private static final int REQUEST_CAMERA_PERMISSIONS_TO_SCAN = 0x6789;
+
+ private boolean handled = false;
+
+ public static void scan(Activity activity) {
+ if (ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
+ Intent intent = new Intent(activity, UriHandlerActivity.class);
+ intent.setAction(UriHandlerActivity.ACTION_SCAN_QR_CODE);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
+ activity.startActivity(intent);
+ } else {
+ ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSIONS_TO_SCAN);
+ }
+ }
+
+ public static void onRequestPermissionResult(Activity activity, int requestCode, int[] grantResults) {
+ if (requestCode != REQUEST_CAMERA_PERMISSIONS_TO_SCAN) {
+ return;
+ }
+ if (grantResults.length > 0) {
+ if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ scan(activity);
+ } else {
+ Toast.makeText(activity, R.string.qr_code_scanner_needs_access_to_camera, Toast.LENGTH_SHORT).show();
+ }
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ this.handled = savedInstanceState != null && savedInstanceState.getBoolean("handled", false);
+ }
@Override
public void onStart() {
@@ -24,6 +63,12 @@ public class UriHandlerActivity extends AppCompatActivity {
}
@Override
+ public void onSaveInstanceState(Bundle savedInstanceState) {
+ savedInstanceState.putBoolean("handled", this.handled);
+ super.onSaveInstanceState(savedInstanceState);
+ }
+
+ @Override
public void onNewIntent(Intent intent) {
handleIntent(intent);
}
@@ -31,7 +76,7 @@ public class UriHandlerActivity extends AppCompatActivity {
private void handleUri(Uri uri) {
final Intent intent;
final XmppUri xmppUri = new XmppUri(uri);
- final List<Jid> accounts = DatabaseBackend.getInstance(this).getAccountJids();
+ final List<Jid> accounts = DatabaseBackend.getInstance(this).getAccountJids(); //TODO only look at enabled accounts
if (accounts.size() == 0) {
intent = new Intent(getApplicationContext(), WelcomeActivity.class);
@@ -70,18 +115,24 @@ public class UriHandlerActivity extends AppCompatActivity {
}
private void handleIntent(Intent data) {
+ if (handled) {
+ return;
+ }
if (data == null || data.getAction() == null) {
finish();
return;
}
+ handled = true;
+
switch (data.getAction()) {
case Intent.ACTION_VIEW:
case Intent.ACTION_SENDTO:
handleUri(data.getData());
break;
case ACTION_SCAN_QR_CODE:
- new IntentIntegrator(this).initiateScan(Arrays.asList("AZTEC", "QR_CODE"));
+ Intent intent = new Intent(this, ScanActivity.class);
+ startActivityForResult(intent, REQUEST_SCAN_QR_CODE);
return;
}
@@ -90,23 +141,14 @@ public class UriHandlerActivity extends AppCompatActivity {
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
- if ((requestCode & 0xFFFF) == IntentIntegrator.REQUEST_CODE) {
- IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
-
- if (scanResult != null && scanResult.getFormatName() != null) {
- String data = scanResult.getContents();
- handleUri(Uri.parse(data));
+ super.onActivityResult(requestCode, requestCode, intent);
+ if (requestCode == REQUEST_SCAN_QR_CODE && resultCode == RESULT_OK) {
+ String result = intent.getStringExtra(ScanActivity.INTENT_EXTRA_RESULT);
+ if (result != null) {
+ Uri uri = Uri.parse(result);
+ handleUri(uri);
}
}
-
finish();
- super.onActivityResult(requestCode, requestCode, intent);
- }
-
- public static void scan(Activity activity) {
- Intent intent = new Intent(activity, UriHandlerActivity.class);
- intent.setAction(UriHandlerActivity.ACTION_SCAN_QR_CODE);
- intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
- activity.startActivity(intent);
}
} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/ui/VerifyOTRActivity.java b/src/main/java/de/pixart/messenger/ui/VerifyOTRActivity.java
index ea9bcc5a8..ded1f90c7 100644
--- a/src/main/java/de/pixart/messenger/ui/VerifyOTRActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/VerifyOTRActivity.java
@@ -1,10 +1,10 @@
package de.pixart.messenger.ui;
-import android.support.v7.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
+import android.support.v7.app.AlertDialog;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
@@ -23,8 +23,6 @@ import de.pixart.messenger.entities.Conversation;
import de.pixart.messenger.services.XmppConnectionService;
import de.pixart.messenger.utils.CryptoHelper;
import de.pixart.messenger.utils.XmppUri;
-import de.pixart.messenger.utils.zxing.IntentIntegrator;
-import de.pixart.messenger.utils.zxing.IntentResult;
import de.pixart.messenger.xmpp.jid.InvalidJidException;
import de.pixart.messenger.xmpp.jid.Jid;
@@ -208,7 +206,8 @@ public class VerifyOTRActivity extends XmppActivity implements XmppConnectionSer
}
this.mode = intent.getIntExtra("mode", MODE_MANUAL_VERIFICATION);
if (this.mode == MODE_SCAN_FINGERPRINT) {
- new IntentIntegrator(this).initiateScan();
+ // todo
+ // new IntentIntegrator(this).initiateScan();
return false;
}
return true;
@@ -219,7 +218,8 @@ public class VerifyOTRActivity extends XmppActivity implements XmppConnectionSer
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
- if ((requestCode & 0xFFFF) == IntentIntegrator.REQUEST_CODE) {
+ // todo
+ /*if ((requestCode & 0xFFFF) == IntentIntegrator.REQUEST_CODE) {
IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
if (scanResult != null && scanResult.getFormatName() != null) {
String data = scanResult.getContents();
@@ -233,7 +233,7 @@ public class VerifyOTRActivity extends XmppActivity implements XmppConnectionSer
} else {
finish();
}
- }
+ }*/
super.onActivityResult(requestCode, requestCode, intent);
}
diff --git a/src/main/java/de/pixart/messenger/ui/service/CameraManager.java b/src/main/java/de/pixart/messenger/ui/service/CameraManager.java
new file mode 100644
index 000000000..1c232928f
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/ui/service/CameraManager.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright 2012-2015 the original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package de.pixart.messenger.ui.service;
+
+import android.annotation.SuppressLint;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.hardware.Camera;
+import android.hardware.Camera.CameraInfo;
+import android.util.Log;
+import android.view.TextureView;
+
+import com.google.zxing.PlanarYUVLuminanceSource;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import de.pixart.messenger.Config;
+
+/**
+ * @author Andreas Schildbach
+ */
+@SuppressWarnings("deprecation")
+public final class CameraManager {
+ private static final int MIN_FRAME_SIZE = 240;
+ private static final int MAX_FRAME_SIZE = 600;
+ private static final int MIN_PREVIEW_PIXELS = 470 * 320; // normal screen
+ private static final int MAX_PREVIEW_PIXELS = 1280 * 720;
+
+ private Camera camera;
+ private CameraInfo cameraInfo = new CameraInfo();
+ private Camera.Size cameraResolution;
+ private Rect frame;
+ private RectF framePreview;
+
+ public Rect getFrame() {
+ return frame;
+ }
+
+ public RectF getFramePreview() {
+ return framePreview;
+ }
+
+ public int getFacing() {
+ return cameraInfo.facing;
+ }
+
+ public int getOrientation() {
+ return cameraInfo.orientation;
+ }
+
+ public Camera open(final TextureView textureView, final int displayOrientation, final boolean continuousAutoFocus)
+ throws IOException {
+ final int cameraId = determineCameraId();
+ Camera.getCameraInfo(cameraId, cameraInfo);
+
+ camera = Camera.open(cameraId);
+
+ if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)
+ camera.setDisplayOrientation((720 - displayOrientation - cameraInfo.orientation) % 360);
+ else if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK)
+ camera.setDisplayOrientation((720 - displayOrientation + cameraInfo.orientation) % 360);
+ else
+ throw new IllegalStateException("facing: " + cameraInfo.facing);
+
+ camera.setPreviewTexture(textureView.getSurfaceTexture());
+
+ final Camera.Parameters parameters = camera.getParameters();
+
+ cameraResolution = findBestPreviewSizeValue(parameters, textureView.getWidth(), textureView.getHeight());
+
+ final int width = textureView.getWidth();
+ final int height = textureView.getHeight();
+
+ final int rawSize = Math.min(width * 2 / 3, height * 2 / 3);
+ final int frameSize = Math.max(MIN_FRAME_SIZE, Math.min(MAX_FRAME_SIZE, rawSize));
+
+ final int leftOffset = (width - frameSize) / 2;
+ final int topOffset = (height - frameSize) / 2;
+ frame = new Rect(leftOffset, topOffset, leftOffset + frameSize, topOffset + frameSize);
+ framePreview = new RectF(frame.left * cameraResolution.width / width,
+ frame.top * cameraResolution.height / height, frame.right * cameraResolution.width / width,
+ frame.bottom * cameraResolution.height / height);
+
+ final String savedParameters = parameters == null ? null : parameters.flatten();
+
+ try {
+ setDesiredCameraParameters(camera, cameraResolution, continuousAutoFocus);
+ } catch (final RuntimeException x) {
+ if (savedParameters != null) {
+ final Camera.Parameters parameters2 = camera.getParameters();
+ parameters2.unflatten(savedParameters);
+ try {
+ camera.setParameters(parameters2);
+ setDesiredCameraParameters(camera, cameraResolution, continuousAutoFocus);
+ } catch (final RuntimeException x2) {
+ Log.d(Config.LOGTAG,"problem setting camera parameters", x2);
+ }
+ }
+ }
+
+ try {
+ camera.startPreview();
+ return camera;
+ } catch (final RuntimeException x) {
+ Log.w(Config.LOGTAG,"something went wrong while starting camera preview", x);
+ camera.release();
+ throw x;
+ }
+ }
+
+ private int determineCameraId() {
+ final int cameraCount = Camera.getNumberOfCameras();
+ final CameraInfo cameraInfo = new CameraInfo();
+
+ // prefer back-facing camera
+ for (int i = 0; i < cameraCount; i++) {
+ Camera.getCameraInfo(i, cameraInfo);
+ if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK)
+ return i;
+ }
+
+ // fall back to front-facing camera
+ for (int i = 0; i < cameraCount; i++) {
+ Camera.getCameraInfo(i, cameraInfo);
+ if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)
+ return i;
+ }
+
+ return -1;
+ }
+
+ public void close() {
+ if (camera != null) {
+ try {
+ camera.stopPreview();
+ } catch (final RuntimeException x) {
+ Log.w(Config.LOGTAG,"something went wrong while stopping camera preview", x);
+ }
+
+ camera.release();
+ }
+ }
+
+ private static final Comparator<Camera.Size> numPixelComparator = new Comparator<Camera.Size>() {
+ @Override
+ public int compare(final Camera.Size size1, final Camera.Size size2) {
+ final int pixels1 = size1.height * size1.width;
+ final int pixels2 = size2.height * size2.width;
+
+ if (pixels1 < pixels2)
+ return 1;
+ else if (pixels1 > pixels2)
+ return -1;
+ else
+ return 0;
+ }
+ };
+
+ private static Camera.Size findBestPreviewSizeValue(final Camera.Parameters parameters, int width, int height) {
+ if (height > width) {
+ final int temp = width;
+ width = height;
+ height = temp;
+ }
+
+ final float screenAspectRatio = (float) width / (float) height;
+
+ final List<Camera.Size> rawSupportedSizes = parameters.getSupportedPreviewSizes();
+ if (rawSupportedSizes == null)
+ return parameters.getPreviewSize();
+
+ // sort by size, descending
+ final List<Camera.Size> supportedPreviewSizes = new ArrayList<Camera.Size>(rawSupportedSizes);
+ Collections.sort(supportedPreviewSizes, numPixelComparator);
+
+ Camera.Size bestSize = null;
+ float diff = Float.POSITIVE_INFINITY;
+
+ for (final Camera.Size supportedPreviewSize : supportedPreviewSizes) {
+ final int realWidth = supportedPreviewSize.width;
+ final int realHeight = supportedPreviewSize.height;
+ final int realPixels = realWidth * realHeight;
+ if (realPixels < MIN_PREVIEW_PIXELS || realPixels > MAX_PREVIEW_PIXELS)
+ continue;
+
+ final boolean isCandidatePortrait = realWidth < realHeight;
+ final int maybeFlippedWidth = isCandidatePortrait ? realHeight : realWidth;
+ final int maybeFlippedHeight = isCandidatePortrait ? realWidth : realHeight;
+ if (maybeFlippedWidth == width && maybeFlippedHeight == height)
+ return supportedPreviewSize;
+
+ final float aspectRatio = (float) maybeFlippedWidth / (float) maybeFlippedHeight;
+ final float newDiff = Math.abs(aspectRatio - screenAspectRatio);
+ if (newDiff < diff) {
+ bestSize = supportedPreviewSize;
+ diff = newDiff;
+ }
+ }
+
+ if (bestSize != null)
+ return bestSize;
+ else
+ return parameters.getPreviewSize();
+ }
+
+ @SuppressLint("InlinedApi")
+ private static void setDesiredCameraParameters(final Camera camera, final Camera.Size cameraResolution,
+ final boolean continuousAutoFocus) {
+ final Camera.Parameters parameters = camera.getParameters();
+ if (parameters == null)
+ return;
+
+ final List<String> supportedFocusModes = parameters.getSupportedFocusModes();
+ final String focusMode = continuousAutoFocus
+ ? findValue(supportedFocusModes, Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE,
+ Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO, Camera.Parameters.FOCUS_MODE_AUTO,
+ Camera.Parameters.FOCUS_MODE_MACRO)
+ : findValue(supportedFocusModes, Camera.Parameters.FOCUS_MODE_AUTO, Camera.Parameters.FOCUS_MODE_MACRO);
+ if (focusMode != null)
+ parameters.setFocusMode(focusMode);
+
+ parameters.setPreviewSize(cameraResolution.width, cameraResolution.height);
+
+ camera.setParameters(parameters);
+ }
+
+ public void requestPreviewFrame(final android.hardware.Camera.PreviewCallback callback) {
+ try {
+ camera.setOneShotPreviewCallback(callback);
+ } catch (final RuntimeException x) {
+ Log.d(Config.LOGTAG,"problem requesting preview frame, callback won't be called", x);
+ }
+ }
+
+ public PlanarYUVLuminanceSource buildLuminanceSource(final byte[] data) {
+ return new PlanarYUVLuminanceSource(data, cameraResolution.width, cameraResolution.height,
+ (int) framePreview.left, (int) framePreview.top, (int) framePreview.width(),
+ (int) framePreview.height(), false);
+ }
+
+ private static boolean getTorchEnabled(final Camera camera) {
+ final Camera.Parameters parameters = camera.getParameters();
+ if (parameters != null) {
+ final String flashMode = camera.getParameters().getFlashMode();
+ return flashMode != null && (Camera.Parameters.FLASH_MODE_ON.equals(flashMode)
+ || Camera.Parameters.FLASH_MODE_TORCH.equals(flashMode));
+ }
+
+ return false;
+ }
+
+ private static void setTorchEnabled(final Camera camera, final boolean enabled) {
+ final Camera.Parameters parameters = camera.getParameters();
+
+ final List<String> supportedFlashModes = parameters.getSupportedFlashModes();
+ if (supportedFlashModes != null) {
+ final String flashMode;
+ if (enabled)
+ flashMode = findValue(supportedFlashModes, Camera.Parameters.FLASH_MODE_TORCH,
+ Camera.Parameters.FLASH_MODE_ON);
+ else
+ flashMode = findValue(supportedFlashModes, Camera.Parameters.FLASH_MODE_OFF);
+
+ if (flashMode != null) {
+ camera.cancelAutoFocus(); // autofocus can cause conflict
+
+ parameters.setFlashMode(flashMode);
+ camera.setParameters(parameters);
+ }
+ }
+ }
+
+ private static String findValue(final Collection<String> values, final String... valuesToFind) {
+ for (final String valueToFind : valuesToFind)
+ if (values.contains(valueToFind))
+ return valueToFind;
+
+ return null;
+ }
+
+ public void setTorch(final boolean enabled) {
+ if (enabled != getTorchEnabled(camera))
+ setTorchEnabled(camera, enabled);
+ }
+} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/ui/widget/ScannerView.java b/src/main/java/de/pixart/messenger/ui/widget/ScannerView.java
new file mode 100644
index 000000000..0a2a80039
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/ui/widget/ScannerView.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2012-2015 the original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package de.pixart.messenger.ui.widget;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Matrix.ScaleToFit;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.google.zxing.ResultPoint;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import de.pixart.messenger.R;
+
+/**
+ * @author Andreas Schildbach
+ */
+
+public class ScannerView extends View {
+ private static final long LASER_ANIMATION_DELAY_MS = 100l;
+ private static final int DOT_OPACITY = 0xa0;
+ private static final int DOT_TTL_MS = 500;
+
+ private final Paint maskPaint;
+ private final Paint laserPaint;
+ private final Paint dotPaint;
+ private final int maskColor, maskResultColor;
+ private final int laserColor;
+ private final int dotColor, dotResultColor;
+ private final Map<float[], Long> dots = new HashMap<float[], Long>(16);
+ private final Matrix matrix = new Matrix();
+ private boolean isResult;
+ private Rect frame;
+
+ public ScannerView(final Context context, final AttributeSet attrs) {
+ super(context, attrs);
+
+ final Resources res = getResources();
+ maskColor = res.getColor(R.color.scan_mask);
+ maskResultColor = res.getColor(R.color.scan_result_view);
+ laserColor = res.getColor(R.color.scan_laser);
+ dotColor = res.getColor(R.color.scan_dot);
+ dotResultColor = res.getColor(R.color.scan_result_dots);
+
+ maskPaint = new Paint();
+ maskPaint.setStyle(Style.FILL);
+
+ laserPaint = new Paint();
+ laserPaint.setStrokeWidth(res.getDimensionPixelSize(R.dimen.scan_laser_width));
+ laserPaint.setStyle(Style.STROKE);
+
+ dotPaint = new Paint();
+ dotPaint.setAlpha(DOT_OPACITY);
+ dotPaint.setStyle(Style.STROKE);
+ dotPaint.setStrokeWidth(res.getDimension(R.dimen.scan_dot_size));
+ dotPaint.setAntiAlias(true);
+ }
+
+ public void setFraming(final Rect frame, final RectF framePreview, final int displayRotation,
+ final int cameraRotation, final boolean cameraFlip) {
+ this.frame = frame;
+ matrix.setRectToRect(framePreview, new RectF(frame), ScaleToFit.FILL);
+ matrix.postRotate(-displayRotation, frame.exactCenterX(), frame.exactCenterY());
+ matrix.postScale(cameraFlip ? -1 : 1, 1, frame.exactCenterX(), frame.exactCenterY());
+ matrix.postRotate(cameraRotation, frame.exactCenterX(), frame.exactCenterY());
+
+ invalidate();
+ }
+
+ public void setIsResult(final boolean isResult) {
+ this.isResult = isResult;
+
+ invalidate();
+ }
+
+ public void addDot(final ResultPoint dot) {
+ dots.put(new float[]{dot.getX(), dot.getY()}, System.currentTimeMillis());
+
+ invalidate();
+ }
+
+ @Override
+ public void onDraw(final Canvas canvas) {
+ if (frame == null)
+ return;
+
+ final long now = System.currentTimeMillis();
+
+ final int width = canvas.getWidth();
+ final int height = canvas.getHeight();
+
+ final float[] point = new float[2];
+
+ // draw mask darkened
+ maskPaint.setColor(isResult ? maskResultColor : maskColor);
+ canvas.drawRect(0, 0, width, frame.top, maskPaint);
+ canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, maskPaint);
+ canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, maskPaint);
+ canvas.drawRect(0, frame.bottom + 1, width, height, maskPaint);
+
+ if (isResult) {
+ laserPaint.setColor(dotResultColor);
+ laserPaint.setAlpha(160);
+
+ dotPaint.setColor(dotResultColor);
+ } else {
+ laserPaint.setColor(laserColor);
+ final boolean laserPhase = (now / 600) % 2 == 0;
+ laserPaint.setAlpha(laserPhase ? 160 : 255);
+
+ dotPaint.setColor(dotColor);
+
+ // schedule redraw
+ postInvalidateDelayed(LASER_ANIMATION_DELAY_MS);
+ }
+
+ canvas.drawRect(frame, laserPaint);
+
+ // draw points
+ for (final Iterator<Map.Entry<float[], Long>> i = dots.entrySet().iterator(); i.hasNext(); ) {
+ final Map.Entry<float[], Long> entry = i.next();
+ final long age = now - entry.getValue();
+ if (age < DOT_TTL_MS) {
+ dotPaint.setAlpha((int) ((DOT_TTL_MS - age) * 256 / DOT_TTL_MS));
+
+ matrix.mapPoints(point, entry.getKey());
+ canvas.drawPoint(point[0], point[1], dotPaint);
+ } else {
+ i.remove();
+ }
+ }
+ }
+} \ No newline at end of file