/*
* Copyright (C) 2014 AChep@xda <artemchep@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package com.achep.acdisplay.notifications;
import android.annotation.SuppressLint;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.service.notification.StatusBarNotification;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import com.achep.acdisplay.Config;
import com.achep.acdisplay.services.MediaService;
import com.achep.acdisplay.utils.PendingIntentUtils;
import com.achep.base.Device;
import com.achep.base.utils.Operator;
import com.achep.base.utils.ResUtils;
/**
* Created by Artem on 30.12.13.
*/
public class NotificationUtils {
private static final String TAG = "NotificationUtils";
/**
* Return whether the keyguard requires a password to unlock and may
* have any privacy restrictions.
*/
public static boolean isSecure(@NonNull Context context) {
KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
return km.isKeyguardSecure() && km.isKeyguardLocked();
}
public static boolean isSecret(@NonNull Context context, @NonNull OpenNotification n,
int minVisibility, int privacyMask) {
final int privacyMode = Config.getInstance().getPrivacyMode();
return n.getVisibility() <= minVisibility
&& Operator.bitAnd(privacyMode, privacyMask)
&& isSecure(context);
}
/**
* Imitates a click on given notification: launches content intent and
* dismisses notification from app and system.
*
* @return {@code true} if launched successfully, {@code false} otherwise.
*/
public static boolean startContentIntent(@NonNull OpenNotification n) {
PendingIntent pi = n.getNotification().contentIntent;
if (pi == null) {
pi = n.getNotification().fullScreenIntent; // nullable
if (pi != null) Log.i(TAG, "Sending full screen intent, instead of content one!");
}
boolean successful = PendingIntentUtils.sendPendingIntent(pi);
if (successful && Operator.bitAnd(
n.getNotification().flags,
Notification.FLAG_AUTO_CANCEL)) {
dismissNotification(n);
}
return successful;
}
/**
* Dismisses given notification from system and app.
*/
@SuppressWarnings("deprecation")
@SuppressLint("NewApi")
public static void dismissNotification(@NonNull OpenNotification n) {
NotificationPresenter.getInstance().removeNotification(n, 0);
StatusBarNotification sbn = n.getStatusBarNotification();
if (sbn != null && Device.hasJellyBeanMR2Api()) {
MediaService service = MediaService.sService;
if (service != null) {
// FIXME: Should I call the #deleteIntent?
PendingIntentUtils.sendPendingIntent(sbn.getNotification().deleteIntent);
try {
if (Device.hasLollipopApi()) {
service.cancelNotification(sbn.getKey());
} else {
service.cancelNotification(
sbn.getPackageName(),
sbn.getTag(),
sbn.getId());
}
} catch (SecurityException e) {
// FIXME: Fix disallowed call from unknown listener exception.
// java.lang.SecurityException: Disallowed call from unknown listener: android.service.notification.INotificationListener$Stub$Proxy@42339520
// at android.os.Parcel.readException(Parcel.java:1465)
// at android.os.Parcel.readException(Parcel.java:1419)
// at android.app.INotificationManager$Stub$Proxy.cancelNotificationFromListener(INotificationManager.java:469)
// at android.service.notification.NotificationListenerService.cancelNotification(NotificationListenerService.java:116)
Log.e(TAG, "Failed to dismiss notification.");
e.printStackTrace();
}
} else {
Log.e(TAG, "Failed to dismiss notification because notification service is offline.");
}
}
}
@SuppressLint("NewApi")
public static void dismissAllNotifications() {
NotificationPresenter.getInstance().clear(true);
if (Device.hasJellyBeanMR2Api()) {
MediaService service = MediaService.sService;
if (service != null) {
try {
service.cancelAllNotifications();
} catch (SecurityException e) {
// FIXME: Fix disallowed call from unknown listener exception.
// java.lang.SecurityException: Disallowed call from unknown listener: android.service.notification.INotificationListener$Stub$Proxy@42339520
// at android.os.Parcel.readException(Parcel.java:1465)
// at android.os.Parcel.readException(Parcel.java:1419)
// at android.app.INotificationManager$Stub$Proxy.cancelNotificationFromListener(INotificationManager.java:469)
// at android.service.notification.NotificationListenerService.cancelNotification(NotificationListenerService.java:116)
Log.e(TAG, "Failed to dismiss notification.");
e.printStackTrace();
}
} else {
Log.e(TAG, "Failed to dismiss notification because notification service is offline.");
}
}
}
@Nullable
public static Drawable getDrawable(@NonNull Context context,
@NonNull OpenNotification n,
@DrawableRes int iconRes) {
Context pkgContext = createContext(context, n);
if (pkgContext != null)
try {
return ResUtils.getDrawable(pkgContext, iconRes);
} catch (Resources.NotFoundException nfe) { /* unused */ }
return null;
}
@Nullable
public static Context createContext(@NonNull Context context, @NonNull OpenNotification n) {
try {
return context.createPackageContext(n.getPackageName(), Context.CONTEXT_RESTRICTED);
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "Failed to create notification\'s context");
return null;
}
}
/**
* @see com.achep.acdisplay.notifications.OpenNotification#hasIdenticalIds(OpenNotification)
*/
public static boolean hasIdenticalIds(@Nullable OpenNotification n,
@Nullable OpenNotification n2) {
return n == n2 || n != null && n.hasIdenticalIds(n2);
}
}