1package eu.siacs.conversations.ui;
2
3import android.Manifest;
4import android.content.ActivityNotFoundException;
5import android.content.Intent;
6import android.content.pm.ActivityInfo;
7import android.net.Uri;
8import android.os.Bundle;
9import android.security.KeyChain;
10import android.security.KeyChainAliasCallback;
11import android.util.Log;
12import android.view.Menu;
13import android.view.MenuItem;
14import android.widget.Toast;
15
16import androidx.annotation.NonNull;
17import androidx.appcompat.app.AppCompatActivity;
18import androidx.databinding.DataBindingUtil;
19
20import java.util.Arrays;
21import java.util.List;
22
23import eu.siacs.conversations.Config;
24import eu.siacs.conversations.R;
25import eu.siacs.conversations.databinding.ActivityWelcomeBinding;
26import eu.siacs.conversations.entities.Account;
27import eu.siacs.conversations.services.XmppConnectionService;
28import eu.siacs.conversations.utils.Compatibility;
29import eu.siacs.conversations.utils.InstallReferrerUtils;
30import eu.siacs.conversations.utils.SignupUtils;
31import eu.siacs.conversations.utils.XmppUri;
32import eu.siacs.conversations.xmpp.Jid;
33
34import static eu.siacs.conversations.utils.PermissionUtils.allGranted;
35import static eu.siacs.conversations.utils.PermissionUtils.writeGranted;
36
37public class WelcomeActivity extends XmppActivity implements XmppConnectionService.OnAccountCreated, KeyChainAliasCallback {
38
39 private static final int REQUEST_IMPORT_BACKUP = 0x63fb;
40
41 private XmppUri inviteUri;
42
43 public static void launch(AppCompatActivity activity) {
44 Intent intent = new Intent(activity, WelcomeActivity.class);
45 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
46 activity.startActivity(intent);
47 activity.overridePendingTransition(0, 0);
48 }
49
50 public void onInstallReferrerDiscovered(final Uri referrer) {
51 Log.d(Config.LOGTAG, "welcome activity: on install referrer discovered " + referrer);
52 if ("xmpp".equalsIgnoreCase(referrer.getScheme())) {
53 final XmppUri xmppUri = new XmppUri(referrer);
54 runOnUiThread(() -> processXmppUri(xmppUri));
55 } else {
56 Log.i(Config.LOGTAG, "install referrer was not an XMPP uri");
57 }
58 }
59
60 private void processXmppUri(final XmppUri xmppUri) {
61 if (!xmppUri.isValidJid()) {
62 return;
63 }
64 final String preAuth = xmppUri.getParameter(XmppUri.PARAMETER_PRE_AUTH);
65 final Jid jid = xmppUri.getJid();
66 final Intent intent;
67 if (xmppUri.isAction(XmppUri.ACTION_REGISTER)) {
68 intent = SignupUtils.getTokenRegistrationIntent(this, jid, preAuth);
69 } else if (xmppUri.isAction(XmppUri.ACTION_ROSTER) && "y".equals(xmppUri.getParameter(XmppUri.PARAMETER_IBR))) {
70 intent = SignupUtils.getTokenRegistrationIntent(this, jid.getDomain(), preAuth);
71 intent.putExtra(StartConversationActivity.EXTRA_INVITE_URI, xmppUri.toString());
72 } else {
73 intent = null;
74 }
75 if (intent != null) {
76 startActivity(intent);
77 finish();
78 return;
79 }
80 this.inviteUri = xmppUri;
81 }
82
83 @Override
84 protected void refreshUiReal() {
85
86 }
87
88 @Override
89 void onBackendConnected() {
90
91 }
92
93 @Override
94 public void onStart() {
95 super.onStart();
96 final int theme = findTheme();
97 if (this.mTheme != theme) {
98 recreate();
99 }
100 new InstallReferrerUtils(this);
101 }
102
103 @Override
104 public void onStop() {
105 super.onStop();
106 }
107
108 @Override
109 public void onNewIntent(Intent intent) {
110 if (intent != null) {
111 setIntent(intent);
112 }
113 }
114
115 @Override
116 protected void onCreate(final Bundle savedInstanceState) {
117 if (getResources().getBoolean(R.bool.portrait_only)) {
118 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
119 }
120 super.onCreate(savedInstanceState);
121 ActivityWelcomeBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_welcome);
122 setSupportActionBar(binding.toolbar);
123 configureActionBar(getSupportActionBar(), false);
124 binding.registerNewAccount.setOnClickListener(v -> {
125 final Intent intent = new Intent(this, MagicCreateActivity.class);
126 addInviteUri(intent);
127 startActivity(intent);
128 });
129 binding.useExisting.setOnClickListener(v -> {
130 final List<Account> accounts = xmppConnectionService.getAccounts();
131 Intent intent = new Intent(WelcomeActivity.this, EditAccountActivity.class);
132 intent.putExtra(EditAccountActivity.EXTRA_FORCE_REGISTER, false);
133 if (accounts.size() == 1) {
134 intent.putExtra("jid", accounts.get(0).getJid().asBareJid().toString());
135 intent.putExtra("init", true);
136 } else if (accounts.size() >= 1) {
137 intent = new Intent(WelcomeActivity.this, ManageAccountActivity.class);
138 }
139 addInviteUri(intent);
140 startActivity(intent);
141 });
142 binding.useSnikket.setOnClickListener(v -> {
143 final List<Account> accounts = xmppConnectionService.getAccounts();
144 Intent intent = new Intent(WelcomeActivity.this, EditAccountActivity.class);
145 intent.putExtra(EditAccountActivity.EXTRA_FORCE_REGISTER, false);
146 intent.putExtra("snikket", true);
147 if (accounts.size() == 1) {
148 intent.putExtra("jid", accounts.get(0).getJid().asBareJid().toString());
149 intent.putExtra("init", true);
150 } else if (accounts.size() >= 1) {
151 intent = new Intent(WelcomeActivity.this, ManageAccountActivity.class);
152 }
153 addInviteUri(intent);
154 startActivity(intent);
155 });
156 }
157
158 @Override
159 public boolean onCreateOptionsMenu(Menu menu) {
160 getMenuInflater().inflate(R.menu.welcome_menu, menu);
161 final MenuItem scan = menu.findItem(R.id.action_scan_qr_code);
162 scan.setVisible(Compatibility.hasFeatureCamera(this));
163 return super.onCreateOptionsMenu(menu);
164 }
165
166
167
168 @Override
169 public boolean onOptionsItemSelected(MenuItem item) {
170 switch (item.getItemId()) {
171 case R.id.action_import_backup:
172 if (hasStoragePermission(REQUEST_IMPORT_BACKUP)) {
173 startActivity(new Intent(this, ImportBackupActivity.class));
174 }
175 break;
176 case R.id.action_scan_qr_code:
177 UriHandlerActivity.scan(this, true);
178 break;
179 case R.id.action_add_account_with_cert:
180 addAccountFromKey();
181 break;
182 }
183 return super.onOptionsItemSelected(item);
184 }
185
186 private void addAccountFromKey() {
187 try {
188 KeyChain.choosePrivateKeyAlias(this, this, null, null, null, -1, null);
189 } catch (ActivityNotFoundException e) {
190 Toast.makeText(this, R.string.device_does_not_support_certificates, Toast.LENGTH_LONG).show();
191 }
192 }
193
194 @Override
195 public void alias(final String alias) {
196 if (alias != null) {
197 xmppConnectionService.createAccountFromKey(alias, this);
198 }
199 }
200
201 @Override
202 public void onAccountCreated(final Account account) {
203 final Intent intent = new Intent(this, EditAccountActivity.class);
204 intent.putExtra("jid", account.getJid().asBareJid().toEscapedString());
205 intent.putExtra("init", true);
206 addInviteUri(intent);
207 startActivity(intent);
208 }
209
210 @Override
211 public void informUser(final int r) {
212 runOnUiThread(() -> Toast.makeText(this, r, Toast.LENGTH_LONG).show());
213 }
214
215 @Override
216 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
217 UriHandlerActivity.onRequestPermissionResult(this, requestCode, grantResults);
218 if (grantResults.length > 0) {
219 if (allGranted(grantResults)) {
220 switch (requestCode) {
221 case REQUEST_IMPORT_BACKUP:
222 startActivity(new Intent(this, ImportBackupActivity.class));
223 break;
224 }
225 } else if (Arrays.asList(permissions).contains(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
226 Toast.makeText(this, R.string.no_storage_permission, Toast.LENGTH_SHORT).show();
227 }
228 }
229 if (writeGranted(grantResults, permissions)) {
230 if (xmppConnectionService != null) {
231 xmppConnectionService.restartFileObserver();
232 }
233 }
234 }
235
236 public void addInviteUri(Intent to) {
237 final Intent from = getIntent();
238 if (from != null && from.hasExtra(StartConversationActivity.EXTRA_INVITE_URI)) {
239 final String invite = from.getStringExtra(StartConversationActivity.EXTRA_INVITE_URI);
240 to.putExtra(StartConversationActivity.EXTRA_INVITE_URI, invite);
241 } else if (this.inviteUri != null) {
242 Log.d(Config.LOGTAG, "injecting referrer uri into on-boarding flow");
243 to.putExtra(StartConversationActivity.EXTRA_INVITE_URI, this.inviteUri.toString());
244 }
245 }
246
247}