Skip to content

Commit 5ef756c

Browse files
committed
Add support for product flavors
Add support for third-party app stores like Samsung Galaxy Store. Update `link` utils to accept an optional `flavor` parameter.
1 parent d97a4c2 commit 5ef756c

File tree

16 files changed

+300
-28
lines changed

16 files changed

+300
-28
lines changed

dynamic-utils/src/main/AndroidManifest.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<!--
3-
Copyright 2017-2022 Pranav Pandey
3+
Copyright 2017-2024 Pranav Pandey
44
55
Licensed under the Apache License, Version 2.0 (the "License");
66
you may not use this file except in compliance with the License.
@@ -18,6 +18,11 @@
1818
<manifest
1919
xmlns:android="http://schemas.android.com/apk/res/android">
2020

21+
<!-- Query packages on API 30 and above. -->
22+
<queries>
23+
<package android:name="com.google.android.gms" />
24+
</queries>
25+
2126
<!-- Query intents on API 30 and above. -->
2227
<queries>
2328
<intent>

dynamic-utils/src/main/java/com/pranavpandey/android/dynamic/util/DynamicLinkUtils.java

Lines changed: 223 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2022 Pranav Pandey
2+
* Copyright 2017-2024 Pranav Pandey
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -72,6 +72,18 @@ public class DynamicLinkUtils {
7272
private static final String URL_GOOGLE_PLAY_SEARCH_PUB =
7373
"http://play.google.com/store/search?q=pub:";
7474

75+
/**
76+
* Samsung Galaxy Store app URL template to open app details.
77+
*/
78+
private static final String URL_SAMSUNG_GALAXY_STORE =
79+
"https://apps.samsung.com/appquery/appDetail.as?appId=";
80+
81+
/**
82+
* Samsung Galaxy Store app search query template to search apps of a publisher.
83+
*/
84+
private static final String URL_SAMSUNG_GALAXY_STORE_SEARCH_PUB =
85+
"https://apps.samsung.com/appquery/sellerProductList.as?SellerID=";
86+
7587
/**
7688
* Constant for the bookmarks URI.
7789
*/
@@ -173,13 +185,15 @@ public static boolean copyToClipboard(@NonNull Context context,
173185
* <p>{@code null} to supply app and package name.
174186
* @param uri The optional content URI to be shared.
175187
* @param mimeType The optional mime type for the file.
188+
* @param flavor The product flavor to be used.
176189
*
177190
* @return {@code true} on successful operation.
178191
*
179192
* @see Intent#ACTION_SEND
180193
*/
181194
public static boolean share(@Nullable Context context, @Nullable String title,
182-
@Nullable String message, @Nullable Uri uri, @Nullable String mimeType) {
195+
@Nullable String message, @Nullable Uri uri, @Nullable String mimeType,
196+
@DynamicSdkUtils.DynamicFlavor String flavor) {
183197
if (context == null) {
184198
return false;
185199
}
@@ -194,9 +208,17 @@ public static boolean share(@Nullable Context context, @Nullable String title,
194208
}
195209

196210
if (message == null) {
197-
message = String.format(context.getString(R.string.adu_share_desc),
198-
context.getApplicationInfo().loadLabel(context.getPackageManager()),
199-
context.getPackageName());
211+
if (DynamicSdkUtils.DynamicFlavor.EXTERNAL.equals(flavor)
212+
&& DynamicDeviceUtils.isSamsungOneUI()) {
213+
message = String.format(context.getString(
214+
R.string.adu_share_desc_samsung_galaxy_store),
215+
context.getApplicationInfo().loadLabel(context.getPackageManager()),
216+
context.getPackageName());
217+
} else {
218+
message = String.format(context.getString(R.string.adu_share_desc),
219+
context.getApplicationInfo().loadLabel(context.getPackageManager()),
220+
context.getPackageName());
221+
}
200222
}
201223

202224
intent.putExtra(Intent.EXTRA_TEXT, message);
@@ -219,6 +241,27 @@ public static boolean share(@Nullable Context context, @Nullable String title,
219241
return false;
220242
}
221243

244+
/**
245+
* Share application via system default share intent so that user can select from the
246+
* available apps if more than one apps are available.
247+
*
248+
* @param context The context to be used.
249+
* @param title The application chooser title if more than one apps are available.
250+
* @param message The default share message which user can modify.
251+
* <p>{@code null} to supply app and package name.
252+
* @param image The optional image bitmap URI to be shared.
253+
* @param flavor The product flavor to be used.
254+
*
255+
* @return {@code true} on successful operation.
256+
*
257+
* @see Intent#ACTION_SEND
258+
*/
259+
public static boolean share(@Nullable Context context,
260+
@Nullable String title, @Nullable String message, @Nullable Uri image,
261+
@DynamicSdkUtils.DynamicFlavor String flavor) {
262+
return share(context, title, message, image, "image/*", flavor);
263+
}
264+
222265
/**
223266
* Share application via system default share intent so that user can select from the
224267
* available apps if more than one apps are available.
@@ -235,7 +278,26 @@ public static boolean share(@Nullable Context context, @Nullable String title,
235278
*/
236279
public static boolean share(@Nullable Context context, @Nullable String title,
237280
@Nullable String message, @Nullable Uri image) {
238-
return share(context, title, message, image, "image/*");
281+
return share(context, title, message, image, DynamicSdkUtils.DynamicFlavor.GOOGLE);
282+
}
283+
284+
/**
285+
* Share application via system default share intent so that user can select from the
286+
* available apps if more than one apps are available.
287+
*
288+
* @param context The context to be used.
289+
* @param title The application chooser title if more than one apps are available.
290+
* @param message The default share message which user can modify.
291+
* <p>{@code null} to supply app and package name.
292+
* @param flavor The product flavor to be used.
293+
*
294+
* @return {@code true} on successful operation.
295+
*
296+
* @see Intent#ACTION_SEND
297+
*/
298+
public static boolean share(@Nullable Context context, @Nullable String title,
299+
@Nullable String message, @DynamicSdkUtils.DynamicFlavor String flavor) {
300+
return share(context, title, message, null, flavor);
239301
}
240302

241303
/**
@@ -253,7 +315,23 @@ public static boolean share(@Nullable Context context, @Nullable String title,
253315
*/
254316
public static boolean share(@Nullable Context context,
255317
@Nullable String title, @Nullable String message) {
256-
return share(context, title, message, null);
318+
return share(context, title, message, DynamicSdkUtils.DynamicFlavor.GOOGLE);
319+
}
320+
321+
/**
322+
* Share application via system default share intent so that user can select from the
323+
* available apps if more than one apps are available.
324+
*
325+
* @param context The context to be used.
326+
* @param flavor The product flavor to be used.
327+
*
328+
* @return {@code true} on successful operation.
329+
*
330+
* @see #share(Context, String, String)
331+
*/
332+
public static boolean shareApp(@Nullable Context context,
333+
@DynamicSdkUtils.DynamicFlavor String flavor) {
334+
return share(context, null, null, flavor);
257335
}
258336

259337
/**
@@ -267,7 +345,7 @@ public static boolean share(@Nullable Context context,
267345
* @see #share(Context, String, String)
268346
*/
269347
public static boolean shareApp(@Nullable Context context) {
270-
return share(context, null, null);
348+
return shareApp(context, DynamicSdkUtils.DynamicFlavor.GOOGLE);
271349
}
272350

273351
/**
@@ -301,7 +379,7 @@ public static boolean viewUrl(@Nullable Context context, @Nullable String url) {
301379
* {@code https or http} in {@code AndroidManifest} to support API 30.
302380
*
303381
* @param context The context to be used.
304-
* @param packageName Application package name to build the search query.
382+
* @param packageName The app package name to build the search query.
305383
*
306384
* @return {@code true} on successful operation.
307385
*
@@ -316,24 +394,140 @@ public static boolean viewInGooglePlay(@Nullable Context context,
316394
return viewUrl(context, URL_PLAY_STORE + packageName);
317395
}
318396

397+
/**
398+
* View app on Samsung Galaxy Store.
399+
* <p>Use {@code queries} tag for {@link Intent#ACTION_VIEW} with scheme
400+
* {@code https or http} in {@code AndroidManifest} to support API 30.
401+
*
402+
* @param context The context to be used.
403+
* @param packageName The app package name to build the search query.
404+
*
405+
* @return {@code true} on successful operation.
406+
*
407+
* @see Intent#ACTION_VIEW
408+
*/
409+
public static boolean viewInSamsungGalaxyStore(@Nullable Context context,
410+
@NonNull String packageName) {
411+
return viewUrl(context, URL_SAMSUNG_GALAXY_STORE + packageName);
412+
}
413+
414+
/**
415+
* View app on Google Play (or Android Market) or Samsung Galaxy Store if available.
416+
* <p>Can be used to view app details within the supported stores.
417+
* <p>Use {@code queries} tag for {@link Intent#ACTION_VIEW} with scheme
418+
* {@code https or http} in {@code AndroidManifest} to support API 30.
419+
*
420+
* @param context The context to be used.
421+
* @param packageName The app package name to build the search query.
422+
* @param flavor The product flavor to be used.
423+
*
424+
* @return {@code true} on successful operation.
425+
*
426+
* @see #viewInGooglePlay(Context, String)
427+
* @see #viewInSamsungGalaxyStore(Context, String)
428+
* @see DynamicSdkUtils.DynamicFlavor
429+
*/
430+
public static boolean viewApp(@Nullable Context context, @NonNull String packageName,
431+
@DynamicSdkUtils.DynamicFlavor String flavor) {
432+
if (DynamicSdkUtils.DynamicFlavor.EXTERNAL.equals(flavor)) {
433+
return viewAppExternal(context, packageName);
434+
} else if (context == null) {
435+
return false;
436+
}
437+
438+
if (viewInGooglePlay(context, packageName)) {
439+
return true;
440+
} else if (DynamicDeviceUtils.isSamsungOneUI()) {
441+
return viewInSamsungGalaxyStore(context, packageName);
442+
}
443+
444+
return false;
445+
}
446+
447+
/**
448+
* View app on Google Play (or Android Market) or Samsung Galaxy Store if available.
449+
* <p>Can be used to view app details within the supported stores.
450+
* <p>Use {@code queries} tag for {@link Intent#ACTION_VIEW} with scheme
451+
* {@code https or http} in {@code AndroidManifest} to support API 30.
452+
*
453+
* @param context The context to be used.
454+
* @param packageName The app package name to build the search query.
455+
*
456+
* @return {@code true} on successful operation.
457+
*
458+
* @see #viewApp(Context, String, String)
459+
* @see DynamicSdkUtils.DynamicFlavor#GOOGLE
460+
*/
461+
public static boolean viewApp(@Nullable Context context, @NonNull String packageName) {
462+
return viewApp(context, packageName, DynamicSdkUtils.DynamicFlavor.GOOGLE);
463+
}
464+
465+
/**
466+
* View app on Google Play (or Android Market) or Samsung Galaxy Store if available.
467+
* External stores will be preferred first.
468+
* <p>Can be used to view app details within the supported stores.
469+
* <p>Use {@code queries} tag for {@link Intent#ACTION_VIEW} with scheme
470+
* {@code https or http} in {@code AndroidManifest} to support API 30.
471+
*
472+
* @param context The context to be used.
473+
* @param packageName The app package name to build the search query.
474+
*
475+
* @return {@code true} on successful operation.
476+
*
477+
* @see #viewInGooglePlay(Context, String)
478+
* @see #viewInSamsungGalaxyStore(Context, String)
479+
*/
480+
public static boolean viewAppExternal(@Nullable Context context, @NonNull String packageName) {
481+
if (context == null) {
482+
return false;
483+
}
484+
485+
486+
if (DynamicDeviceUtils.isSamsungOneUI()
487+
&& viewInSamsungGalaxyStore(context, packageName)) {
488+
return true;
489+
} else {
490+
return viewInGooglePlay(context, packageName);
491+
}
492+
}
493+
319494
/**
320495
* View app on Google Play or Android Market.
321496
* <p>Can be used for the quick feedback or rating from the user.
322497
* <p>Use {@code queries} tag for {@link Intent#ACTION_VIEW} with scheme
323498
* {@code https or http} in {@code AndroidManifest} to support API 30.
324499
*
325500
* @param context The context to be used.
501+
* @param flavor The product flavor to be used.
326502
*
327503
* @return {@code true} on successful operation.
328504
*
329-
* @see #viewInGooglePlay(Context, String)
505+
* @see #viewApp(Context, String, String)
506+
* @see DynamicSdkUtils.DynamicFlavor
330507
*/
331-
public static boolean rateApp(@Nullable Context context) {
508+
public static boolean rateApp(@Nullable Context context,
509+
@DynamicSdkUtils.DynamicFlavor String flavor) {
332510
if (context == null) {
333511
return false;
334512
}
335513

336-
return viewInGooglePlay(context, context.getPackageName());
514+
return viewApp(context, context.getPackageName(), flavor);
515+
}
516+
517+
/**
518+
* View app on Google Play or Android Market.
519+
* <p>Can be used for the quick feedback or rating from the user.
520+
* <p>Use {@code queries} tag for {@link Intent#ACTION_VIEW} with scheme
521+
* {@code https or http} in {@code AndroidManifest} to support API 30.
522+
*
523+
* @param context The context to be used.
524+
*
525+
* @return {@code true} on successful operation.
526+
*
527+
* @see #rateApp(Context, String)
528+
*/
529+
public static boolean rateApp(@Nullable Context context) {
530+
return rateApp(context, DynamicSdkUtils.DynamicFlavor.GOOGLE);
337531
}
338532

339533
/**
@@ -346,7 +540,7 @@ public static boolean rateApp(@Nullable Context context) {
346540
*
347541
* @return {@code true} on successful operation.
348542
*
349-
* @see Intent#ACTION_VIEW
543+
* @see #viewUrl(Context, String)
350544
*/
351545
public static boolean moreApps(@Nullable Context context, @NonNull String publisher) {
352546
if (viewUrl(context, URL_MARKET_SEARCH_PUB + publisher)) {
@@ -356,6 +550,22 @@ public static boolean moreApps(@Nullable Context context, @NonNull String publis
356550
return viewUrl(context, URL_GOOGLE_PLAY_SEARCH_PUB + publisher);
357551
}
358552

553+
/**
554+
* View other apps of a Samsung Galaxy Store.
555+
* <p>Use {@code queries} tag for {@link Intent#ACTION_VIEW} with scheme
556+
* {@code https or http} in {@code AndroidManifest} to support API 30.
557+
*
558+
* @param context The context to be used.
559+
* @param publisher The publisher name to build the search query.
560+
*
561+
* @return {@code true} on successful operation.
562+
*
563+
* @see #viewUrl(Context, String)
564+
*/
565+
public static boolean moreAppsSamsung(@Nullable Context context, @NonNull String publisher) {
566+
return viewUrl(context, URL_SAMSUNG_GALAXY_STORE_SEARCH_PUB + publisher);
567+
}
568+
359569
/**
360570
* Send email according to the supplied parameters.
361571
*

dynamic-utils/src/main/java/com/pranavpandey/android/dynamic/util/DynamicSdkUtils.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2022 Pranav Pandey
2+
* Copyright 2017-2024 Pranav Pandey
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -28,6 +28,22 @@
2828
@TargetApi(Build.VERSION_CODES.M)
2929
public class DynamicSdkUtils {
3030

31+
/**
32+
* Product flavors to support external app stores.
33+
*/
34+
public @interface DynamicFlavor {
35+
36+
/**
37+
* Constant for the Google Play Store.
38+
*/
39+
String GOOGLE = "google";
40+
41+
/**
42+
* Constant for the external app store.
43+
*/
44+
String EXTERNAL = "external";
45+
}
46+
3147
/**
3248
* Detects if the current API version is a preview.
3349
*

0 commit comments

Comments
 (0)