There are many (one, two, three, four) questions on this topic on SO already. However, none of the answers I have found so far resolves the issue for me.
The problem is that the ActivityCompat.requestPermissions
does not trigger a popup, asking the user to give permission for notifications.
Setup:
<uses-permission android:name="android.permission.POST_NOTIFICATION" />
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_DENIED)
{
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.POST_NOTIFICATIONS}, 1);
}
and the callback is like so:
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(MainScreenActivity.this, "Woho, you have enabled notifications!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainScreenActivity.this, "Ouch, this is gonna hurt without notifications", Toast.LENGTH_SHORT).show();
}
return;
}
}
Here are the build.gradle files:
TheApp\build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
maven { url 'https://raw.github.com/xujiaao/mvn-repository/master/releases' }
maven {
url 'https://jitpack.io'
}
maven { url 'http://dl.bintray.com/ahmedrizwan/maven'
allowInsecureProtocol = true
}
google()
}
dependencies {
classpath 'com.google.gms:google-services:4.3.10' // Google Services plugin
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.5.2'
classpath 'com.android.tools.build:gradle:7.3.1'
classpath "io.realm:realm-gradle-plugin:10.0.0"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
maven { url 'http://oss.jfrog.org/artifactory/oss-snapshot-local'
allowInsecureProtocol = true
}
google()
jcenter()
flatDir {
dirs 'src/main/libs'
}
}
}
TheApp\app\build.gradle
apply plugin: 'com.android.application'
apply plugin: 'realm-android'
apply plugin: 'com.google.firebase.crashlytics'
android {
compileSdkVersion 33
lintOptions {
abortOnError false
}
buildFeatures{
dataBinding = true
}
defaultConfig {
applicationId "test.myapp"
minSdkVersion 29
targetSdkVersion 33
versionCode 60
versionName "1.60"
}
buildTypes {
debug {
signingConfig signingConfigs.debug_keystore
aaptOptions.setProperty("cruncherEnabled", false)
}
release {
signingConfig signingConfigs.release_keystore
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
aaptOptions.setProperty("cruncherEnabled", false)
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
namespace 'test.myapp'
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'com.google.firebase:firebase-core:17.5.1'
implementation 'com.google.firebase:firebase-messaging:20.3.0'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'com.google.android.gms:play-services-gcm:17.0.0'
implementation 'com.google.android.gms:play-services-location:17.1.0'
implementation 'com.google.android.gms:play-services-maps:17.0.0'
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
implementation "androidx.preference:preference-ktx:1.1.1"
implementation 'com.google.firebase:firebase-crashlytics:17.2.2'
implementation 'com.google.firebase:firebase-analytics:17.6.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.2'
implementation 'com.google.android.play:app-update:2.0.1'
def fragment_version = "1.5.4"
// Java language implementation
implementation "androidx.fragment:fragment:$fragment_version"
// Kotlin
implementation "androidx.fragment:fragment-ktx:$fragment_version"
// Testing Fragments in Isolation
debugImplementation "androidx.fragment:fragment-testing:$fragment_version"
}
apply plugin: 'com.google.gms.google-services' // Google Play services Gradle plugin
I have stepped through the code via the debugger, and can confirm that the requestPermissions
is executed, but that the onRequestPermissionsResult
is triggered immediately with no popup on device.
I also read this, but I figured that it was down to developers not implementing the opt-in model as described here, but maybe, this is an issue after all? Because I cannot make sense of this...
I ask for other permissions in other parts of the app, and this line works well - I get the popup to grant permission:
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE}, BaseActivity.PHONE_STATE_PERMISSION_CODE);
In another part of the code base, I have the same requestPermission call, but for another permission, and this works fine:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE}, BaseActivity.PHONE_STATE_PERMISSION_CODE);
}
When this is executed, I get this:
But, if I change the requestPermissions call so it looks like this, nothing happens and I get to the callback immediately, with a "rejected":
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.POST_NOTIFICATIONS}, BaseActivity.PHONE_STATE_PERMISSION_CODE);
}
Picture:
I have also tried using the new ActivityResultLauncher
, but the behaviour is the same - it goes directly to the callback without showing any popup.
Stupid me. In the Q above, I did post what the AndroidManifest contained, and I wrote:
<uses-permission android:name="android.permission.POST_NOTIFICATION" />
This is not correct. I am missing an s
, it shoul be:
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
Oops! :-)