Skip to content

Commit

Permalink
#395 Add sample project
Browse files Browse the repository at this point in the history
Signed-off-by: Stefan Niedermann <[email protected]>
  • Loading branch information
stefan-niedermann committed Nov 4, 2021
1 parent c0fed8f commit 75f2489
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 3 deletions.
6 changes: 5 additions & 1 deletion sample/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,15 @@ android {

dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'

implementation project(path: ':lib')
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
testImplementation 'junit:junit:4.+'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'

testImplementation 'junit:junit:4.13.2'

androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,47 @@
package com.nextcloud.android.sso.sample;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.google.gson.GsonBuilder;
import com.nextcloud.android.sso.AccountImporter;
import com.nextcloud.android.sso.api.NextcloudAPI;
import com.nextcloud.android.sso.exceptions.AccountImportCancelledException;
import com.nextcloud.android.sso.exceptions.AndroidGetAccountsPermissionNotGranted;
import com.nextcloud.android.sso.exceptions.NextcloudFilesAppNotInstalledException;
import com.nextcloud.android.sso.helper.SingleAccountHelper;
import com.nextcloud.android.sso.model.SingleSignOnAccount;

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import retrofit2.NextcloudRetrofitApiBuilder;

@SuppressLint("SetTextI18n")
@SuppressWarnings("ConstantConditions")
public class MainActivity extends AppCompatActivity {

private static final String TAG = MainActivity.class.getSimpleName();
private final ExecutorService executor = Executors.newSingleThreadExecutor();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.chooseAccountBtn).setOnClickListener(v -> {
try {
/*
* Prompt dialog to select existing or create a new account
* As soon as an account has been imported, we will continue in #onActivityResult()
*/
AccountImporter.pickNewAccount(this);
} catch (NextcloudFilesAppNotInstalledException | AndroidGetAccountsPermissionNotGranted e) {
e.printStackTrace();
Expand All @@ -35,9 +55,48 @@ protected void onActivityResult(int requestCode, int resultCode, @Nullable Inten
try {
AccountImporter.onActivityResult(requestCode, resultCode, data, this, ssoAccount -> {
Log.i(TAG, "Imported account: " + ssoAccount.name);
SingleAccountHelper.setCurrentAccount(this, ssoAccount.name);
executor.submit(() -> {

// Create local bridge API to the Nextcloud Files Android app
final var nextcloudAPI = createNextcloudAPI(ssoAccount);

// Create the Ocs API to talk to the server
final var ocsAPI = new NextcloudRetrofitApiBuilder(nextcloudAPI, "ocs/v2.php/cloud/").create(OcsAPI.class);

try {
// Perform actual requests
final var userName = ocsAPI.getUser(ssoAccount.userId).execute().body().ocs.data.displayName;
final var instanceName = ocsAPI.getCapabilities().execute().body().ocs.data.theming.name;

((TextView) findViewById(R.id.result)).setText(userName + " on " + instanceName);
} catch (IOException e) {
e.printStackTrace();
}

nextcloudAPI.stop();
});
});
} catch (AccountImportCancelledException e) {
Log.i(TAG, "Account import cancelled.");
}
}

private NextcloudAPI createNextcloudAPI(@NonNull SingleSignOnAccount ssoAccount) {
return new NextcloudAPI(this, ssoAccount, new GsonBuilder().create(), new NextcloudAPI.ApiConnectedListener() {
@Override
public void onConnected() {
/*
* We don't have to wait for this callback because requests are queued and executed
* automatically as soon as the connection has been established.
*/
Log.i(TAG, "SSO API connected for " + ssoAccount);
}

@Override
public void onError(Exception e) {
e.printStackTrace();
}
});
}
}
71 changes: 71 additions & 0 deletions sample/src/main/java/com/nextcloud/android/sso/sample/OcsAPI.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.nextcloud.android.sso.sample;


import com.google.gson.annotations.SerializedName;

import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Path;


/**
* @see <a href="https://deck.readthedocs.io/en/latest/API-Nextcloud/">Nextcloud REST API</a>
*/
public interface OcsAPI {

@GET("capabilities?format=json")
Call<OcsResponse<OcsCapabilities>> getCapabilities();

@GET("users/{search}?format=json")
Call<OcsResponse<OcsUser>> getUser(@Path("search") String userId);

/**
* <p>A generic wrapper for <a href="https://www.open-collaboration-services.org/">OpenCollaborationServices</a> calls.</p>
* <p>This is needed for API endpoints located at <code>/ocs/...</code>. It is usually not used for APIs of 3rd party server apps like <a href="https://deck.readthedocs.io/en/latest/API/">Deck</a> or <a href="https://github.com/nextcloud/notes/blob/master/docs/api/README.md">Notes</a></p>
*
* @param <T> defines the payload of this {@link OcsResponse}.
*/
class OcsResponse<T> {
public OcsWrapper<T> ocs;

public static class OcsWrapper<T> {
public OcsMeta meta;
public T data;
}

public static class OcsMeta {
public String status;
public int statuscode;
public String message;
}
}

/*
* Extend the classes by the attributes you are actually using, for example:</p>
* <ul>
* <li><code>version</code></li>
* <li><code>theming</code></li>
* <li><code>server_status</code></li>
* <li><code>deck</code></li>
* <li>…</li>
* </ul>
*/
class OcsCapabilities {
public Theming theming;

static class Theming {
public String name;
}
}

/**
* You can map the node names to other variable names using {@link SerializedName}.
* See <a href="https://github.com/google/gson">Gson-</a> and <a href="https://square.github.io/retrofit/">Retrofit-</a>Documentation for all possibilities.
*/
class OcsUser {
@SerializedName("id")
public String userId;
@SerializedName("displayname")
public String displayName;
}
}
14 changes: 12 additions & 2 deletions sample/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,18 @@
android:layout_height="wrap_content"
android:text="Choose account"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<TextView
android:id="@+id/result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="@id/chooseAccountBtn"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/chooseAccountBtn"
tools:text="John Doe on Example Cloud" />

</androidx.constraintlayout.widget.ConstraintLayout>

0 comments on commit 75f2489

Please sign in to comment.