diff --git a/src/cheogram/java/eu/siacs/conversations/ui/WelcomeActivity.java b/src/cheogram/java/eu/siacs/conversations/ui/WelcomeActivity.java index 9f91e0b687c8299ba15b8ab8e9573e0d74337e2c..5c23520c596c8381b7e8c934b33bbc3bc2725901 100644 --- a/src/cheogram/java/eu/siacs/conversations/ui/WelcomeActivity.java +++ b/src/cheogram/java/eu/siacs/conversations/ui/WelcomeActivity.java @@ -17,15 +17,18 @@ import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.databinding.DataBindingUtil; +import java.security.SecureRandom; import java.util.Arrays; import java.util.List; import java.util.HashSet; +import java.util.UUID; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.databinding.ActivityWelcomeBinding; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.services.XmppConnectionService; +import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.Compatibility; import eu.siacs.conversations.utils.InstallReferrerUtils; import eu.siacs.conversations.utils.SignupUtils; @@ -35,11 +38,12 @@ import eu.siacs.conversations.xmpp.Jid; import static eu.siacs.conversations.utils.PermissionUtils.allGranted; import static eu.siacs.conversations.utils.PermissionUtils.writeGranted; -public class WelcomeActivity extends XmppActivity implements XmppConnectionService.OnAccountCreated, KeyChainAliasCallback { +public class WelcomeActivity extends XmppActivity implements XmppConnectionService.OnAccountCreated, XmppConnectionService.OnAccountUpdate, KeyChainAliasCallback { private static final int REQUEST_IMPORT_BACKUP = 0x63fb; private XmppUri inviteUri; + private Account onboardingAccount = null; public static void launch(AppCompatActivity activity) { Intent intent = new Intent(activity, WelcomeActivity.class); @@ -82,8 +86,21 @@ public class WelcomeActivity extends XmppActivity implements XmppConnectionServi } @Override - protected void refreshUiReal() { + protected synchronized void refreshUiReal() { + if (onboardingAccount == null) return; + if (onboardingAccount.getStatus() != Account.State.ONLINE) return; + Intent intent = new Intent(this, StartConversationActivity.class); + intent.putExtra("init", true); + intent.putExtra(EXTRA_ACCOUNT, onboardingAccount.getJid().asBareJid().toEscapedString()); + onboardingAccount = null; + startActivity(intent); + finish(); + } + + @Override + public void onAccountUpdate() { + refreshUi(); } @Override @@ -124,9 +141,18 @@ public class WelcomeActivity extends XmppActivity implements XmppConnectionServi setSupportActionBar(binding.toolbar); configureActionBar(getSupportActionBar(), false); binding.registerNewAccount.setOnClickListener(v -> { - final Intent intent = new Intent(this, MagicCreateActivity.class); - addInviteUri(intent); - startActivity(intent); + if (hasInviteUri()) { + final Intent intent = new Intent(this, MagicCreateActivity.class); + addInviteUri(intent); + startActivity(intent); + } else { + binding.registerNewAccount.setText("Working..."); + binding.registerNewAccount.setEnabled(false); + onboardingAccount = new Account(Jid.ofLocalAndDomain(UUID.randomUUID().toString(), Config.ONBOARDING_DOMAIN.toEscapedString()), CryptoHelper.createPassword(new SecureRandom())); + onboardingAccount.setOption(Account.OPTION_REGISTER, true); + onboardingAccount.setOption(Account.OPTION_FIXED_USERNAME, true); + xmppConnectionService.createAccount(onboardingAccount); + } }); binding.useExisting.setOnClickListener(v -> { final List accounts = xmppConnectionService.getAccounts(); @@ -235,6 +261,12 @@ public class WelcomeActivity extends XmppActivity implements XmppConnectionServi } } + protected boolean hasInviteUri() { + final Intent from = getIntent(); + if (from != null && from.hasExtra(StartConversationActivity.EXTRA_INVITE_URI)) return true; + return this.inviteUri != null; + } + public void addInviteUri(Intent to) { final Intent from = getIntent(); if (from != null && from.hasExtra(StartConversationActivity.EXTRA_INVITE_URI)) { diff --git a/src/cheogram/java/eu/siacs/conversations/utils/SignupUtils.java b/src/cheogram/java/eu/siacs/conversations/utils/SignupUtils.java index fb088234a24e10ea315bafebd910e28df9caa270..14dc3f79443f98597f8f2306e522284327bb8a3f 100644 --- a/src/cheogram/java/eu/siacs/conversations/utils/SignupUtils.java +++ b/src/cheogram/java/eu/siacs/conversations/utils/SignupUtils.java @@ -62,7 +62,7 @@ public class SignupUtils { if (Config.X509_VERIFICATION) { intent = new Intent(activity, ManageAccountActivity.class); } else if (Config.MAGIC_CREATE_DOMAIN != null) { - intent = getSignUpIntent(activity); + intent = activity.xmppConnectionService.getPreferences().contains("onboarding_action") ? new Intent(activity, MagicCreateActivity.class) : getSignUpIntent(activity); } else { intent = new Intent(activity, EditAccountActivity.class); } @@ -70,8 +70,7 @@ public class SignupUtils { intent = new Intent(activity, StartConversationActivity.class); } } - intent.putExtra("init", true); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); return intent; } -} \ No newline at end of file +} diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index 681fdee3c7a3c9822aa3565d6c92b1a9f7215c66..73453583c237a0ad8b8c3e7b03fcb7a80f74c12d 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -48,6 +48,7 @@ public final class Config { public static final String DOMAIN_LOCK = null; //only allow account creation for this domain public static final String MAGIC_CREATE_DOMAIN = "chatterboxtown.us"; public static final Jid QUICKSY_DOMAIN = Jid.of("cheogram.com"); + public static final Jid ONBOARDING_DOMAIN = Jid.of("onboarding.cheogram.com"); public static final String CHANNEL_DISCOVERY = "https://search.jabber.network"; diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index 28899827f9ebdab85ea0f183c0d54c67985e00ce..43a4ffd7c55b906e5fb5dc2630951c948fb4b2b2 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -3,6 +3,7 @@ package eu.siacs.conversations.entities; import android.content.ContentValues; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; import android.database.Cursor; import android.database.DataSetObserver; import android.graphics.drawable.BitmapDrawable; @@ -102,6 +103,7 @@ import eu.siacs.conversations.persistance.DatabaseBackend; import eu.siacs.conversations.services.AvatarService; import eu.siacs.conversations.services.QuickConversationsService; import eu.siacs.conversations.services.XmppConnectionService; +import eu.siacs.conversations.ui.UriHandlerActivity; import eu.siacs.conversations.ui.text.FixedURLSpan; import eu.siacs.conversations.ui.util.ShareUtil; import eu.siacs.conversations.ui.util.SoftKeyboardUtils; @@ -1301,8 +1303,12 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl pagerAdapter.startCommand(command, xmppConnectionService); } - public void setupViewPager(ViewPager pager, TabLayout tabs) { - pagerAdapter.setupViewPager(pager, tabs); + public boolean switchToSession(final String node) { + return pagerAdapter.switchToSession(node); + } + + public void setupViewPager(ViewPager pager, TabLayout tabs, boolean onboarding) { + pagerAdapter.setupViewPager(pager, tabs, onboarding); } public void showViewPager() { @@ -1341,10 +1347,12 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl ArrayList sessions = null; protected View page1 = null; protected View page2 = null; + protected boolean mOnboarding = false; - public void setupViewPager(ViewPager pager, TabLayout tabs) { + public void setupViewPager(ViewPager pager, TabLayout tabs, boolean onboarding) { mPager = pager; mTabs = tabs; + mOnboarding = onboarding; if (mPager == null) return; if (sessions != null) show(); @@ -1370,7 +1378,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl sessions = new ArrayList<>(); notifyDataSetChanged(); } - if (mTabs != null) mTabs.setVisibility(View.VISIBLE); + if (!mOnboarding && mTabs != null) mTabs.setVisibility(View.VISIBLE); } public void hide() { @@ -1390,27 +1398,32 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl final Element c = packet.addChild("command", Namespace.COMMANDS); c.setAttribute("node", command.getAttribute("node")); c.setAttribute("action", "execute"); - View v = mPager; + + final TimerTask task = new TimerTask() { + @Override + public void run() { + if (getAccount().getStatus() != Account.State.ONLINE) { + new Timer().schedule(this, 1000); + } else { + xmppConnectionService.sendIqPacket(getAccount(), packet, (a, iq) -> { + session.updateWithResponse(iq); + }); + } + } + }; + task.run(); if (command.getAttribute("node").equals("jabber:iq:register") && packet.getTo().asBareJid().equals(Jid.of("cheogram.com"))) { - new com.cheogram.android.CheogramLicenseChecker(v.getContext(), (signedData, signature) -> { + new com.cheogram.android.CheogramLicenseChecker(mPager.getContext(), (signedData, signature) -> { if (signedData != null && signature != null) { c.addChild("license", "https://ns.cheogram.com/google-play").setContent(signedData); c.addChild("licenseSignature", "https://ns.cheogram.com/google-play").setContent(signature); } - xmppConnectionService.sendIqPacket(getAccount(), packet, (a, iq) -> { - v.post(() -> { - session.updateWithResponse(iq); - }); - }); + task.run(); }).checkLicense(); } else { - xmppConnectionService.sendIqPacket(getAccount(), packet, (a, iq) -> { - v.post(() -> { - session.updateWithResponse(iq); - }); - }); + task.run(); } sessions.add(session); @@ -1423,6 +1436,21 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl notifyDataSetChanged(); } + public boolean switchToSession(final String node) { + if (sessions == null) return false; + + int i = 0; + for (CommandSession session : sessions) { + if (session.mNode.equals(node)) { + if (mPager != null) mPager.setCurrentItem(i + 2); + return true; + } + i++; + } + + return false; + } + @NonNull @Override public Object instantiateItem(@NonNull ViewGroup container, int position) { @@ -2376,6 +2404,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl protected GridLayoutManager layoutManager; protected WebView actionToWebview = null; protected int fillableFieldCount = 0; + protected IqPacket pendingResponsePacket = null; CommandSession(String title, String node, XmppConnectionService xmppConnectionService) { loading(); @@ -2401,7 +2430,15 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl return mTitle; } - public void updateWithResponse(IqPacket iq) { + public void updateWithResponse(final IqPacket iq) { + if (getView() != null && getView().isAttachedToWindow()) { + getView().post(() -> updateWithResponseUiThread(iq)); + } else { + pendingResponsePacket = iq; + } + } + + protected void updateWithResponseUiThread(final IqPacket iq) { this.loadingTimer.cancel(); this.loadingTimer = new Timer(); this.loading = false; @@ -2476,6 +2513,13 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl this.responseElement = el; break; } + if (scheme.equals("xmpp")) { + final Intent intent = new Intent(getView().getContext(), UriHandlerActivity.class); + intent.setAction(Intent.ACTION_VIEW); + intent.setData(Uri.parse(url)); + getView().getContext().startActivity(intent); + break; + } } } if (el.getName().equals("note") && el.getNamespace().equals("http://jabber.org/protocol/commands")) { @@ -2485,6 +2529,16 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl } if (responseElement == null && command.getAttribute("status") != null && (command.getAttribute("status").equals("completed") || command.getAttribute("status").equals("canceled"))) { + if (mNode.equals("jabber:iq:register") && command.getAttribute("status").equals("canceled")) { + if (xmppConnectionService.isOnboarding()) { + if (!xmppConnectionService.getPreferences().contains("onboarding_action")) { + xmppConnectionService.getPreferences().edit().putString("onboarding_action", "cancel").commit(); + } + xmppConnectionService.deleteAccount(getAccount()); + } + xmppConnectionService.archiveConversation(Conversation.this); + } + removeSession(this); return; } @@ -2498,7 +2552,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl if (!actionsAdapter.isEmpty() || fillableFieldCount > 0) { if (command.getAttribute("status").equals("completed") || command.getAttribute("status").equals("canceled")) { actionsAdapter.add(Pair.create("close", "close")); - } else if (actionsAdapter.getPosition("cancel") < 0) { + } else if (actionsAdapter.getPosition("cancel") < 0 && !xmppConnectionService.isOnboarding()) { actionsAdapter.insert(Pair.create("cancel", "cancel"), 0); } } @@ -2508,6 +2562,25 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl actionsAdapter.add(Pair.create("close", "close")); } + actionsAdapter.sort((x, y) -> { + if (x.first.equals("cancel")) return -1; + if (y.first.equals("cancel")) return 1; + if (x.first.equals("prev") && xmppConnectionService.isOnboarding()) return -1; + if (y.first.equals("prev") && xmppConnectionService.isOnboarding()) return 1; + return 0; + }); + + Data dataForm = null; + if (responseElement != null && responseElement.getName().equals("x") && responseElement.getNamespace().equals("jabber:x:data")) dataForm = Data.parse(responseElement); + if (mNode.equals("jabber:iq:register") && + xmppConnectionService.getPreferences().contains("onboarding_action") && + dataForm != null && dataForm.getFieldByName("gateway-jid") != null) { + + + dataForm.put("gateway-jid", xmppConnectionService.getPreferences().getString("onboarding_action", "")); + execute(); + } + xmppConnectionService.getPreferences().edit().remove("onboarding_action").commit(); notifyDataSetChanged(); } @@ -2693,6 +2766,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl } public View getView() { + if (mBinding == null) return null; return mBinding.getRoot(); } @@ -2750,6 +2824,10 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl c.setAttribute("action", "execute"); } + if (mNode.equals("jabber:iq:register") && xmppConnectionService.isOnboarding() && form.getValue("gateway-jid") != null) { + xmppConnectionService.getPreferences().edit().putString("onboarding_action", form.getValue("gateway-jid")).commit(); + } + responseElement.setAttribute("type", "submit"); Element rsm = responseElement.findChild("set", "http://jabber.org/protocol/rsm"); if (rsm != null) { @@ -2764,9 +2842,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl if (c.getAttribute("action") == null) c.setAttribute("action", action); xmppConnectionService.sendIqPacket(getAccount(), packet, (a, iq) -> { - getView().post(() -> { - updateWithResponse(iq); - }); + updateWithResponse(iq); }); loading(); @@ -2861,6 +2937,12 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl }); actionsAdapter.notifyDataSetChanged(); + + if (pendingResponsePacket != null) { + final IqPacket pending = pendingResponsePacket; + pendingResponsePacket = null; + updateWithResponseUiThread(pending); + } } // https://stackoverflow.com/a/36037991/8611 diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index c4e7e4f6fb8daab7af161d951843f7311f5f8bd1..5f802cd165771568a8832f89e90d4c4282a9061f 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -1805,6 +1805,10 @@ public class XmppConnectionService extends Service { sendMessage(message, true, delay); } + public boolean isOnboarding() { + return getAccounts().size() == 1 && getAccounts().get(0).getJid().getDomain().equals(Config.ONBOARDING_DOMAIN); + } + public void requestEasyOnboardingInvite(final Account account, final EasyOnboardingInvite.OnInviteRequested callback) { final XmppConnection connection = account.getXmppConnection(); final Jid jid = connection == null ? null : connection.getJidForCommand(Namespace.EASY_ONBOARDING_INVITE); diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 264cca2bc2249b4d3c2491a9040e5020afa87f94..4aea64e4fbcea08a93d84f49d81e241bc67a897e 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -1202,6 +1202,8 @@ public class ConversationFragment extends XmppFragment @Override public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { + if (activity.xmppConnectionService.isOnboarding()) return; + menuInflater.inflate(R.menu.fragment_conversation, menu); final MenuItem menuMucDetails = menu.findItem(R.id.action_muc_details); final MenuItem menuContactDetails = menu.findItem(R.id.action_contact_details); @@ -1357,7 +1359,7 @@ public class ConversationFragment extends XmppFragment messageListAdapter.setOnContactPictureClicked(null); messageListAdapter.setOnContactPictureLongClicked(null); messageListAdapter.setOnInlineImageLongClicked(null); - if (conversation != null) conversation.setupViewPager(null, null); + if (conversation != null) conversation.setupViewPager(null, null, false); } private void quoteText(String text) { @@ -2836,12 +2838,12 @@ public class ConversationFragment extends XmppFragment .setOpenConversation(this.conversation); if (commandAdapter != null && conversation != originalConversation) { - originalConversation.setupViewPager(null, null); - conversation.setupViewPager(binding.conversationViewPager, binding.tabLayout); + originalConversation.setupViewPager(null, null, false); + conversation.setupViewPager(binding.conversationViewPager, binding.tabLayout, activity.xmppConnectionService.isOnboarding()); refreshCommands(false); } if (commandAdapter == null && conversation != null) { - conversation.setupViewPager(binding.conversationViewPager, binding.tabLayout); + conversation.setupViewPager(binding.conversationViewPager, binding.tabLayout, activity.xmppConnectionService.isOnboarding()); commandAdapter = new CommandAdapter((XmppActivity) getActivity()); binding.commandsView.setAdapter(commandAdapter); binding.commandsView.setOnItemClickListener((parent, view, position, id) -> { @@ -2862,6 +2864,9 @@ public class ConversationFragment extends XmppFragment if (commandAdapter == null) return; Jid commandJid = conversation.getContact().resourceWhichSupport(Namespace.COMMANDS); + if (commandJid == null && conversation.getJid().isDomainJid()) { + commandJid = conversation.getJid(); + } if (commandJid == null) { conversation.hideViewPager(); } else { @@ -3006,6 +3011,11 @@ public class ConversationFragment extends XmppFragment if (message != null) { startDownloadable(message); } + if (activity.xmppConnectionService.isOnboarding() && conversation.getJid().equals(Jid.of("cheogram.com"))) { + if (!conversation.switchToSession("jabber:iq:register")) { + conversation.startCommand(commandFor(Jid.of("cheogram.com/CHEOGRAM%jabber:iq:register"), "jabber:iq:register"), activity.xmppConnectionService); + } + } } private Element commandFor(final Jid jid, final String node) { diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java index 5af53409fb5fbfba05b4e142f59fb3c9a92ef2f4..0ef347cfc21fc33b36c86453015ae0d8067c3a72 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java @@ -199,6 +199,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio if (xmppConnectionService == null) { return false; } + boolean isConversationsListEmpty = xmppConnectionService.isConversationsListEmpty(ignore); if (isConversationsListEmpty && mRedirectInProcess.compareAndSet(false, true)) { final Intent intent = SignupUtils.getRedirectionIntent(this); @@ -216,7 +217,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio } private void showDialogsIfMainIsOverview() { - if (xmppConnectionService == null) { + if (xmppConnectionService == null || xmppConnectionService.isOnboarding()) { return; } final Fragment fragment = getFragmentManager().findFragmentById(R.id.main_fragment); @@ -486,7 +487,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio getMenuInflater().inflate(R.menu.activity_conversations, menu); final MenuItem qrCodeScanMenuItem = menu.findItem(R.id.action_scan_qr_code); if (qrCodeScanMenuItem != null) { - if (isCameraFeatureAvailable()) { + if (isCameraFeatureAvailable() && (xmppConnectionService == null || !xmppConnectionService.isOnboarding())) { Fragment fragment = getFragmentManager().findFragmentById(R.id.main_fragment); boolean visible = getResources().getBoolean(R.bool.show_qr_code_scan) && fragment instanceof ConversationsOverviewFragment; @@ -576,7 +577,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio final Conversation conversation = xmppConnectionService.findUniqueConversationByJid(xmppUri); if (conversation != null) { if (xmppUri.isAction("command")) { - startCommand(conversation.getAccount(), conversation.getJid(), xmppUri.getParameter("node")); + startCommand(conversation.getAccount(), xmppUri.getJid(), xmppUri.getParameter("node")); } else { Bundle extras = new Bundle(); extras.putString(Intent.EXTRA_TEXT, xmppUri.getBody()); @@ -740,10 +741,10 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio final Conversation conversation = ((ConversationFragment) mainFragment).getConversation(); if (conversation != null) { actionBar.setTitle(conversation.getName()); - actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setDisplayHomeAsUpEnabled(!xmppConnectionService.isOnboarding()); ActionBarUtil.setActionBarOnClickListener( binding.toolbar, - (v) -> openConversationDetails(conversation) + (v) -> { if(!xmppConnectionService.isOnboarding()) openConversationDetails(conversation); } ); return; } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java index 239c68c68cc85a56e7ee3b48271d0bd2fbf6da3a..bc3667332ddcf9f7781c937ce001fe609a59b93a 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java @@ -316,6 +316,13 @@ public class ConversationsOverviewFragment extends XmppFragment { AccountUtils.showHideMenuItems(menu); final MenuItem easyOnboardInvite = menu.findItem(R.id.action_easy_invite); easyOnboardInvite.setVisible(EasyOnboardingInvite.anyHasSupport(activity == null ? null : activity.xmppConnectionService)); + if (activity.xmppConnectionService != null && activity.xmppConnectionService.isOnboarding()) { + final MenuItem manageAccounts = menu.findItem(R.id.action_accounts); + if (manageAccounts != null) manageAccounts.setVisible(false); + + final MenuItem settings = menu.findItem(R.id.action_settings); + if (settings != null) settings.setVisible(false); + } } @Override @@ -380,6 +387,11 @@ public class ConversationsOverviewFragment extends XmppFragment { @Override public void onBackendConnected() { refresh(); + if (activity.xmppConnectionService.isOnboarding()) { + binding.fab.setVisibility(View.GONE); + } else { + binding.fab.setVisibility(View.VISIBLE); + } } @Override diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java index 6c6a9b0ea46e88147ef1853025ccb33903e2d214..14d32493b48e98551f2bb206c6aeddefa8471f08 100644 --- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java @@ -95,9 +95,13 @@ import eu.siacs.conversations.ui.widget.SwipeRefreshListFragment; import eu.siacs.conversations.utils.AccountUtils; import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.utils.XmppUri; +import eu.siacs.conversations.xml.Element; +import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xmpp.Jid; import eu.siacs.conversations.xmpp.OnUpdateBlocklist; import eu.siacs.conversations.xmpp.XmppConnection; +import eu.siacs.conversations.xmpp.forms.Data; +import eu.siacs.conversations.xmpp.stanzas.IqPacket; public class StartConversationActivity extends XmppActivity implements XmppConnectionService.OnConversationUpdate, OnRosterUpdate, OnUpdateBlocklist, CreatePrivateGroupChatDialog.CreateConferenceDialogListener, JoinConferenceDialog.JoinConferenceDialogListener, SwipeRefreshLayout.OnRefreshListener, CreatePublicChannelDialog.CreatePublicChannelDialogListener { @@ -913,13 +917,19 @@ public class StartConversationActivity extends XmppActivity implements XmppConne configureHomeButton(); Intent intent = pendingViewIntent.pop(); - if (intent != null && intent.getBooleanExtra("init", false)) { + final boolean onboardingCancel = xmppConnectionService.getPreferences().getString("onboarding_action", "").equals("cancel"); + if (onboardingCancel) xmppConnectionService.getPreferences().edit().remove("onboarding_action").commit(); + + if (intent != null && intent.getBooleanExtra("init", false) && !onboardingCancel) { Account selectedAccount = xmppConnectionService.getAccounts().get(0); final String accountJid = intent.getStringExtra(EXTRA_ACCOUNT); intent = null; boolean hasPstnOrSms = false; + Account onboardingAccount = null; outer: for (Account account : xmppConnectionService.getAccounts()) { + if (onboardingAccount == null && account.getJid().getDomain().equals(Config.ONBOARDING_DOMAIN)) onboardingAccount = account; + if (accountJid != null) { if(account.getJid().asBareJid().toEscapedString().equals(accountJid)) { selectedAccount = account; @@ -941,9 +951,88 @@ public class StartConversationActivity extends XmppActivity implements XmppConne } if (!hasPstnOrSms) { - startCommand(selectedAccount, Jid.of("cheogram.com/CHEOGRAM%jabber:iq:register"), "jabber:iq:register"); - finish(); - return; + if (onboardingAccount != null && !selectedAccount.getJid().equals(onboardingAccount.getJid())) { + final Account onboardAccount = onboardingAccount; + final Account newAccount = selectedAccount; + final IqPacket packet = new IqPacket(IqPacket.TYPE.SET); + packet.setTo(Jid.of("cheogram.com")); + final Element c = packet.addChild("command", Namespace.COMMANDS); + c.setAttribute("node", "change jabber id"); + c.setAttribute("action", "execute"); + + xmppConnectionService.sendIqPacket(onboardingAccount, packet, (a, iq) -> { + Element command = iq.findChild("command", "http://jabber.org/protocol/commands"); + if (command == null) { + Log.e(Config.LOGTAG, "Did not get expected data form from cheogram, got: " + iq); + return; + } + + Element form = command.findChild("x", "jabber:x:data"); + Data dataForm = form == null ? null : Data.parse(form); + if (dataForm == null || dataForm.getFieldByName("new-jid") == null) { + Log.e(Config.LOGTAG, "Did not get expected data form from cheogram, got: " + iq); + return; + } + + dataForm.put("new-jid", newAccount.getJid().toEscapedString()); + dataForm.submit(); + command.setAttribute("action", "execute"); + iq.setTo(iq.getFrom()); + iq.setAttribute("type", "set"); + iq.removeAttribute("from"); + iq.removeAttribute("id"); + xmppConnectionService.sendIqPacket(a, iq, (a2, iq2) -> { + Element command2 = iq2.findChild("command", "http://jabber.org/protocol/commands"); + if (command2 != null && command2.getAttribute("status") != null && command2.getAttribute("status").equals("completed")) { + final IqPacket regPacket = new IqPacket(IqPacket.TYPE.SET); + regPacket.setTo(Jid.of("cheogram.com/CHEOGRAM%jabber:iq:register")); + final Element c2 = regPacket.addChild("command", Namespace.COMMANDS); + c2.setAttribute("node", "jabber:iq:register"); + c2.setAttribute("action", "execute"); + xmppConnectionService.sendIqPacket(newAccount, regPacket, (a3, iq3) -> { + Element command3 = iq3.findChild("command", "http://jabber.org/protocol/commands"); + if (command3 == null) { + Log.e(Config.LOGTAG, "Did not get expected data form from cheogram, got: " + iq3); + return; + } + + Element form3 = command3.findChild("x", "jabber:x:data"); + Data dataForm3 = form3 == null ? null : Data.parse(form3); + if (dataForm3 == null || dataForm3.getFieldByName("confirm") == null) { + Log.e(Config.LOGTAG, "Did not get expected data form from cheogram, got: " + iq3); + return; + } + + dataForm3.put("confirm", "true"); + dataForm3.submit(); + command3.setAttribute("action", "execute"); + iq3.setTo(iq3.getFrom()); + iq3.setAttribute("type", "set"); + iq3.removeAttribute("from"); + iq3.removeAttribute("id"); + xmppConnectionService.sendIqPacket(newAccount, iq3, (a4, iq4) -> { + Element command4 = iq2.findChild("command", "http://jabber.org/protocol/commands"); + if (command4 != null && command4.getAttribute("status") != null && command4.getAttribute("status").equals("completed")) { + xmppConnectionService.createContact(newAccount.getRoster().getContact(iq4.getFrom().asBareJid()), true); + Conversation withCheogram = xmppConnectionService.findOrCreateConversation(newAccount, iq4.getFrom().asBareJid(), true, true, true); + xmppConnectionService.markRead(withCheogram); + xmppConnectionService.clearConversationHistory(withCheogram); + xmppConnectionService.deleteAccount(onboardAccount); + } else { + Log.e(Config.LOGTAG, "Error confirming jid switch, got: " + iq4); + } + }); + }); + } else { + Log.e(Config.LOGTAG, "Error during jid switch, got: " + iq2); + } + }); + }); + } else { + startCommand(selectedAccount, Jid.of("cheogram.com/CHEOGRAM%jabber:iq:register"), "jabber:iq:register"); + finish(); + return; + } } } @@ -1119,7 +1208,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne final boolean sopranicaDeleted = getPreferences().getBoolean("cheogram_sopranica_bookmark_deleted", false); - if (!sopranicaDeleted && !foundSopranica && (needle == null || needle.equals(""))) { + if (!sopranicaDeleted && !foundSopranica && (needle == null || needle.equals("")) && xmppConnectionService.getAccounts().size() > 0) { Bookmark bookmark = new Bookmark( xmppConnectionService.getAccounts().get(0), Jid.of("discuss@conference.soprani.ca") diff --git a/src/main/java/eu/siacs/conversations/xmpp/forms/Option.java b/src/main/java/eu/siacs/conversations/xmpp/forms/Option.java index f810fffec8a602af3b4f2734cb38867ec93b593e..4f506594f66f14e67ea2eb5627d7864e81355104 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/forms/Option.java +++ b/src/main/java/eu/siacs/conversations/xmpp/forms/Option.java @@ -14,7 +14,7 @@ public class Option { public static List