Deeplink Jetpack Compose with no URI - android

The GPS Matter Commissioning intent filter looks like this, it does not use a URI scheme. If I try adding a URI GPS can't find my app any more.
<intent-filter>
<action android:name="com.google.android.gms.home.matter.ACTION_COMMISSION_DEVICE"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
So how do I use this intent to navigate in Jetpack compose? This deeplink does not trigger.
fun NavGraphBuilder.lowpanGraph(appState: LowpanAppState) {
composable(route = "$DEVICES_SCREEN",
deepLinks = listOf(navDeepLink { action = "com.google.android.gms.home.matter.ACTION_COMMISSION_DEVICE"})
) {
DevicesScreen(openScreen = { route -> appState.navigate(route) })
}

The answer here: make sure you don't have a launchMode set in your manifest file.

Related

Implicit intent does not find activity if data type is specified

I am trying to make an example of invoking an activity using implicit intent.
Intents and Intent Filters
I do it according to the code of the example indicated here.
getSecondActivity.setOnClickListener() {
val gameNameStr = getTextFromView(gamerName)
val gameStatusStr = getTextFromView(gameStatus)
if (gameNameStr != null && gameStatus != null) {
val sendIntent = Intent().apply {
action = Intent.ACTION_VIEW
putExtra(GAMER_NAME, gameNameStr)
putExtra(GAME_STATUS, gameStatusStr)
type = "text/plain"
}
//Verify the original intent will resolve to at least one activity
if (sendIntent.resolveActivity(packageManager) != null) {
startActivity(sendIntent)
} else {
Toast.makeText(this#MainActivity, "No Activity", Toast.LENGTH_SHORT).show()
}
}
}
I specified filters in the manifest.
<activity android:name=".ShowInfoFromFirst">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
At startup, a message is displayed that no matching activity was found. If I remove the type, then everything works. I came across a description in the class Intent.java
"type -- Specifies an explicit type (a MIME type) of the
intent data. Normally the type is inferred from the data itself.
By setting this attribute, **you disable that evaluation and force
an explicit type "
Then I do not understand why the example does not work for me.

Deep link not opening specified Activity but opens other Activity

I have created a DynamicLink programatically which includes sub-domain syntax, some title and preview Image. I have also specified the IntentFilter which should open that activity when clicked. But when the link is clicked it open another Activity which also have Deep link. page.link domain is provided by google itself in Firebase Console
The code for creating Dynamic Link is
String e="https://learnandroid.page.link/?link=https://learn.android/&apn=com.learnandro&amv=16&st=Please view the ContentEvent&si="+some Image Url+"&afl=https://play.google.com/store/apps/details?id=app Package name";
Task<ShortDynamicLink> shortLinkTask = FirebaseDynamicLinks.getInstance()
.createDynamicLink()
.setLongLink(Uri.parse(e))
.buildShortDynamicLink()
.addOnCompleteListener(new OnCompleteListener<ShortDynamicLink>() {
#Override
public void onComplete(#NonNull Task<ShortDynamicLink> task) {
Uri get=task.getResult().getShortLink();
Intent sh=new Intent(Intent.ACTION_SEND);
sh.setType("text/plain");
sh.putExtra(Intent.EXTRA_TEXT,"Vi ew the Amazing Event "+get);
startActivity(Intent.createChooser(sh,"View"));
}
});
The Intent filter for Activity is given as
<activity android:name=".content.Home"
android:launchMode="singleTask"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="learn.android"
android:scheme="https" />
</intent-filter>
</activity>
But when the link generated is clicked it opens some Another activity.
If you have deeplink in multiple activities then you should use android:pathPattern to differentiate them from each other.
Here is sample code
<data
android:host="learn.android"
android:pathPattern="/home"
android:scheme="https" />
and add /home to your link
String e="https://learnandroid.page.link/?link=https://learn.android/home/&apn=com.learnandro&amv=16&st=Please view the ContentEvent&si="+some Image Url+"&afl=https://play.google.com/store/apps/details?id=app Package name";
You can try below snippet :
val data: Uri? = intent?.data
if (Uri.EMPTY != data)
{
val id = intent.data?.getQueryParameter("ID")
intent = Intent(this, ActivityName::class.java)
startActivity(intent)
finish()
}
In getQueryParameter, you need to pass KEY name which contains data in URL
Define this set of code in Activity which is defined in Manifest file

TelecomManager.ACTION_CHANGE_DEFAULT_DIALER returns RESULT_CANCELED on huawei P8 Lite

I want to change Android default dialer and want to make my own customized dialer. For this purpose I have choose this GIthub repo as start up project. This works well on all other phone and stops working on huawei p8 lite. The default pop up message does not shows up for setting the app as default.
Here is code block
private fun checkDefaultDialer() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return
val telecomManager = getSystemService(TELECOM_SERVICE) as TelecomManager
val isAlreadyDefaultDialer = packageName == telecomManager.defaultDialerPackage
if (isAlreadyDefaultDialer) return
val intent = Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER).putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME, packageName)
startActivityForResult(intent, REQUEST_CODE_SET_DEFAULT_DIALER)
}
private fun checkSetDefaultDialerResult(resultCode: Int) {
val message = when (resultCode) {
RESULT_OK -> "User accepted request to become default dialer"
RESULT_CANCELED -> "User declined request to become default dialer"
else -> "Unexpected result code $resultCode"
}
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
StertActivityforResult returns with RESULT_CANCELED and message
User declined request to become default dialer
Can't find any solution for this. Any help will be greatly appreciated.
If you run this code in Android Q or above it will not work. Its just fine for below Q. To get it working in Android Q try the code below:
RoleManager rm = (RoleManager) getSystemService(Context.ROLE_SERVICE);
startActivityForResult(rm.createRequestRoleIntent(RoleManager.ROLE_DIALER), 120);
It will popup the app chooser dialog.
You'll also get a RESULT_CANCELED when targeting Android Q or higher, as the PermissionPolicyService removes the Action. You should use RoleManager.createRequestRoleIntent() instead.
Try to add some intent filters to your Activity in AndroidManifest.
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<action android:name="android.intent.action.DIAL"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="tel"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.DIAL"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
My way:
#SuppressLint("QueryPermissionsNeeded")
#TargetApi(Build.VERSION_CODES.M)
fun launchSetDefaultDialerIntent(activity: AppCompatActivity) {
Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER).putExtra(
TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME,
activity.packageName
).apply {
if (resolveActivity(activity.packageManager) != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val rm: RoleManager? = activity.getSystemService(RoleManager::class.java)
if (rm?.isRoleAvailable(RoleManager.ROLE_DIALER) == true) {
#Suppress("DEPRECATION")
activity.startActivityForResult(
rm.createRequestRoleIntent(RoleManager.ROLE_DIALER),
REQUEST_CODE_SET_DEFAULT_DIALER
)
}
} else {
#Suppress("DEPRECATION")
activity.startActivityForResult(this, REQUEST_CODE_SET_DEFAULT_DIALER)
}
} else {
activity.toastShort(R.string.no_contacts_found)
}
}
}
Then use it directly in Activity.

Android custom chrome tab with deep links

I have an Android/Kotlin application and I would like to configure deep links for certain pages to open inside my application (to look native).
At the moment, I have intent filters that redirect the user to an activity with WebView in which I open the desired url:
<activity android:name=".activity.WebViewActivity">
<intent-filter android:label="Futurity">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="api.example.com"
android:pathPrefix="/auth/confirm"
android:scheme="https" />
</intent-filter>
</activity>
class WebViewActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_web_view)
val data = intent.data
// construct url
val url = if (intent.data != null ) {
"https://" + data.host + data.path + "?" + data.query
}
appWebView.webViewClient = WebViewClient()
appWebView.loadUrl(url)
}
}
This works fine, but I would like to use Chrome custom tabs instead for security reasons.
However, when I try to configure the custom tab instead of WebView, I am getting an infinite loop of redirects between the page (launched in the chrome tab) and the intent filter which immediately redirects user back to the activity:
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.launchUrl(this, Uri.parse(url));
How can I achieve the same behavior as with webviews but without modifying the url? Is it even doable?
I did some digging and found out that you should search for packages that support the "warming services". If a package is returned then you can assign the package name to the Intent. Google has a GitHub repo with some helper classes. The one in question is CustomTabHelper#getPackageNameToUse().
So in your case:
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
CustomTabsIntent customTabsIntent = builder.build();
String packageName = CustomTabsHelper.getPackageNameToUse(getContext());
if (packageName != null) {
customTabsIntent.intent.setPackage(packageName);
}
customTabsIntent.launchUrl(this, Uri.parse(url));
If a package is not found then you'll want to have some fallback code else the infinite loop will keep happening.

How to launch an app using a deeplink in android

I want to launch app using my own app but not by giving the package name, I want to open a custom URL.
I do this to start an application.
Intent intent = getPackageManager().getLaunchIntentForPackage(packageInfo.packageName);
startActivity(intent);
Instead of package name is it possible to give a deep-link for example:
"mobiledeeplinkingprojectdemo://product/123"
Reference
You need to define a activity that will subscribe to required intent filters:
<activity
android:name="DeepLinkListener"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="host"
android:pathPattern="some regex"
android:scheme="scheme" />
</intent-filter>
</activity>
Then in onCreate of your DeepLinkListener activity you can access the host, scheme etc.:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent deepLinkingIntent= getIntent();
deepLinkingIntent.getScheme();
deepLinkingIntent.getData().getPath();
}
Perform check on path and again fire a Intent to take the user to corresponding activity. Refer data documentation for more help.
Now fire a Intent:
Intent intent = new Intent (Intent.ACTION_VIEW);
intent.setData(Uri.parse(DEEP_LINK_URL));
Don't forget to handle the exception. If there is no activity that can handle the deep link, startActivity will return an exception.
try {
context.startActivity(
Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse(deepLink)
}
)
} catch (exception: Exception) {
Toast.makeText(context, exception.localizedMessage, Toast.LENGTH_LONG).show()
}

Categories

Resources