Android custom notification for music player Example

 

In this tutorial, you will learn how to create Custom Notifications in your Android music player application. A notification is a message you can display to the user in the status bar outside of your Android application. Notifications can be clicked to perform an action or to open a new activity. We will be creating a custom notification that is usually used by music player apps.
Lets get started.

Create an empty android application project and copy the following contents to MainActivity.java :

package com.tutorialsface.customnotification;
 
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
 
public class MainActivity extends ActionBarActivity {
 
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
 
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
 
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
 
public void startService(View v) {
Intent serviceIntent = new Intent(MainActivity.this, NotificationService.class);
serviceIntent.setAction(Constants.ACTION.STARTFOREGROUND_ACTION);
startService(serviceIntent);
}
}

Change the contents of the layout file activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.tutorialsface.customnotification.MainActivity" >
 
    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="53dp"
        android:text="Custom Notification Tutorial" />
 
    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:onClick="startService"
        android:text="Show Notification" />
 
</RelativeLayout>

In music player, playback of songs has to be done within a service which runs in background even after the application is closed. We will create such service to handle the inputs given through the buttons shown by the Notification layout.

To learn more about Android Services you can follow this.

Lets create a service now.

Create a new java file named NotificationService.java and extend it for Service as shown below:

package com.tutorialsface.customnotification;
 
import android.os.IBinder;
import android.app.Service;
import android.content.Intent;
 
public class NotificationService extends Service {
 
@Override
public void onDestroy() {
super.onDestroy();
}
 
@Override
public IBinder onBind(Intent intent) {
return null;
}
 
}

Override the method OnStartCommand() of Service class.

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent.getAction().equals(Constants.ACTION.STARTFOREGROUND_ACTION)) {
showNotification();
Toast.makeText(this, "Service Started", Toast.LENGTH_SHORT).show();
 
} else if (intent.getAction().equals(Constants.ACTION.PREV_ACTION)) {
Toast.makeText(this, "Clicked Previous", Toast.LENGTH_SHORT).show();
Log.i(LOG_TAG, "Clicked Previous");
} else if (intent.getAction().equals(Constants.ACTION.PLAY_ACTION)) {
Toast.makeText(this, "Clicked Play", Toast.LENGTH_SHORT).show();
Log.i(LOG_TAG, "Clicked Play");
} else if (intent.getAction().equals(Constants.ACTION.NEXT_ACTION)) {
Toast.makeText(this, "Clicked Next", Toast.LENGTH_SHORT).show();
Log.i(LOG_TAG, "Clicked Next");
} else if (intent.getAction().equals(
Constants.ACTION.STOPFOREGROUND_ACTION)) {
Log.i(LOG_TAG, "Received Stop Foreground Intent");
Toast.makeText(this, "Service Stoped", Toast.LENGTH_SHORT).show();
stopForeground(true);
stopSelf();
}
return START_STICKY;
}

You will get some errors after adding the above code. So to resolve them, create a new class named Constants to store all the required constant variables.

Copy the following code for Constants.java:

package com.tutorialsface.customnotification;
 
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
 
public class Constants {
public interface ACTION {
public static String MAIN_ACTION = "com.marothiatechs.customnotification.action.main";
public static String INIT_ACTION = "com.marothiatechs.customnotification.action.init";
public static String PREV_ACTION = "com.marothiatechs.customnotification.action.prev";
public static aString PLAY_ACTION = "com.marothiatechs.customnotification.action.play";
public static String NEXT_ACTION = "com.marothiatechs.customnotification.action.next";
public static String STARTFOREGROUND_ACTION = "com.marothiatechs.customnotification.action.startforeground";
public static String STOPFOREGROUND_ACTION = "com.marothiatechs.customnotification.action.stopforeground";
 
}
 
public interface NOTIFICATION_ID {
public static int FOREGROUND_SERVICE = 101;
}
 
public static Bitmap getDefaultAlbumArt(Context context) {
Bitmap bm = null;
BitmapFactory.Options options = new BitmapFactory.Options();
try {
bm = BitmapFactory.decodeResource(context.getResources(),
R.drawable.default_album_art, options);
} catch (Error ee) {
} catch (Exception e) {
}
return bm;
}
 
}

Now create a new method inside your NotificationService.java with the name showNotification() and copy the content as shown below:

Notification status;
private final String LOG_TAG = "NotificationService";
 
private void showNotification() {
// Using RemoteViews to bind custom layouts into Notification
RemoteViews views = new RemoteViews(getPackageName(),
R.layout.status_bar);
RemoteViews bigViews = new RemoteViews(getPackageName(),
R.layout.status_bar_expanded);
 
// showing default album image
views.setViewVisibility(R.id.status_bar_icon, View.VISIBLE);
views.setViewVisibility(R.id.status_bar_album_art, View.GONE);
bigViews.setImageViewBitmap(R.id.status_bar_album_art,
Constants.getDefaultAlbumArt(this));
 
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.setAction(Constants.ACTION.MAIN_ACTION);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
 
Intent previousIntent = new Intent(this, NotificationService.class);
previousIntent.setAction(Constants.ACTION.PREV_ACTION);
PendingIntent ppreviousIntent = PendingIntent.getService(this, 0,
previousIntent, 0);
 
Intent playIntent = new Intent(this, NotificationService.class);
playIntent.setAction(Constants.ACTION.PLAY_ACTION);
PendingIntent pplayIntent = PendingIntent.getService(this, 0,
playIntent, 0);
 
Intent nextIntent = new Intent(this, NotificationService.class);
nextIntent.setAction(Constants.ACTION.NEXT_ACTION);
PendingIntent pnextIntent = PendingIntent.getService(this, 0,
nextIntent, 0);
 
Intent closeIntent = new Intent(this, NotificationService.class);
closeIntent.setAction(Constants.ACTION.STOPFOREGROUND_ACTION);
PendingIntent pcloseIntent = PendingIntent.getService(this, 0,
closeIntent, 0);
 
views.setOnClickPendingIntent(R.id.status_bar_play, pplayIntent);
bigViews.setOnClickPendingIntent(R.id.status_bar_play, pplayIntent);
 
views.setOnClickPendingIntent(R.id.status_bar_next, pnextIntent);
bigViews.setOnClickPendingIntent(R.id.status_bar_next, pnextIntent);
 
views.setOnClickPendingIntent(R.id.status_bar_prev, ppreviousIntent);
bigViews.setOnClickPendingIntent(R.id.status_bar_prev, ppreviousIntent);
 
views.setOnClickPendingIntent(R.id.status_bar_collapse, pcloseIntent);
bigViews.setOnClickPendingIntent(R.id.status_bar_collapse, pcloseIntent);
 
views.setImageViewResource(R.id.status_bar_play,
R.drawable.apollo_holo_dark_pause);
bigViews.setImageViewResource(R.id.status_bar_play,
R.drawable.apollo_holo_dark_pause);
 
views.setTextViewText(R.id.status_bar_track_name, "Song Title");
bigViews.setTextViewText(R.id.status_bar_track_name, "Song Title");
 
views.setTextViewText(R.id.status_bar_artist_name, "Artist Name");
bigViews.setTextViewText(R.id.status_bar_artist_name, "Artist Name");
 
bigViews.setTextViewText(R.id.status_bar_album_name, "Album Name");
 
status = new Notification.Builder(this).build();
status.contentView = views;
status.bigContentView = bigViews;
status.flags = Notification.FLAG_ONGOING_EVENT;
status.icon = R.drawable.ic_launcher;
status.contentIntent = pendingIntent;
startForeground(Constants.NOTIFICATION_ID.FOREGROUND_SERVICE, status);
}

You need to add the following imports for the new references in the method we just defined:

import android.app.Notification;
import android.app.PendingIntent;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews;
import android.widget.Toast;

In showNotification() method we created a new notification and added our custom layouts named status_layout.xml and status_bar_expanded.xml

status_bar.xml is the layout for small notification while status_layout_expanded.xml is for the big layout.

Leta create these two layout files and move them to layouts folder in the res directory of your project:

status_bar.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >
 
    <ImageView
        android:id="@+id/status_bar_album_art"
        android:layout_width="@dimen/status_bar_album_art"
        android:layout_height="@dimen/status_bar_album_art"
        android:gravity="center" />
 
    <ImageView
        android:id="@+id/status_bar_icon"
        android:layout_width="@dimen/status_bar_album_art"
        android:layout_height="@dimen/status_bar_album_art"
        android:background="@drawable/status_bg"
        android:scaleType="center"
        android:src="@drawable/ic_launcher"
        android:visibility="gone" />
 
    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_weight="1"
        android:orientation="vertical"
        android:paddingLeft="@dimen/status_bar_button_info_container_padding_left" >
 
        <TextView
            android:id="@+id/status_bar_track_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="@color/white"
            android:textSize="@dimen/text_size_medium"
            android:textStyle="bold" />
 
        <TextView
            android:id="@+id/status_bar_artist_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
 
    </LinearLayout>
 
    <ImageButton
        android:id="@+id/status_bar_play"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:contentDescription="@string/cd_play" />
 
    <ImageButton
        android:id="@+id/status_bar_next"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:contentDescription="@string/cd_next"
        android:src="@drawable/apollo_holo_dark_next" />
 
    <ImageButton
        android:id="@+id/status_bar_collapse"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/apollo_holo_dark_notifiation_bar_collapse" />
 
</LinearLayout>

status_bar_expanded.xml

 
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="@+id/notificationbg" android:layout_width="fill_parent" android:layout_height="128.0dip"
    
    <ImageView
        android:id="@+id/status_bar_album_art"
        android:layout_width="@dimen/notification_expanded_height"
        android:layout_height="@dimen/notification_expanded_height"
        android:scaleType="centerCrop"
        android:layout_alignParentLeft="true"
        android:layout_alignParentBottom="true"/>
     
    <LinearLayout
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:id="@+id/buttons"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:divider="?android:listDivider"
        android:layout_toRightOf="@id/status_bar_album_art"
        android:layout_alignParentRight="true"
        android:layout_alignParentBottom="true"
        android:showDividers="middle"
        android:dividerPadding="12.0dip">
       <ImageButton
           android:id="@+id/status_bar_prev"
           android:background="?android:selectableItemBackground"
           android:padding="10.0dip"
           android:layout_width="0.0dip"
           android:layout_height="@dimen/play_controls_notification"
           android:src="@drawable/apollo_holo_dark_prev"
           android:scaleType="fitCenter"
           android:layout_weight="1.0" />
       <ImageButton
           android:id="@+id/status_bar_play"
           android:background="?android:selectableItemBackground"
           android:padding="10.0dip"
           android:layout_width="0.0dip"
           android:layout_height="@dimen/play_controls_notification"
           android:src="@drawable/apollo_holo_dark_play"
           android:scaleType="fitCenter"
           android:layout_weight="1.0" />
       <ImageButton android:id="@+id/status_bar_next"
           android:background="?android:selectableItemBackground"
           android:padding="10.0dip"
           android:layout_width="0.0dip"
           android:layout_height="@dimen/play_controls_notification"
           android:src="@drawable/apollo_holo_dark_next"
           android:scaleType="fitCenter"
           android:layout_weight="1.0" />
    </LinearLayout>
    <ImageView
        android:background="?android:dividerHorizontal"
        android:layout_width="wrap_content"
        android:layout_height="1.0px"
        android:layout_toRightOf="@id/status_bar_album_art"
        android:layout_above="@+id/buttons"
        android:layout_alignParentRight="true" />
    <ImageButton
        android:id="@id/status_bar_collapse"
        android:background="?android:selectableItemBackground"
        android:padding="8.0dip"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/apollo_holo_dark_notifiation_bar_collapse"
        android:layout_alignParentTop="true"
        android:layout_alignParentRight="true" />
    <LinearLayout
        android:layout_gravity="center_vertical"
        android:orientation="vertical"
        android:id="@+id/textarea"
        android:paddingLeft="@dimen/notification_padding"
        android:paddingTop="8.0dip"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_toLeftOf="@id/status_bar_collapse"
        android:layout_toRightOf="@id/status_bar_album_art"
        android:layout_alignParentTop="true">
        <TextView
           android:ellipsize="marquee"
           android:layout_gravity="left"
           android:id="@+id/status_bar_track_name"
           android:focusable="true"
           android:fadingEdge="horizontal"
           android:layout_width="fill_parent"
           android:layout_height="wrap_content"
           android:singleLine="true"
            />
        <TextView
           android:ellipsize="marquee"
           android:layout_gravity="left"
           android:id="@+id/status_bar_artist_name"
           android:fadingEdge="horizontal"
           android:layout_width="fill_parent"
           android:layout_height="wrap_content"
           android:maxLines="1"
            />
        <TextView
           android:ellipsize="marquee"
           android:layout_gravity="left"
           android:id="@+id/status_bar_album_name"
           android:fadingEdge="horizontal"
           android:layout_width="fill_parent"
           android:layout_height="wrap_content"
           android:maxLines="1"
            />
    </LinearLayout>
</RelativeLayout>

You will see many errors in each of the files we created but don’t worry, we will resolve all of them.
Create a folder named drawable inside /res directory of your android project and copy the following file:

status_bg.xml

<?xml version="1.0" encoding="utf-8"?>
    android:src="@drawable/notify_panel_notification_icon_bg"
    android:tileMode="repeat" />

Now copy the following three files in /res/values directory in your project.

strings.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
 
    <!-- App name -->
    <string name="app_name">Music Notification</string>
    <string name="app_version_number">1.0</string>
    <string name="menu_settings">Settings</string>
 
    <string name="cd_repeat">Repeat one or all</string>
    <string name="cd_previous">Skip backwards</string>
    <string name="cd_play">Play and pause</string>
    <string name="cd_next">Skip forwards</string>
 
</resources>

colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
 
    <!-- A transparent black -->
    <color name="transparent_black">#aa000000</color>
 
    <!-- selected tab text -->
    <color name="selected_tabtext">#bb000000</color>
 
    <!-- non selected tab text -->
    <color name="unselected_tabtext">#77000000</color>
    <color name="shuffle_grey">#ffdedede</color>
    <color name="background_grey">#ffdedede</color>
 
    <!-- Transparent -->
    <color name="transparent">#00000000</color>
 
    <!-- Black -->
    <color name="black">#ff000000</color>
 
    <!-- White -->
    <color name="white">#ffffffff</color>
 
</resources>

dimens.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
 
    <!-- Text sizes -->
    <dimen name="text_size_extra_micro">10sp</dimen>
    <dimen name="text_size_micro">12sp</dimen>
    <dimen name="text_size_small">14sp</dimen>
    <dimen name="text_size_medium">16sp</dimen>
    <dimen name="text_size_large">18sp</dimen>
     
    <!-- Nofication bar button -->
    <dimen name="status_bar_button_width_height">48dp</dimen>
    <dimen name="status_bar_album_art">64dp</dimen>
    <dimen name="status_bar_button_info_container_padding_left">11dp</dimen>
    <dimen name="notification_expanded_height">128.0dip</dimen>
    <dimen name="play_controls_notification">48.0dip</dimen>
    <dimen name="notification_padding">8.0dip</dimen>
 
</resources>

Copy these image files into /res/drawable-hdpi folder your project.


 
Now modify the AndroidManifest.xml as follows:

<?xml version="1.0" encoding="utf-8"?>
    package="com.tutorialsface.customnotification"
    android:versionCode="1"
    android:versionName="1.0" >
 
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="21" />
 
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.tutorialsface.customnotification.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
 
        <service android:name="com.tutorialsface.customnotification.NotificationService" />
    </application>
 
</manifest>

Now run the application.

The Screenshot for the final app displaying custom Notification for a Music Player:

Music Player custom notification

自定义android 音乐通知栏 ——可伸缩扩展的更多相关文章

  1. android音乐播放器开发教程

    android音乐播放器开发教程 Android扫描sd卡和系统文件 Android 关于录音文件的编解码 实现米聊 微信一类的录音上传的功能 android操作sdcard中的多媒体文件——音乐列表 ...

  2. Android音乐播放器源码(歌词.均衡器.收藏.qq5.0菜单.通知)

    一款Android音乐播放器源码,基本功能都实现了 qq5.0菜单(歌词.均衡器.收藏.qq5.0菜单.通知) 只有向右滑动出现,菜单键和指定按钮都还没有添加. 源码下载:http://code.66 ...

  3. 一款非常简单的android音乐播放器源码分享给大家

    一款非常简单的android音乐播放器源码分享给大家,该应用虽然很小,大家常用的播放器功能基本实现了,可能有点还不够完善,大家也可以自己完善一下,源码在源码天堂那里已经有了,大家可以到那里下载学习吧. ...

  4. Android开发之ExpandableListView扩展(BaseExpandableListAdapter的使用)(完整版)

    Android开发之ExpandableListView扩展(BaseExpandableListAdapter的使用)(完整版)

  5. vue自定义指令clickoutside使用以及扩展用法

    vue自定义指令clickoutside使用以及扩展用法 产品使用vue+element作为前端框架.在功能开发过程中,难免遇到使用element的组件没办法满足特殊的业务需要,需要对其进行定制,例如 ...

  6. Android音乐、视频类APP常用控件:DraggablePanel(2)

     Android音乐.视频类APP常用控件:DraggablePanel(2) 附录文章1主要演示了如何使用DraggablePanel 的DraggableView.DraggablePanel ...

  7. Android音乐、视频类APP常用控件:DraggablePanel(1)

     Android音乐.视频类APP常用控件:DraggablePanel(1) Android的音乐视频类APP开发中,常涉及到用户拖曳视频.音乐播放器产生一定交互响应的设计需求,最典型的以You ...

  8. 【Gradle】自定义Android Gradle工程

    自定义Android Gradle工程 defaultConfig默认配置 defaultConfig是Android对象中的一个配置项,负责定义所有的默认配置.一个基本的defaultConfig配 ...

  9. android显示通知栏Notification以及自定义Notification的View

    遇到的最大的问题是监听不到用户清除通知栏的广播.所以是不能监听到的. 自定义通知栏的View,然后service运行时更改notification的信息. /** * Show a notificat ...

随机推荐

  1. 2018 ICPC 沈阳网络预赛 Fantastic Graph (优先队列)

    [传送门]https://nanti.jisuanke.com/t/31447 [题目大意]:有一个二分图,问能不能找到它的一个子图,使得这个子图中所有点的度数在区间[L,R]之内. [题解]首先我们 ...

  2. luogu P1043 数字游戏

    题目描述 丁丁最近沉迷于一个数字游戏之中.这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易.游戏是这样的,在你面前有一圈整数(一共n个),你要按顺序将其分 ...

  3. solr 简要笔记

    创建搜索1 创建directory 2.分词器 analyzer 3indexwriter writer dic an 4.document doc.add writer.adddocument(do ...

  4. ASP.NET Core 依赖注入(构造函数注入,属性注入等)

    原文:ASP.NET Core 依赖注入(构造函数注入,属性注入等) 如果你不熟悉ASP.NET Core依赖注入,先阅读文章: 在ASP.NET Core中使用依赖注入   构造函数注入 构造函数注 ...

  5. Override和Overload差别,Overloaded的方法能否够改变返回值的类型?

    Overload是重载的意思, Override是覆盖的意思,也就是重写. 重载Overload表示同一个类中能够有多个名称同样的方法,但这些方法的參数列表各不同样(即參数个数或类型不同). 重写Ov ...

  6. iOS类的合理设计,面向对象思想

    每天更新的东西可能有反复的内容.当时每一部分的知识点是不同的,须要大家认真阅读 这里介绍了iOS类的合理设计.面向对象思想 main.m #import <Foundation/Foundati ...

  7. 【Mongodb教程 第十八课 】MongoDB常用命令 数据库命令 集合操作命令

    面向文档的 NoSQL 数据库主要解决的问题不是高性能的并发读写,而是保证海量数据存储的同时,具有良好的查询性能.  条件操作符 <, <=, >, >=  这个操作符就不用多 ...

  8. mysql添加删除索引,查看某个表的建表语句

    查看某个表的建表语句 :show create table data_statdata; drop index ts on data_statdata; 索引是加速查询的主要手段,特别对于涉及多个表的 ...

  9. 关于Widget预览图的改动

    在做项目时候,由于常常不带GPS功能.所以在有些细节上须要做处理,当中之中的一个就是.快捷开关的预览图和实际效果图的差异 在我们快捷开关的预览图中,总是能够看到五个快捷开关,事实上就包含GPS信息 而 ...

  10. bash_profile打不开怎么办,用nano .bash_profile打开

    I’ve spent years curating a collection of Mac bash aliases and shortcuts to make my life easier. My ...