Skip to content

Commit fe7965b

Browse files
Merge pull request #16301 from nextcloud/ecosystem-link-handling
ecosystem link handling
2 parents 18d4441 + 0f607a6 commit fe7965b

8 files changed

Lines changed: 162 additions & 69 deletions

File tree

app/build.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,8 +504,9 @@ dependencies {
504504
"gplayImplementation"(libs.bundles.gplay)
505505
// endregion
506506

507-
// region UI
507+
// region common
508508
implementation(libs.ui)
509+
implementation(libs.common.core)
509510
// endregion
510511

511512
// region Image loading

app/src/main/AndroidManifest.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,13 @@
147147
android:exported="true"
148148
android:launchMode="singleTop"
149149
android:theme="@style/Theme.ownCloud.Launcher">
150+
151+
<intent-filter>
152+
<action android:name="com.nextcloud.intent.OPEN_ECOSYSTEM_APP" />
153+
<category android:name="android.intent.category.DEFAULT" />
154+
</intent-filter>
155+
156+
150157
<intent-filter>
151158
<action android:name="android.intent.action.SEARCH" />
152159
</intent-filter>

app/src/main/java/com/nextcloud/utils/LinkHelper.kt

Lines changed: 1 addition & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -10,53 +10,17 @@ package com.nextcloud.utils
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.nextcloud.client.account.User
1614
import com.owncloud.android.lib.common.utils.Log_OC
17-
import com.owncloud.android.ui.activity.FileDisplayActivity
1815
import java.util.Locale
19-
import java.util.Optional
20-
import kotlin.jvm.optionals.getOrNull
2116

2217
object LinkHelper {
23-
const val APP_NEXTCLOUD_NOTES = "it.niedermann.owncloud.notes"
24-
const val APP_NEXTCLOUD_TALK = "com.nextcloud.talk2"
2518
private const val TAG = "LinkHelper"
2619

2720
fun isHttpOrHttpsLink(link: String?): Boolean = link?.lowercase(Locale.getDefault())?.let {
2821
it.startsWith("http://") || it.startsWith("https://")
2922
} == true
3023

31-
/**
32-
* Open specified app and, if not installed redirect to corresponding download.
33-
*
34-
* @param packageName of app to be opened
35-
* @param user to pass in intent
36-
*/
37-
fun openAppOrStore(packageName: String, user: Optional<User>, context: Context) {
38-
openAppOrStore(packageName, user.getOrNull(), context)
39-
}
40-
41-
/**
42-
* Open specified app and, if not installed redirect to corresponding download.
43-
*
44-
* @param packageName of app to be opened
45-
* @param user to pass in intent
46-
*/
47-
fun openAppOrStore(packageName: String, user: User?, context: Context) {
48-
val intent = context.packageManager.getLaunchIntentForPackage(packageName)
49-
if (intent != null) {
50-
// app installed - open directly
51-
// TODO handle null user?
52-
intent.putExtra(FileDisplayActivity.KEY_ACCOUNT, user.hashCode())
53-
context.startActivity(intent)
54-
} else {
55-
// app not found - open market (Google Play Store, F-Droid, etc.)
56-
openAppStore(packageName, false, context)
57-
}
58-
}
59-
6024
/**
6125
* Open app store page of specified app or search for specified string. Will attempt to open browser when no app
6226
* store is available.
@@ -69,7 +33,7 @@ object LinkHelper {
6933
val intent = Intent(Intent.ACTION_VIEW, "market://$suffix".toUri())
7034
try {
7135
context.startActivity(intent)
72-
} catch (activityNotFoundException1: ActivityNotFoundException) {
36+
} catch (_: ActivityNotFoundException) {
7337
// all is lost: open google play store web page for app
7438
if (!search) {
7539
suffix = "apps/$suffix"
@@ -82,32 +46,6 @@ object LinkHelper {
8246
// region Validation
8347
private const val HTTP = "http"
8448
private const val HTTPS = "https"
85-
private const val FILE = "file"
86-
private const val CONTENT = "content"
87-
88-
/**
89-
* Validates if a string can be converted to a valid URI
90-
*/
91-
@Suppress("TooGenericExceptionCaught", "ReturnCount")
92-
fun validateAndGetURI(uriString: String?): Uri? {
93-
if (uriString.isNullOrBlank()) {
94-
Log_OC.w(TAG, "Given uriString is null or blank")
95-
return null
96-
}
97-
98-
return try {
99-
val uri = uriString.toUri()
100-
if (uri.scheme == null) {
101-
return null
102-
}
103-
104-
val validSchemes = listOf(HTTP, HTTPS, FILE, CONTENT)
105-
if (uri.scheme in validSchemes) uri else null
106-
} catch (e: Exception) {
107-
Log_OC.e(TAG, "Invalid URI string: $uriString -- $e")
108-
null
109-
}
110-
}
11149

11250
/**
11351
* Validates if a URL string is valid

app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949
import com.google.android.material.button.MaterialButton;
5050
import com.google.android.material.navigation.NavigationView;
5151
import com.google.android.material.progressindicator.LinearProgressIndicator;
52+
import com.nextcloud.android.common.core.utils.ecosystem.EcosystemApp;
53+
import com.nextcloud.android.common.core.utils.ecosystem.EcosystemManager;
5254
import com.nextcloud.android.common.ui.theme.utils.ColorRole;
5355
import com.nextcloud.client.account.User;
5456
import com.nextcloud.client.di.Injectable;
@@ -205,6 +207,8 @@ public abstract class DrawerActivity extends ToolbarActivity
205207

206208
private BottomNavigationView bottomNavigationView;
207209

210+
private EcosystemManager ecosystemManager;
211+
208212
@Inject
209213
AppPreferences preferences;
210214

@@ -429,8 +433,13 @@ private void showTopBanner(ConstraintLayout banner) {
429433
LinearLayout moreView = banner.findViewById(R.id.drawer_ecosystem_more);
430434
LinearLayout assistantView = banner.findViewById(R.id.drawer_ecosystem_assistant);
431435

432-
notesView.setOnClickListener(v -> LinkHelper.INSTANCE.openAppOrStore(LinkHelper.APP_NEXTCLOUD_NOTES, getUser(), this));
433-
talkView.setOnClickListener(v -> LinkHelper.INSTANCE.openAppOrStore(LinkHelper.APP_NEXTCLOUD_TALK, getUser(), this));
436+
final var optionalUser = getUser();
437+
if (optionalUser.isPresent()) {
438+
final var accountName = optionalUser.get().getAccountName();
439+
notesView.setOnClickListener(v -> ecosystemManager.openApp(EcosystemApp.NOTES, accountName));
440+
talkView.setOnClickListener(v -> ecosystemManager.openApp(EcosystemApp.TALK, accountName));
441+
}
442+
434443
moreView.setOnClickListener(v -> LinkHelper.INSTANCE.openAppStore("Nextcloud", true, this));
435444
assistantView.setOnClickListener(v -> {
436445
DrawerActivity.menuItemId = Menu.NONE;
@@ -727,6 +736,10 @@ private void launchActivityForSearch(SearchEvent searchEvent, int menuItemId) {
727736
startActivity(intent);
728737
}
729738

739+
public EcosystemManager getEcosystemManager() {
740+
return ecosystemManager;
741+
}
742+
730743
/**
731744
* sets the new/current account and restarts. In case the given account equals the actual/current account the call
732745
* will be ignored.
@@ -1136,6 +1149,7 @@ protected void onCreate(Bundle savedInstanceState) {
11361149

11371150
externalLinksProvider = new ExternalLinksProvider(getContentResolver());
11381151
arbitraryDataProvider = new ArbitraryDataProviderImpl(this);
1152+
ecosystemManager = new EcosystemManager(this);
11391153
}
11401154

11411155
@Override

app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager
5252
import com.google.android.material.appbar.AppBarLayout
5353
import com.google.android.material.dialog.MaterialAlertDialogBuilder
5454
import com.google.android.material.snackbar.Snackbar
55+
import com.nextcloud.android.common.core.utils.ecosystem.AccountReceiverCallback
5556
import com.nextcloud.appReview.InAppReviewHelper
5657
import com.nextcloud.client.account.User
5758
import com.nextcloud.client.appinfo.AppInfo
@@ -256,6 +257,7 @@ class FileDisplayActivity :
256257

257258
intent?.let {
258259
handleCommonIntents(it)
260+
handleEcosystemIntent(it)
259261
}
260262

261263
loadSavedInstanceState(savedInstanceState)
@@ -547,6 +549,7 @@ class FileDisplayActivity :
547549
handleCommonIntents(intent)
548550
handleSpecialIntents(intent)
549551
handleRestartIntent(intent)
552+
handleEcosystemIntent(intent)
550553
}
551554

552555
private fun handleSpecialIntents(intent: Intent) {
@@ -3073,6 +3076,28 @@ class FileDisplayActivity :
30733076
})
30743077
}
30753078

3079+
private fun handleEcosystemIntent(intent: Intent?) {
3080+
ecosystemManager.receiveAccount(
3081+
intent,
3082+
object : AccountReceiverCallback {
3083+
override fun onAccountReceived(accountName: String) {
3084+
val account = accountManager.getUser(accountName).orElse(null)
3085+
?: run {
3086+
Log_OC.w(TAG, "user is not present")
3087+
DisplayUtils.showSnackMessage(this@FileDisplayActivity, R.string.account_not_found)
3088+
return
3089+
}
3090+
3091+
accountClicked(account)
3092+
}
3093+
3094+
override fun onAccountError(reason: String) {
3095+
Log_OC.w(TAG, "handleEcosystemIntent: $reason")
3096+
}
3097+
}
3098+
)
3099+
}
3100+
30763101
// region MetadataSyncJob
30773102
private fun startMetadataSyncForRoot() {
30783103
backgroundJobManager.startMetadataSyncJob(OCFile.ROOT_PATH)

app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@
2626

2727
import com.elyeproj.loaderviewlibrary.LoaderImageView;
2828
import com.google.android.material.chip.Chip;
29+
import com.nextcloud.android.common.core.utils.ecosystem.EcosystemApp;
2930
import com.nextcloud.android.common.ui.theme.utils.ColorRole;
3031
import com.nextcloud.client.account.User;
3132
import com.nextcloud.client.database.entity.OfflineOperationEntity;
3233
import com.nextcloud.client.jobs.upload.FileUploadHelper;
3334
import com.nextcloud.client.preferences.AppPreferences;
3435
import com.nextcloud.model.OfflineOperationType;
35-
import com.nextcloud.utils.LinkHelper;
3636
import com.nextcloud.utils.extensions.OCFileExtensionsKt;
3737
import com.nextcloud.utils.extensions.ViewExtensionsKt;
3838
import com.nextcloud.utils.mdm.MDMConfig;
@@ -55,6 +55,7 @@
5555
import com.owncloud.android.lib.resources.status.OCCapability;
5656
import com.owncloud.android.lib.resources.tags.Tag;
5757
import com.owncloud.android.ui.activity.ComponentsGetter;
58+
import com.owncloud.android.ui.activity.DrawerActivity;
5859
import com.owncloud.android.ui.activity.FileDisplayActivity;
5960
import com.owncloud.android.ui.adapter.helper.OCFileListAdapterDataProvider;
6061
import com.owncloud.android.ui.adapter.helper.OCFileListAdapterHelper;
@@ -449,7 +450,12 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi
449450
listHeaderOpenInBinding.openInButton.setText(String.format(activity.getString(R.string.open_in_app),
450451
activity.getString(R.string.ecosystem_apps_display_notes)));
451452

452-
listHeaderOpenInBinding.openInButton.setOnClickListener(v -> LinkHelper.INSTANCE.openAppOrStore(LinkHelper.APP_NEXTCLOUD_NOTES, user, activity));
453+
if (activity instanceof DrawerActivity drawerActivity) {
454+
final var ecosystemManager = drawerActivity.getEcosystemManager();
455+
if (ecosystemManager != null) {
456+
listHeaderOpenInBinding.openInButton.setOnClickListener(v -> ecosystemManager.openApp(EcosystemApp.NOTES, user.getAccountName()));
457+
}
458+
}
453459
}
454460

455461
} else {

gradle/libs.versions.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# SPDX-License-Identifier: AGPL-3.0-or-later
33

44
[versions]
5-
androidCommonLibraryVersion = "0.31.0"
5+
androidCommonLibraryVersion = "4fc0f29981"
66
androidGifDrawableVersion = "1.2.30"
77
androidImageCropperVersion = "4.7.0"
88
androidLibraryVersion ="839366c261c52437425cde740c9e5a4ab8c8bace"
@@ -232,6 +232,7 @@ prism4j-bundler = { module = "io.noties:prism4j-bundler", version.ref = "prismVe
232232

233233
# Nextcloud libraries
234234
ui = { module = "com.github.nextcloud.android-common:ui", version.ref = "androidCommonLibraryVersion" }
235+
common-core = { module = "com.github.nextcloud.android-common:core", version.ref = "androidCommonLibraryVersion" }
235236
qrcodescanner = { module = "com.github.nextcloud-deps:qrcodescanner", version.ref = "qrcodescannerVersion" }
236237

237238
# Worker

0 commit comments

Comments
 (0)