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