Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit eb3627ac authored by David Luhmer's avatar David Luhmer Committed by GitHub
Browse files

Merge pull request #63 from nextcloud/allowDevApp

add support for dev app
parents 7e9c21a8 9ac17927
Loading
Loading
Loading
Loading
+53 −30
Original line number Diff line number Diff line
@@ -34,6 +34,10 @@ import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;

import com.nextcloud.android.sso.exceptions.AndroidGetAccountsPermissionNotGranted;
import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException;
import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountPermissionNotGrantedException;
@@ -45,12 +49,9 @@ import com.nextcloud.android.sso.ui.UiExceptionManager;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;

import io.reactivex.annotations.NonNull;

import static android.app.Activity.RESULT_CANCELED;
@@ -71,15 +72,19 @@ public class AccountImporter {

    private static SharedPreferences SHARED_PREFERENCES;

    private static final List<String> APPS = Arrays.asList(Constants.PACKAGE_NAME_PROD, Constants.PACKAGE_NAME_DEV);
    private static final String[] ACCOUNT_TYPES = {Constants.ACCOUNT_TYPE_PROD, Constants.ACCOUNT_TYPE_DEV};

    public static boolean accountsToImportAvailable(Context context) {
        return findAccounts(context).size() > 0;
    }

    public static void pickNewAccount(Activity activity) throws NextcloudFilesAppNotInstalledException, AndroidGetAccountsPermissionNotGranted {
    public static void pickNewAccount(Activity activity) throws NextcloudFilesAppNotInstalledException,
            AndroidGetAccountsPermissionNotGranted {
        checkAndroidAccountPermissions(activity);
        
        if (appInstalledOrNot(activity, "com.nextcloud.client")) {
            Intent intent = AccountManager.newChooseAccountIntent(null, null, new String[]{"nextcloud"},
        if (appInstalledOrNot(activity)) {
            Intent intent = AccountManager.newChooseAccountIntent(null, null, ACCOUNT_TYPES,
                                                                  true, null, null, null, null);
            activity.startActivityForResult(intent, CHOOSE_ACCOUNT_SSO);
        } else {
@@ -87,11 +92,12 @@ public class AccountImporter {
        }
    }

    public static void pickNewAccount(Fragment fragment) throws NextcloudFilesAppNotInstalledException, AndroidGetAccountsPermissionNotGranted {
    public static void pickNewAccount(Fragment fragment) throws NextcloudFilesAppNotInstalledException,
            AndroidGetAccountsPermissionNotGranted {
        checkAndroidAccountPermissions(fragment.getContext());
        
        if (appInstalledOrNot(fragment.getContext(), "com.nextcloud.client")) {
            Intent intent = AccountManager.newChooseAccountIntent(null, null, new String[]{"nextcloud"},
        if (appInstalledOrNot(fragment.getContext())) {
            Intent intent = AccountManager.newChooseAccountIntent(null, null, ACCOUNT_TYPES,
                                                                  true, null, null, null, null);
            fragment.startActivityForResult(intent, CHOOSE_ACCOUNT_SSO);
        } else {
@@ -100,13 +106,15 @@ public class AccountImporter {
    }

    public static void requestAndroidAccountPermissionsAndPickAccount(Activity activity) {
        ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.GET_ACCOUNTS}, REQUEST_GET_ACCOUNTS_PERMISSION);
        ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.GET_ACCOUNTS},
                                          REQUEST_GET_ACCOUNTS_PERMISSION);
    }

    private static void checkAndroidAccountPermissions(Context context) throws AndroidGetAccountsPermissionNotGranted {
        // https://developer.android.com/reference/android/accounts/AccountManager#getAccountsByType(java.lang.String)
        // Caller targeting API level below Build.VERSION_CODES.O that have not been granted the Manifest.permission.GET_ACCOUNTS permission,
        // will only see those accounts managed by AbstractAccountAuthenticators whose signature matches the client.
        // Caller targeting API level below Build.VERSION_CODES.O that have not been granted the 
        // Manifest.permission.GET_ACCOUNTS permission, will only see those accounts managed by 
        // AbstractAccountAuthenticators whose signature matches the client.
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            // Do something for lollipop and above versions
            if (ContextCompat.checkSelfPermission(context, Manifest.permission.GET_ACCOUNTS) != PackageManager.PERMISSION_GRANTED) {
@@ -118,28 +126,34 @@ public class AccountImporter {
        }
    }

    private static boolean appInstalledOrNot(Context context, String uri) {
    private static boolean appInstalledOrNot(Context context) {
        boolean returnValue = false;
        PackageManager pm = context.getPackageManager();
        for (String app : APPS) {
            try {
            pm.getPackageInfo(uri, PackageManager.GET_ACTIVITIES);
            return true;
                pm.getPackageInfo(app, PackageManager.GET_ACTIVITIES);
                returnValue = true;
                break;
            } catch (PackageManager.NameNotFoundException e) {
                Log.v(TAG, e.getMessage());
            }
        return false;
        }
        return returnValue;
    }

    // Find all currently installed nextcloud accounts on the phone
    public static List<Account> findAccounts(final Context context) {
        final AccountManager accMgr = AccountManager.get(context);
        final Account[] accounts = accMgr.getAccountsByType("nextcloud");
        final Account[] accounts = accMgr.getAccounts();

        List<Account> accountsAvailable = new ArrayList<>();
        for (final Account account : accounts) {
            if ("nextcloud".equals(account.type)) {
            for (String accountType : ACCOUNT_TYPES) {
                if (accountType.equals(account.type)) {
                    accountsAvailable.add(account);
                }
            }
        }
        return accountsAvailable;
    }

@@ -188,10 +202,11 @@ public class AccountImporter {
        }
        String token = future.getString(Constants.SSO_TOKEN);
        String serverUrl = future.getString(Constants.SSO_SERVER_URL);
        String type = future.getString("accountType");

        SharedPreferences mPrefs = getSharedPreferences(context);
        String prefKey = getPrefKeyForAccount(accountName);
        SingleSignOnAccount ssoAccount = new SingleSignOnAccount(accountName, userId, token, serverUrl);
        SingleSignOnAccount ssoAccount = new SingleSignOnAccount(accountName, userId, token, serverUrl, type);
        try {
            mPrefs.edit().putString(prefKey, SingleSignOnAccount.toString(ssoAccount)).apply();
        } catch (IOException e) {
@@ -351,8 +366,16 @@ public class AccountImporter {
        if(account == null) {
            throw new NextcloudFilesAppAccountPermissionNotGrantedException();
        }

        String componentName;
        if (account.type.equalsIgnoreCase(Constants.ACCOUNT_TYPE_DEV)) {
            componentName = Constants.PACKAGE_NAME_DEV;
        } else {
            componentName = Constants.PACKAGE_NAME_PROD;
        }
        
        Intent authIntent = new Intent();
        authIntent.setComponent(new ComponentName("com.nextcloud.client",
        authIntent.setComponent(new ComponentName(componentName,
                                                  "com.owncloud.android.ui.activity.SsoGrantPermissionActivity"));
        authIntent.putExtra(NEXTCLOUD_FILES_ACCOUNT, account);
        return authIntent;
+7 −0
Original line number Diff line number Diff line
@@ -38,4 +38,11 @@ public class Constants {
    public static final String EXCEPTION_INVALID_REQUEST_URL = "CE_4";
    public static final String EXCEPTION_HTTP_REQUEST_FAILED = "CE_5";
    public static final String EXCEPTION_ACCOUNT_ACCESS_DECLINED = "CE_6";

    // package related constans
    public static final String PACKAGE_NAME_PROD = "com.nextcloud.client";
    public static final String PACKAGE_NAME_DEV = "com.nextcloud.android.beta";
    public static final String ACCOUNT_TYPE_PROD = "nextcloud";
    public static final String ACCOUNT_TYPE_DEV = "nextcloud.beta";
    
}
+10 −4
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@ import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Log;

import com.nextcloud.android.sso.Constants;
import com.nextcloud.android.sso.aidl.IInputStreamService;
import com.nextcloud.android.sso.aidl.IThreadListener;
import com.nextcloud.android.sso.aidl.NextcloudRequest;
@@ -67,17 +68,22 @@ public class AidlNetworkRequest extends NetworkRequest {
        }
    };

    public void connect() {
        super.connect();
    public void connect(String type) {
        super.connect(type);

        // Disconnect if connected
        if (mBound.get()) {
            stop();
        }

        String componentName = Constants.PACKAGE_NAME_PROD;
        if (type.equals(Constants.ACCOUNT_TYPE_DEV)) {
            componentName = Constants.PACKAGE_NAME_DEV;
        }

        try {
            Intent intentService = new Intent();
            intentService.setComponent(new ComponentName("com.nextcloud.client",
            intentService.setComponent(new ComponentName(componentName,
                                                         "com.owncloud.android.services.AccountManagerService"));
            if (!mContext.bindService(intentService, mConnection, Context.BIND_AUTO_CREATE)) {
                Log.d(TAG, "Binding to AccountManagerService returned false");
+4 −7
Original line number Diff line number Diff line
@@ -27,8 +27,8 @@ public abstract class NetworkRequest {
    }


    protected void connect() {
        Log.v(TAG, "Nextcloud Single sign-on connect() called [" + Thread.currentThread().getName() + "]");
    protected void connect(String type) {
        Log.v(TAG, "Nextcloud Single sign-on connect() called [" + Thread.currentThread().getName() + "] Account-Type: [" + type + "]");
        if (mDestroyed) {
            throw new IllegalStateException("API already destroyed! You cannot reuse a stopped API instance");
        }
@@ -37,11 +37,8 @@ public abstract class NetworkRequest {
    protected abstract InputStream performNetworkRequest(NextcloudRequest request, InputStream requestBodyInputStream) throws Exception;

    protected void connectApiWithBackoff() {
        new ExponentialBackoff(1000, 10000, 2, 5, Looper.getMainLooper(), new Runnable() {
            @Override
            public void run() {
            connect();
            }
        new ExponentialBackoff(1000, 10000, 2, 5, Looper.getMainLooper(), () -> {
            connect(mAccount.type);
        }).start();
    }

+3 −1
Original line number Diff line number Diff line
@@ -37,12 +37,14 @@ public class SingleSignOnAccount implements Serializable {
    public String userId;
    public String token;
    public String url;
    public String type;

    public SingleSignOnAccount(String name, String userId, String token, String url) {
    public SingleSignOnAccount(String name, String userId, String token, String url, String type) {
        this.name = name;
        this.userId = userId;
        this.token = token;
        this.url = url;
        this.type = type;
    }

    /** Read the object from Base64 string. */