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