I am going to make custom notification bar. But not great.
I would like to create an Large icon.
remoteViews = new RemoteViews(getPackageName(), R.layout.widget_main);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
.setContentTitle("Title")
.setTicker("Ticker")
.setSmallIcon(R.mipmap.howlong)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.howlong))//I dot understand why entering this icon.
.setContent(remoteViews).setOngoing(true);
This my code.
https://www.dropbox.com/s/njywqp5s5swtfdd/img.jpg?dl=0
This my notification state.
How can I have put the Large icon?
------------------------------------add code-------------------------------
package com.example.namsoo.mynotificationpractice5;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.widget.RemoteViews;
import android.widget.Toast;
/**
* Created by namsoo on 2015-07-22.
*/
/*
Add code for manifest
<service android:name=".WidgetService"
android:enabled="true"
android:exported="true" >
</service>
*/
/*
Add code for MainActivity.onCreate
Intent widgetIntent = new Intent(this, WidgetService.class);
startService(widgetIntent);
*/
public class WidgetService extends Service {
RemoteViews remoteViews;
NotificationManager notificationManager;
int NOTIFICATION_ID = 111;
int INITIAL_VALUE = 0;//초기값
int FUNCTION_ON =1;//ON
int FUNCTION_OFF =2;//OFF
int functionFlag = 0;//0 = 초기 1 = ON 2 = OFF
#Override
public void onCreate() {
Toast.makeText(getApplicationContext(), "Start Widget Service", Toast.LENGTH_LONG).show();
startWidget();
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
remoteViews = new RemoteViews(getPackageName(), R.layout.widget_main);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
String btn = intent.getStringExtra("btn");
if (btn != null)
{
if (btn.equals("state"))
{
//function code or Value redirects.
startWidget();
Toast.makeText(getApplicationContext(), "btn : " + btn + startId + " " + flags, Toast.LENGTH_LONG).show();
}
else if (btn.equals("exit"))
{
Toast.makeText(getApplicationContext(), "btn : " + btn + startId + " " + flags, Toast.LENGTH_LONG).show();
notificationManager.cancelAll();
stopService(intent);
System.exit(1);
}
else
{
Toast.makeText(getApplicationContext(), "not null btn : " + btn, Toast.LENGTH_LONG).show();
}
}
else
{
Toast.makeText(getApplicationContext(), " null btn", Toast.LENGTH_LONG).show();
}
return super.onStartCommand(intent, flags, startId);
}//서비스 실행
public void startWidget() {
if (functionFlag != INITIAL_VALUE) {
remoteViews.removeAllViews(R.id.widgetLayout);
}//노피티케이션 뷰 삭제(처음이 아닐때만 실행)
remoteViews = new RemoteViews(getPackageName(), R.layout.widget_main);//뷰 추가
setWidgetButtonListeners();//버튼이벤트 추가
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContent(remoteViews).setOngoing(true);
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(this, MainActivity.class);
resultIntent.addFlags(resultIntent.FLAG_ACTIVITY_NEW_TASK | resultIntent.FLAG_ACTIVITY_SINGLE_TOP);//화면이 없는 상태에서 만들어주는 플래그 || 화면이 있으면 화면을 재사용하세요.
PendingIntent resultPendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, resultIntent, 0);
// start the activity when the user clicks the notification text
mBuilder.setContentIntent(resultPendingIntent).setAutoCancel(false);
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// pass the Notification object to the system
notificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
public void setWidgetButtonListeners() {
if (functionFlag == INITIAL_VALUE) {
remoteViews.setImageViewResource(R.id.btnState, android.R.drawable.ic_media_pause);
remoteViews.setTextViewText(R.id.tv, "On~~");
functionFlag = FUNCTION_ON;
} else if (functionFlag == FUNCTION_ON)//On 일 때
{
remoteViews.setImageViewResource(R.id.btnState, android.R.drawable.ic_media_play);
remoteViews.setTextViewText(R.id.tv, "Off~~");
functionFlag = FUNCTION_OFF;
} else if (functionFlag == FUNCTION_OFF)//Off 일 때
{
remoteViews.setImageViewResource(R.id.btnState, android.R.drawable.ic_media_pause);
remoteViews.setTextViewText(R.id.tv, "On");
functionFlag = FUNCTION_ON;
}//버튼과 텍스트의 값 변경
Intent intentBtnState = new Intent(getApplicationContext(), this.getClass());
intentBtnState.putExtra("btn", "state");
PendingIntent piState = PendingIntent.getService(getApplicationContext(), R.id.btnState, intentBtnState, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.btnState, piState);
Intent intentBtnExit = new Intent(getApplicationContext(), this.getClass());
intentBtnExit.putExtra("btn", "exit");
PendingIntent piExit = PendingIntent.getService(getApplicationContext(), R.id.btnExit, intentBtnExit, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.btnExit, piExit);
//이벤트 추가
}
#Override
public void onDestroy() {
Toast.makeText(getApplicationContext(), "Destroy", Toast.LENGTH_LONG).show();
super.onDestroy();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
private Bitmap getCircleBitmap(Bitmap bitmap) {
final Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(output);
final int color = Color.RED;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
final RectF rectF = new RectF(rect);
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawOval(rectF, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
bitmap.recycle();
return output;
}
Related
I'm trying to create a dynamic Icon for my notifications using a function that creates a Bitmap from a String.
When I started my project, I wanted to use API level 22, but I realized that public Notification.Builder setSmallIcon (Icon icon) was not available until API 23.
So I changed my MinSDKVersion, but i'm still getting that incompatible types error ...
package com.example.netmetah;
import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.support.v4.app.NotificationCompat;
import android.widget.Toast;
import android.app.Notification.Builder;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class NetMonitorService extends IntentService {
public NetMonitorService() {
super("NetMeterListening");
}
#Override
protected void onHandleIntent(Intent workIntent) {
Context context = getApplicationContext();
CharSequence text = "Le service marche";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
createNotification(createBitmapFromString("23","kb"));
}
private Bitmap createBitmapFromString(String speed, String units) {
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setTextSize(55);
paint.setTextAlign(Paint.Align.CENTER);
Paint unitsPaint = new Paint();
unitsPaint.setAntiAlias(true);
unitsPaint.setTextSize(40);
unitsPaint.setTextAlign(Paint.Align.CENTER);
Rect textBounds = new Rect();
paint.getTextBounds(speed, 0, speed.length(), textBounds);
Rect unitsTextBounds = new Rect();
unitsPaint.getTextBounds(units, 0, units.length(), unitsTextBounds);
int width = (textBounds.width() > unitsTextBounds.width()) ? textBounds.width() : unitsTextBounds.width();
Bitmap bitmap = Bitmap.createBitmap(width + 10, 90,
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawText(speed, width / 2 + 5, 50, paint);
canvas.drawText(units, width / 2, 90, unitsPaint);
return bitmap;
}
public static long[] readProc() {
BufferedReader br;
String line;
String[] lines;
long rx = 0;
long tx = 0;
try {
br = new BufferedReader(new FileReader("/proc/net/dev"));
while ((line = br.readLine()) != null) {
if (line.contains("eth") || line.contains("wlan")) {
lines = line.trim().split("\\s+");
rx += Long.parseLong(lines[1]);
tx += Long.parseLong(lines[9]);
}
}
br.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
long[] bytes = {rx, tx};
return bytes;
}
private void createNotification(Bitmap icon) {
Intent notificationIntent = new Intent(Intent.ACTION_VIEW);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
notificationIntent.setData(Uri.parse("http://www.google.ca"));
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, "fuck")
.setCategory(Notification.CATEGORY_PROMO)
.setSmallIcon(Icon.createWithBitmap(icon))
.setContentTitle("C'est quoi un titre")
.setContentText("C'est quoi un text")
.setAutoCancel(true)
.setVisibility(1) //Public
.addAction(android.R.drawable.ic_menu_view, "View details", contentIntent)
.setContentIntent(contentIntent)
.setPriority(Notification.PRIORITY_HIGH)
.setChannelId("fuck")
.setVibrate(new long[]{1000, 1000, 1000, 1000, 1000}).build();
NotificationManager notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(123, notification);
}
}
You are using NotificationCompat.Builder. According to the documentation the setSmallIcon methods take a drawable resource ID.
It's easy to confuse this with the methods for Notification.Builder where one takes a drawable resource ID and the other one an Icon.
I'm receiving several notifications each with its own unique id.
The desired scenario is for each notification to have its own extra.
But when I store/stash the notifications in a Bundle object all notifications are assigned the same extra-(i.e. the extra that belongs to the last notification).
I have confirmed this because when I click on any notification, I'm sent to the last post I received.
While I want to be sent to the post corresponding to the notification I just clicked.
Below is the relevant code snippet:-
public void createNotif(Poste poste, Comment comment, Boolean checkGroupSon) {
if (comment == null) {
emeteur = poste.getEmmet();
message = poste.getTx();
pathImg = poste.getImg();
} else {
emeteur = comment.getEmmet();
message = comment.getComment();
pathImg = comment.getImage();
}
//onDismiss Intent
Intent intent = new Intent(mContext, NotificationControllerReceiver.class);
PendingIntent mBroadcastIntentController = PendingIntent.getBroadcast(mContext, 0, intent, 0);
Intent notificationIntent = new Intent(mContext, CommentPhotoActivity.class);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // Intent.FLAG_ACTIVITY_CLEAR_TASK|
notificationIntent.putExtra("pid", poste.getId());
PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
//TEST notification.setLatestEventInfo(getApplicationContext(), "YuYu", "Vous avez reçu un nouveau poste", contentIntent);
//TEST notification.flags = Notification.FLAG_AUTO_CANCEL;
//TEST
// NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(getApplicationContext()).setContentTitle("Poste: "+emeteur).setSmallIcon(R.drawable.ic_launcher).setContentIntent(contentIntent).setContentText(message).setDeleteIntent(mBroadcastIntentController).setPriority(Notification.PRIORITY_MAX);
NotificationCompat.Builder notificationBuilder = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notificationBuilder = new NotificationCompat.Builder(mContext, "poste");
if (pathImg == null)
notificationBuilder.setContentTitle(emeteur).setSmallIcon(R.drawable.ic_launcher).setContentIntent(contentIntent).setContentText(emeteur + ": " + message).setDeleteIntent(mBroadcastIntentController).setPriority(NotificationCompat.PRIORITY_MAX);
else
notificationBuilder.setContentTitle(emeteur).setSmallIcon(R.drawable.ic_launcher).setContentIntent(contentIntent).setContentText(emeteur + ": Photo \uD83D\uDCF7 " + message).setDeleteIntent(mBroadcastIntentController).setPriority(NotificationCompat.PRIORITY_MAX);
}
// notificationBuilder.setContentTitle("Poste: "+emeteur).setSmallIcon(R.drawable.ic_launcher).setContentIntent(contentIntent).setContentText(message).setDeleteIntent(mBroadcastIntentController).setPriority(Notification.PRIORITY_MAX);
}
// long[] v = {500,1000};
// notificationBuilder.setVibrate(v);
notifications = null;
boolean b = notifHashMap.containsKey(poste.getId());
if (b) {
notifications = notifHashMap.get(poste.getId());
// Add your All messages here or use Loop to generate messages
if (pathImg == null)
notifications.add(emeteur + ":" + message);
else
notifications.add(emeteur + ": Photo \uD83D\uDCF7 " + message);
notifHashMap.put(poste.getId(), notifications);
} else {
notifications = new ArrayList<String>();
// Add your All messages here or use Loop to generate messages
if (pathImg == null)
notifications.add(emeteur + ":" + message);
else
notifications.add(emeteur + ": Photo \uD83D\uDCF7 " + message);
notifHashMap.put(poste.getId(), notifications);
}
// if (inboxStyle == null)
// inboxStyle = new NotificationCompat.InboxStyle();
//else
inboxStyle = new NotificationCompat.InboxStyle(notificationBuilder);
if (notifications.size() > 1) {
if (poste.getImg() == null)
inboxStyle.setBigContentTitle("Poste:" + poste.getTx());
else
inboxStyle.setBigContentTitle("Poste: \uD83D\uDCF7 " + poste.getTx());
inboxStyle.setSummaryText("Vous avez " + notifications.size() + " notifications.");
for (int i = 0; i < notifications.size(); i++) {
inboxStyle.addLine(notifications.get(i));
}
} else if (notifications.size() == 1) {
inboxStyle.addLine(notifications.get(0));
}
notificationBuilder.setStyle(inboxStyle);
notificationBuilder.setVibrate(new long[]{0L});
//notificationBuilder.setNumber(value++);
if (!checkGroupSon) {
Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
notificationBuilder.setSound(alarmSound);
}
NotifManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
/* Create or update. */
mChannel = new NotificationChannel("poste", "YuYu", NotificationManager.IMPORTANCE_LOW);
mChannel.enableLights(true);
mChannel.setLightColor(Color.RED);
mChannel.canShowBadge();
mChannel.setVibrationPattern(new long[]{ 0 });
mChannel.enableVibration(true);
/* if (!checkGroupSon) {
mChannel.enableVibration(true);
mChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
} */
assert NotifManager != null;
notificationBuilder.setChannelId("poste");
// NotifManager.deleteNotificationChannel("poste");
NotifManager.createNotificationChannel(mChannel);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
summaryNotification = new NotificationCompat.Builder(mContext, "poste")
.setSmallIcon(R.drawable.ic_launcher)
.setStyle(new NotificationCompat.InboxStyle()
.addLine("1")
.addLine("2")
.setBigContentTitle("nouveau messages")
.setSummaryText("Nouveau message"))
.setPriority(NotificationCompat.PRIORITY_LOW)
.setGroup("example_group")
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_CHILDREN)
.setGroupSummary(true).build();
}
Notification notification = notificationBuilder.setGroup("example_group").build();
notification.flags = Notification.FLAG_AUTO_CANCEL;
// assert NotifPostMsgManager != null;
//TEST manager.notify(ID_NOTIFICATION, notification);
NotifManager.notify(poste.getId(), notification);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
NotifManager.notify(1, summaryNotification);
}
you are using the same id in your NotifManager.notify(1, summaryNotification) //id == 1 that's why you get the same intent result , you should use different id and it should be stored in some saved data as sharedPreferences
I am developing a pedometer. I have a service which is running fine. I made my service foreground also. But how do I update my notification with sensor data. I am getting steps from sensor. I just want to show it in a notification which is showing usig the foreground service.
public class StepCounterService extends Service {
private static final String LOG_TAG = "ForegroundService";
public static Boolean FLAG = false;
private SensorManager mSensorManager;
private StepDetector detector;
private PowerManager mPowerManager;
private WakeLock mWakeLock;
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
startServiceForeground(intent, flags, startId);
Log.d("zzz", "start command");
return START_STICKY;
}
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
new StepCountManager(this);
FLAG = true;
Log.e("Service_Started", "");
detector = new StepDetector(this);
mSensorManager = (SensorManager) this.getSystemService(SENSOR_SERVICE);
mSensorManager.registerListener(detector,
mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL);
mPowerManager = (PowerManager) this
.getSystemService(Context.POWER_SERVICE);
mWakeLock = mPowerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK
| PowerManager.ACQUIRE_CAUSES_WAKEUP, "S");
mWakeLock.acquire();
reloadSettings();
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
FLAG = false;
if (detector != null) {
mSensorManager.unregisterListener(detector);
}
if (mWakeLock != null) {
mWakeLock.release();
}
Log.e("Service_destroyed", "");
}
public void reloadSettings() {
if (detector != null) {
detector.setSensitivity(
Float.valueOf("10")
);
}
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Intent restartService = new Intent(getApplicationContext(),
this.getClass());
restartService.setPackage(getPackageName());
PendingIntent restartServicePI = PendingIntent.getService(
getApplicationContext(), 1, restartService,
PendingIntent.FLAG_ONE_SHOT);
//Restart the service once it has been killed android
((AlarmManager) getSystemService(Context.ALARM_SERVICE))
.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, PendingIntent
.getService(this, 3, new Intent(this, StepCounterService.class), 0));
}
public int startServiceForeground(Intent intent, int flags, int startId) {
Intent notificationIntent = new Intent(this, HomeActivity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Mobiefit Walk")
.setContentIntent(pendingIntent)
.setOngoing(true)
.build();
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(300, notification);
Notification n;
startForeground(300, notification);
return START_STICKY;
}
}
I just want to show my steps under this notification which I am getting from sensor.
Here is my step_detector class:
public class StepDetector implements SensorEventListener {
public static UpdateStepCount mStepsUpdater;
public static int CURRENT_SETP = 0;
public static float SENSITIVITY = 0; //SENSITIVITY
private float mLastValues[] = new float[3 * 2];
private float mScale[] = new float[2];
private float mYOffset;
private static long end = 0;
private static long start = 0;
private float mLimit = 10;
private float mLastDirections[] = new float[3 * 2];
private float mLastExtremes[][] = { new float[3 * 2], new float[3 * 2] };
private float mLastDiff[] = new float[3 * 2];
private int mLastMatch = -1;
public StepDetector(Context context) {
// TODO Auto-generated constructor stub
super();
int h = 480;
mYOffset = h * 0.5f;
mScale[0] = -(h * 0.5f * (1.0f / (SensorManager.STANDARD_GRAVITY * 2)));
mScale[1] = -(h * 0.5f * (1.0f / (SensorManager.MAGNETIC_FIELD_EARTH_MAX)));
}
public void setSensitivity(float sensitivity) {
mLimit = sensitivity; // 1.97 2.96 4.44 6.66 10.00 15.00 22.50 33.75 50.62
}
#Override
public void onSensorChanged(SensorEvent event) {
Log.d("AAA", "Sensor changed");
Sensor sensor = event.sensor;
// Log.i(Constant.STEP_DETECTOR, "onSensorChanged");
synchronized (this) {
if (sensor.getType() == Sensor.TYPE_ORIENTATION) {
} else {
int j = (sensor.getType() == Sensor.TYPE_ACCELEROMETER) ? 1 : 0;
if (j == 1) {
float vSum = 0;
for (int i = 0; i < 3; i++) {
final float v = mYOffset + event.values[i] * mScale[j];
vSum += v;
}
int k = 0;
float v = vSum / 3;
float direction = (v > mLastValues[k] ? 1: (v < mLastValues[k] ? -1 : 0));
if (direction == -mLastDirections[k]) {
// Direction changed
int extType = (direction > 0 ? 0 : 1); // minimum or
// maximum?
mLastExtremes[extType][k] = mLastValues[k];
float diff = Math.abs(mLastExtremes[extType][k]- mLastExtremes[1 - extType][k]);
if (diff > mLimit) {
boolean isAlmostAsLargeAsPrevious = diff > (mLastDiff[k] * 2 / 3);
boolean isPreviousLargeEnough = mLastDiff[k] > (diff / 3);
boolean isNotContra = (mLastMatch != 1 - extType);
if (isAlmostAsLargeAsPrevious && isPreviousLargeEnough && isNotContra) {
end = System.currentTimeMillis();
if (end - start > 500) {
Log.i("Step_Detector", "CURRENT_SETP:"
+ CURRENT_SETP);
CURRENT_SETP++;
mLastMatch = extType;
start = end;
}
} else {
mLastMatch = -1;
}
}
mLastDiff[k] = diff;
}
mLastDirections[k] = direction;
mLastValues[k] = v;
}
}
}
Log.d("sensorSteps", String.valueOf(CURRENT_SETP));
if(mStepsUpdater!=null){
mStepsUpdater.UpdateStepCount(CURRENT_SETP);
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
public static void callBackInit(StepCountManager stepCountManager) {
mStepsUpdater= stepCountManager;
}
}
If you want to keep your service running even if the app is killed, make sure to return START_STICKY in onStartCommand() as follows :
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// restart service every hour to get the current step count
((AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE))
.set(AlarmManager.RTC, System.currentTimeMillis() + AlarmManager.INTERVAL_HOUR,
PendingIntent.getService(getApplicationContext(), 2,
new Intent(this, SensorListener.class),
PendingIntent.FLAG_UPDATE_CURRENT));
return START_STICKY;
}
You need to start a Foreground Service.
This is my music player Foreground service code.
public class ForegroundService extends Service {
private static final String LOG_TAG = "ForegroundService";
String audioPath;
boolean audioPlayed = false;
MediaPlayer mp;
Thread backgroundThread;
#Override
public void onCreate() {
super.onCreate();
mp = MediaPlayer.create(this,R.raw.shapeofyou);
mp.setLooping(true);
backgroundThread = new Thread(new Runnable() {
#Override
public void run() {
playMusic();
}
});
}
private void playMusic() {
mp.start();
audioPlayed = true;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// audioPath = intent.getStringExtra("path");
if (intent.getAction().equals(Constants.ACTION.STARTFOREGROUND_ACTION)) {
if (mp.isPlaying()){
Toast.makeText(this,"Already playing",Toast.LENGTH_SHORT).show();
} else {
backgroundThread.start();
}
Log.i(LOG_TAG, "Received Start Foreground Intent ");
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, ForegroundService.class);
previousIntent.setAction(Constants.ACTION.PREV_ACTION);
PendingIntent ppreviousIntent = PendingIntent.getService(this, 0,
previousIntent, 0);
Intent playIntent = new Intent(this, ForegroundService.class);
playIntent.setAction(Constants.ACTION.PLAY_ACTION);
PendingIntent pplayIntent = PendingIntent.getService(this, 0,
playIntent, 0);
Intent nextIntent = new Intent(this, ForegroundService.class);
nextIntent.setAction(Constants.ACTION.NEXT_ACTION);
PendingIntent pnextIntent = PendingIntent.getService(this, 0,
nextIntent, 0);
Bitmap icon = BitmapFactory.decodeResource(getResources(),
R.mipmap.ic_launcher);
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("Music Player")
.setTicker("Music Player")
.setContentText("My Music")
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(
Bitmap.createScaledBitmap(icon, 128, 128, false))
.setContentIntent(pendingIntent)
.setOngoing(true)
.addAction(android.R.drawable.ic_menu_close_clear_cancel,
"Stop", ppreviousIntent)
.addAction(android.R.drawable.ic_media_play, "Play",
pplayIntent).build();
startForeground(Constants.NOTIFICATION_ID.FOREGROUND_SERVICE,
notification);
} else if (intent.getAction().equals(Constants.ACTION.PREV_ACTION)) {
stopForeground(true);
stopSelf();
if (mp.isPlaying()) {
mp.release();
}
backgroundThread = null;
Log.i(LOG_TAG, "Clicked Previous");
} else if (intent.getAction().equals(Constants.ACTION.PLAY_ACTION)) {
if (audioPlayed) {
mp.pause();
audioPlayed = false;
} else {
mp.start();
audioPlayed = true;
}
Log.i(LOG_TAG, "Clicked Play");
} else if (intent.getAction().equals(Constants.ACTION.NEXT_ACTION)) {
Log.i(LOG_TAG, "Clicked Next");
} else if (intent.getAction().equals(
Constants.ACTION.STOPFOREGROUND_ACTION)) {
Log.i(LOG_TAG, "Received Stop Foreground Intent");
stopForeground(true);
stopSelf();
if (mp.isPlaying()) {
mp.release();
}
backgroundThread = null;
}
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.i(LOG_TAG, "In onDestroy");
}
#Override
public IBinder onBind(Intent intent) {
// Used only in case of bound services.
return null;
}
}
return START_STICKY;
to automatically restart the service when it gets killed for some reasons like low memory.
I have a clock widget that updates every minute. It renders a bitmap and replaces an imageview. This is to use a custom font in a widget. Below I showed the important pieces of my code. My problem is that the widget is there, but nothing shows up. I can still tap the widget to bring up the settings, so I know it's there. It's like the service update isn't working correctly in Kitkat but it does in Lollipop. Any suggestions?
public class DigitalClockWidget_2x1 extends AppWidgetProvider {
public RemoteViews mRemoteViews;
static String APP_SETTINGS = "8BitSettings";
#Override
public void onEnabled(Context context) {
super.onEnabled(context);
context.startService(new Intent(UpdateTimeService.UPDATE_TIME));
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
mRemoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
Intent LaunchIntent = getLaunchIntent(context);
PendingIntent clickPendIntent = PendingIntent.getActivity(context, 0, LaunchIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mRemoteViews.setOnClickPendingIntent(R.id.widget_root, clickPendIntent);
ComponentName componentName = new ComponentName(context.getPackageName(),DigitalClockWidget_2x1.class.getName());
appWidgetManager.updateAppWidget(componentName, mRemoteViews);
context.startService(new Intent(UpdateTimeService.UPDATE_TIME));
}
public static Intent getLaunchIntent(Context context){
SharedPreferences clockSettings = context.getSharedPreferences("ClockSettings", 0);
String launchString = clockSettings.getString("tappedAction", APP_SETTINGS);
if(launchString.compareTo(APP_SETTINGS) == 0){
return new Intent(context, SettingsPage.class);
}
return context.getPackageManager().getLaunchIntentForPackage(launchString);
}
public static final class UpdateTimeService extends Service {
static final String UPDATE_TIME = "org.penguinproductions.eight_bit_clock.action.UPDATE_TIME_2x1";
RemoteViews mRemoteViews;
private Calendar mCalendar;
private final static IntentFilter mIntentFilter = new IntentFilter();
int textColor = 0;
boolean tweentyfourHour = false;
SharedPreferences clockSettings;
String APP_SETTINGS = "8BitSettings";
static {
mIntentFilter.addAction(Intent.ACTION_TIME_TICK);
mIntentFilter.addAction(Intent.ACTION_TIME_CHANGED);
mIntentFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
}
#Override
public void onCreate() {
super.onCreate();
mCalendar = Calendar.getInstance();
registerReceiver(mTimeChangedReceiver, mIntentFilter);
}
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(mTimeChangedReceiver);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
if (intent != null) {
if (UPDATE_TIME.equals(intent.getAction())) {
updateTime();
}
}
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private final BroadcastReceiver mTimeChangedReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
updateTime();
}
};
private void updateTime() {
mCalendar.setTimeInMillis(System.currentTimeMillis());
mRemoteViews = new RemoteViews(getPackageName(), R.layout.widget);
String date = DateFormat.format(getString(R.string.date_format), mCalendar).toString();
mRemoteViews.setImageViewBitmap(R.id.imageView_txt, buildUpdate(getTodaysTime(), mCalendar.get(Calendar.AM_PM), date));
ComponentName mComponentName = new ComponentName(this, DigitalClockWidget_2x1.class);
AppWidgetManager mAppWidgetManager = AppWidgetManager.getInstance(this);
mAppWidgetManager.updateAppWidget(mComponentName, mRemoteViews);
Intent LaunchIntent = getLaunchIntent(getBaseContext());
PendingIntent clickPendIntent = PendingIntent.getActivity(getBaseContext(), 0, LaunchIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mRemoteViews.setOnClickPendingIntent(R.id.widget_root, clickPendIntent);
mAppWidgetManager = AppWidgetManager.getInstance(getBaseContext());
mAppWidgetManager.updateAppWidget(mComponentName, mRemoteViews);
}
}
EDIT:
The issue seems to have to do with the Bitmap rendering. I replaced the imageview with a textview and it worked. So the Bitmap isn't displaying in KitKat, but it does in Lollipop
public Bitmap buildUpdate(String time, int AMPM, String date) {
Log.v("Penguin", "Building time string:" + time);
clockSettings = this.getSharedPreferences("ClockSettings", 0);
boolean showDate = clockSettings.getBoolean("showDate", true);
boolean showampm = clockSettings.getBoolean("ampm", true);
boolean leading0 = clockSettings.getBoolean("leading0", true);
textColor = clockSettings.getInt("clockColor", Color.WHITE);
int dateColor = clockSettings.getInt("dateColor", Color.WHITE);
Bitmap myBitmap = Bitmap.createBitmap(2500, 1100, Bitmap.Config.ARGB_8888);
int fontSize = 425;
Canvas myCanvas = new Canvas(myBitmap);
Paint paint = new Paint();
Typeface clock = Typeface.createFromAsset(this.getAssets(), "fonts/PressStart2P.ttf");
paint.setAntiAlias(true);
paint.setSubpixelText(true);
paint.setTypeface(clock);
paint.setStyle(Paint.Style.FILL);
paint.setColor(textColor);
paint.setTextSize(fontSize);
paint.setTextAlign(Paint.Align.CENTER);
myCanvas.drawText(time, myBitmap.getWidth() / 2, fontSize+200, paint);
paint.setTextSize(100);
if(showampm) {
// alert("AMPM");
String ampm = "AM";
if (AMPM == 1) ampm = "PM";
myCanvas.drawText(ampm, (myBitmap.getWidth() / 2) + ((time.length() * fontSize) / 2) + 100, 300, paint);
}
paint.setTextSize(125);
if(showDate) {
paint.setColor(dateColor);
myCanvas.drawText(date, myBitmap.getWidth() / 2, (myBitmap.getHeight() / 2 + 400), paint);
}
return myBitmap;
}
So the issue was that the size limit for my older phone running KitKat only allows for texture sizes no bigger than 2048x2048 pixels. My bitmap was 2500x1100, so scaling it down has fixed the issue
I want to update widget item when I Add or Remove item using activity in my WelcomeWidget class onReceive() as
public void onReceive(Context context, Intent intent) {
setup(context);
if (datalist.size() != 0)
{
if (intent.getAction().equals(ACTION_NEXT_TIP)) {
mMessage = getNextMessageIndex();
SharedPreferences.Editor pref = context.getSharedPreferences(
PREFS_NAME, 0).edit();
pref.putInt(PREFS_TIP_NUMBER, mMessage);
pref.commit();
refresh();
}
else if (intent.getAction().equals(ACTION_SETTING))
{
Intent articleIntent = new Intent(context,
LoremActivity.class);
articleIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(articleIntent);
} else {
refresh();
} } }
where refresh method is as :
private void refresh() {
RemoteViews rv = buildUpdate(mContext);
for (int i : mWidgetIds) {
mWidgetManager.updateAppWidget(i, rv);
}
Using Animation as :
AnimationSet farsiTelLogoAnimation = new AnimationSet(true);
RotateAnimation rotate = new RotateAnimation(0, 360,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
rotate.setFillAfter(true);
rotate.setDuration(1000);
farsiTelLogoAnimation.addAnimation(rotate);
}
getting message index
private int getNextMessageIndex() {
return (mMessage + 1) % datalist.size();
}
where buildUpdate () method is as
public RemoteViews buildUpdate(Context context) {
RemoteViews updateViews =
new RemoteViews(context.getPackageName(), R.layout.widget);
// Action for tap on bubble
Intent bcast = new Intent(context,
WelcomeWidget.class);
bcast.setAction(ACTION_NEXT_TIP);
PendingIntent pending = PendingIntent.getBroadcast(context,
0, bcast, PendingIntent.FLAG_UPDATE_CURRENT);
updateViews.setOnClickPendingIntent(R.id.widget, pending);
// RemoteViews updateViews1 = new
RemoteViews(context.getPackageName(), // R.id.setting);
Intent bcast1 = new Intent(context, WelcomeWidget.class);
bcast1.setAction(ACTION_SETTING); PendingIntent pending1 =
PendingIntent.getBroadcast(context,
0, bcast1, PendingIntent.FLAG_UPDATE_CURRENT);
updateViews.
setOnClickPendingIntent(R.id.setting, pending1);
// Tip bubble text if (mMessage >= 0) { // String[] parts =
sNewlineRegex.split(mTips[mMessage], 2);
String to = datalist.get(mMessage).getFrom();
String from = datalist.get(mMessage).getTo();
String rate = datalist.get(mMessage).getRate();
// Look for a callout graphic referenced in the text Matcher m =
sDrawableRegex.matcher(to);
if (m.find()) {
String imageName = m.group(1);
int resId = context.getResources().getIdentifier(
imageName, null, context.getPackageName());
// updateViews.setImageViewResource(R.id.tip_callout, resId);
// updateViews.setViewVisibility(R.id.tip_callout,
// View.VISIBLE);
to = m.replaceFirst(""); } else {
// updateViews.setImageViewResource(R.id.tip_callout, 0);0
// updateViews.setViewVisibility(R.id.tip_callout, View.GONE); }
updateViews.setTextViewText(R.id.to, to);
updateViews.setTextViewText(R.id.from, from);
updateViews.setTextViewText(R.id.rate, rate);
updateViews.setTextViewText(
R.id.tip_footer,
context.getResources().getString(R.string.pager_footer,
(1 + mMessage), datalist.size()));
updateViews.setViewVisibility(R.id.tip_bubble, View.VISIBLE);
}
else {
updateViews.setViewVisibility(R.id.tip_bubble, View.INVISIBLE);
}
return updateViews;
}
where Button click event reload widget
I don't really understand your code because the format is horrible.
Anyway, to update a widget from your activity you can send a Broadcast intent with APPWIDGET_UPDATE. Use the following code:
Intent intent = new Intent(YourActivity.this, YourWidgetProvider.class);
intent.setAction("android.appwidget.action.APPWIDGET_UPDATE");
int ids[] = AppWidgetManager.getInstance(getApplication()).getAppWidgetIds(new ComponentName(getApplication(), ASquareAnalogClockProvider.class));
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,ids);
sendBroadcast(intent);
Hope it helps :)