Added downloading Outlook contacts

This commit is contained in:
M66B
2023-06-12 14:34:20 +02:00
parent f07a4682dd
commit b8085a64f1
6 changed files with 266 additions and 0 deletions

View File

@@ -54,6 +54,7 @@ import android.widget.CompoundButton;
import android.widget.ImageButton;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -70,7 +71,31 @@ import androidx.lifecycle.Observer;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.preference.PreferenceManager;
import net.openid.appauth.AppAuthConfiguration;
import net.openid.appauth.AuthState;
import net.openid.appauth.AuthorizationException;
import net.openid.appauth.AuthorizationRequest;
import net.openid.appauth.AuthorizationResponse;
import net.openid.appauth.AuthorizationService;
import net.openid.appauth.AuthorizationServiceConfiguration;
import net.openid.appauth.ClientAuthentication;
import net.openid.appauth.ClientSecretPost;
import net.openid.appauth.GrantTypeValues;
import net.openid.appauth.NoClientAuthentication;
import net.openid.appauth.ResponseTypeValues;
import net.openid.appauth.TokenRequest;
import net.openid.appauth.TokenResponse;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
public class FragmentSetup extends FragmentBase implements SharedPreferences.OnSharedPreferenceChangeListener {
@@ -107,6 +132,7 @@ public class FragmentSetup extends FragmentBase implements SharedPreferences.OnS
private Button btnPermissions;
private TextView tvPermissionsWhy;
private TextView tvImportContacts;
private Button btnGraphContacts;
private TextView tvDozeDone;
private Button btnDoze;
@@ -146,6 +172,8 @@ public class FragmentSetup extends FragmentBase implements SharedPreferences.OnS
private boolean manual = false;
private static final String GRAPH_SCOPE_READ_CONTACTS = "https://graph.microsoft.com/Contacts.Read";
@Override
@Nullable
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
@@ -195,6 +223,7 @@ public class FragmentSetup extends FragmentBase implements SharedPreferences.OnS
btnPermissions = view.findViewById(R.id.btnPermissions);
tvPermissionsWhy = view.findViewById(R.id.tvPermissionsWhy);
tvImportContacts = view.findViewById(R.id.tvImportContacts);
btnGraphContacts = view.findViewById(R.id.btnGraphContacts);
tvDozeDone = view.findViewById(R.id.tvDozeDone);
btnDoze = view.findViewById(R.id.btnDoze);
@@ -564,6 +593,20 @@ public class FragmentSetup extends FragmentBase implements SharedPreferences.OnS
}
});
btnGraphContacts.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Bundle args = new Bundle();
args.putInt("type", EntityAccount.TYPE_IMAP);
args.putString("filter", "outlook");
FragmentDialogSelectAccount fragment = new FragmentDialogSelectAccount();
fragment.setArguments(args);
fragment.setTargetFragment(FragmentSetup.this, ActivitySetup.REQUEST_GRAPH_CONTACTS);
fragment.show(getParentFragmentManager(), "account:contacts");
}
});
btnDoze.setOnClickListener(new View.OnClickListener() {
@Override
@SuppressLint("BatteryLife")
@@ -1073,6 +1116,14 @@ public class FragmentSetup extends FragmentBase implements SharedPreferences.OnS
if (resultCode == RESULT_OK && data != null)
onDeleteAccount(data.getBundleExtra("args"));
break;
case ActivitySetup.REQUEST_GRAPH_CONTACTS:
if (resultCode == RESULT_OK && data != null)
handleImportGraphContacts(data.getBundleExtra("args"));
break;
case ActivitySetup.REQUEST_GRAPH_CONTACTS_OAUTH:
if (resultCode == RESULT_OK && data != null)
onHandleGraphContactsOAuth(data);
break;
}
} catch (Throwable ex) {
Log.e(ex);
@@ -1213,6 +1264,132 @@ public class FragmentSetup extends FragmentBase implements SharedPreferences.OnS
.show();
}
private void handleImportGraphContacts(Bundle args) {
try {
final Context context = getContext();
long account = args.getLong("account");
String user = args.getString("user");
EmailProvider provider = EmailProvider.getProvider(context, "outlookgraph");
AppAuthConfiguration appAuthConfig = new AppAuthConfiguration.Builder()
.build();
AuthorizationService authService = new AuthorizationService(context, appAuthConfig);
AuthorizationServiceConfiguration serviceConfig = new AuthorizationServiceConfiguration(
Uri.parse(provider.graph.authorizationEndpoint),
Uri.parse(provider.graph.tokenEndpoint));
AuthorizationRequest.Builder authRequestBuilder =
new AuthorizationRequest.Builder(
serviceConfig,
provider.graph.clientId,
ResponseTypeValues.CODE,
Uri.parse(provider.graph.redirectUri))
.setScopes(GRAPH_SCOPE_READ_CONTACTS)
.setState(provider.id + ":" + account)
.setLoginHint(user);
if (!TextUtils.isEmpty(provider.graph.prompt))
authRequestBuilder.setPrompt(provider.graph.prompt);
Intent authIntent = authService.getAuthorizationRequestIntent(authRequestBuilder.build());
Log.i("Graph/contacts intent=" + authIntent);
startActivityForResult(authIntent, ActivitySetup.REQUEST_GRAPH_CONTACTS_OAUTH);
} catch (Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}
private void onHandleGraphContactsOAuth(@NonNull Intent data) {
try {
Log.i("Graph/contacts authorized");
AuthorizationResponse auth = AuthorizationResponse.fromIntent(data);
if (auth == null) {
AuthorizationException ex = AuthorizationException.fromIntent(data);
if (ex == null)
throw new IllegalArgumentException("No response data");
else
throw ex;
}
final Context context = getContext();
final EmailProvider provider = EmailProvider.getProvider(context, "outlookgraph");
AuthorizationService authService = new AuthorizationService(context);
ClientAuthentication clientAuth;
if (provider.graph.clientSecret == null)
clientAuth = NoClientAuthentication.INSTANCE;
else
clientAuth = new ClientSecretPost(provider.graph.clientSecret);
TokenRequest.Builder builder = new TokenRequest.Builder(
auth.request.configuration,
auth.request.clientId)
.setGrantType(GrantTypeValues.AUTHORIZATION_CODE)
.setRedirectUri(auth.request.redirectUri)
.setCodeVerifier(auth.request.codeVerifier)
.setAuthorizationCode(auth.authorizationCode)
.setNonce(auth.request.nonce);
if (provider.graph.tokenScopes)
builder.setScope(GRAPH_SCOPE_READ_CONTACTS);
authService.performTokenRequest(
builder.build(),
clientAuth,
new AuthorizationService.TokenResponseCallback() {
@Override
public void onTokenRequestCompleted(TokenResponse access, AuthorizationException error) {
try {
if (error != null)
throw error;
if (access == null || access.accessToken == null)
throw new IllegalStateException("No access token");
Log.i("Graph/contacts got token");
int semi = auth.request.state.lastIndexOf(':');
long account = Long.parseLong(auth.request.state.substring(semi + 1));
Bundle args = new Bundle();
args.putLong("account", account);
args.putString("accessToken", access.accessToken);
new SimpleTask<Void>() {
@Override
protected Void onExecute(Context context, Bundle args) throws Throwable {
long account = args.getLong("account");
String accessToken = args.getString("accessToken");
MicrosoftGraph.downloadContacts(context, account, accessToken);
return null;
}
@Override
protected void onExecuted(Bundle args, Void data) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
prefs.edit().putBoolean("suggest_sent", true).apply();
ToastEx.makeText(context, R.string.title_completed, Toast.LENGTH_LONG).show();
}
@Override
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.execute(FragmentSetup.this, args, "graph:contacts");
} catch (Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}
});
} catch (Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}
private ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {