Back to project page netmbuddy.
The source code is released under:
------- Default ------- Copyright (C) 2012, 2013, 2014 Younghyung Cho. <yhcting77@gmail.com> All rights reserved. This file is part of NetMBuddy This program is licensed under the FreeBSD license R...
If you think the Android project netmbuddy listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
/****************************************************************************** * Copyright (C) 2012, 2013, 2014//from ww w . jav a2s . c om * Younghyung Cho. <yhcting77@gmail.com> * All rights reserved. * * This file is part of NetMBuddy * * This program is licensed under the FreeBSD license * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation * are those of the authors and should not be interpreted as representing * official policies, either expressed or implied, of the FreeBSD Project. *****************************************************************************/ package free.yhc.netmbuddy.model; import static free.yhc.netmbuddy.utils.Utils.eAssert; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.support.v4.app.NotificationCompat; import android.widget.RemoteViews; import free.yhc.netmbuddy.R; import free.yhc.netmbuddy.YTMPActivity; import free.yhc.netmbuddy.utils.Utils; public class NotiManager { private static final boolean DBG = false; private static final Utils.Logger P = new Utils.Logger(NotiManager.class); private static final String NOTI_INTENT_DELETE = "ytmplayer.intent.action.NOTIFICATION_DELETE"; private static final String NOTI_INTENT_ACTION = "ytmplayer.intent.action.NOTIFICATION_ACTION"; private static final String NOTI_INTENT_STOP_PLAYER = "ytmplayer.intent.action.NOTIFICATION_STOP_PLAYER"; private static NotiManager sInstance = null; // active notification set. private final NotificationManager mNm = (NotificationManager)Utils.getAppContext() .getSystemService(Context.NOTIFICATION_SERVICE); private Notification mLastPlayerNotification = null; // NOTE public static enum NotiType { // All player type notification uses same notification id because // these notification SHOULD NOT be multiple-displayed. BASE (R.drawable.noti_base, getPlayerNotificationId()), START (R.drawable.noti_start, getPlayerNotificationId()), PAUSE (R.drawable.noti_pause, getPlayerNotificationId()), STOP (R.drawable.noti_stop, getPlayerNotificationId()), ALERT (R.drawable.noti_alert, getPlayerNotificationId()), // General notification - not used yet. // Why? // In case of GMail, ImportShareActivity seems to be started with NEW_TASK. // See below steps. // - 1. After starting importing, ImportShareActivity is running foreground. // - 2. Backing to launcher by touching 'Home' button. // - 3a. Touch GMail icon again to go to GMail. // => ImportShareActivity is not shown anymore! // - 3b. Touch NetMBuddy to see ImportShareActivity // => ImportShareActivity is not shown any more. // As described above, there is no way to back to ImportShareActivity // after backing to launcher by touching 'Home' key. // // To workaround this, notification may be considered. // But, it doesn't help too. // Resuming app. or starting ImportShareActivity with singleTop // always tries to start new Activity instance. // I didn't find any solution for this issue. // So, by any reasonable solution is found, this notification is left as 'UNUSED'. IMPORT (R.drawable.noti_import,R.drawable.noti_import); private final int _mIcon; private final int _mId; NotiType(int icon, int id) { _mIcon = icon; _mId = id; } int getId() { return _mId; } int getIcon() { return _mIcon; } } public static class NotiIntentReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, final Intent intent) { Utils.getUiHandler().post(new Runnable() { @Override public void run() { handleNotificationIntent(intent); } }); } } private NotiManager() { } private static void handleNotificationIntent(Intent intent) { String action = intent.getAction(); NotiManager nm = NotiManager.get(); YTPlayer ytp = YTPlayer.get(); if (NOTI_INTENT_DELETE.equals(action)) nm.removePlayerNotification(); else if (NOTI_INTENT_STOP_PLAYER.equals(action)) ytp.stopVideos(); else if (NOTI_INTENT_ACTION.equals(action)) { String typeName = intent.getStringExtra("type"); if (DBG) P.v("Intent action type : " + typeName); eAssert(null != typeName); NotiType nt = NotiType.valueOf(typeName); eAssert(null != nt); switch (nt) { case BASE: // Ignore this action!! break; case START: ytp.playerStart(); break; case PAUSE: ytp.playerPause(); break; case STOP: ytp.stopVideos(); break; case ALERT: // Just remove notification nm.removePlayerNotification(); break; case IMPORT: Utils.resumeApp(); break; default: eAssert(false); } } } private Notification buildNotificationICS(NotiType ntype, CharSequence videoTitle) { RemoteViews rv = new RemoteViews(Utils.getAppContext().getPackageName(), R.layout.player_notification); NotificationCompat.Builder nbldr = new NotificationCompat.Builder(Utils.getAppContext()); rv.setTextViewText(R.id.title, videoTitle); Intent intent = new Intent(Utils.getAppContext(), NotiManager.NotiIntentReceiver.class); intent.setAction(NOTI_INTENT_ACTION); intent.putExtra("type", ntype.name()); PendingIntent pi = PendingIntent.getBroadcast(Utils.getAppContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); rv.setImageViewResource(R.id.action, ntype.getIcon()); rv.setOnClickPendingIntent(R.id.action, pi); intent = new Intent(Utils.getAppContext(), NotiManager.NotiIntentReceiver.class); intent.setAction(NOTI_INTENT_STOP_PLAYER); pi = PendingIntent.getBroadcast(Utils.getAppContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); rv.setImageViewResource(R.id.stop, R.drawable.ic_media_stop); rv.setOnClickPendingIntent(R.id.stop, pi); intent = new Intent(Utils.getAppContext(), NotiManager.NotiIntentReceiver.class); intent.setAction(NOTI_INTENT_DELETE); PendingIntent piDelete = PendingIntent.getBroadcast(Utils.getAppContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); intent = new Intent(Utils.getAppContext(), YTMPActivity.class); intent.setAction(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_LAUNCHER); PendingIntent piContent = PendingIntent.getActivity(Utils.getAppContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); nbldr.setContent(rv) .setContentIntent(piContent) .setDeleteIntent(piDelete) .setAutoCancel(true) .setSmallIcon(ntype.getIcon()) .setTicker(null); return nbldr.build(); } private Notification buildNotificationGB(NotiType ntype, CharSequence videoTitle) { Intent intent = new Intent(Utils.getAppContext(), NotiManager.NotiIntentReceiver.class); intent.setAction(NOTI_INTENT_DELETE); PendingIntent piDelete = PendingIntent.getBroadcast(Utils.getAppContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); intent = new Intent(Utils.getAppContext(), NotiManager.NotiIntentReceiver.class); intent.setAction(NOTI_INTENT_ACTION); intent.putExtra("type", ntype.name()); PendingIntent piContent = PendingIntent.getBroadcast(Utils.getAppContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); /* * NOTE * Below way is deprecated but works well better than using recommended way - notification builder. * (See commends below about using builder) */ Notification n = new Notification(ntype.getIcon(), null, System.currentTimeMillis()); n.setLatestEventInfo(Utils.getAppContext(), Utils.getResString(R.string.app_name), videoTitle, piContent); n.deleteIntent = piDelete; n.flags = 0; return n; /* Below code generates "java.lang.NoClassDefFoundError : android.support.v4.app.NotificationCompat$Builder" * So, comment out! * (Damn Android! * NotificationCompat.Builder nbldr = new NotificationCompat.Builder(Utils.getAppContext()); nbldr.setSmallIcon(ntype.getIcon()) .setTicker(null) .setContentTitle(title) .setContentText(desc) .setAutoCancel(true) .setContentIntent(piContent) .setDeleteIntent(piDelete); return nbldr.build(); */ } Notification buildNotification(NotiType ntype, CharSequence videoTitle) { if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) return buildNotificationGB(ntype, videoTitle); else return buildNotificationICS(ntype, videoTitle); } public static NotiManager get() { if (null == sInstance) sInstance = new NotiManager(); return sInstance; } public static final int getPlayerNotificationId() { return R.drawable.noti_base; } public void removeNotification(NotiType type) { // To avoid unexpected race-condition. eAssert(Utils.isUiThread()); // Player notification shares same notification id. mNm.cancel(type.getId()); } public void removePlayerNotification() { removeNotification(NotiType.BASE); mLastPlayerNotification = null; } public void putNotification(NotiType type, String videoTitle) { // To avoid unexpected race-condition. eAssert(Utils.isUiThread()); // Set event time. Notification n = buildNotification(type, videoTitle); n.when = System.currentTimeMillis(); mNm.notify(type.getId(), n); switch (type) { case BASE: case START: case PAUSE: case STOP: case ALERT: // In case of player notification mLastPlayerNotification = n; default: // ignored for other cases. } } public void putPlayerNotification(NotiType type, String videoTitle) { putNotification(type, videoTitle); } public Notification getLastPlayerNotification() { return mLastPlayerNotification; } }