Skip to content

Commit 6558917

Browse files
Merge pull request #3007 from nextcloud/ecosystem-link-handle
ecosystem link handle
2 parents d1b731f + 6d899bd commit 6558917

File tree

7 files changed

+158
-98
lines changed

7 files changed

+158
-98
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@
3737
android:label="@string/app_name"
3838
android:theme="@style/Theme.App.Starting"
3939
android:exported="true">
40+
41+
<intent-filter>
42+
<action android:name="com.nextcloud.intent.OPEN_ECOSYSTEM_APP" />
43+
<category android:name="android.intent.category.DEFAULT" />
44+
</intent-filter>
45+
4046
<intent-filter>
4147
<action android:name="android.intent.action.MAIN" />
4248
<category android:name="android.intent.category.LAUNCHER" />

app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,13 @@
2626
import android.content.Intent;
2727
import android.content.res.ColorStateList;
2828
import android.content.res.Resources;
29-
import android.graphics.Color;
3029
import android.graphics.drawable.GradientDrawable;
3130
import android.net.Uri;
3231
import android.os.Bundle;
3332
import android.text.TextUtils;
3433
import android.util.DisplayMetrics;
3534
import android.util.Log;
36-
import android.view.Menu;
3735
import android.view.View;
38-
import android.widget.ImageView;
39-
import android.widget.LinearLayout;
40-
import android.widget.TextView;
4136

4237
import androidx.activity.OnBackPressedCallback;
4338
import androidx.annotation.ColorInt;
@@ -46,7 +41,6 @@
4641
import androidx.appcompat.app.ActionBarDrawerToggle;
4742
import androidx.appcompat.view.ActionMode;
4843
import androidx.appcompat.widget.SearchView;
49-
import androidx.constraintlayout.widget.ConstraintLayout;
5044
import androidx.coordinatorlayout.widget.CoordinatorLayout;
5145
import androidx.core.app.ActivityCompat;
5246
import androidx.core.content.ContextCompat;
@@ -67,6 +61,9 @@
6761
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
6862
import com.google.android.material.floatingactionbutton.FloatingActionButton;
6963
import com.google.android.material.snackbar.Snackbar;
64+
import com.nextcloud.android.common.core.utils.ecosystem.AccountReceiverCallback;
65+
import com.nextcloud.android.common.core.utils.ecosystem.EcosystemApp;
66+
import com.nextcloud.android.common.core.utils.ecosystem.EcosystemManager;
7067
import com.nextcloud.android.common.ui.theme.utils.ColorRole;
7168
import com.nextcloud.android.sso.AccountImporter;
7269
import com.nextcloud.android.sso.exceptions.AccountImportCancelledException;
@@ -76,16 +73,16 @@
7673
import com.nextcloud.android.sso.exceptions.TokenMismatchException;
7774
import com.nextcloud.android.sso.exceptions.UnknownErrorException;
7875
import com.nextcloud.android.sso.helper.SingleAccountHelper;
76+
import com.owncloud.android.lib.common.utils.Log_OC;
77+
78+
import org.jetbrains.annotations.NotNull;
7979

8080
import java.net.HttpURLConnection;
81-
import java.util.Arrays;
8281
import java.util.LinkedList;
83-
import java.util.List;
8482
import java.util.concurrent.ExecutorService;
8583
import java.util.concurrent.Executors;
8684
import java.util.stream.Collectors;
8785

88-
import hct.Hct;
8986
import it.niedermann.android.util.ColorUtil;
9087
import it.niedermann.owncloud.notes.LockedActivity;
9188
import it.niedermann.owncloud.notes.NotesApplication;
@@ -121,6 +118,7 @@
121118
import it.niedermann.owncloud.notes.shared.model.NavigationCategory;
122119
import it.niedermann.owncloud.notes.shared.model.NoteClickListener;
123120
import it.niedermann.owncloud.notes.shared.util.CustomAppGlideModule;
121+
import it.niedermann.owncloud.notes.shared.util.DisplayUtils;
124122
import it.niedermann.owncloud.notes.shared.util.NoteUtil;
125123
import it.niedermann.owncloud.notes.shared.util.ShareUtil;
126124
import it.niedermann.owncloud.notes.util.LinkHelper;
@@ -133,6 +131,8 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A
133131

134132
protected MainViewModel mainViewModel;
135133

134+
private EcosystemManager ecosystemManager;
135+
136136
private boolean gridView = true;
137137

138138
public static final String ADAPTER_KEY_RECENT = "recent";
@@ -173,6 +173,8 @@ protected void onCreate(Bundle savedInstanceState) {
173173

174174
setContentView(binding.getRoot());
175175

176+
ecosystemManager = new EcosystemManager(this);
177+
handleEcosystemIntent(getIntent());
176178
this.coordinatorLayout = binding.activityNotesListView.activityNotesListView;
177179
this.swipeRefreshLayout = binding.activityNotesListView.swiperefreshlayout;
178180
this.fabCreate = binding.activityNotesListView.fabCreate;
@@ -379,12 +381,20 @@ private void setupDrawerAppMenu() {
379381
}
380382

381383
private void setupDrawerAppMenuListener() {
382-
// Add listeners to the ecosystem items to launch the app or app-store
383-
binding.drawerEcosystemFiles.setOnClickListener(v -> LinkHelper.INSTANCE.openAppOrStore(LinkHelper.APP_NEXTCLOUD_FILES, mainViewModel.getCurrentAccount().getValue().getAccountName(), this));
384-
binding.drawerEcosystemTalk.setOnClickListener(v -> LinkHelper.INSTANCE.openAppOrStore(LinkHelper.APP_NEXTCLOUD_TALK, mainViewModel.getCurrentAccount().getValue().getAccountName(), this));
384+
binding.drawerEcosystemFiles.setOnClickListener(v -> ecosystemManager.openApp(EcosystemApp.FILES, getAccountName()));
385+
binding.drawerEcosystemTalk.setOnClickListener(v -> ecosystemManager.openApp(EcosystemApp.TALK, getAccountName()));
385386
binding.drawerEcosystemMore.setOnClickListener(v -> LinkHelper.INSTANCE.openAppStore("Nextcloud", true, this));
386387
}
387388

389+
private String getAccountName() {
390+
final var currentAccount = mainViewModel.getCurrentAccount().getValue();
391+
if (currentAccount == null) {
392+
return null;
393+
}
394+
395+
return currentAccount.getAccountName();
396+
}
397+
388398
private void themeDrawerAppMenu(int color) {
389399
ColorStateList colorStateList = ColorStateList.valueOf(color);
390400
binding.drawerEcosystemFilesIcon.setImageTintList(colorStateList);
@@ -482,6 +492,26 @@ protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
482492
mainViewModel.restoreInstanceState();
483493
}
484494

495+
private void handleEcosystemIntent(Intent intent) {
496+
ecosystemManager.receiveAccount(intent, new AccountReceiverCallback() {
497+
@Override
498+
public void onAccountReceived(@NotNull String accountName) {
499+
final var account = mainViewModel.getAccountByName(accountName);
500+
if (account != null) {
501+
onAccountChosen(account);
502+
} else {
503+
Log_OC.w(TAG, "account not found");
504+
DisplayUtils.showSnackMessage(MainActivity.this, R.string.account_not_found);
505+
}
506+
}
507+
508+
@Override
509+
public void onAccountError(@NotNull String reason) {
510+
Log_OC.w(TAG, "handleEcosystemIntent: " + reason);
511+
}
512+
});
513+
}
514+
485515
private void setupToolbars() {
486516
setSupportActionBar(binding.activityNotesListView.searchToolbar);
487517
activityBinding.searchBar.homeToolbar.setOnClickListener((v) -> {
@@ -754,6 +784,7 @@ protected void onNewIntent(Intent intent) {
754784
activityBinding.searchView.setQuery(intent.getStringExtra(SearchManager.QUERY), true);
755785
}
756786
super.onNewIntent(intent);
787+
handleEcosystemIntent(intent);
757788
}
758789

759790
@Override

app/src/main/java/it/niedermann/owncloud/notes/main/MainViewModel.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ public LiveData<Account> getCurrentAccount() {
126126
return distinctUntilChanged(currentAccount);
127127
}
128128

129+
public Account getAccountByName(String accountName) {
130+
return repo.getAccountByName(accountName);
131+
}
132+
129133
public void postCurrentAccount(@NonNull Account account) {
130134
state.set(KEY_CURRENT_ACCOUNT, account);
131135
BrandingUtil.saveBrandColor(getApplication(), account.getColor());

app/src/main/java/it/niedermann/owncloud/notes/util/LinkHelper.kt

Lines changed: 1 addition & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -10,46 +10,16 @@ package it.niedermann.owncloud.notes.util
1010
import android.content.ActivityNotFoundException
1111
import android.content.Context
1212
import android.content.Intent
13-
import android.net.Uri
1413
import androidx.core.net.toUri
15-
import com.owncloud.android.lib.common.utils.Log_OC
16-
import java.util.Locale
1714

1815
/**
1916
* Helper class for opening Nextcloud apps if present
2017
* or falling back to opening the app store
2118
* in case the app is not yet installed on the device.
2219
*/
2320
object LinkHelper {
24-
const val APP_NEXTCLOUD_FILES = "com.nextcloud.client"
25-
const val APP_NEXTCLOUD_NOTES = "it.niedermann.owncloud.notes"
26-
const val APP_NEXTCLOUD_TALK = "com.nextcloud.talk2"
27-
const val KEY_ACCOUNT: String = "KEY_ACCOUNT"
2821
private const val TAG = "LinkHelper"
2922

30-
/**
31-
* Open specified app and, if not installed redirect to corresponding download.
32-
*
33-
* @param packageName of app to be opened
34-
* @param userHash to pass in intent
35-
*/
36-
fun openAppOrStore(
37-
packageName: String,
38-
userHash: String?,
39-
context: Context,
40-
) {
41-
val intent = context.packageManager.getLaunchIntentForPackage(packageName)
42-
if (intent != null) {
43-
// app installed - open directly
44-
// TODO handle null user?
45-
intent.putExtra(KEY_ACCOUNT, userHash)
46-
context.startActivity(intent)
47-
} else {
48-
// app not found - open market (Google Play Store, F-Droid, etc.)
49-
openAppStore(packageName, false, context)
50-
}
51-
}
52-
5323
/**
5424
* Open app store page of specified app or search for specified string. Will attempt to open browser when no app
5525
* store is available.
@@ -66,7 +36,7 @@ object LinkHelper {
6636
val intent = Intent(Intent.ACTION_VIEW, "market://$suffix".toUri())
6737
try {
6838
context.startActivity(intent)
69-
} catch (activityNotFoundException1: ActivityNotFoundException) {
39+
} catch (_: ActivityNotFoundException) {
7040
// all is lost: open google play store web page for app
7141
if (!search) {
7242
suffix = "apps/$suffix"
@@ -75,58 +45,4 @@ object LinkHelper {
7545
context.startActivity(intent)
7646
}
7747
}
78-
79-
// region Validation
80-
private const val HTTP = "http"
81-
private const val HTTPS = "https"
82-
private const val FILE = "file"
83-
private const val CONTENT = "content"
84-
85-
/**
86-
* Validates if a string can be converted to a valid URI
87-
*/
88-
@Suppress("TooGenericExceptionCaught", "ReturnCount")
89-
fun validateAndGetURI(uriString: String?): Uri? {
90-
if (uriString.isNullOrBlank()) {
91-
Log_OC.w(TAG, "Given uriString is null or blank")
92-
return null
93-
}
94-
95-
return try {
96-
val uri = uriString.toUri()
97-
if (uri.scheme == null) {
98-
return null
99-
}
100-
101-
val validSchemes = listOf(HTTP, HTTPS, FILE, CONTENT)
102-
if (uri.scheme in validSchemes) uri else null
103-
} catch (e: Exception) {
104-
Log_OC.e(TAG, "Invalid URI string: $uriString -- $e")
105-
null
106-
}
107-
}
108-
109-
/**
110-
* Validates if a URL string is valid
111-
*/
112-
@Suppress("TooGenericExceptionCaught", "ReturnCount")
113-
fun validateAndGetURL(url: String?): String? {
114-
if (url.isNullOrBlank()) {
115-
Log_OC.w(TAG, "Given url is null or blank")
116-
return null
117-
}
118-
119-
return try {
120-
val uri = url.toUri()
121-
if (uri.scheme == null) {
122-
return null
123-
}
124-
val validSchemes = listOf(HTTP, HTTPS)
125-
if (uri.scheme in validSchemes) url else null
126-
} catch (e: Exception) {
127-
Log_OC.e(TAG, "Invalid URL: $url -- $e")
128-
null
129-
}
130-
}
131-
// endregion
13248
}

app/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,4 +520,5 @@
520520
<string name="activity_sharing_details_title">Sharing Details</string>
521521
<string name="share_expires">Share expires on %1$s</string>
522522
<string name="dismiss">Dismiss</string>
523+
<string name="account_not_found">Account not found!</string>
523524
</resources>

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ buildscript {
1313
kotlinVersion = '2.3.0'
1414
commonsVersion = '2.4.1'
1515
androidCommonsVersion = '1.1.1'
16-
nextcloudAndroidCommonLib = "0.31.0"
16+
nextcloudAndroidCommonLib = "4fc0f29981"
1717
singleSignOnVersion = "1.3.4"
1818
}
1919
repositories {

0 commit comments

Comments
 (0)