diff options
4 files changed, 207 insertions, 149 deletions
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 7bde645f..d73ac79a 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" - package="eu.siacs.conversations"> + package="eu.siacs.conversations"> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> @@ -12,16 +12,17 @@ <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.VIBRATE" /> + <uses-permission android:name="android.permission.NFC" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" - tools:replace="android:label" - android:theme="@style/ConversationsTheme" > + android:theme="@style/ConversationsTheme" + tools:replace="android:label"> <service android:name="eu.siacs.conversations.services.XmppConnectionService" /> - <receiver android:name="eu.siacs.conversations.services.EventReceiver" > + <receiver android:name="eu.siacs.conversations.services.EventReceiver"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> @@ -33,7 +34,7 @@ android:name="eu.siacs.conversations.ui.ConversationActivity" android:label="@string/title_activity_conversations" android:launchMode="singleTask" - android:windowSoftInputMode="stateHidden" > + android:windowSoftInputMode="stateHidden"> <intent-filter> <action android:name="android.intent.action.MAIN" /> @@ -43,8 +44,7 @@ <activity android:name="eu.siacs.conversations.ui.StartConversationActivity" android:configChanges="orientation|screenSize" - android:label="@string/title_activity_start_conversation" - android:logo="@drawable/ic_activity" > + android:label="@string/title_activity_start_conversation"> <intent-filter> <action android:name="android.intent.action.SENDTO" /> @@ -61,42 +61,40 @@ <data android:scheme="xmpp" /> </intent-filter> + <intent-filter> + <action android:name="android.nfc.action.NDEF_DISCOVERED" /> + <category android:name="android.intent.category.DEFAULT" /> + <data android:mimeType="application/vnd.eu.siacs.conversations.jid" /> + </intent-filter> </activity> <activity android:name="eu.siacs.conversations.ui.SettingsActivity" - android:label="@string/title_activity_settings" > - </activity> + android:label="@string/title_activity_settings"></activity> <activity android:name="eu.siacs.conversations.ui.ChooseContactActivity" - android:label="@string/title_activity_choose_contact" > - </activity> + android:label="@string/title_activity_choose_contact"></activity> <activity android:name="eu.siacs.conversations.ui.ManageAccountActivity" android:configChanges="orientation|screenSize" - android:label="@string/title_activity_manage_accounts" > - </activity> + android:label="@string/title_activity_manage_accounts"></activity> <activity android:name="eu.siacs.conversations.ui.EditAccountActivity" - android:windowSoftInputMode="stateHidden|adjustResize" > - </activity> + android:windowSoftInputMode="stateHidden|adjustResize"></activity> <activity android:name="eu.siacs.conversations.ui.ConferenceDetailsActivity" android:label="@string/title_activity_conference_details" - android:windowSoftInputMode="stateHidden" > - </activity> + android:windowSoftInputMode="stateHidden"></activity> <activity android:name="eu.siacs.conversations.ui.ContactDetailsActivity" android:label="@string/title_activity_contact_details" - android:windowSoftInputMode="stateHidden" > - </activity> + android:windowSoftInputMode="stateHidden"></activity> <activity android:name="eu.siacs.conversations.ui.PublishProfilePictureActivity" android:label="@string/mgmt_account_publish_avatar" - android:windowSoftInputMode="stateHidden" > - </activity> + android:windowSoftInputMode="stateHidden"></activity> <activity android:name="eu.siacs.conversations.ui.ShareWithActivity" - android:label="@string/title_activity_conversations" > + android:label="@string/title_activity_conversations"> <intent-filter> <action android:name="android.intent.action.SEND" /> diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 1d7364d6..67f227d8 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -1,21 +1,5 @@ package eu.siacs.conversations.ui; -import java.util.ArrayList; -import java.util.List; - -import eu.siacs.conversations.R; -import eu.siacs.conversations.entities.Contact; -import eu.siacs.conversations.entities.Conversation; -import eu.siacs.conversations.entities.Message; -import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate; -import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdate; -import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate; -import eu.siacs.conversations.ui.adapter.ConversationAdapter; -import eu.siacs.conversations.utils.ExceptionHelper; -import android.net.Uri; -import android.os.Bundle; -import android.os.SystemClock; -import android.provider.MediaStore; import android.annotation.SuppressLint; import android.app.ActionBar; import android.app.AlertDialog; @@ -23,8 +7,16 @@ import android.app.FragmentTransaction; import android.app.PendingIntent; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; -import android.content.IntentSender.SendIntentException; import android.content.Intent; +import android.content.IntentSender.SendIntentException; +import android.net.Uri; +import android.nfc.NdefMessage; +import android.nfc.NdefRecord; +import android.nfc.NfcAdapter; +import android.nfc.NfcEvent; +import android.os.Bundle; +import android.os.SystemClock; +import android.provider.MediaStore; import android.support.v4.widget.SlidingPaneLayout; import android.support.v4.widget.SlidingPaneLayout.PanelSlideListener; import android.view.KeyEvent; @@ -40,6 +32,19 @@ import android.widget.PopupMenu; import android.widget.PopupMenu.OnMenuItemClickListener; import android.widget.Toast; +import java.util.ArrayList; +import java.util.List; + +import eu.siacs.conversations.R; +import eu.siacs.conversations.entities.Contact; +import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.entities.Message; +import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate; +import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdate; +import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate; +import eu.siacs.conversations.ui.adapter.ConversationAdapter; +import eu.siacs.conversations.utils.ExceptionHelper; + public class ConversationActivity extends XmppActivity implements OnAccountUpdate, OnConversationUpdate, OnRosterUpdate { @@ -78,6 +83,18 @@ public class ConversationActivity extends XmppActivity implements private Uri pendingImageUri = null; + private NfcAdapter.CreateNdefMessageCallback mNdefPushMessageCallback = new NfcAdapter.CreateNdefMessageCallback() { + @Override + public NdefMessage createNdefMessage(NfcEvent nfcEvent) { + Conversation conversation = getSelectedConversation(); + NdefMessage msg = new NdefMessage(new NdefRecord[]{ + NdefRecord.createUri("xmpp:"+conversation.getAccount().getJid().getBytes()), + NdefRecord.createApplicationRecord("eu.siacs.conversations") + }); + return msg; + } + }; + public List<Conversation> getConversationList() { return this.conversationList; } @@ -147,6 +164,8 @@ public class ConversationActivity extends XmppActivity implements getActionBar().setDisplayHomeAsUpEnabled(false); getActionBar().setHomeButtonEnabled(false); + registerNdefPushMessageCallback(this.mNdefPushMessageCallback); + this.listAdapter = new ConversationAdapter(this, conversationList); listView.setAdapter(this.listAdapter); @@ -154,7 +173,7 @@ public class ConversationActivity extends XmppActivity implements @Override public void onItemClick(AdapterView<?> arg0, View clickedView, - int position, long arg3) { + int position, long arg3) { paneShouldBeOpen = false; if (getSelectedConversation() != conversationList.get(position)) { setSelectedConversation(conversationList.get(position)); @@ -224,7 +243,7 @@ public class ConversationActivity extends XmppActivity implements ab.setHomeButtonEnabled(true); if (getSelectedConversation().getMode() == Conversation.MODE_SINGLE || ConversationActivity.this - .useSubjectToIdentifyConference()) { + .useSubjectToIdentifyConference()) { ab.setTitle(getSelectedConversation().getName()); } else { ab.setTitle(getSelectedConversation().getContactJid() @@ -324,7 +343,7 @@ public class ConversationActivity extends XmppActivity implements @Override public void userInputRequried(PendingIntent pi, - Contact contact) { + Contact contact) { ConversationActivity.this.runIntent(pi, attachmentChoice); } @@ -348,7 +367,7 @@ public class ConversationActivity extends XmppActivity implements @Override public void onClick(DialogInterface dialog, - int which) { + int which) { conversation .setNextEncryption(Message.ENCRYPTION_NONE); xmppConnectionService.databaseBackend @@ -379,41 +398,41 @@ public class ConversationActivity extends XmppActivity implements return true; } else if (getSelectedConversation() != null) { switch (item.getItemId()) { - case R.id.action_attach_file: - attachFileDialog(); - break; - case R.id.action_archive: - this.endConversation(getSelectedConversation()); - break; - case R.id.action_contact_details: - Contact contact = this.getSelectedConversation().getContact(); - if (contact.showInRoster()) { - switchToContactDetails(contact); - } else { - showAddToRosterDialog(getSelectedConversation()); - } - break; - case R.id.action_muc_details: - Intent intent = new Intent(this, - ConferenceDetailsActivity.class); - intent.setAction(ConferenceDetailsActivity.ACTION_VIEW_MUC); - intent.putExtra("uuid", getSelectedConversation().getUuid()); - startActivity(intent); - break; - case R.id.action_invite: - inviteToConversation(getSelectedConversation()); - break; - case R.id.action_security: - selectEncryptionDialog(getSelectedConversation()); - break; - case R.id.action_clear_history: - clearHistoryDialog(getSelectedConversation()); - break; - case R.id.action_mute: - muteConversationDialog(getSelectedConversation()); - break; - default: - break; + case R.id.action_attach_file: + attachFileDialog(); + break; + case R.id.action_archive: + this.endConversation(getSelectedConversation()); + break; + case R.id.action_contact_details: + Contact contact = this.getSelectedConversation().getContact(); + if (contact.showInRoster()) { + switchToContactDetails(contact); + } else { + showAddToRosterDialog(getSelectedConversation()); + } + break; + case R.id.action_muc_details: + Intent intent = new Intent(this, + ConferenceDetailsActivity.class); + intent.setAction(ConferenceDetailsActivity.ACTION_VIEW_MUC); + intent.putExtra("uuid", getSelectedConversation().getUuid()); + startActivity(intent); + break; + case R.id.action_invite: + inviteToConversation(getSelectedConversation()); + break; + case R.id.action_security: + selectEncryptionDialog(getSelectedConversation()); + break; + case R.id.action_clear_history: + clearHistoryDialog(getSelectedConversation()); + break; + case R.id.action_mute: + muteConversationDialog(getSelectedConversation()); + break; + default: + break; } return super.onOptionsItemSelected(item); } else { @@ -471,15 +490,15 @@ public class ConversationActivity extends XmppActivity implements @Override public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()) { - case R.id.attach_choose_picture: - attachFile(ATTACHMENT_CHOICE_CHOOSE_IMAGE); - break; - case R.id.attach_take_picture: - attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO); - break; - case R.id.attach_record_voice: - attachFile(ATTACHMENT_CHOICE_RECORD_VOICE); - break; + case R.id.attach_choose_picture: + attachFile(ATTACHMENT_CHOICE_CHOOSE_IMAGE); + break; + case R.id.attach_take_picture: + attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO); + break; + case R.id.attach_record_voice: + attachFile(ATTACHMENT_CHOICE_RECORD_VOICE); + break; } return false; } @@ -501,32 +520,32 @@ public class ConversationActivity extends XmppActivity implements @Override public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()) { - case R.id.encryption_choice_none: - conversation.setNextEncryption(Message.ENCRYPTION_NONE); - item.setChecked(true); - break; - case R.id.encryption_choice_otr: - conversation.setNextEncryption(Message.ENCRYPTION_OTR); - item.setChecked(true); - break; - case R.id.encryption_choice_pgp: - if (hasPgp()) { - if (conversation.getAccount().getKeys() - .has("pgp_signature")) { - conversation - .setNextEncryption(Message.ENCRYPTION_PGP); - item.setChecked(true); + case R.id.encryption_choice_none: + conversation.setNextEncryption(Message.ENCRYPTION_NONE); + item.setChecked(true); + break; + case R.id.encryption_choice_otr: + conversation.setNextEncryption(Message.ENCRYPTION_OTR); + item.setChecked(true); + break; + case R.id.encryption_choice_pgp: + if (hasPgp()) { + if (conversation.getAccount().getKeys() + .has("pgp_signature")) { + conversation + .setNextEncryption(Message.ENCRYPTION_PGP); + item.setChecked(true); + } else { + announcePgp(conversation.getAccount(), + conversation); + } } else { - announcePgp(conversation.getAccount(), - conversation); + showInstallPgpDialog(); } - } else { - showInstallPgpDialog(); - } - break; - default: - conversation.setNextEncryption(Message.ENCRYPTION_NONE); - break; + break; + default: + conversation.setNextEncryption(Message.ENCRYPTION_NONE); + break; } xmppConnectionService.databaseBackend .updateConversation(conversation); @@ -546,20 +565,20 @@ public class ConversationActivity extends XmppActivity implements } } switch (conversation.getNextEncryption(forceEncryption())) { - case Message.ENCRYPTION_NONE: - none.setChecked(true); - break; - case Message.ENCRYPTION_OTR: - otr.setChecked(true); - break; - case Message.ENCRYPTION_PGP: - popup.getMenu().findItem(R.id.encryption_choice_pgp) - .setChecked(true); - break; - default: - popup.getMenu().findItem(R.id.encryption_choice_none) - .setChecked(true); - break; + case Message.ENCRYPTION_NONE: + none.setChecked(true); + break; + case Message.ENCRYPTION_OTR: + otr.setChecked(true); + break; + case Message.ENCRYPTION_PGP: + popup.getMenu().findItem(R.id.encryption_choice_pgp) + .setChecked(true); + break; + default: + popup.getMenu().findItem(R.id.encryption_choice_none) + .setChecked(true); + break; } popup.show(); } @@ -736,7 +755,7 @@ public class ConversationActivity extends XmppActivity implements @Override protected void onActivityResult(int requestCode, int resultCode, - final Intent data) { + final Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { if (requestCode == REQUEST_DECRYPT_PGP) { @@ -798,7 +817,7 @@ public class ConversationActivity extends XmppActivity implements @Override public void userInputRequried(PendingIntent pi, - Message object) { + Message object) { hidePrepareImageToast(); ConversationActivity.this.runIntent(pi, ConversationActivity.REQUEST_SEND_PGP_IMAGE); @@ -849,7 +868,7 @@ public class ConversationActivity extends XmppActivity implements @Override public void userInputRequried(PendingIntent pi, - Message message) { + Message message) { ConversationActivity.this.runIntent(pi, ConversationActivity.REQUEST_SEND_MESSAGE); } diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java index 416e926a..2dd74d9f 100644 --- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java @@ -1,6 +1,8 @@ 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; @@ -19,11 +21,15 @@ import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.net.Uri; +import android.nfc.NdefMessage; +import android.nfc.NfcAdapter; import android.os.Bundle; +import android.os.Parcelable; 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; @@ -40,6 +46,8 @@ import android.widget.CheckBox; import android.widget.EditText; import android.widget.ListView; import android.widget.Spinner; + +import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Bookmark; @@ -371,7 +379,7 @@ public class StartConversationActivity extends XmppActivity { } @SuppressLint("InflateParams") - protected void showJoinConferenceDialog() { + protected void showJoinConferenceDialog(String prefilledJid) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.join_conference); View dialogView = getLayoutInflater().inflate( @@ -381,6 +389,9 @@ public class StartConversationActivity extends XmppActivity { .findViewById(R.id.jid); jid.setAdapter(new KnownHostsAdapter(this, android.R.layout.simple_list_item_1, mKnownConferenceHosts)); + if (prefilledJid != null) { + jid.append(prefilledJid); + } populateAccountSpinner(spinner); final CheckBox bookmarkCheckBox = (CheckBox) dialogView .findViewById(R.id.bookmark); @@ -493,7 +504,7 @@ public class StartConversationActivity extends XmppActivity { showCreateContactDialog(null); break; case R.id.action_join_conference: - showJoinConferenceDialog(); + showJoinConferenceDialog(null); break; } return super.onOptionsItemSelected(item); @@ -520,7 +531,7 @@ public class StartConversationActivity extends XmppActivity { this.mKnownHosts = xmppConnectionService.getKnownHosts(); this.mKnownConferenceHosts = xmppConnectionService .getKnownConferenceHosts(); - if (!startByIntent()) { + if (!handleIntent(getIntent())) { if (mSearchEditText != null) { filter(mSearchEditText.getText().toString()); } else { @@ -529,26 +540,48 @@ public class StartConversationActivity extends XmppActivity { } } - protected boolean startByIntent() { - if (getIntent() != null - && Intent.ACTION_SENDTO.equals(getIntent().getAction())) { - try { - String jid = URLDecoder.decode( - getIntent().getData().getEncodedPath(), "UTF-8").split( - "/")[1]; - setIntent(null); - return handleJid(jid); - } catch (UnsupportedEncodingException e) { - setIntent(null); + protected boolean handleIntent(Intent intent) { + if (intent==null || intent.getAction() == null) { + return false; + } + String jid; + switch(intent.getAction()) { + case Intent.ACTION_SENDTO: + try { + jid = URLDecoder.decode( + intent.getData().getEncodedPath(), "UTF-8").split( + "/")[1]; + return handleJid(jid); + } catch (UnsupportedEncodingException e) { + 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); + return false; + } else { + return handleJid(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); + } else { + return false; + } + default: return false; - } - } else if (getIntent() != null - && Intent.ACTION_VIEW.equals(getIntent().getAction())) { - Uri uri = getIntent().getData(); - String jid = uri.getSchemeSpecificPart().split("\\?")[0]; - return handleJid(jid); } - return false; } private boolean handleJid(String jid) { diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index 222f3295..53602571 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -38,6 +38,7 @@ import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.nfc.NfcAdapter; import android.os.AsyncTask; import android.os.Bundle; import android.os.IBinder; @@ -543,6 +544,13 @@ public abstract class XmppActivity extends Activity { return false; } + protected void registerNdefPushMessageCallback(NfcAdapter.CreateNdefMessageCallback callback) { + NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this); + if (nfcAdapter!=null && nfcAdapter.isEnabled()) { + nfcAdapter.setNdefPushMessageCallback(callback,this); + } + } + public AvatarService avatarService() { return xmppConnectionService.getAvatarService(); } |