Commit 8f67f67b authored by Amit Kumar's avatar Amit Kumar
Browse files

Add notification badge feature

parent 4d6bc580
......@@ -5,6 +5,25 @@
<uses-permission android:name="android.permission.SET_WALLPAPER" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="com.android.email.permission.ACCESS_PROVIDER" />
<uses-permission android:name="com.google.android.gm.permission.READ_CONTENT_PROVIDER" />
<uses-permission android:name="com.sec.android.provider.badge.permission.READ" />
<uses-permission android:name="com.fsck.k9.permission.READ_MESSAGES" />
<uses-permission android:name="com.kaitenmail.permission.READ_MESSAGES" />
<uses-permission android:name="com.kaitenmail.adsupported.permission.READ_MESSAGES" />
<uses-permission android:name="android.intent.action.BADGE_COUNT_UPDATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.email.permission.READ_ATTACHMENT" />
<uses-permission android:name="android.email.permission.ACCESS_PROVIDER" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<application
android:name=".BlissLauncher"
android:allowBackup="true"
......@@ -14,7 +33,7 @@
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".ui.DesktopActivity"
android:name=".ui.LauncherActivity"
android:clearTaskOnLaunch="true"
android:launchMode="singleTask"
android:screenOrientation="nosensor"
......@@ -28,9 +47,20 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<service
android:name=".notification.NotificationService"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
<meta-data
android:name="io.fabric.ApiKey"
android:value="8fcf342f1b8ac74d6980872082b7216ef4682a29" />
</application>
</manifest>
package org.indin.blisslaunchero.db;
package org.indin.blisslaunchero.data.db;
import android.content.Context;
import android.content.SharedPreferences;
......@@ -7,7 +7,7 @@ import android.util.Log;
import android.view.ViewGroup;
import android.widget.GridLayout;
import org.indin.blisslaunchero.model.AppItem;
import org.indin.blisslaunchero.data.model.AppItem;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
......
package org.indin.blisslaunchero.model;
package org.indin.blisslaunchero.data.model;
import android.content.Intent;
import android.graphics.drawable.Drawable;
......@@ -8,133 +8,134 @@ import java.util.List;
public class AppItem {
private CharSequence label;
private String packageName;
private Drawable icon;
private Intent intent;
private String componentName;
private boolean iconFromIconPack;
private boolean isSystemApp;
private boolean isClock;
private boolean isCalendar;
private CharSequence mLabel;
private String mPackageName;
private Drawable mIcon;
private Intent mIntent;
private String mComponentName;
private boolean mIconFromIconPack;
private boolean mIsSystemApp;
private boolean mIsClock;
private boolean mIsCalendar;
private boolean isPinnedApp;
// Folder specific
private boolean belongsToFolder;
private boolean isFolder;
private String folderID;
private List<AppItem> subApps;
private boolean mBelongsToFolder;
private boolean mIsFolder;
private String mFolderID;
private List<AppItem> mSubApps;
public AppItem(CharSequence label, String packageName, Drawable icon,
Intent intent, String componentName, boolean iconFromIconPack, boolean isSystemApp,
boolean isClock, boolean isCalendar) {
this.label = label;
this.packageName = packageName;
this.icon = icon;
this.intent = intent;
this.componentName = componentName;
this.iconFromIconPack = iconFromIconPack;
this.isSystemApp = isSystemApp;
this.isClock = isClock;
this.isCalendar = isCalendar;
this.mLabel = label;
this.mPackageName = packageName;
this.mIcon = icon;
this.mIntent = intent;
this.mComponentName = componentName;
this.mIconFromIconPack = iconFromIconPack;
this.mIsSystemApp = isSystemApp;
this.mIsClock = isClock;
this.mIsCalendar = isCalendar;
}
public CharSequence getLabel() {
return label;
return mLabel;
}
public void setLabel(CharSequence label) {
this.label = label;
this.mLabel = label;
}
public String getPackageName() {
return packageName;
return mPackageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
this.mPackageName = packageName;
}
public Drawable getIcon() {
return icon;
return mIcon;
}
public boolean isSystemApp() {
return isSystemApp;
return mIsSystemApp;
}
public boolean isClock() {
return isClock;
return mIsClock;
}
public boolean isCalendar() {
return isCalendar;
return mIsCalendar;
}
public void setSystemApp(boolean isSystemApp) {
this.isSystemApp = isSystemApp;
this.mIsSystemApp = isSystemApp;
}
public void setIcon(Drawable icon) {
this.icon = icon;
this.mIcon = icon;
}
public Intent getIntent() {
return intent;
return mIntent;
}
public void setIntent(Intent intent) {
this.intent = intent;
this.mIntent = intent;
}
public String getComponentName() {
return componentName;
return mComponentName;
}
public void setComponentName(String componentName) {
this.componentName = componentName;
this.mComponentName = componentName;
}
public boolean isIconFromIconPack() {
return iconFromIconPack;
return mIconFromIconPack;
}
public void setIconFromIconPack(boolean iconFromIconPack) {
this.iconFromIconPack = iconFromIconPack;
this.mIconFromIconPack = iconFromIconPack;
}
public boolean isFolder() {
return isFolder;
return mIsFolder;
}
public void setFolder(boolean folder) {
isFolder = folder;
mIsFolder = folder;
}
public String getFolderID() {
return folderID;
return mFolderID;
}
public void setFolderID(String folderID) {
this.folderID = folderID;
this.mFolderID = folderID;
}
public List<AppItem> getSubApps() {
if (subApps == null) {
subApps = new ArrayList<>();
if (mSubApps == null) {
mSubApps = new ArrayList<>();
}
return subApps;
return mSubApps;
}
public void setSubApps(List<AppItem> subApps) {
this.subApps = subApps;
this.mSubApps = subApps;
}
public boolean isBelongsToFolder() {
return belongsToFolder;
return mBelongsToFolder;
}
public void setBelongsToFolder(boolean belongsToFolder) {
this.belongsToFolder = belongsToFolder;
this.mBelongsToFolder = belongsToFolder;
}
}
package org.indin.blisslaunchero.data.model;
import android.widget.TextView;
/**
* Created by falcon on 17/3/18.
*/
public class CalendarIcon {
public TextView monthTextView;
public TextView dayTextView;
public CalendarIcon(TextView monthTextView, TextView dayTextView) {
this.monthTextView = monthTextView;
this.dayTextView = dayTextView;
}
}
package org.indin.blisslaunchero.data.model;
/**
* Created by falcon on 18/3/18.
*/
public class OtherInfo {
public int count;
public String packageName;
}
package org.indin.blisslaunchero.notification;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.Log;
/**
* Created by falcon on 20/3/18.
*/
public class DotRenderer {
private static final String TAG = "DotRenderer";
private static final float SIZE_PERCENTAGE = 0.25f;
private final int mSize;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG |
Paint.FILTER_BITMAP_FLAG);
public DotRenderer(int iconSizePx){
this.mSize = (int) (SIZE_PERCENTAGE *iconSizePx);
}
public void drawDot(Canvas canvas, Rect iconBounds){
Log.d(TAG, "drawDot() called with: canvas = [" + canvas + "], iconBounds = [" + iconBounds
+ "]");
int badgeCenterX = (int) (iconBounds.left + mSize*0.25);
int badgeCenterY = (int) (iconBounds.top + mSize*0.25);
mPaint.setColor(Color.parseColor("#FF0800"));
canvas.drawCircle(badgeCenterX, badgeCenterY, mSize/2, mPaint);
}
}
package org.indin.blisslaunchero.notification;
import android.service.notification.StatusBarNotification;
import android.util.Log;
import com.jakewharton.rxrelay2.BehaviorRelay;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Created by Amit Kumar
* Email : mr.doc10jl96@gmail.com
*/
public class NotificationRepository {
private BehaviorRelay<Set<String>> notificationRelay;
private static final String TAG = "NotificationRepository";
private static NotificationRepository sInstance;
private NotificationRepository() {
notificationRelay = BehaviorRelay.createDefault(Collections.emptySet());
}
public static NotificationRepository getNotificationRepository() {
if (sInstance == null) {
sInstance = new NotificationRepository();
}
return sInstance;
}
public void updateNotification(List<StatusBarNotification> list) {
Log.d(TAG, "updateNotification() called with: list = [" + list.size() + "]");
Set<String> notificationSet = new HashSet<>();
for (StatusBarNotification statusBarNotification : list) {
notificationSet.add(statusBarNotification.getPackageName());
}
this.notificationRelay.accept(notificationSet);
}
public BehaviorRelay<Set<String>> getNotifications() {
return this.notificationRelay;
}
}
package org.indin.blisslaunchero.notification;
import android.content.Intent;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.Log;
import org.indin.blisslaunchero.utils.ListUtil;
/**
* Created by falcon on 14/3/18.
*/
public class NotificationService extends NotificationListenerService {
NotificationRepository mNotificationRepository;
private static final String TAG = "NotificationService";
@Override
public void onCreate() {
super.onCreate();
mNotificationRepository = NotificationRepository.getNotificationRepository();
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public void onListenerConnected() {
Log.d(TAG, "onListenerConnected() called");
mNotificationRepository.updateNotification(ListUtil.asSafeList(getActiveNotifications()));
}
@Override
public void onNotificationPosted(StatusBarNotification sbn) {
Log.d(TAG, "onNotificationPosted() called with: sbn = [" + sbn + "]");
mNotificationRepository.updateNotification(ListUtil.asSafeList(getActiveNotifications()));
}
@Override
public void onNotificationRemoved(StatusBarNotification sbn) {
Log.d(TAG, "onNotificationRemoved() called with: sbn = [" + sbn + "]");
mNotificationRepository.updateNotification(ListUtil.asSafeList(getActiveNotifications()));
}
}
package org.indin.blisslaunchero.ui;
import android.content.Context;
import android.view.View;
import org.indin.blisslaunchero.utils.AppUtil;
import io.reactivex.Observable;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
/**
* Created by falcon on 18/3/18.
*/
public class LauncherPresenter {
private LauncherView mLauncherView;
private Context mContext;
private CompositeDisposable mCompositeDisposable;
private LauncherPresenter(Context context) {
this.mContext = context;
this.mCompositeDisposable = new CompositeDisposable();
}
public void attachView(LauncherView view) {
this.mLauncherView = view;
}
public void detachView() {
mCompositeDisposable.dispose();
mLauncherView = null;
}
public boolean isViewAttached() {
return mLauncherView != null;
}
public void loadApps(){
}
}
package org.indin.blisslaunchero.ui;
import org.indin.blisslaunchero.data.model.AppItem;
import java.util.List;
import java.util.Map;
/**
* Created by falcon on 18/3/18.
*/
public interface LauncherView {
void showApps(List<AppItem> allAppItems, List<AppItem> pinnedAppItems);
void showNotificationBadges(Map<String, Integer> map);
void showLoading();
void hideLoading();
}
......@@ -12,7 +12,7 @@ import android.os.Bundle;
import android.provider.MediaStore;
import android.support.annotation.Nullable;
import org.indin.blisslaunchero.model.AppItem;
import org.indin.blisslaunchero.data.model.AppItem;
import org.indin.blisslaunchero.R;
import java.text.Collator;
......
......@@ -2,6 +2,7 @@ package org.indin.blisslaunchero.utils;
import android.content.Context;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import java.util.Calendar;
......@@ -21,6 +22,10 @@ public class ConverterUtil {
return px / metrics.scaledDensity;
}
public static int spToPx(float sp, Context context) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, context.getResources().getDisplayMetrics());
}
public static String convertMonthToString(int month) {
switch (month) {
case Calendar.JANUARY:
......
......@@ -15,7 +15,7 @@ import android.renderscript.ScriptIntrinsicBlur;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import org.indin.blisslaunchero.model.AppItem;
import org.indin.blisslaunchero.data.model.AppItem;
import org.indin.blisslaunchero.R;
public class GraphicsUtil {
......
package org.indin.blisslaunchero.utils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Created by Amit Kumar
* Email : mr.doc10jl96@gmail.com
*/
public class ListUtil {
@SafeVarargs
public static <T> List<T> asSafeList(T... tArr) {
return (tArr == null || tArr.length == 0) ? new ArrayList() : Arrays.asList(tArr);
}
}
package org.indin.blisslaunchero.widgets;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Property;
import android.widget.FrameLayout;
import org.indin.blisslaunchero.notification.DotRenderer;
import org.indin.blisslaunchero.ui.LauncherActivity;
import org.indin.blisslaunchero.utils.ConverterUtil;
/**
* Created by falcon on 20/3/18.
*/
public class BlissFrameLayout extends FrameLayout {
private static final String TAG = "BlissFrameLayout";
private final Context mContext;
private boolean hasBadge = false;
private Rect mTempIconBounds = new Rect();
private float mBadgeScale;
private static final Property<BlissFrameLayout, Float> BADGE_SCALE_PROPERTY
= new Property<BlissFrameLayout, Float>(Float.TYPE, "badgeScale") {
@Override
public Float get(BlissFrameLayout bubbleTextView) {
return bubbleTextView.mBadgeScale;
}
@Override
public void set(BlissFrameLayout bubbleTextView, Float value) {