Android Play Notification Sound From Different Resources

In the previous series of tutorial we have seen how to create notification both in kotlin and java 

In this tutorial we will see playing notification sound different resources( audio file kept different resource like from project "res/raw" and hosted in CDN ) .


Kotlin


To play notification sound we need Uri of the file hosted .


1. Default
val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val r = RingtoneManager.getRingtone(context, defaultSoundUri)
r.play()

2. Resource 

Make Sure you have kept custom_sound audio inside "res/raw" folder 

val rawPathUri: Uri = Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.custom_sound);
val r = RingtoneManager.getRingtone(context, rawPathUri)
r.play()

3. Remote CDN
val cdnPathUri: Uri = Uri.parse("https://www.myinstants.com/media/sounds/beeper_emergency_call.mp3")
val r = RingtoneManager.getRingtone(context, cdnPathUri)
r.play()


JAVA


To play notification sound we need Uri of the file hosted .


1. Default
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone r = RingtoneManager.getRingtone(MainActivity.this, defaultSoundUri);
r.play();)

2. Resource

Make Sure you have kept custom_sound audio inside "res/raw" folder .
 
Uri rawPathUri = Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.custom_sound);
Ringtone r = RingtoneManager.getRingtone(MainActivity.this, rawPathUri);
r.play();

3. Remote CDN
Uri cdnPathUri = Uri.parse("https://www.myinstants.com/media/sounds/beeper_emergency_call.mp3");
Ringtone r = RingtoneManager.getRingtone(MainActivity.this, cdnPathUri);
r.play();

Read More »

Android Notification Load Image from Url Using Glide In Kotlin

 A Notification is a message that Android displays outside your app's UI to provide the user with reminders , In the previous tutorial we have seen notification anatomy how to create notification with title content and image , If you have requirement where you have to load image which is hosted in remote CDN into notification , In such case we will make request to fetch image and load ,to make it more easy and clean code we will glide library 

To Know more about creating notification with title content and channel please have a look at  https://www.tutorialsbuzz.com/2020/08/android-notification-koltin-example.html

1. Add Glide Dependency to build.gradle(app-level)


Add Glide dependency to build.gradle(app-level) 

file : build.gradle
dependencies {
    ...............
	...............
    implementation 'com.github.bumptech.glide:glide:4.11.0'
    kapt 'com.github.bumptech.glide:compiler:4.11.0'
}

1. Android Manifest


1. Add Internet Permission to Android Manifest .

2. Add usesCleartextTraffic flag to manifest application tag , required for glide library  ( Android N offers finer-grained control over cleartext traffic policy. As opposed to android:usesCleartextTraffic attribute which applies to all destinations with which an app communicates .)

file : AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tutorialsbuzz.notificationimgload">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:usesCleartextTraffic="true"
        android:theme="@style/Theme.NotificationImgLoad">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>


2. XML Layout


Create XML Layout inside res/layout/ and add button .

file : activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/notifyBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Notify"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>


1. Create App Glide Module


Create app glide module by "AppNameGlideModule" by extending AppGlideModule 

file : AppNameGlideModule.java
package com.tutorialsbuzz.notificationimgload

import android.content.Context
import com.bumptech.glide.GlideBuilder
import com.bumptech.glide.annotation.GlideModule
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.module.AppGlideModule
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.signature.ObjectKey

@GlideModule
class AppNameGlideModule : AppGlideModule() {
    override fun applyOptions(context: Context, builder: GlideBuilder) {
        super.applyOptions(context, builder)
        val requestOptions = RequestOptions().diskCacheStrategy(DiskCacheStrategy.ALL)
            .signature(
                ObjectKey(
                    System.currentTimeMillis() / (24 * 60 * 60 * 1000)
                )
            )
        builder.setDefaultRequestOptions(requestOptions)
    }
}



1. Loading Image Into Notification (setLargeIcon and BigPicture) From Url


We will load image hosted at "https://raw.githubusercontent.com/TutorialsBuzz/cdn/main/android.jpg" into notification largeIcon and bigPicture .

  • Using GlideModule reference we will make request by passing requestUrl .
  • Create a Glide CustomTarget and override the onResourceReady and onLoadCleared 
  • Inside onResourceReady , the onResourceReady method contains bitmap now load this bitmap into your notification and call notify using notificationManager .
  val imageUrl = "https://raw.githubusercontent.com/TutorialsBuzz/cdn/main/android.jpg"
  
  GlideApp.with(applicationContext)
	.asBitmap()
	.load(imageUrl)
	.into(object : CustomTarget<Bitmap>() {
		override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
			//largeIcon
			notificationBuilder.setLargeIcon(resource)
			//Big Picture
			notificationBuilder.setStyle(
				NotificationCompat.BigPictureStyle().bigPicture(resource)
			)
			val notification = notificationBuilder.build()
			notificationManager.notify(NotificationID.iD, notification)
		}

		override fun onLoadCleared(placeholder: Drawable?) {}
	})

1. MainActivity


Main activity complete code

file : MainActivity.java
package com.tutorialsbuzz.notificationimgload

import android.app.NotificationChannel
import android.app.NotificationManager
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.os.Build
import android.os.Bundle
import android.view.View
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import java.util.concurrent.atomic.AtomicInteger


class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val notifyBtn = findViewById<Button>(R.id.notifyBtn)
        notifyBtn.setOnClickListener { v: View? ->
            createNotification(
                resources.getString(R.string.notification_title),
                resources.getString(R.string.notification_content),
                resources.getString(R.string.notification_channel),
            )
        }
    }

    /**
     * Create Notification
     * Param
     * 1. title
     * 2. content
     * 3. channelId
     * 4.priorty
     * 5. notificationId
     */
    private fun createNotification(
        title: String, content: String,
        channedId: String
    ) {

        val notificationBuilder = NotificationCompat.Builder(applicationContext, channedId)
            .setSmallIcon(R.drawable.ic_notifications_active)
            .setAutoCancel(true)
            .setLights(Color.BLUE, 500, 500)
            .setVibrate(longArrayOf(500, 500, 500))
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setContentTitle(title)
            .setContentText(content)
            .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)

        // Since android Oreo notification channel is needed.
        val notificationManager = NotificationManagerCompat.from(this@MainActivity)

        // Since android Oreo notification channel is needed.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                channedId,
                channedId,
                NotificationManager.IMPORTANCE_HIGH
            )
            channel.lockscreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
            notificationManager.createNotificationChannel(channel)
        }

        val imageUrl = "https://raw.githubusercontent.com/TutorialsBuzz/cdn/main/android.jpg"

        GlideApp.with(applicationContext)
            .asBitmap()
            .load(imageUrl)
            .into(object : CustomTarget<Bitmap>() {
                override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
                    notificationBuilder.setLargeIcon(resource)
                    val notification = notificationBuilder.build()
                    notificationManager.notify(NotificationID.iD, notification)
                }

                override fun onLoadCleared(placeholder: Drawable?) {

                }
            })

    }

    internal object NotificationID {
        private val c = AtomicInteger(100)
        val iD: Int
            get() = c.incrementAndGet()
    }
}




Read More »

Android Notification Load Image from Url Using Glide In Java

 A Notification is a message that Android displays outside your app's UI to provide the user with reminders , In the previous tutorial we have seen notification anatomy how to create notification with title content and image , If you have requirement where you have to load image which is hosted in remote CDN into notification , In such case we will make request to fetch image and load ,to make it more easy and clean code we will glide library 

To Know more about creating notification with title content and channel please have a look at  https://www.tutorialsbuzz.com/2021/02/android-notification-java-example.html

1. Add Glide Dependency to build.gradle(app-level)


Add Glide dependency to build.gradle(app-level) 

file : build.gradle
dependencies {
    ..................
    ...................	
    implementation 'com.github.bumptech.glide:glide:4.11.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
}


1. Android Manifest


1. Add Internet Permission to Android Manifest .

2. Add usesCleartextTraffic flag to manifest application tag , required for glide library  ( Android N offers finer-grained control over cleartext traffic policy. As opposed to android:usesCleartextTraffic attribute which applies to all destinations with which an app communicates .)

file : AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tutorialsbuzz.notificationimgload">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:usesCleartextTraffic="true"
        android:theme="@style/Theme.NotificationImgLoad">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>


2. XML Layout


Create XML Layout inside res/layout/ and add button .

file : activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/notifyBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Notify"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>


1. Create App Glide Module


Create app glide module by "AppNameGlideModule" by extending AppGlideModule 

file : AppNameGlideModule.java
package com.tutorialsbuzz.notificationimgload;

import android.content.Context;

import androidx.annotation.NonNull;

import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.module.AppGlideModule;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.signature.ObjectKey;

@GlideModule
public class AppNameGlideModule extends AppGlideModule {


    @Override
    public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
        super.applyOptions(context, builder);

        RequestOptions requestOptions = new RequestOptions().diskCacheStrategy(DiskCacheStrategy.ALL)
                .signature(new ObjectKey(
                        System.currentTimeMillis() / (24 * 60 * 60 * 1000)));

        builder.setDefaultRequestOptions(requestOptions);
    }
}



1. Loading Image Into Notification (setLargeIcon and BigPicture) From Url


We will load image hosted at "https://raw.githubusercontent.com/TutorialsBuzz/cdn/main/android.jpg" into notification largeIcon and bigPicture .

  • Using GlideModule reference we will make request by passing requestUrl .
  • Create a Glide CustomTarget and override the onResourceReady and onLoadCleared 
  • Inside onResourceReady , the onResourceReady method contains bitmap now load this bitmap into your notification and call notify using notificationManager .
String imageUrl = "https://raw.githubusercontent.com/TutorialsBuzz/cdn/main/android.jpg";

GlideApp.with(getApplicationContext())
	.asBitmap()
	.load(imageUrl)
	.into(new CustomTarget<Bitmap>() {
		@Override
		public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
			//largeIcon
			notificationBuilder.setLargeIcon(resource);
			//Big Picture
			notificationBuilder.setStyle(new NotificationCompat.BigPictureStyle().bigPicture(resource));

			Notification notification = notificationBuilder.build();
			notificationManager.notify(NotificationID.getID(), notification);
		}

		@Override
		public void onLoadCleared(@Nullable Drawable placeholder) {
		}
	}); 


1. MainActivity


Main activity complete code

file : MainActivity.java
package com.tutorialsbuzz.notificationimgload;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.widget.Button;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;

import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;

import java.util.concurrent.atomic.AtomicInteger;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button notifyBtn = findViewById(R.id.notifyBtn);

        notifyBtn.setOnClickListener(v -> {

            createNotification(
                    getResources().getString(R.string.notification_title),
                    getResources().getString(R.string.notification_content),
                    getResources().getString(R.string.notification_channel)
            );

        });

    }

    /**
     * Create Notification
     * Param
     * 1. title
     * 2. content
     * 3. channelId
     * 4.priorty
     * 5. notificationId
     */

    private void createNotification(String title, String content,
                                    String channedId) {


        NotificationCompat.Builder notificationBuilder =
                new NotificationCompat.Builder(getApplicationContext(), channedId)
                        .setSmallIcon(R.drawable.ic_notifications_active)
                        .setAutoCancel(true)
                        .setLights(Color.BLUE, 500, 500)
                        .setVibrate(new long[]{500, 500, 500})
                        .setPriority(NotificationCompat.PRIORITY_HIGH)
                        .setContentTitle(title)
                        .setContentText(content)
                        .setVisibility(NotificationCompat.VISIBILITY_PUBLIC);


        // Since android Oreo notification channel is needed.
        NotificationManagerCompat notificationManager = NotificationManagerCompat.from(MainActivity.this);

        // Since android Oreo notification channel is needed.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(channedId,
                    channedId,
                    NotificationManager.IMPORTANCE_HIGH);
            channel.setLockscreenVisibility(NotificationCompat.VISIBILITY_PUBLIC);
            notificationManager.createNotificationChannel(channel);
        }

        String imageUrl = "https://raw.githubusercontent.com/TutorialsBuzz/cdn/main/android.jpg";

        GlideApp.with(getApplicationContext())
                .asBitmap()
                .load(imageUrl)
                .into(new CustomTarget<Bitmap>() {
                    @Override
                    public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
                        //largeIcon
                        notificationBuilder.setLargeIcon(resource);
                        //Big Picture
                        notificationBuilder.setStyle(new NotificationCompat.BigPictureStyle().bigPicture(resource));

                        Notification notification = notificationBuilder.build();
                        notificationManager.notify(NotificationID.getID(), notification);
                    }

                    @Override
                    public void onLoadCleared(@Nullable Drawable placeholder) {
                    }

                    @Override
                    public void onLoadFailed(@Nullable Drawable errorDrawable) {
                        super.onLoadFailed(errorDrawable);
                    }
                });
    }

    static class NotificationID {
        private final static AtomicInteger c = new AtomicInteger(100);

        public static int getID() {
            return c.incrementAndGet();
        }
    }

}





Read More »

Android Notification Java Example

Notifications provide short, timely information about events in your app while it's not in use
A notification is a message that Android displays outside your app's UI to provide the user with reminders, communication from other people, or other timely information from your app. Users can tap the notification to open your app or take an action directly from the notification.

Notification Anatomy



The most common parts of a notification are indicated above diagram as follows:
  1. SmallIcon :   This is set by calling setSmallIcon() .
  2. App Name :  This is by default provided by system .
  3. Time :  This is by default provided by system , It can be overridden by calline setWhen() or hide by calling setShowWhen(false) .
  4. Title :  This is set by calling setContentTitle() .
  5. Content :  This is set by calling setContentText() .
  6. LargeIcon :  This is set by calling setLargeIcon() .

 NotificationCompat.Builder notificationBuilder =
                new NotificationCompat.Builder(getApplicationContext(), channedId)
                        .setSmallIcon(R.drawable.ic_notifications_active)
                        .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
                        .setAutoCancel(true)
                        .setLights(Color.BLUE, 500, 500)
                        .setVibrate(new long[]{500, 500, 500})
                        .setPriority(priorty)
                        .setContentTitle(title)
                        .setContentText(content)

Setting Pending Intent to Notification


 A PendingIntent is a token that you give to a foreign application which allows the foreign application to use your application's permissions to execute a predefined piece of code.

Create an explicit intent 
Intent intent = new Intent(this, NotifyActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

Bundle extras = new Bundle();
extras.putString(NotifyActivity.notify_title, title);
extras.putString(NotifyActivity.notify_content, content);
intent.putExtras(extras);
intent.setAction(Intent.ACTION_VIEW);


A pending intent is a wrapper around regular intent that is designed to be used by another application. 
 PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), notificationID, intent,
			PendingIntent.FLAG_UPDATE_CURRENT);

and then set the pending to your notification builder 
 NotificationCompat.Builder notificationBuilder =
                new NotificationCompat.Builder(getApplicationContext(), channedId)
				.setContentIntent(pendingIntent)

Notification Channel

  • Starting in Android 8.0 (API level 26), all notifications must be assigned to a channel or it will not appear.
  • Categorizing notifications into channels User can disable notification for particular category instead of all 
// Since android Oreo notification channel is needed.
	NotificationManagerCompat notificationManager = NotificationManagerCompat.from(MainActivity.this);

	// Since android Oreo notification channel is needed.
	if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
		NotificationChannel channel = new NotificationChannel(channedId,
				channedId,
				NotificationManager.IMPORTANCE_HIGH);
		channel.setLockscreenVisibility(NotificationCompat.VISIBILITY_PUBLIC);
		notificationManager.createNotificationChannel(channel);
	}



Notification importance


The possible importance levels are the following:
  1. Urgent: Makes a sound and appears as a heads-up notification.
  2. High: Makes a sound.
  3. Medium: No sound.
  4. Low: No sound and does not appear in the status bar. 

Play Notification Sound


 public void playNotificationSound() {
	try {
		Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
		Ringtone r = RingtoneManager.getRingtone(MainActivity.this, defaultSoundUri);
		r.play();
	} catch (Exception e) {
		e.printStackTrace();
	}
}

Lock Screen Notification


If you want notification to be shown even when device is locked it can be done by calling on notificationChannel reference .
 NotificationChannel channel = new NotificationChannel(channedId,
		channedId,
		NotificationManager.IMPORTANCE_HIGH);
channel.setLockscreenVisibility(NotificationCompat.VISIBILITY_PUBLIC);


Sample Example



Lets see sample example where we will have two activity one is MainActivity and another NotificationActivity 

  1.  In MainActivity we will have button on click of create notification and notify .
  2. When a notification is called launch NotificationActivity and retrieve notification data .

1. XML Layout


Create XML Layout inside res/layout/

1.a  XML Layout for MainActivity  

file : activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/politics"
        style="@style/btn_style"
        android:text="@string/channel_politics" />

    <Button
        android:id="@+id/sports"
        style="@style/btn_style"
        android:text="@string/channel_sports" />

    <Button
        android:id="@+id/entertainment"
        style="@style/btn_style"
        android:text="@string/channel_entertainment" />

</LinearLayout>

2.b XML Layout for NotificationActivity 

file :  activity_notify.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/notifyText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:textSize="22sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>


2. Activities


2.a MainActivity

file : MainActivity.java
package com.tutorialsbuzz.notification;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initViews();
    }

    private void initViews() {
        Button politics, sports, entertainment;

        politics = findViewById(R.id.politics);
        sports = findViewById(R.id.sports);
        entertainment = findViewById(R.id.entertainment);

        politics.setOnClickListener(this);
        sports.setOnClickListener(this);
        entertainment.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {

            case R.id.politics:
                // politics politics
                createNotification(
                        getResources().getString(R.string.channel_politics),
                        getResources().getString(R.string.politics_content),
                        getResources().getString(R.string.channel_politics),
                        NotificationCompat.PRIORITY_HIGH,
                        100
                );
                break;

            case R.id.sports:
                //Sports politics
                createNotification(
                        getResources().getString(R.string.channel_sports),
                        getResources().getString(R.string.sports_content),
                        getResources().getString(R.string.channel_sports),
                        NotificationCompat.PRIORITY_DEFAULT,
                        101
                );
                break;

            case R.id.entertainment:
                //Entertainment Notification
                createNotification(
                        getResources().getString(R.string.channel_entertainment),
                        getResources().getString(R.string.entertainment_content),
                        getResources().getString(R.string.channel_entertainment),
                        NotificationCompat.PRIORITY_LOW,
                        102
                );

                break;
        }
    }

    /**
     * Create Notification
     * Param
     * 1. title
     * 2. content
     * 3. channelId
     * 4.priorty
     * 5. notificationId
     */

    private void createNotification(String title, String content,
                                    String channedId, int priorty, int notificationID) {


        Intent intent = new Intent(this, NotifyActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

        Bundle extras = new Bundle();
        extras.putString(NotifyActivity.notify_title, title);
        extras.putString(NotifyActivity.notify_content, content);
        intent.putExtras(extras);
        intent.setAction(Intent.ACTION_VIEW);

        PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), notificationID, intent,
                PendingIntent.FLAG_UPDATE_CURRENT);

        NotificationCompat.Builder notificationBuilder =
                new NotificationCompat.Builder(getApplicationContext(), channedId)
                        .setSmallIcon(R.drawable.ic_notifications_active)
                        .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
                        .setAutoCancel(true)
                        .setLights(Color.BLUE, 500, 500)
                        .setVibrate(new long[]{500, 500, 500})
                        .setPriority(priorty)
                        .setContentTitle(title)
                        .setContentText(content)
                        .setContentIntent(pendingIntent)
                        .setVisibility(NotificationCompat.VISIBILITY_PUBLIC);


        // Since android Oreo notification channel is needed.
        NotificationManagerCompat notificationManager = NotificationManagerCompat.from(MainActivity.this);

        // Since android Oreo notification channel is needed.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(channedId,
                    channedId,
                    NotificationManager.IMPORTANCE_HIGH);
            channel.setLockscreenVisibility(NotificationCompat.VISIBILITY_PUBLIC);
            notificationManager.createNotificationChannel(channel);
        }
        Notification notification = notificationBuilder.build();

        notificationManager.notify(notificationID, notification);

        playNotificationSound();
    }

    public void playNotificationSound() {
        try {
            Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
            Ringtone r = RingtoneManager.getRingtone(MainActivity.this, defaultSoundUri);
            r.play();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

 2.b NotifyActivity

file : NotifyActivity.java
package com.tutorialsbuzz.notification;

import android.os.Bundle;
import android.os.PersistableBundle;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

public class NotifyActivity extends AppCompatActivity {

    public static String notify_title = "notify_title";
    public static String notify_content = "notify_content";

    private TextView textView;


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_notify);
        textView = findViewById(R.id.notifyText);
        updateUI();
    }

    private void updateUI() {
        String notifyData =
                getIntent().getExtras().get(notify_title) + " \n" +
                        getIntent().getExtras().get(notify_content);

        textView.setText(notifyData);
    }

}



Read More »

Android Handling Permission Deny With Don't Ask Again In Kotlin

In the previous example we have seen how to make runtime permission request and handle once user action i.e allow and deny ,when you make request for permission system will generate popup for user action .


When you make request for permission there will be 3 actions user's can perform .

  • Action 1 :  Allow 
  • Action 2 :  Just Deny ( deny without selecting the check-box "don't ask again")
  • Action 3 :  Force Deny ( deny with selecting the check-box "don't ask again")

Action 1 and 2 we have seen in previous example , In this tutorial we will handling Action 3 .

When you deny permission by selecting the check-box "don't ask again" After that when you make subsequent request again for the same permission Nothing will happen ( i.e The system will not show "Allow Deny" popup again )  .

Lets See Sample Example .

  UseCase  
Scenerio
1
  Request Permission > Pop-up > allow > (TextView Updated With Permission Granted).

 2
   Request Permission > Pop-up > deny > (TextView Updated With Permission Denied).

 3

    Request Permission > Pop-up > deny with "don't ask again" selected >
    (TextView Updated With Permission Denied and Show Button for visit settings).
 
   Now on Click of "visit settings" you will navigate to app settings 
   once you grant permission and resume back to app  inside onResume
   again we will check if permission update the UI  (i.e TextView Updated 
   with Permission  Granted and hide Button for visit settings ).



Use Case 1 ( Permission Granted )



Use Case 2 ( Permission Denied )
 



Use Case 3 ( Pemission Deny By Selecting Don't Ask Again )



MainActivity


file : MainActivity.kt 
package com.tutorialsbuzz.permissiondeny

import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import kotlinx.android.synthetic.main.activity_main.*


class MainActivity : AppCompatActivity(), View.OnClickListener {

    companion object {
        const val REQUEST_WRITE_PERMISSION = 100
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        initViews()
    }

    private fun initViews() {
        requestbtn.setOnClickListener(this)
        allow_permission.setOnClickListener(this)
    }

    override fun onResume() {
        super.onResume()
        if (checkPermissionForReadExtertalStorage()) {
               label!!.setText(R.string.permission_granted)
              allow_permission.visibility=View.GONE
        }
    }

    override fun onClick(view: View) {
        when (view.id) {
            R.id.requestbtn -> if (checkPermissionForReadExtertalStorage()) {
                label!!.setText(R.string.permission_granted)
            } else {
                //Make Request
                requestPermission()
            }
            R.id.allow_permission -> {
                val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                val uri = Uri.fromParts("package", packageName, null)
                intent.data = uri
                startActivity(intent)
            }
        }
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (grantResults.size > 0) {
            if (requestCode == REQUEST_WRITE_PERMISSION) {
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // permission granted
                    label!!.setText(R.string.permission_granted)
                    allow_permission!!.visibility = View.GONE
                } else {
                    // permission denied
                    label!!.setText(R.string.permission_denied)
                    // Check wheather checked dont ask again
                    checkUserRequestedDontAskAgain()
                }
            }
        }
    }

    fun checkPermissionForReadExtertalStorage(): Boolean {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            (ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.READ_EXTERNAL_STORAGE
            ) == PackageManager.PERMISSION_GRANTED
                    || ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
            ) == PackageManager.PERMISSION_GRANTED)
        } else false
    }

    private fun requestPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            requestPermissions(
                arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
                REQUEST_WRITE_PERMISSION
            )
        }
    }

    private fun checkUserRequestedDontAskAgain() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val rationalFalgREAD =
                shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)
            val rationalFalgWRITE =
                shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE)
            if (!rationalFalgREAD && !rationalFalgWRITE) {
                label!!.setText(R.string.permission_denied_forcefully)
                allow_permission!!.visibility = View.VISIBLE
            }
        }
    }

}


Read More »

Android Handling Permission Deny With Don't Ask Again In Java

In the previous example we have seen how to make runtime permission request and handle once user action i.e allow and deny ,when you make request for permission system will generate popup for user action .


When you make request for permission there will be 3 actions user's can perform .

  • Action 1 :  Allow 
  • Action 2 :  Just Deny ( deny without selecting the check-box "don't ask again")
  • Action 3 :  Force Deny ( deny with selecting the check-box "don't ask again")

Action 1 and 2 we have seen in previous example , In this tutorial we will handling Action 3 .

When you deny permission by selecting the check-box "don't ask again" After that when you make subsequent request again for the same permission Nothing will happen ( i.e The system will not show "Allow Deny" popup again )  .

Lets See Sample Example .

  UseCase  
Scenerio
1
  Request Permission > Pop-up > allow > (TextView Updated With Permission Granted).

 2
   Request Permission > Pop-up > deny > (TextView Updated With Permission Denied).

 3

    Request Permission > Pop-up > deny with "don't ask again" selected >
    (TextView Updated With Permission Denied and Show Button for visit settings).
 
   Now on Click of "visit settings" you will navigate to app settings 
   once you grant permission and resume back to app  inside onResume
   again we will check if permission update the UI  (i.e TextView Updated 
   with Permission  Granted and hide Button for visit settings ).



Use Case 1 ( Permission Granted )



Use Case 2 ( Permission Denied )
 



Use Case 3 ( Pemission Deny By Selecting Don't Ask Again )



MainActivity


file : MainActivity.java
package com.tutorialsbuzz.permissiondeny;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    public static final int REQUEST_WRITE_PERMISSION = 100;
    private Button allowPermissionViaSettingsBtn;
    private TextView label;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initViews();
    }

    private void initViews() {
        label = findViewById(R.id.label);

        Button requestPermissionBtn = findViewById(R.id.btn);
        requestPermissionBtn.setOnClickListener(this);

        allowPermissionViaSettingsBtn = findViewById(R.id.allow_permission);
        allowPermissionViaSettingsBtn.setOnClickListener(this);
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (checkPermissionForReadExtertalStorage()) {
            label.setText(R.string.permission_granted);
            allowPermissionViaSettingsBtn.setVisibility(View.GONE);
        }
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn:

                if (checkPermissionForReadExtertalStorage()) {
                    label.setText(R.string.permission_granted);
                } else {
                    //Make Request
                    requestPermission();
                }

                break;

            case R.id.allow_permission:

                Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                Uri uri = Uri.fromParts("package", getPackageName(), null);
                intent.setData(uri);
                startActivity(intent);

                break;
        }
    }


    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if (grantResults.length > 0) {
            if (requestCode == REQUEST_WRITE_PERMISSION)
                if (grantResults[0]
                        == PackageManager.PERMISSION_GRANTED) {
                    // permission granted
                    label.setText(R.string.permission_granted);
                    allowPermissionViaSettingsBtn.setVisibility(View.GONE);

                } else {
                    // permission denied
                    label.setText(R.string.permission_denied);
                    // Check wheather checked dont ask again
                    checkUserRequestedDontAskAgain();
                }
        }
    }

    public boolean checkPermissionForReadExtertalStorage() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

            return ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
                    || ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
        }
        return false;
    }

    private void requestPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            requestPermissions(new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    REQUEST_WRITE_PERMISSION);
        }
    }

    private void checkUserRequestedDontAskAgain() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            boolean rationalFalgREAD = shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE);
            boolean rationalFalgWRITE = shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE);

            if (!rationalFalgREAD && !rationalFalgWRITE) {
                label.setText(R.string.permission_denied_forcefully);
                allowPermissionViaSettingsBtn.setVisibility(View.VISIBLE);
            }
        }
    }

}



Read More »

Android Working With App Permission In Kotlin

The Word Permission means allowing sometime , to do a particular thing – it is consent or authorization given to perform any kind of action , Android apps are built to perform a set of actions, some of them requiring permissions from users .

With the introduction of Android 6.0 Marshmallow, Google has changed the way permissions are handled by the app , Before Marshmallow all permissions are granted by the system automatically .


From Marshmallow Android Permissions are divided into dangerous and normal Permission , The common thing in both the types is that they need to be defined in the Manifest file. 
  1. Normal Permission. 
  2. Runtime Permission ( Dangerous Permission ).

1. Normal Permission : 

  • These permissions allow access to data and actions that extend beyond your app's sandbox.
  • The system grants these permissions automatically
  • Poses Low or No Risk .
  • These include connecting to the internet, getting network, Bluetooth, wifi, and NFC information, setting alarms & wallpapers, and modifying audio settings on a device
  

2. Runtime Permission : 

  • Dangerous permissions are permissions which could potentially affect the user’s privacy or the device’s operation .
  • The user must explicitly agree to grant those permissions. 
  • Poses High Risk .
  • These include accessing the camera, contacts, location, microphone, sensors, SMS, and storage.


1. Declaring Permissions Needed by Your App In Apps Manifest


Add Permission to manifest . 

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tutorialsbuzz.permissionexample">

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <application
       ---------------------
	   ---------------->
 	    ----------------
       	 ---------------   
    </application>

</manifest>

2. Check is Permission Granted


Before Making Request check is Permission already granted .
private fun checkPermissionForReadExtertalStorage(): Boolean {
	return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
		(ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
				|| ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)
	} else false
}

3. Requesting Permissions for Your App


Making Request by passing request code .

private fun requestPermission() {
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
		requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
				REQUEST_WRITE_PERMISSION)
	} 
}

4. Handling Permissions Granted to Your App


Override the onRequestPermissionsResult callback of AppCompatActivity Inside this we will get to know the status of requested permission .
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
	super.onRequestPermissionsResult(requestCode, permissions, grantResults)
	if (grantResults.size > 0) {
		if (requestCode == REQUEST_WRITE_PERMISSION)
			if (grantResults[0]
					== PackageManager.PERMISSION_GRANTED) {
				// permission granted
				label?.setText(R.string.permission_granted)
			} else {
				// permission denied
				label?.setText(R.string.permission_denied)
			}
	}
}

MainActivity


Complete MainActivity Code .
package com.tutorialsbuzz.permissionexample

import android.Manifest
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat


class MainActivity : AppCompatActivity() {

    private var label: TextView? = null

    companion object {
        const val REQUEST_WRITE_PERMISSION = 100
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        label = findViewById(R.id.label)
        val requestBtn = findViewById<Button>(R.id.requestBtn)
        requestBtn.setOnClickListener { v: View? ->
            if (checkPermissionForReadExtertalStorage()) {
                // Permission Already Granted
                label?.setText(R.string.permission_granted)
            } else {
                // Make Permission Request
                requestPermission()
            }
        }
    }

    fun checkPermissionForReadExtertalStorage(): Boolean {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
                    || ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)
        } else false
    }

    private fun requestPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
                    REQUEST_WRITE_PERMISSION)
        }
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (grantResults.size > 0) {
            if (requestCode == REQUEST_WRITE_PERMISSION)
                if (grantResults[0]
                        == PackageManager.PERMISSION_GRANTED) {
                    // permission granted
                    label?.setText(R.string.permission_granted)
                } else {
                    // permission denied
                    label?.setText(R.string.permission_denied)
                }
        }
    }
}



Read More »