diff options
-rw-r--r-- | build.gradle | 2 | ||||
-rw-r--r-- | src/main/java/eu/siacs/conversations/ui/ConversationActivity.java | 2 | ||||
-rw-r--r-- | src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java | 96 | ||||
-rw-r--r-- | src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java | 175 | ||||
-rw-r--r-- | src/main/java/eu/siacs/conversations/ui/XmppActivity.java | 8 | ||||
-rw-r--r-- | src/main/res/menu/editaccount.xml | 8 | ||||
-rw-r--r-- | src/main/res/menu/start_conversation.xml | 16 | ||||
-rw-r--r-- | src/main/res/values/strings.xml | 3 |
8 files changed, 235 insertions, 75 deletions
diff --git a/build.gradle b/build.gradle index a37b92c4..e5edcb9a 100644 --- a/build.gradle +++ b/build.gradle @@ -34,6 +34,8 @@ dependencies { compile 'com.android.support:support-v13:19.1.0' compile 'org.bouncycastle:bcprov-jdk15on:1.50' compile 'net.java:otr4j:0.21' + compile 'com.google.zxing:core:3.1.0' + compile 'com.google.zxing:android-integration:3.1.0' } android { diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 67f227d8..b4a8e56a 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -88,7 +88,7 @@ public class ConversationActivity extends XmppActivity implements public NdefMessage createNdefMessage(NfcEvent nfcEvent) { Conversation conversation = getSelectedConversation(); NdefMessage msg = new NdefMessage(new NdefRecord[]{ - NdefRecord.createUri("xmpp:"+conversation.getAccount().getJid().getBytes()), + NdefRecord.createUri("xmpp:"+conversation.getAccount().getJid()), NdefRecord.createApplicationRecord("eu.siacs.conversations") }); return msg; diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index 58ca49cc..4942816d 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -1,23 +1,44 @@ package eu.siacs.conversations.ui; +import android.app.AlertDialog; import android.app.PendingIntent; import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.Point; import android.os.Bundle; import android.text.Editable; import android.text.TextWatcher; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.AutoCompleteTextView; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; +import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.EditText; import android.widget.ImageButton; +import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.EncodeHintType; +import com.google.zxing.WriterException; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.integration.android.IntentIntegrator; +import com.google.zxing.integration.android.IntentResult; +import com.google.zxing.qrcode.QRCodeWriter; +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; + +import java.util.Hashtable; + +import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate; @@ -173,13 +194,13 @@ public class EditAccountActivity extends XmppActivity { @Override public void onTextChanged(CharSequence s, int start, int before, - int count) { + int count) { updateSaveButton(); } @Override public void beforeTextChanged(CharSequence s, int start, int count, - int after) { + int after) { } @@ -216,9 +237,45 @@ public class EditAccountActivity extends XmppActivity { } else { return (!mAccount.getJid().equals(mAccountJid.getText().toString())) || (!mAccount.getPassword().equals( - mPassword.getText().toString()) || mAccount - .isOptionSet(Account.OPTION_REGISTER) != mRegisterNew - .isChecked()); + mPassword.getText().toString()) || mAccount + .isOptionSet(Account.OPTION_REGISTER) != mRegisterNew + .isChecked()); + } + } + + protected void showQrCode() { + Point size = new Point(); + getWindowManager().getDefaultDisplay().getSize(size); + final int width = (size.x < size.y ? size.x : size.y); + String jid = mAccount.getJid(); + Bitmap bitmap = createQrCodeBitmap("xmpp:" + jid, width); + ImageView view = new ImageView(this); + view.setImageBitmap(bitmap); + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setView(view); + builder.create().show(); + } + + protected Bitmap createQrCodeBitmap(String input, int size) { + try { + final QRCodeWriter QR_CODE_WRITER = new QRCodeWriter(); + final Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>(); + hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M); + final BitMatrix result = QR_CODE_WRITER.encode(input, BarcodeFormat.QR_CODE, size, size, hints); + final int width = result.getWidth(); + final int height = result.getHeight(); + final int[] pixels = new int[width * height]; + for (int y = 0; y < height; y++) { + final int offset = y * width; + for (int x = 0; x < width; x++) { + pixels[offset + x] = result.get(x, y) ? Color.BLACK : Color.TRANSPARENT; + } + } + final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + bitmap.setPixels(pixels, 0, width, 0, 0, width, height); + return bitmap; + } catch (final WriterException e) { + return null; } } @@ -257,7 +314,7 @@ public class EditAccountActivity extends XmppActivity { return (!this.mAccount.getJid().equals( this.mAccountJid.getText().toString())) || (!this.mAccount.getPassword().equals( - this.mPassword.getText().toString())); + this.mPassword.getText().toString())); } @Override @@ -287,7 +344,7 @@ public class EditAccountActivity extends XmppActivity { @Override public void onCheckedChanged(CompoundButton buttonView, - boolean isChecked) { + boolean isChecked) { if (isChecked) { mPasswordConfirm.setVisibility(View.VISIBLE); } else { @@ -299,6 +356,27 @@ public class EditAccountActivity extends XmppActivity { } @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + getMenuInflater().inflate(R.menu.editaccount, menu); + MenuItem showQrCode = menu.findItem(R.id.action_show_qr_code); + if (mAccount == null) { + showQrCode.setVisible(false); + } + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.action_show_qr_code: + showQrCode(); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override protected void onStart() { super.onStart(); if (getIntent() != null) { @@ -387,7 +465,7 @@ public class EditAccountActivity extends XmppActivity { @Override public void onClick(View v) { - if (copyTextToClipboard(fingerprint,R.string.otr_fingerprint)) { + if (copyTextToClipboard(fingerprint, R.string.otr_fingerprint)) { Toast.makeText( EditAccountActivity.this, R.string.toast_message_otr_fingerprint, diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java index 2dd74d9f..aa19ff0e 100644 --- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java @@ -1,13 +1,5 @@ package eu.siacs.conversations.ui; -import java.io.UnsupportedEncodingException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLDecoder; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - import android.annotation.SuppressLint; import android.app.ActionBar; import android.app.ActionBar.Tab; @@ -22,6 +14,7 @@ import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.net.Uri; import android.nfc.NdefMessage; +import android.nfc.NdefRecord; import android.nfc.NfcAdapter; import android.os.Bundle; import android.os.Parcelable; @@ -29,7 +22,6 @@ import android.support.v13.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; import android.text.Editable; import android.text.TextWatcher; -import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.KeyEvent; @@ -47,7 +39,15 @@ import android.widget.EditText; import android.widget.ListView; import android.widget.Spinner; -import eu.siacs.conversations.Config; +import com.google.zxing.integration.android.IntentIntegrator; +import com.google.zxing.integration.android.IntentResult; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Bookmark; @@ -77,6 +77,8 @@ public class StartConversationActivity extends XmppActivity { private List<String> mKnownHosts; private List<String> mKnownConferenceHosts; + private Invite mPendingInvite = null; + private Menu mOptionsMenu; private EditText mSearchEditText; @@ -147,12 +149,12 @@ public class StartConversationActivity extends XmppActivity { @Override public void beforeTextChanged(CharSequence s, int start, int count, - int after) { + int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, - int count) { + int count) { } }; private OnRosterUpdate onRosterUpdate = new OnRosterUpdate() { @@ -214,7 +216,7 @@ public class StartConversationActivity extends XmppActivity { @Override public void onItemClick(AdapterView<?> arg0, View arg1, - int position, long arg3) { + int position, long arg3) { openConversationForBookmark(position); } }); @@ -227,7 +229,7 @@ public class StartConversationActivity extends XmppActivity { @Override public void onItemClick(AdapterView<?> arg0, View arg1, - int position, long arg3) { + int position, long arg3) { openConversationForContact(position); } }); @@ -500,12 +502,15 @@ public class StartConversationActivity extends XmppActivity { @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case R.id.action_create_contact: - showCreateContactDialog(null); - break; - case R.id.action_join_conference: - showJoinConferenceDialog(null); - break; + case R.id.action_create_contact: + showCreateContactDialog(null); + return true; + case R.id.action_join_conference: + showJoinConferenceDialog(null); + return true; + case R.id.action_scan_qr_code: + new IntentIntegrator(this).initiateScan(); + return true; } return super.onOptionsItemSelected(item); } @@ -520,6 +525,29 @@ public class StartConversationActivity extends XmppActivity { } @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(); + Invite invite = parseInviteUri(data); + if (xmppConnectionServiceBound) { + if (invite.muc) { + showJoinConferenceDialog(invite.jid); + } else { + handleJid(invite.jid); + } + } else if (invite.jid != null) { + this.mPendingInvite = invite; + } else { + this.mPendingInvite = null; + } + } + } + super.onActivityResult(requestCode, requestCode, intent); + } + + @Override protected void onBackendConnected() { xmppConnectionService.setOnRosterUpdateListener(this.onRosterUpdate); this.mActivatedAccounts.clear(); @@ -531,21 +559,31 @@ public class StartConversationActivity extends XmppActivity { this.mKnownHosts = xmppConnectionService.getKnownHosts(); this.mKnownConferenceHosts = xmppConnectionService .getKnownConferenceHosts(); - if (!handleIntent(getIntent())) { + if (this.mPendingInvite != null) { + if (this.mPendingInvite.muc) { + showJoinConferenceDialog(this.mPendingInvite.jid); + } else { + handleJid(this.mPendingInvite.jid); + } + this.mPendingInvite = null; + } else if (!handleIntent(getIntent())) { if (mSearchEditText != null) { filter(mSearchEditText.getText().toString()); } else { filter(null); } } + setIntent(null); } protected boolean handleIntent(Intent intent) { - if (intent==null || intent.getAction() == null) { + if (intent == null || intent.getAction() == null) { return false; } String jid; - switch(intent.getAction()) { + Uri uri; + Invite invite; + switch (intent.getAction()) { case Intent.ACTION_SENDTO: try { jid = URLDecoder.decode( @@ -556,26 +594,28 @@ public class StartConversationActivity extends XmppActivity { return false; } case Intent.ACTION_VIEW: - Uri uri = intent.getData(); - boolean muc = uri.getQuery() != null && uri.getQuery().equalsIgnoreCase("join"); - if (uri.getAuthority() != null) { - jid = uri.getAuthority(); - } else { - jid = uri.getSchemeSpecificPart().split("\\?")[0]; - } - if (muc) { - showJoinConferenceDialog(jid); + uri = intent.getData(); + invite = parseInviteUri(uri); + if (invite.muc) { + showJoinConferenceDialog(invite.jid); return false; } else { - return handleJid(jid); + return handleJid(invite.jid); } case NfcAdapter.ACTION_NDEF_DISCOVERED: - Parcelable[] messages = getIntent().getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); - NdefMessage message = (NdefMessage) messages[0]; - String payload = message.getRecords()[0].toString(); - if (payload.startsWith("xmpp:")) { - jid = payload.substring(5); - return handleJid(jid); + if (android.os.Build.VERSION.SDK_INT >= 16) { + Parcelable[] messages = getIntent().getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); + NdefMessage message = (NdefMessage) messages[0]; + NdefRecord record = message.getRecords()[0]; + invite = parseInviteUri(record.toUri()); + if (invite != null) { + if (invite.muc) { + showJoinConferenceDialog(invite.jid); + return false; + } else { + return handleJid(invite.jid); + } + } } else { return false; } @@ -584,6 +624,25 @@ public class StartConversationActivity extends XmppActivity { } } + private Invite parseInviteUri(String uri) { + try { + return parseInviteUri(Uri.parse(uri)); + } catch (IllegalArgumentException e) { + return null; + } + } + + private Invite parseInviteUri(Uri uri) { + Invite invite = new Invite(); + invite.muc = uri.getQuery() != null && uri.getQuery().equalsIgnoreCase("join"); + if (uri.getAuthority() != null) { + invite.jid = uri.getAuthority(); + } else { + invite.jid = uri.getSchemeSpecificPart().split("\\?")[0]; + } + return invite; + } + private boolean handleJid(String jid) { List<Contact> contacts = xmppConnectionService.findContacts(jid); if (contacts.size() == 0) { @@ -595,7 +654,8 @@ public class StartConversationActivity extends XmppActivity { } else { if (mMenuSearchView != null) { mMenuSearchView.expandActionView(); - mSearchEditText.setText(jid); + mSearchEditText.setText(""); + mSearchEditText.append(jid); filter(jid); } else { mInitialJid = jid; @@ -673,7 +733,7 @@ public class StartConversationActivity extends XmppActivity { @Override public void onCreateContextMenu(ContextMenu menu, View v, - ContextMenuInfo menuInfo) { + ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); StartConversationActivity activity = (StartConversationActivity) getActivity(); activity.getMenuInflater().inflate(mResContextMenu, menu); @@ -689,22 +749,27 @@ public class StartConversationActivity extends XmppActivity { public boolean onContextItemSelected(MenuItem item) { StartConversationActivity activity = (StartConversationActivity) getActivity(); switch (item.getItemId()) { - case R.id.context_start_conversation: - activity.openConversationForContact(); - break; - case R.id.context_contact_details: - activity.openDetailsForContact(); - break; - case R.id.context_delete_contact: - activity.deleteContact(); - break; - case R.id.context_join_conference: - activity.openConversationForBookmark(); - break; - case R.id.context_delete_conference: - activity.deleteConference(); + case R.id.context_start_conversation: + activity.openConversationForContact(); + break; + case R.id.context_contact_details: + activity.openDetailsForContact(); + break; + case R.id.context_delete_contact: + activity.deleteContact(); + break; + case R.id.context_join_conference: + activity.openConversationForBookmark(); + break; + case R.id.context_delete_conference: + activity.deleteConference(); } return true; } } + + private class Invite { + public String jid; + public boolean muc; + } } diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index 53602571..56aa47b0 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -545,9 +545,11 @@ public abstract class XmppActivity extends Activity { } protected void registerNdefPushMessageCallback(NfcAdapter.CreateNdefMessageCallback callback) { - NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this); - if (nfcAdapter!=null && nfcAdapter.isEnabled()) { - nfcAdapter.setNdefPushMessageCallback(callback,this); + if (android.os.Build.VERSION.SDK_INT >= 16) { + NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this); + if (nfcAdapter != null && nfcAdapter.isEnabled()) { + nfcAdapter.setNdefPushMessageCallback(callback, this); + } } } diff --git a/src/main/res/menu/editaccount.xml b/src/main/res/menu/editaccount.xml new file mode 100644 index 00000000..2301caf0 --- /dev/null +++ b/src/main/res/menu/editaccount.xml @@ -0,0 +1,8 @@ +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + + <item + android:id="@+id/action_show_qr_code" + android:title="@string/show_qr_code" + android:showAsAction="never" /> + +</menu>
\ No newline at end of file diff --git a/src/main/res/menu/start_conversation.xml b/src/main/res/menu/start_conversation.xml index f7230169..2c23af59 100644 --- a/src/main/res/menu/start_conversation.xml +++ b/src/main/res/menu/start_conversation.xml @@ -1,31 +1,35 @@ <?xml version="1.0" encoding="utf-8"?> -<menu xmlns:android="http://schemas.android.com/apk/res/android" > +<menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/action_search" android:actionLayout="@layout/actionview_search" android:icon="@drawable/ic_action_search" android:showAsAction="collapseActionView|always" - android:title="@string/search"/> + android:title="@string/search" /> <item android:id="@+id/action_create_contact" android:icon="@drawable/ic_action_add_person" android:showAsAction="always" - android:title="@string/create_contact"/> + android:title="@string/create_contact" /> <item android:id="@+id/action_join_conference" android:icon="@drawable/ic_action_add_group" android:showAsAction="always" - android:title="@string/join_conference"/> + android:title="@string/join_conference" /> + <item + android:id="@+id/action_scan_qr_code" + android:showAsAction="never" + android:title="@string/scan_qr_code" /> <item android:id="@+id/action_accounts" android:orderInCategory="90" android:showAsAction="never" - android:title="@string/action_accounts"/> + android:title="@string/action_accounts" /> <item android:id="@+id/action_settings" android:orderInCategory="100" android:showAsAction="never" - android:title="@string/action_settings"/> + android:title="@string/action_settings" /> </menu>
\ No newline at end of file diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index e941ed6d..f8e4eef2 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -282,5 +282,6 @@ <string name="url_copied_to_clipboard">URL copied to clipboard</string> <string name="message_copied_to_clipboard">Message copied to clipboard</string> <string name="image_transmission_failed">Image transmission failed</string> - + <string name="scan_qr_code">Scan QR code</string> + <string name="show_qr_code">Show QR code</string> </resources>
\ No newline at end of file |