mirror of
https://github.com/M66B/FairEmail.git
synced 2025-01-01 04:35:57 +00:00
Added Gmail wizard
This commit is contained in:
parent
85e2374c90
commit
0bffc2b0f4
6 changed files with 548 additions and 264 deletions
|
@ -114,7 +114,9 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
|
|||
static final int REQUEST_EXPORT = 3;
|
||||
static final int REQUEST_IMPORT = 4;
|
||||
static final int REQUEST_CHOOSE_ACCOUNT = 5;
|
||||
static final int REQUEST_DONE = 6;
|
||||
|
||||
static final String ACTION_QUICK_GMAIL = BuildConfig.APPLICATION_ID + ".ACTION_QUICK_GMAIL";
|
||||
static final String ACTION_QUICK_SETUP = BuildConfig.APPLICATION_ID + ".ACTION_QUICK_SETUP";
|
||||
static final String ACTION_VIEW_ACCOUNTS = BuildConfig.APPLICATION_ID + ".ACTION_VIEW_ACCOUNTS";
|
||||
static final String ACTION_VIEW_IDENTITIES = BuildConfig.APPLICATION_ID + ".ACTION_VIEW_IDENTITIES";
|
||||
|
@ -296,6 +298,7 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
|
|||
|
||||
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
|
||||
IntentFilter iff = new IntentFilter();
|
||||
iff.addAction(ACTION_QUICK_GMAIL);
|
||||
iff.addAction(ACTION_QUICK_SETUP);
|
||||
iff.addAction(ACTION_VIEW_ACCOUNTS);
|
||||
iff.addAction(ACTION_VIEW_IDENTITIES);
|
||||
|
@ -1004,6 +1007,12 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
|
|||
return channel;
|
||||
}
|
||||
|
||||
private void onViewGmail(Intent intent) {
|
||||
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
|
||||
fragmentTransaction.replace(R.id.content_frame, new FragmentGmail()).addToBackStack("quick");
|
||||
fragmentTransaction.commit();
|
||||
}
|
||||
|
||||
private void onViewQuickSetup(Intent intent) {
|
||||
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
|
||||
fragmentTransaction.replace(R.id.content_frame, new FragmentQuickSetup()).addToBackStack("quick");
|
||||
|
@ -1116,7 +1125,9 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
|
|||
public void onReceive(Context context, Intent intent) {
|
||||
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
|
||||
String action = intent.getAction();
|
||||
if (ACTION_QUICK_SETUP.equals(action))
|
||||
if (ACTION_QUICK_GMAIL.equals(action))
|
||||
onViewGmail(intent);
|
||||
else if (ACTION_QUICK_SETUP.equals(action))
|
||||
onViewQuickSetup(intent);
|
||||
else if (ACTION_VIEW_ACCOUNTS.equals(action))
|
||||
onViewAccounts(intent);
|
||||
|
|
429
app/src/main/java/eu/faircode/email/FragmentGmail.java
Normal file
429
app/src/main/java/eu/faircode/email/FragmentGmail.java
Normal file
|
@ -0,0 +1,429 @@
|
|||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2019 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import android.Manifest;
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.AccountManagerCallback;
|
||||
import android.accounts.AccountManagerFuture;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.provider.ContactsContract;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import static android.accounts.AccountManager.newChooseAccountIntent;
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
|
||||
public class FragmentGmail extends FragmentBase {
|
||||
private ViewGroup view;
|
||||
private ScrollView scroll;
|
||||
|
||||
private Button btnGrant;
|
||||
private TextView tvGranted;
|
||||
private EditText etName;
|
||||
private Button btnSelect;
|
||||
private ContentLoadingProgressBar pbSelect;
|
||||
|
||||
private TextView tvError;
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
setSubtitle(R.string.title_setup_quick);
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
view = (ViewGroup) inflater.inflate(R.layout.fragment_gmail, container, false);
|
||||
scroll = view.findViewById(R.id.scroll);
|
||||
|
||||
// Get controls
|
||||
btnGrant = view.findViewById(R.id.btnGrant);
|
||||
tvGranted = view.findViewById(R.id.tvGranted);
|
||||
etName = view.findViewById(R.id.etName);
|
||||
btnSelect = view.findViewById(R.id.btnSelect);
|
||||
pbSelect = view.findViewById(R.id.pbSelect);
|
||||
|
||||
tvError = view.findViewById(R.id.tvError);
|
||||
|
||||
List<String> permissions = new ArrayList<>();
|
||||
permissions.add(Manifest.permission.READ_CONTACTS); // profile
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
|
||||
permissions.add(Manifest.permission.GET_ACCOUNTS);
|
||||
|
||||
// Wire controls
|
||||
|
||||
btnGrant.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
requestPermissions(permissions.toArray(new String[0]), ActivitySetup.REQUEST_CHOOSE_ACCOUNT);
|
||||
}
|
||||
});
|
||||
|
||||
btnSelect.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
startActivityForResult(
|
||||
Helper.getChooser(getContext(), newChooseAccountIntent(
|
||||
null,
|
||||
null,
|
||||
new String[]{"com.google"},
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null)),
|
||||
ActivitySetup.REQUEST_CHOOSE_ACCOUNT);
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize
|
||||
Helper.setViewsEnabled(view, false);
|
||||
pbSelect.setVisibility(View.GONE);
|
||||
tvError.setVisibility(View.GONE);
|
||||
|
||||
boolean granted = true;
|
||||
for (String permission : permissions)
|
||||
if (!hasPermission(permission)) {
|
||||
granted = false;
|
||||
break;
|
||||
}
|
||||
|
||||
setGranted(granted);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.menu_quick_setup, menu);
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_help:
|
||||
onMenuHelp();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void onMenuHelp() {
|
||||
Bundle args = new Bundle();
|
||||
args.putString("name", "SETUP.md");
|
||||
|
||||
FragmentDialogMarkdown fragment = new FragmentDialogMarkdown();
|
||||
fragment.setArguments(args);
|
||||
fragment.show(getChildFragmentManager(), "help");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
boolean granted = true;
|
||||
for (int i = 0; i < permissions.length; i++)
|
||||
granted = (granted && grantResults[i] == PackageManager.PERMISSION_GRANTED);
|
||||
|
||||
setGranted(granted);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
switch (requestCode) {
|
||||
case ActivitySetup.REQUEST_CHOOSE_ACCOUNT:
|
||||
if (resultCode == Activity.RESULT_OK && data != null)
|
||||
onAccountSelected(data);
|
||||
break;
|
||||
case ActivitySetup.REQUEST_DONE:
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void setGranted(boolean granted) {
|
||||
btnGrant.setEnabled(!granted);
|
||||
tvGranted.setVisibility(granted ? View.VISIBLE : View.GONE);
|
||||
|
||||
if (granted) {
|
||||
try (Cursor cursor = getContext().getContentResolver().query(
|
||||
ContactsContract.Profile.CONTENT_URI,
|
||||
new String[]{ContactsContract.Profile.DISPLAY_NAME}, null, null, null)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
int colDisplay = cursor.getColumnIndex(ContactsContract.Profile.DISPLAY_NAME);
|
||||
etName.setText(cursor.getString(colDisplay));
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
Log.e(ex);
|
||||
}
|
||||
}
|
||||
|
||||
etName.setEnabled(granted);
|
||||
btnSelect.setEnabled(granted);
|
||||
}
|
||||
|
||||
private void onAccountSelected(Intent data) {
|
||||
String name = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
|
||||
String type = data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE);
|
||||
|
||||
AccountManager am = AccountManager.get(getContext());
|
||||
Account[] accounts = am.getAccountsByType(type);
|
||||
for (final Account account : accounts)
|
||||
if (name.equals(account.name)) {
|
||||
am.getAuthToken(
|
||||
account,
|
||||
MailService.getAuthTokenType(type),
|
||||
new Bundle(),
|
||||
getActivity(),
|
||||
new AccountManagerCallback<Bundle>() {
|
||||
@Override
|
||||
public void run(AccountManagerFuture<Bundle> future) {
|
||||
try {
|
||||
Bundle bundle = future.getResult();
|
||||
String token = bundle.getString(AccountManager.KEY_AUTHTOKEN);
|
||||
if (token == null)
|
||||
throw new IllegalArgumentException("no token");
|
||||
Log.i("Got token");
|
||||
|
||||
onAuthorized(name, token);
|
||||
} catch (Throwable ex) {
|
||||
Log.e(ex);
|
||||
tvError.setText(Helper.formatThrowable(ex));
|
||||
|
||||
new Handler().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
scroll.smoothScrollTo(0, tvError.getBottom());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void onAuthorized(String user, String password) {
|
||||
Bundle args = new Bundle();
|
||||
args.putString("name", etName.getText().toString());
|
||||
args.putString("user", user);
|
||||
args.putString("password", password);
|
||||
|
||||
new SimpleTask<Void>() {
|
||||
@Override
|
||||
protected void onPreExecute(Bundle args) {
|
||||
etName.setEnabled(false);
|
||||
btnSelect.setEnabled(false);
|
||||
pbSelect.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Bundle args) {
|
||||
etName.setEnabled(true);
|
||||
btnSelect.setEnabled(true);
|
||||
pbSelect.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void onExecute(Context context, Bundle args) throws Throwable {
|
||||
String name = args.getString("name");
|
||||
String user = args.getString("user");
|
||||
String password = args.getString("password");
|
||||
|
||||
if (!user.contains("@"))
|
||||
throw new IllegalArgumentException(
|
||||
context.getString(R.string.title_email_invalid, user));
|
||||
|
||||
String domain = user.split("@")[1];
|
||||
EmailProvider provider = EmailProvider.fromDomain(context, domain, EmailProvider.Discover.ALL);
|
||||
|
||||
List<EntityFolder> folders;
|
||||
|
||||
String aprotocol = provider.imap.starttls ? "imap" : "imaps";
|
||||
try (MailService iservice = new MailService(context, aprotocol, null, false, true)) {
|
||||
iservice.connect(provider.imap.host, provider.imap.port, MailService.AUTH_TYPE_GMAIL, user, password);
|
||||
|
||||
folders = iservice.getFolders();
|
||||
|
||||
if (folders == null)
|
||||
throw new IllegalArgumentException(
|
||||
context.getString(R.string.title_setup_no_settings, domain));
|
||||
}
|
||||
|
||||
String iprotocol = provider.smtp.starttls ? "smtp" : "smtps";
|
||||
try (MailService iservice = new MailService(context, iprotocol, null, false, true)) {
|
||||
iservice.connect(provider.smtp.host, provider.smtp.port, MailService.AUTH_TYPE_GMAIL, user, password);
|
||||
}
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
try {
|
||||
db.beginTransaction();
|
||||
|
||||
EntityAccount primary = db.account().getPrimaryAccount();
|
||||
|
||||
// Create account
|
||||
EntityAccount account = new EntityAccount();
|
||||
|
||||
account.host = provider.imap.host;
|
||||
account.starttls = provider.imap.starttls;
|
||||
account.port = provider.imap.port;
|
||||
account.auth_type = MailService.AUTH_TYPE_GMAIL;
|
||||
account.user = user;
|
||||
account.password = password;
|
||||
|
||||
account.name = provider.name;
|
||||
|
||||
account.synchronize = true;
|
||||
account.primary = (primary == null);
|
||||
|
||||
account.created = new Date().getTime();
|
||||
account.last_connected = account.created;
|
||||
|
||||
account.id = db.account().insertAccount(account);
|
||||
args.putLong("account", account.id);
|
||||
EntityLog.log(context, "Gmail account=" + account.name);
|
||||
|
||||
// Create folders
|
||||
for (EntityFolder folder : folders) {
|
||||
folder.account = account.id;
|
||||
folder.id = db.folder().insertFolder(folder);
|
||||
EntityLog.log(context, "Gmail folder=" + folder.name + " type=" + folder.type);
|
||||
}
|
||||
|
||||
// Set swipe left/right folder
|
||||
for (EntityFolder folder : folders)
|
||||
if (EntityFolder.TRASH.equals(folder.type))
|
||||
account.swipe_left = folder.id;
|
||||
else if (EntityFolder.ARCHIVE.equals(folder.type))
|
||||
account.swipe_right = folder.id;
|
||||
|
||||
db.account().updateAccount(account);
|
||||
|
||||
if (TextUtils.isEmpty(name))
|
||||
name = user.split("@")[0];
|
||||
|
||||
// Create identity
|
||||
EntityIdentity identity = new EntityIdentity();
|
||||
identity.name = name;
|
||||
identity.email = user;
|
||||
identity.account = account.id;
|
||||
|
||||
identity.host = provider.smtp.host;
|
||||
identity.starttls = provider.smtp.starttls;
|
||||
identity.port = provider.smtp.port;
|
||||
identity.auth_type = MailService.AUTH_TYPE_GMAIL;
|
||||
identity.user = user;
|
||||
identity.password = password;
|
||||
identity.synchronize = true;
|
||||
identity.primary = true;
|
||||
|
||||
identity.id = db.identity().insertIdentity(identity);
|
||||
args.putLong("identity", identity.id);
|
||||
EntityLog.log(context, "Gmail identity=" + identity.name + " email=" + identity.email);
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
ServiceSynchronize.reload(getContext(), "Gmail");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExecuted(Bundle args, Void data) {
|
||||
FragmentDialogDone fragment = new FragmentDialogDone();
|
||||
fragment.setArguments(args);
|
||||
fragment.setTargetFragment(FragmentGmail.this, ActivitySetup.REQUEST_DONE);
|
||||
fragment.show(getFragmentManager(), "quick:done");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Bundle args, Throwable ex) {
|
||||
Log.e(ex);
|
||||
tvError.setText(Helper.formatThrowable(ex));
|
||||
|
||||
new Handler().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
scroll.smoothScrollTo(0, tvError.getBottom());
|
||||
}
|
||||
});
|
||||
}
|
||||
}.execute(this, args, "setup:gmail");
|
||||
}
|
||||
|
||||
public static class FragmentDialogDone extends FragmentDialogBase {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
return new AlertDialog.Builder(getContext())
|
||||
.setMessage(R.string.title_setup_quick_success)
|
||||
.setPositiveButton(R.string.title_review, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
Bundle args = getArguments();
|
||||
long account = args.getLong("account");
|
||||
|
||||
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
|
||||
lbm.sendBroadcast(
|
||||
new Intent(ActivitySetup.ACTION_EDIT_ACCOUNT)
|
||||
.putExtra("id", account)
|
||||
.putExtra("pop", false));
|
||||
|
||||
sendResult(RESULT_OK);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -80,8 +80,6 @@ public class FragmentQuickSetup extends FragmentBase {
|
|||
|
||||
private Group grpSetup;
|
||||
|
||||
private static final int REQUEST_DONE = 1;
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
|
@ -363,15 +361,14 @@ public class FragmentQuickSetup extends FragmentBase {
|
|||
} else {
|
||||
FragmentDialogDone fragment = new FragmentDialogDone();
|
||||
fragment.setArguments(args);
|
||||
fragment.setTargetFragment(FragmentQuickSetup.this, REQUEST_DONE);
|
||||
fragment.setTargetFragment(FragmentQuickSetup.this, ActivitySetup.REQUEST_DONE);
|
||||
fragment.show(getFragmentManager(), "quick:done");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(final Bundle args, Throwable ex) {
|
||||
Log.i("Quick ex=" + Helper.formatThrowable(ex, false));
|
||||
|
||||
Log.e(ex);
|
||||
if (ex instanceof IllegalArgumentException || ex instanceof UnknownHostException)
|
||||
tvError.setText(ex.getMessage());
|
||||
else
|
||||
|
@ -411,7 +408,7 @@ public class FragmentQuickSetup extends FragmentBase {
|
|||
|
||||
try {
|
||||
switch (requestCode) {
|
||||
case REQUEST_DONE:
|
||||
case ActivitySetup.REQUEST_DONE:
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -20,12 +20,6 @@ package eu.faircode.email;
|
|||
*/
|
||||
|
||||
import android.Manifest;
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.AccountManagerCallback;
|
||||
import android.accounts.AccountManagerFuture;
|
||||
import android.accounts.AccountsException;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
|
@ -33,14 +27,12 @@ import android.content.DialogInterface;
|
|||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.ContactsContract;
|
||||
import android.provider.Settings;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
|
@ -56,21 +48,12 @@ import androidx.annotation.Nullable;
|
|||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.PopupMenu;
|
||||
import androidx.constraintlayout.widget.Group;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import static android.accounts.AccountManager.newChooseAccountIntent;
|
||||
|
||||
public class FragmentSetup extends FragmentBase {
|
||||
private ViewGroup view;
|
||||
|
||||
|
@ -185,12 +168,12 @@ public class FragmentSetup extends FragmentBase {
|
|||
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
|
||||
switch (item.getItemId()) {
|
||||
case R.string.title_setup_gmail:
|
||||
onGmail();
|
||||
lbm.sendBroadcast(new Intent(ActivitySetup.ACTION_QUICK_GMAIL));
|
||||
return true;
|
||||
case R.string.title_setup_other:
|
||||
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
|
||||
lbm.sendBroadcast(new Intent(ActivitySetup.ACTION_QUICK_SETUP));
|
||||
return true;
|
||||
default:
|
||||
|
@ -426,17 +409,11 @@ public class FragmentSetup extends FragmentBase {
|
|||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
boolean granted = true;
|
||||
for (int i = 0; i < permissions.length; i++)
|
||||
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
|
||||
if (Manifest.permission.READ_CONTACTS.equals(permissions[i]))
|
||||
setContactsPermission(true);
|
||||
} else
|
||||
granted = false;
|
||||
|
||||
if (requestCode == ActivitySetup.REQUEST_CHOOSE_ACCOUNT)
|
||||
if (granted)
|
||||
selectAccount();
|
||||
}
|
||||
}
|
||||
|
||||
private void setContactsPermission(boolean granted) {
|
||||
|
@ -449,235 +426,6 @@ public class FragmentSetup extends FragmentBase {
|
|||
btnPermissions.setEnabled(!granted);
|
||||
}
|
||||
|
||||
private void onGmail() {
|
||||
List<String> permissions = new ArrayList<>();
|
||||
permissions.add(Manifest.permission.READ_CONTACTS); // profile
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
|
||||
permissions.add(Manifest.permission.GET_ACCOUNTS);
|
||||
|
||||
boolean granted = true;
|
||||
for (String permission : permissions)
|
||||
if (!hasPermission(permission)) {
|
||||
granted = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (granted)
|
||||
selectAccount();
|
||||
else
|
||||
new AlertDialog.Builder(getContext())
|
||||
.setMessage(R.string.title_setup_gmail_rationale)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
requestPermissions(permissions.toArray(new String[0]), ActivitySetup.REQUEST_CHOOSE_ACCOUNT);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
private void selectAccount() {
|
||||
Log.i("Select account");
|
||||
startActivityForResult(
|
||||
Helper.getChooser(getContext(), newChooseAccountIntent(
|
||||
null,
|
||||
null,
|
||||
new String[]{"com.google"},
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null)),
|
||||
ActivitySetup.REQUEST_CHOOSE_ACCOUNT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
switch (requestCode) {
|
||||
case ActivitySetup.REQUEST_CHOOSE_ACCOUNT:
|
||||
if (resultCode == Activity.RESULT_OK && data != null)
|
||||
onAccountSelected(data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void onAccountSelected(Intent data) {
|
||||
String name = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
|
||||
String type = data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE);
|
||||
|
||||
AccountManager am = AccountManager.get(getContext());
|
||||
Account[] accounts = am.getAccountsByType(type);
|
||||
for (final Account account : accounts)
|
||||
if (name.equals(account.name)) {
|
||||
Snackbar.make(view, R.string.title_authorizing, Snackbar.LENGTH_LONG).show();
|
||||
|
||||
am.getAuthToken(
|
||||
account,
|
||||
MailService.getAuthTokenType(type),
|
||||
new Bundle(),
|
||||
getActivity(),
|
||||
new AccountManagerCallback<Bundle>() {
|
||||
@Override
|
||||
public void run(AccountManagerFuture<Bundle> future) {
|
||||
try {
|
||||
Bundle bundle = future.getResult();
|
||||
String token = bundle.getString(AccountManager.KEY_AUTHTOKEN);
|
||||
Log.i("Got token");
|
||||
onAuthorized(name, token);
|
||||
} catch (Throwable ex) {
|
||||
if (ex instanceof AccountsException || ex instanceof IOException) {
|
||||
Log.w(ex);
|
||||
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED))
|
||||
Snackbar.make(view, Helper.formatThrowable(ex), Snackbar.LENGTH_LONG).show();
|
||||
} else
|
||||
Helper.unexpectedError(getFragmentManager(), ex);
|
||||
}
|
||||
}
|
||||
},
|
||||
null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void onAuthorized(String user, String password) {
|
||||
Bundle args = new Bundle();
|
||||
args.putString("user", user);
|
||||
args.putString("password", password);
|
||||
|
||||
new SimpleTask<Void>() {
|
||||
@Override
|
||||
protected Void onExecute(Context context, Bundle args) throws Throwable {
|
||||
String user = args.getString("user");
|
||||
String password = args.getString("password");
|
||||
|
||||
if (!user.contains("@"))
|
||||
throw new IllegalArgumentException(
|
||||
context.getString(R.string.title_email_invalid, user));
|
||||
|
||||
String domain = user.split("@")[1];
|
||||
EmailProvider provider = EmailProvider.fromDomain(context, domain, EmailProvider.Discover.ALL);
|
||||
|
||||
List<EntityFolder> folders;
|
||||
|
||||
String aprotocol = provider.imap.starttls ? "imap" : "imaps";
|
||||
try (MailService iservice = new MailService(context, aprotocol, null, false, true)) {
|
||||
iservice.connect(provider.imap.host, provider.imap.port, MailService.AUTH_TYPE_GMAIL, user, password);
|
||||
|
||||
folders = iservice.getFolders();
|
||||
|
||||
if (folders == null)
|
||||
throw new IllegalArgumentException(
|
||||
context.getString(R.string.title_setup_no_settings, domain));
|
||||
}
|
||||
|
||||
String iprotocol = provider.smtp.starttls ? "smtp" : "smtps";
|
||||
try (MailService iservice = new MailService(context, iprotocol, null, false, true)) {
|
||||
iservice.connect(provider.smtp.host, provider.smtp.port, MailService.AUTH_TYPE_GMAIL, user, password);
|
||||
}
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
try {
|
||||
db.beginTransaction();
|
||||
|
||||
EntityAccount primary = db.account().getPrimaryAccount();
|
||||
|
||||
// Create account
|
||||
EntityAccount account = new EntityAccount();
|
||||
|
||||
account.host = provider.imap.host;
|
||||
account.starttls = provider.imap.starttls;
|
||||
account.port = provider.imap.port;
|
||||
account.auth_type = MailService.AUTH_TYPE_GMAIL;
|
||||
account.user = user;
|
||||
account.password = password;
|
||||
|
||||
account.name = provider.name;
|
||||
|
||||
account.synchronize = true;
|
||||
account.primary = (primary == null);
|
||||
|
||||
account.created = new Date().getTime();
|
||||
account.last_connected = account.created;
|
||||
|
||||
account.id = db.account().insertAccount(account);
|
||||
args.putLong("account", account.id);
|
||||
EntityLog.log(context, "Gmail account=" + account.name);
|
||||
|
||||
// Create folders
|
||||
for (EntityFolder folder : folders) {
|
||||
folder.account = account.id;
|
||||
folder.id = db.folder().insertFolder(folder);
|
||||
EntityLog.log(context, "Gmail folder=" + folder.name + " type=" + folder.type);
|
||||
}
|
||||
|
||||
// Set swipe left/right folder
|
||||
for (EntityFolder folder : folders)
|
||||
if (EntityFolder.TRASH.equals(folder.type))
|
||||
account.swipe_left = folder.id;
|
||||
else if (EntityFolder.ARCHIVE.equals(folder.type))
|
||||
account.swipe_right = folder.id;
|
||||
|
||||
db.account().updateAccount(account);
|
||||
|
||||
String name = user.split("@")[0];
|
||||
try (Cursor cursor = context.getContentResolver().query(
|
||||
ContactsContract.Profile.CONTENT_URI,
|
||||
new String[]{ContactsContract.Profile.DISPLAY_NAME}, null, null, null)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
int colDisplay = cursor.getColumnIndex(ContactsContract.Profile.DISPLAY_NAME);
|
||||
name = cursor.getString(colDisplay);
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
Log.e(ex);
|
||||
}
|
||||
|
||||
// Create identity
|
||||
EntityIdentity identity = new EntityIdentity();
|
||||
identity.name = name;
|
||||
identity.email = user;
|
||||
identity.account = account.id;
|
||||
|
||||
identity.host = provider.smtp.host;
|
||||
identity.starttls = provider.smtp.starttls;
|
||||
identity.port = provider.smtp.port;
|
||||
identity.auth_type = MailService.AUTH_TYPE_GMAIL;
|
||||
identity.user = user;
|
||||
identity.password = password;
|
||||
identity.synchronize = true;
|
||||
identity.primary = true;
|
||||
|
||||
identity.id = db.identity().insertIdentity(identity);
|
||||
args.putLong("identity", identity.id);
|
||||
EntityLog.log(context, "Gmail identity=" + identity.name + " email=" + identity.email);
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
ServiceSynchronize.reload(getContext(), "Gmail");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExecuted(Bundle args, Void data) {
|
||||
FragmentQuickSetup.FragmentDialogDone fragment = new FragmentQuickSetup.FragmentDialogDone();
|
||||
fragment.setArguments(args);
|
||||
fragment.show(getFragmentManager(), "gmail:done");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Bundle args, Throwable ex) {
|
||||
if (ex instanceof IllegalArgumentException || ex instanceof UnknownHostException)
|
||||
Snackbar.make(view, ex.getMessage(), Snackbar.LENGTH_LONG).show();
|
||||
else
|
||||
Snackbar.make(view, Helper.formatThrowable(ex, false), Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}.execute(this, args, "setup:gmail");
|
||||
}
|
||||
|
||||
public static class FragmentDialogDoze extends FragmentDialogBase {
|
||||
@NonNull
|
||||
@Override
|
||||
|
|
100
app/src/main/res/layout/fragment_gmail.xml
Normal file
100
app/src/main/res/layout/fragment_gmail.xml
Normal file
|
@ -0,0 +1,100 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/scroll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="12dp"
|
||||
android:scrollbarStyle="outsideOverlay"
|
||||
tools:context=".ActivitySetup">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvHint"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/title_setup_gmail_rationale"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textStyle="italic"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnGrant"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:tag="disable"
|
||||
android:text="@string/title_setup_grant"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvHint" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvGranted"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:drawableStart="@drawable/baseline_check_24"
|
||||
android:drawablePadding="6dp"
|
||||
android:text="@string/title_setup_done"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
app:layout_constraintBottom_toBottomOf="@id/btnGrant"
|
||||
app:layout_constraintStart_toEndOf="@id/btnGrant"
|
||||
app:layout_constraintTop_toTopOf="@id/btnGrant" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:autofillHints="name"
|
||||
android:hint="@string/title_identity_name"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="textPersonName|textCapWords"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/btnGrant">
|
||||
|
||||
<requestFocus />
|
||||
</EditText>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnSelect"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:tag="disable"
|
||||
android:text="@string/title_setup_select_account"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/etName" />
|
||||
|
||||
<eu.faircode.email.ContentLoadingProgressBar
|
||||
android:id="@+id/pbSelect"
|
||||
style="@style/Base.Widget.AppCompat.ProgressBar"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:indeterminate="true"
|
||||
app:layout_constraintBottom_toBottomOf="@id/btnSelect"
|
||||
app:layout_constraintStart_toEndOf="@id/btnSelect"
|
||||
app:layout_constraintTop_toTopOf="@id/btnSelect" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvError"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:autoLink="web"
|
||||
android:text="error"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:textColor="?attr/colorWarning"
|
||||
android:textIsSelectable="true"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btnSelect" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</ScrollView>
|
|
@ -138,6 +138,7 @@
|
|||
<string name="title_setup_gmail" translatable="false">Gmail</string>
|
||||
<string name="title_setup_other">Other provider</string>
|
||||
<string name="title_setup_gmail_rationale">Please grant permissions to select an account and read your name</string>
|
||||
<string name="title_setup_select_account">Select account</string>
|
||||
<string name="title_setup_instructions">Setup instructions</string>
|
||||
<string name="title_setup_no_settings">No settings found for domain \'%1$s\'</string>
|
||||
<string name="title_setup_quick_success">An account and an identity have successfully been added</string>
|
||||
|
@ -418,8 +419,6 @@
|
|||
<string name="title_pop_support">The POP3 protocol supports downloading and deleting messages only. So, it will not be possible to mark message favorite, move messages, etc. POP3 will use more battery power than IMAP. Therefore, consider using the IMAP protocol whenever possible.</string>
|
||||
<string name="title_activesync_support">ActiveSync is not supported</string>
|
||||
<string name="title_oauth_support">OAuth is not supported</string>
|
||||
<string name="title_authorize">Authorize</string>
|
||||
<string name="title_authorizing">Authorizing …</string>
|
||||
<string name="title_review">Review</string>
|
||||
|
||||
<string name="title_synchronize_now">Synchronize now</string>
|
||||
|
|
Loading…
Reference in a new issue