How to launch an Activity from another Application in Android 30 - java

I have been using the following code to open my other app from within my app. This code works upto Android 29 devices but this code does not work in Android 30 devices. Can somebody please help me make it work for Android 30 as well. Thanks
case R.id.btAudio:
Intent launchIntent = getPackageManager().getLaunchIntentForPackage(getString("com.android.audioapp"));
Intent uin = new Intent(MainActivity.this, AudioInstall.class);
if (launchIntent != null) {
startActivity(launchIntent);
} else {
startActivity(uin);
}
this.finish();
break;

Android 11 added restrictions regarding the visibility of other apps. Apps that have targetSdk set to >= 30 can't interact with and open other apps without specifying this in the manifest.
To specify that your app interacts with another specific app, you need to add a <queries> element to your manifest file:
<manifest package="com.example.game">
<queries>
<package android:name="com.android.audioapp" />
</queries>
...
</manifest>
The link below contains other examples in case you need to specify a broader range of apps which you want to interact with.
Source: https://developer.android.com/training/basics/intents/package-visibility

Related

Android in-app language switcher works with emulator and local device, but not when published in Google Play (signed bundle)

I have an in-app language switcher in a Kotlin app (two buttons, one button for English, one button for Romanian).
It does not work on devices with Android 12 (API level 32) and lower. On the newer ones, it works perfectly.
I'm following the official guide here. I have a class LocaleHelper, that has this method:
fun setLanguage(language: String) {
App.preferences.edit().putString(App.LANGUAGE_SELECTION, language).apply()
val tag = "$language-RO"
val appLocale: LocaleListCompat = LocaleListCompat.forLanguageTags(tag)
AppCompatDelegate.setApplicationLocales(appLocale)
}
which I'm calling when a language button is clicked:
when (item?.itemId) {
R.id.romanian_button -> {
LocaleHelper().setLanguage("ro")
}
R.id.english_button_button -> {
LocaleHelper().setLanguage("en")
}
}
The Romanian language IS available on users devices, because in the MainActivity.kt, I'm already downloading the additional language (Romanian) according to the official Google code sample from github.
Also, in AndroidManifest.xml I've put this, according to the official guide for older devices:
<application>
...
<service
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
android:enabled="true"
android:exported="false">
<meta-data
android:name="autoStoreLocales"
android:value="true" />
</service>
...
</application>
The problem is that on devices with Android 12 (API level 32) and lower, this does nothing. When I tap the flags, nothing happens, the language remains English, even if the activity is recreating itself. On newer devices, this code works. What did I do wrong?

Android Email intent not Working on Android 11 java [duplicate]

I've an extension function for opening an intent for my activities:
fun Activity.openIntent(action: String?, type: String?, uri: Uri?) {
Intent()
.apply {
action?.let { this.action = it }
uri?.let { this.data = it }
type?.let { this.type = it }
}
.also { intent ->
packageManager?.let {
if (intent.resolveActivity(it) != null)
startActivity(intent)
else
showToast(R.string.application_not_found)
}
}
}
My targetSdkVersion is 30. It gives me a warning in intent.resolveActivity(it):
Consider adding a queries declaration to your manifest when calling this method.
So What should I do to solve this warning?
The simplest solution is to get rid of resolveActivity(). Replace:
packageManager?.let {
if (intent.resolveActivity(it) != null)
startActivity(intent)
else
showToast(R.string.application_not_found)
}
with:
try {
startActivity(intent)
} catch (ex: ActivityNotFoundException) {
showToast(R.string.application_not_found)
}
This gives you the same result with a bit better performance, and it will get rid of the warning.
Another option would be to add the QUERY_ALL_PACKAGES permission. This may get you banned from the Play Store.
Otherwise, you will need to:
Build a list of every possible openIntent() call that your app may make
Add a <queries> element to your manifest that lists all of those possible Intent structures that you want to be able to use with resolveActivity()
Repeat this process periodically, in case you add new scenarios for openIntent()
So starting Android 11 (i.e, if your app targets Android 11) not all applications will be visible to your application. Some apps are visible by default but in order to access other applications through your application, you will have to declare queries in your manifest else your application will not be able to access them. You can read about that here.
So if your application targets Android 11 and is to access an application that may not be visible by default you will want to add queries for them in the manifest file.
In your case, this warning is not applicable as I believe you are using implicit intents to open other applications. Using implicit intents, other applications can be accessed irrespective of app visibility. If your app target Android 10 or lower you can suppress the warning as all apps are visible by default.
To suppress the lint warning you can either:
Add the suppress annotation, like so:
#SuppressLint("QueryPermissionsNeeded")
fun Activity.openIntent(action: String?, type: String?, uri: Uri?): Activity {
Add the following to your android block in your app module build gradle file:
lintOptions {
ignore "QueryPermissionsNeeded"
}
Replace
if (intent.resolveActivity(it) != null)
with
if (it.resolveActivity(intent, 0) != null)
and the warning will be gone.
From API level 30 package visibility is restricted. So add appropriate query in your AndroidManifest file outside <application> tag.
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="http" />
</intent>
</queries>

Intent Action_dial does not function in android 11

I am currently developing an android app and needed a function that starts a phone call so I added this code.
public void dialPhoneNumber(String phoneNumber) {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:" + phoneNumber));
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
}
.. it seems to work perfectly in older android versions but when I test it in android 11 it doesn't function at all I tried action_call and added the permission <uses-permission android:name="android.permission.CALL_PHONE" /> still doesn't work.
Your problem lies in the line of code intent.resolveActivity(getPackageManager()). When you call resolveActivity, you will get a warning like this:
Consider adding a declaration to your manifest when calling this method; see https://g.co/dev/packagevisibility for details
Check the document under PackageManager, you will see this note:
Note: If your app targets Android 11 (API level 30) or higher, the methods in this class each return a filtered list of apps. Learn more about how to manage package visibility.
So what does that mean?
In android 11, Google added package visibility policy. Apps now have tighter control over viewing other apps. Your application will not be able to view or access applications outside of your application.
What do you need to do?
All you need to do is add below line of code to AndroidManifest.xml:
<manifest>
<queries>
<!-- Specific intents you query for -->
<intent>
<action android:name="android.intent.action.DIAL" />
</intent>
</queries>
</manifest>
More information:
Package visibility in Android 11
Package visibility filtering on Android

How to implement CallScreeningService for Andoid<=28

**What I have done so far : **
I have implement it for Android SDK 29
RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE);
Intent intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_CALL_SCREENING);
startActivityForResult(intent, REQUEST_ID1);
**What I am looking for ? : **
I want to implement Call Screening Service for devices < SDK 29.
Kindly help me if anyone have done it before.
Unfortunately, you can't.
It is impossible to access the RoleManager class on Android versions < 29 because this class was introduced on Android 29. Therefore, you can only use this class on devices running Android 29 and up.
For Android <= 28, to bind the CallScreeningService the app must be set as the default dialer app. On runtime, a dialog can be displayed asking the user to set your app as the default dialer app as follows:
if (getSystemService(TelecomManager.class).getDefaultDialerPackage() != getPackageName()) {
Intent changedDialer= new Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER);
changedDialer.putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME, getPackageName());
startActivity(ChangeDialer);
}

Programmatically open 'About device' page in Settings correctly?

startActivity(new Intent(android.provider.Settings.ACTION_DEVICE_INFO_SETTINGS)); opens this page in Samsung devices:
However, I want it to open this page like the rest of Android devices, how can I do it?
As Pedro Antonio said:
If it doesn't work for SAMSUNG devices I'm afraid it will probably not be possible. At least with no official answer. Many times vendors modify stock Android so for SAMSUNG devices settings app is different than stock AOSP, and the official method will not work.
When we call:
Intent i = new Intent(Settings.ACTION_DEVICE_INFO_SETTINGS);
startActivity(i);
we are referring to activity com.android.settings.Settings$DeviceInfoSettingsActivity and in logs we can see that activity is started
2020-06-26 11:33:43.804 4838-5126/? I/ActivityManager: START u0 {act=null typ=null flg=0x8000 cmp=ComponentInfo{com.android.settings/com.android.settings.Settings$DeviceInfoSettingsActivity}} from uid 1000
On devices like Huawei P10, Software Information data is part of DeviceInfoSettingsActivity. After some digging i found out that on Samsung S7 device Software Information is Fragment that is called inside DeviceInfoSettingsActivity
2020-06-26 11:44:25.780 7103-9703/? D/Settings: packageName : com.android.settings className : com.android.settings.SubSettings
2020-06-26 11:44:25.812 7103-7103/? D/SubSettings: Launching fragment com.samsung.android.settings.deviceinfo.SoftwareInfoSettings
I am not sure is it possible to access DeviceInfoSettingsActivity code (I couldn't) and see if you can send some extra data to open specific Fragment. So at this point i do not believe that it is possible to launch that specific fragment from intent.
The main point is it seems impossible. Let's look at what is the reason.
The DeviceInfoSettingsActivity can be opened by an intent call like:
Intent intent = new Intent(android.provider.Settings.ACTION_DEVICE_INFO_SETTINGS);
startActivity(intent);
or
Intent intent = new Intent();
intent.setClassName(
"com.android.settings",
"com.android.settings.Settings$DeviceInfoSettingsActivity"
);
startActivity(intent)
As you can see here:
https://android.googlesource.com/platform/packages/apps/Settings/+/master/src/com/android/settings/Settings.java
Settings and all of its inner classes are children of SettingsActivity. By taking a look at source code of SettingsActivity, we found out it is possible to show a sub-settings, passing the fragment name as an intent extra with key ":settings:show_fragment" to the SettingsActivity:
SettingsActivity#onCreate() then SettingsActivity#launchSettingFragment()
If we dig into logs where the target screen is shown, we'd see that the target fragment name is com.samsung.android.settings.deviceinfo.SoftwareInfoSettings.
But the problem is that there is a check on fragment names at SettingsActivity#isValidFragment() which allows specific fragments to navigate to and they are SettingsGateway#ENTRY_FRAGMENTS:
protected boolean isValidFragment(String fragmentName) {
// Almost all fragments are wrapped in this,
// except for a few that have their own activities.
for (int i = 0; i < SettingsGateway.ENTRY_FRAGMENTS.length; i++) {
if (SettingsGateway.ENTRY_FRAGMENTS[i].equals(fragmentName)) return true;
}
return false;
}
The alternative for showing other fragments in settings is to open SubSettings activity which overrides the isValidFragment to accepts every fragment.
#Override
protected boolean isValidFragment(String fragmentName) {
Log.d("SubSettings", "Launching fragment " + fragmentName);
return true;
}
That is exactly what happens when the SoftwareInfoSettings is shown:
D/Settings: packageName : com.android.settings className : com.android.settings.SubSettings
D/SubSettings: Launching fragment com.samsung.android.settings.deviceinfo.SoftwareInfoSettings
Unfortunately, starting the SubSettings from uid except launcher's uid isn't possible, because it is not an exported activity to be visible from the outside:
AndroidManifest.xml:
<activity android:name=".SubSettings"
android:parentActivityName="Settings"
android:theme="#style/Theme.SubSettings"/>
If you try to run:
Intent intent = new Intent();
intent.setClassName(
"com.android.settings",
"com.android.settings.SubSettings"
);
intent.putExtra(
":settings:show_fragment",
"com.samsung.android.settings.deviceinfo.SoftwareInfoSettings"
);
startActivity(intent);
will see this error log:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.aminography.settingsapp, PID: 14566
java.lang.SecurityException: Permission Denial:
starting Intent { flg=0x10000000 cmp=com.android.settings/.SubSettings (has extras) }
from ProcessRecord{fac1d09 14566:com.aminography.settingsapp/u0a104} (pid=14566, uid=10104)
not exported from uid 1000
Unfortunately, since isValidFragment() and SettingsGateway#ENTRY_FRAGMENTS are parts of the platform, not your application's runtime, it's impossible to change them even with reflection.
As the android documentation says, you should use
Intent i = new Intent(Settings.ACTION_DEVICE_INFO_SETTINGS);
startActivity(i);
https://developer.android.com/reference/android/provider/Settings#ACTION_DEVICE_INFO_SETTINGS
If it doesn't work for SAMSUNG devices I'm afraid it will probably not be possible. At least with no official answer. Many times vendors modify stock Android so for SAMSUNG devices settings app is different than stock AOSP, and the official method will not work.

Categories

Resources