/* * ____.____ __.____ ___ _____ * | | |/ _| | \ / _ \ ______ ______ * | | < | | / / /_\ \\____ \\____ \ * /\__| | | \| | / / | \ |_> > |_> > * \________|____|__ \______/ \____|__ / __/| __/ * \/ \/|__| |__| * * Copyright (c) 2014-2015 Paul "Marunjar" Pretsch * * This program 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. * * This program 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 this program. If not, see <http://www.gnu.org/licenses/> * */ package org.voidsink.anewjkuapp; import android.accounts.AbstractAccountAuthenticator; import android.accounts.Account; import android.accounts.AccountAuthenticatorResponse; import android.accounts.AccountManager; import android.accounts.NetworkErrorException; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.support.annotation.NonNull; import android.text.TextUtils; import android.util.Log; import org.voidsink.anewjkuapp.activity.KusssAuthenticatorActivity; import org.voidsink.anewjkuapp.analytics.Analytics; import org.voidsink.anewjkuapp.calendar.CalendarContractWrapper; import org.voidsink.anewjkuapp.kusss.KusssHandler; import org.voidsink.anewjkuapp.provider.KusssDatabaseHelper; import org.voidsink.anewjkuapp.utils.AppUtils; public class KusssAuthenticator extends AbstractAccountAuthenticator { // The authority for the sync adapter's content provider // public static final String AUTHORITY_CALENDAR = // "org.voidsink.anewjkuapp.calendar.provider"; // An account type, in the form of a domain name public static final String ACCOUNT_TYPE = BuildConfig.CONFIG_KUSSS_ACCOUNT_TYPE; public static final String AUTHTOKEN_TYPE_READ_ONLY = "Read only"; public static final String AUTHTOKEN_TYPE_READ_ONLY_LABEL = "Read only access to a KUSSS account"; // public static final String AUTHTOKEN_TYPE_FULL_ACCESS = "Full access"; // public static final String AUTHTOKEN_TYPE_FULL_ACCESS_LABEL = // "Full access to a KUSSS account"; public final static String ARG_ACCOUNT_TYPE = "ACCOUNT_TYPE"; public final static String ARG_AUTH_TYPE = "AUTH_TYPE"; public final static String ARG_ACCOUNT_NAME = "ACCOUNT_NAME"; public final static String ARG_IS_ADDING_NEW_ACCOUNT = "IS_ADDING_ACCOUNT"; private static final String TAG = KusssAuthenticator.class.getSimpleName(); private Context mContext = null; public KusssAuthenticator(Context context) { super(context); this.mContext = context; } @Override public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException { final Intent intent = new Intent(mContext, KusssAuthenticatorActivity.class); intent.putExtra(ARG_ACCOUNT_TYPE, accountType); intent.putExtra(ARG_AUTH_TYPE, authTokenType); intent.putExtra(ARG_IS_ADDING_NEW_ACCOUNT, true); intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); final Bundle bundle = new Bundle(); bundle.putParcelable(AccountManager.KEY_INTENT, intent); return bundle; } @Override public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException { return null; } @Override public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) { throw new UnsupportedOperationException(); } @Override public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { // If the caller requested an authToken type we don't support, then // return an error if (!authTokenType.equals(AUTHTOKEN_TYPE_READ_ONLY)) { final Bundle result = new Bundle(); result.putString(AccountManager.KEY_ERROR_MESSAGE, "invalid authTokenType"); return result; } // Extract the username and password from the Account Manager, and ask // the server for an appropriate AuthToken. final AccountManager am = AccountManager.get(mContext); String authToken = am.peekAuthToken(account, authTokenType); Log.d(TAG, "authToken=" + authToken); if (TextUtils.isEmpty(authToken) || !KusssHandler.getInstance().isLoggedIn(mContext, authToken)) { // Lets give another try to authenticate the user final String password = am.getPassword(account); if (password != null) { try { authToken = KusssHandler.getInstance().login(mContext, account.name, password); } catch (Exception e) { e.printStackTrace(); authToken = null; } } } // If we get an authToken - we return it if (!TextUtils.isEmpty(authToken)) { // set new auth token (SessionID) AccountManager.get(mContext).setAuthToken(account, authTokenType, authToken); final Bundle result = new Bundle(); result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type); result.putString(AccountManager.KEY_AUTHTOKEN, authToken); return result; } // If we get here, then we couldn't access the user's password - so we // need to re-prompt them for their credentials. We do that by creating // an intent to display our AuthenticatorActivity. final Intent intent = new Intent(mContext, KusssAuthenticatorActivity.class); intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); intent.putExtra(ARG_ACCOUNT_TYPE, account.type); intent.putExtra(ARG_ACCOUNT_NAME, account.name); final Bundle bundle = new Bundle(); bundle.putParcelable(AccountManager.KEY_INTENT, intent); return bundle; } @Override public String getAuthTokenLabel(String authTokenType) { /* * if (AUTHTOKEN_TYPE_FULL_ACCESS.equals(authTokenType)) return * AUTHTOKEN_TYPE_FULL_ACCESS_LABEL; else */ if (AUTHTOKEN_TYPE_READ_ONLY.equals(authTokenType)) return AUTHTOKEN_TYPE_READ_ONLY_LABEL; else return authTokenType + " (Label)"; } @Override public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException { final Bundle result = new Bundle(); result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false); return result; } @Override public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { final Intent intent = new Intent(mContext, KusssAuthenticatorActivity.class); intent.putExtra(ARG_ACCOUNT_TYPE, account.type); intent.putExtra(ARG_IS_ADDING_NEW_ACCOUNT, false); intent.putExtra(ARG_ACCOUNT_NAME, account.name); intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); final Bundle bundle = new Bundle(); bundle.putParcelable(AccountManager.KEY_INTENT, intent); return bundle; } @Override public @NonNull Bundle getAccountRemovalAllowed( AccountAuthenticatorResponse response, Account account) throws NetworkErrorException { final Bundle result = super.getAccountRemovalAllowed(response, account); if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) { KusssDatabaseHelper.dropUserData(mContext); } return result; } public static void triggerSync(Context context) { try { Account[] accounts = AccountManager.get(context).getAccountsByType( ACCOUNT_TYPE); for (Account account : accounts) { AppUtils.triggerSync(context, account, true, true); } } catch (SecurityException e) { Analytics.sendException(context, e, true); } catch (Exception e) { Analytics.sendException(context, e, false); } } /** * Creates an updated URI that includes query parameters that identify the * source as a sync adapter. */ public static Uri asCalendarSyncAdapter(Uri uri, String account, String accountType) { return uri .buildUpon() .appendQueryParameter( CalendarContractWrapper.CALLER_IS_SYNCADAPTER(), "true") .appendQueryParameter( CalendarContractWrapper.Calendars.ACCOUNT_NAME(), account) .appendQueryParameter( CalendarContractWrapper.Calendars.ACCOUNT_TYPE(), accountType).build(); } /** * Creates an updated URI that includes query parameters that identify the * source as a sync adapter. */ public static Uri asEventSyncAdapter(Uri uri, String account, String accountType) { return uri .buildUpon() .appendQueryParameter( CalendarContractWrapper.CALLER_IS_SYNCADAPTER(), "true") .appendQueryParameter( CalendarContractWrapper.Events.ACCOUNT_NAME(), account) .appendQueryParameter( CalendarContractWrapper.Events.ACCOUNT_TYPE(), accountType).build(); } }