I'm using the library bitcoinj to create a Android wallet. The case is that I want the blockchain to be downloaded in the background so that the user can start using the other features of the app, but when it starts the download and opens a new activity, the application freezes, you can't use anything, not even return to the previous screen. This is part of the code:
public class BitcoinService extends Service {
private final PeerDataEventListener blockchainDownloadListener = new AbstractPeerEventListener() {
private final long CALLBACK_TIME = 1000L;
private final AtomicLong lastMessageTime = new AtomicLong(0);
private int height;
private int blocksLeft;
private Block block;
#Override
public void onBlocksDownloaded(final Peer peer, final Block block, final FilteredBlock filteredBlock, final int blocksLeft) {
config.maybeIncrementBestChainHeightEver(blockChain.getChainHead().getHeight());
delayHandler.removeCallbacksAndMessages(null);
final long now = System.currentTimeMillis();
this.block = block;
this.height = (int) peer.getBestHeight() - blocksLeft;
this.blocksLeft = blocksLeft;
if (now - lastMessageTime.get() > CALLBACK_TIME) {
delayHandler.post(RUNNER);
} else {
delayHandler.postDelayed(RUNNER, CALLBACK_TIME);
}
}
private final Runnable RUNNER = new Runnable() {
#Override
public void run() {
notifyBlockchainProgress(height, (height + blocksLeft));
Log.e(TAG, "LAST_BLOCK=" + height + ", REMAINS=" + blocksLeft);
if (blocksLeft == 0) {
broadcastBlockchainDownloaded();
}
}
};
};
private final BroadcastReceiver connectivityReceiver = new BroadcastReceiver() {
#SuppressLint("Wakelock")
#Override
public void onReceive(final Context context, final Intent intent) {
Log.d(TAG, "acquiring wakelock");
wakeLock.acquire();
// consistency check
final int walletLastBlockSeenHeight = wallet.getLastBlockSeenHeight();
final int bestChainHeight = blockChain.getBestChainHeight();
if (walletLastBlockSeenHeight != -1 && walletLastBlockSeenHeight != bestChainHeight) {
final String message = "wallet/blockchain out of sync: " + walletLastBlockSeenHeight + "/" + bestChainHeight;
Log.e(TAG, message);
}
Log.i(TAG, "starting peergroup");
peerGroup = new PeerGroup(Constants.WALLET.NETWORK_PARAMETERS, blockChain);
peerGroup.setDownloadTxDependencies(false);
peerGroup.setUserAgent("TestWallet", "0.0.1");
peerGroup.setMaxConnections(6);
peerGroup.setConnectTimeoutMillis(15000);
peerGroup.setPeerDiscoveryTimeoutMillis(10000);
// start peergroup
peerGroup.startAsync();
peerGroup.startBlockChainDownload(blockchainDownloadListener);
}
};
private final Handler delayHandler = new Handler();
private PeerGroup peerGroup;
private WakeLock wakeLock;
private PeerConnectivityListener peerConnectivityListener;
private NotificationManager nm;
private Configuration config;
private Wallet wallet;
#Override
public void onCreate() {
wallet = new Wallet(Constants.WALLET.NETWORK_PARAMETERS);
nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
final String lockName = getPackageName() + " blockchain sync";
final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, lockName);
config = Configuration.getInstance();
broadcastPeerState(0);
blockChainFile = Constants.WALLET.BLOCKCHAIN_FILE;
final boolean blockChainFileExists = blockChainFile.exists();
if (!blockChainFileExists) {
new File(Constants.WALLET.WALLET_PATH).mkdirs();
}
try {
blockStore = new SPVBlockStore(Constants.WALLET.NETWORK_PARAMETERS, blockChainFile);
blockStore.getChainHead(); // detect corruptions as early as possible
final long earliestKeyCreationTime = wallet.getEarliestKeyCreationTime();
if (!blockChainFileExists && earliestKeyCreationTime > 0){
try {
config.setDeletingBlockchain(true);
final long start = System.currentTimeMillis();
final InputStream checkpointsInputStream = getAssets().open("bitcoin/" + Constants.WALLET.CHECKPOINTS_FILENAME);
CheckpointManager.checkpoint(Constants.WALLET.NETWORK_PARAMETERS, checkpointsInputStream, blockStore, earliestKeyCreationTime);
Log.i(TAG, String.format("checkpoints loaded from '%1$s', took %2$dms", Constants.WALLET.CHECKPOINTS_FILENAME, System.currentTimeMillis() - start));
} catch (final IOException x) {
Log.e(TAG, "problem reading checkpoints, continuing without", x);
}
}
} catch (final BlockStoreException x) {
blockChainFile.delete();
final String msg = "blockstore cannot be created";
Log.e(TAG, msg, x);
}
try {
blockChain = new BlockChain(Constants.WALLET.NETWORK_PARAMETERS, walletHelper.getMainWallet(), blockStore);
} catch (final BlockStoreException x) {
throw new Error("blockchain cannot be created", x);
}
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_LOW);
intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
registerReceiver(connectivityReceiver, intentFilter); // implicitly start PeerGroup
}
#Override
public int onStartCommand(final Intent intent, final int flags, final int startId) {
Log.e(TAG, "onStartCommand");
...
return START_NOT_STICKY;
}
private void notifyBlockchainProgress(int progress, int max) {
boolean isCompleted = progress == max;
if (config.isDeletingBlockchain()) {
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
long percent = Math.round(Math.floor((progress * 100) / max));
mBuilder.setContentTitle("Blockchain download")
.setContentText(" Synchronization in progress - " + percent + "%")
.setSmallIcon(R.drawable.ic_logo_splash)
.setProgress(max, progress, false)
.setAutoCancel(false);
if (isCompleted) {
mBuilder.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setProgress(0, 0, false)
.setAutoCancel(true)
.setContentText(getString(R.string.synchronization_completed));
config.setDeletingBlockchain(false);
}
Notification notif = mBuilder.build();
if (isCompleted) {
notif.flags = Notification.FLAG_FOREGROUND_SERVICE;
} else {
notif.flags = Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE;
}
nm.notify(2, notif);
}
}
public void broadcastBlockchainDownloaded() {
Intent i = new Intent(UiRefreshReceiver.REFRESH_UI);
LocalBroadcastManager.getInstance(this).sendBroadcast(i);
}
}
I used part of the code of the official project of the Android wallet
Service in android runs in UI thread. You need to put all the job into different thread inside your Service
You need to use IntentService for downloading process.
public class BitcoinService extends IntentService {
private final PeerDataEventListener blockchainDownloadListener = new AbstractPeerEventListener() {
private final long CALLBACK_TIME = 1000L;
private final AtomicLong lastMessageTime = new AtomicLong(0);
private int height;
private int blocksLeft;
private Block block;
#Override
public void onBlocksDownloaded(final Peer peer, final Block block, final FilteredBlock filteredBlock, final int blocksLeft) {
config.maybeIncrementBestChainHeightEver(blockChain.getChainHead().getHeight());
delayHandler.removeCallbacksAndMessages(null);
final long now = System.currentTimeMillis();
this.block = block;
this.height = (int) peer.getBestHeight() - blocksLeft;
this.blocksLeft = blocksLeft;
if (now - lastMessageTime.get() > CALLBACK_TIME) {
delayHandler.post(RUNNER);
} else {
delayHandler.postDelayed(RUNNER, CALLBACK_TIME);
}
}
private final Runnable RUNNER = new Runnable() {
#Override
public void run() {
notifyBlockchainProgress(height, (height + blocksLeft));
Log.e(TAG, "LAST_BLOCK=" + height + ", REMAINS=" + blocksLeft);
if (blocksLeft == 0) {
broadcastBlockchainDownloaded();
}
}
};
};
private final BroadcastReceiver connectivityReceiver = new BroadcastReceiver() {
#SuppressLint("Wakelock")
#Override
public void onReceive(final Context context, final Intent intent) {
Log.d(TAG, "acquiring wakelock");
wakeLock.acquire();
// consistency check
final int walletLastBlockSeenHeight = wallet.getLastBlockSeenHeight();
final int bestChainHeight = blockChain.getBestChainHeight();
if (walletLastBlockSeenHeight != -1 && walletLastBlockSeenHeight != bestChainHeight) {
final String message = "wallet/blockchain out of sync: " + walletLastBlockSeenHeight + "/" + bestChainHeight;
Log.e(TAG, message);
}
Log.i(TAG, "starting peergroup");
peerGroup = new PeerGroup(Constants.WALLET.NETWORK_PARAMETERS, blockChain);
peerGroup.setDownloadTxDependencies(false);
peerGroup.setUserAgent("TestWallet", "0.0.1");
peerGroup.setMaxConnections(6);
peerGroup.setConnectTimeoutMillis(15000);
peerGroup.setPeerDiscoveryTimeoutMillis(10000);
// start peergroup
peerGroup.startAsync();
peerGroup.startBlockChainDownload(blockchainDownloadListener);
}
};
private final Handler delayHandler = new Handler();
private PeerGroup peerGroup;
private WakeLock wakeLock;
private PeerConnectivityListener peerConnectivityListener;
private NotificationManager nm;
private Configuration config;
private Wallet wallet;
#Override
protected void onHandleIntent(Intent intent) {
wallet = new Wallet(Constants.WALLET.NETWORK_PARAMETERS);
nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
final String lockName = getPackageName() + " blockchain sync";
final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, lockName);
config = Configuration.getInstance();
broadcastPeerState(0);
blockChainFile = Constants.WALLET.BLOCKCHAIN_FILE;
final boolean blockChainFileExists = blockChainFile.exists();
if (!blockChainFileExists) {
new File(Constants.WALLET.WALLET_PATH).mkdirs();
}
try {
blockStore = new SPVBlockStore(Constants.WALLET.NETWORK_PARAMETERS, blockChainFile);
blockStore.getChainHead(); // detect corruptions as early as possible
final long earliestKeyCreationTime = wallet.getEarliestKeyCreationTime();
if (!blockChainFileExists && earliestKeyCreationTime > 0){
try {
config.setDeletingBlockchain(true);
final long start = System.currentTimeMillis();
final InputStream checkpointsInputStream = getAssets().open("bitcoin/" + Constants.WALLET.CHECKPOINTS_FILENAME);
CheckpointManager.checkpoint(Constants.WALLET.NETWORK_PARAMETERS, checkpointsInputStream, blockStore, earliestKeyCreationTime);
Log.i(TAG, String.format("checkpoints loaded from '%1$s', took %2$dms", Constants.WALLET.CHECKPOINTS_FILENAME, System.currentTimeMillis() - start));
} catch (final IOException x) {
Log.e(TAG, "problem reading checkpoints, continuing without", x);
}
}
} catch (final BlockStoreException x) {
blockChainFile.delete();
final String msg = "blockstore cannot be created";
Log.e(TAG, msg, x);
}
try {
blockChain = new BlockChain(Constants.WALLET.NETWORK_PARAMETERS, walletHelper.getMainWallet(), blockStore);
} catch (final BlockStoreException x) {
throw new Error("blockchain cannot be created", x);
}
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_LOW);
intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
registerReceiver(connectivityReceiver, intentFilter); // implicitly start PeerGroup
}
private void notifyBlockchainProgress(int progress, int max) {
boolean isCompleted = progress == max;
if (config.isDeletingBlockchain()) {
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
long percent = Math.round(Math.floor((progress * 100) / max));
mBuilder.setContentTitle("Blockchain download")
.setContentText(" Synchronization in progress - " + percent + "%")
.setSmallIcon(R.drawable.ic_logo_splash)
.setProgress(max, progress, false)
.setAutoCancel(false);
if (isCompleted) {
mBuilder.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setProgress(0, 0, false)
.setAutoCancel(true)
.setContentText(getString(R.string.synchronization_completed));
config.setDeletingBlockchain(false);
}
Notification notif = mBuilder.build();
if (isCompleted) {
notif.flags = Notification.FLAG_FOREGROUND_SERVICE;
} else {
notif.flags = Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE;
}
nm.notify(2, notif);
}
}
}
Hope this will help you.
Related
I tried to use new AudioPlaybackCapture method to record some media in an android 10 device.
I managed to record all media sounds such as youtube videos, music etc. But my goal is to check weather we can use this in recording incoming voice calls. I tried to set various values for the usage parameter but with no luck. Always no voice from call is recorded in either case, even with speaker phone on.
I used the following service to record calls. Tried to set
AudioAttributes.USAGE_MEDIA
AudioAttributes.USAGE_VOICE_COMMUNICATION and most other parameters but did not manage to record calls. Other media can be perfectly recorded using this code.
Here's my service, Broadcast massages from an activity is used to invoke start and stop recording functionalities.
public class MediaCaptureService extends Service {
public static final String ACTION_ALL = "ALL";
public static final String ACTION_START = "ACTION_START";
public static final String ACTION_STOP = "ACTION_STOP";
public static final String EXTRA_RESULT_CODE = "EXTRA_RESULT_CODE";
public static final String EXTRA_ACTION_NAME = "ACTION_NAME";
private static final int RECORDER_SAMPLERATE = 8000;
private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_MONO;
private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
NotificationCompat.Builder _notificationBuilder;
NotificationManager _notificationManager;
private String NOTIFICATION_CHANNEL_ID = "ChannelId";
private String NOTIFICATION_CHANNEL_NAME = "Channel";
private String NOTIFICATION_CHANNEL_DESC = "ChannelDescription";
private int NOTIFICATION_ID = 1000;
private static final String ONGING_NOTIFICATION_TICKER = "RecorderApp";
int BufferElements2Rec = 1024; // want to play 2048 (2K) since 2 bytes we use only 1024
int BytesPerElement = 2; // 2 bytes in 16bit format
AudioRecord _recorder;
private boolean _isRecording = false;
private MediaProjectionManager _mediaProjectionManager;
private MediaProjection _mediaProjection;
private Thread _recordingThread = null;
Intent _callingIntent;
public MediaCaptureService() {
}
#Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//Call Start foreground with notification
Intent notificationIntent = new Intent(this, MediaCaptureService.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
_notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_foreground))
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle("Starting Service")
.setContentText("Starting monitoring service")
.setTicker(ONGING_NOTIFICATION_TICKER)
.setContentIntent(pendingIntent);
Notification notification = _notificationBuilder.build();
NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
channel.setDescription(NOTIFICATION_CHANNEL_DESC);
_notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
_notificationManager.createNotificationChannel(channel);
startForeground(NOTIFICATION_ID, notification);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
_mediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
}
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
_callingIntent = intent;
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_ALL);
registerReceiver(_actionReceiver, filter);
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void startRecording(Intent intent) {
//final int resultCode = intent.getIntExtra(EXTRA_RESULT_CODE, 0);
_mediaProjection = _mediaProjectionManager.getMediaProjection(-1, intent);
startRecording(_mediaProjection);
}
#TargetApi(29)
private void startRecording(MediaProjection mediaProjection ) {
AudioPlaybackCaptureConfiguration config =
new AudioPlaybackCaptureConfiguration.Builder(mediaProjection)
.addMatchingUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
.build();
AudioFormat audioFormat = new AudioFormat.Builder()
.setEncoding(RECORDER_AUDIO_ENCODING)
.setSampleRate(RECORDER_SAMPLERATE)
.setChannelMask(RECORDER_CHANNELS)
.build();
_recorder = new AudioRecord.Builder()
//.setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION)
.setAudioFormat(audioFormat)
.setBufferSizeInBytes(BufferElements2Rec * BytesPerElement)
.setAudioPlaybackCaptureConfig(config)
.build();
_recorder.startRecording();
_recordingThread = new Thread(new Runnable() {
public void run() {
writeAudioDataToFile();
}
}, "AudioRecorder Thread");
_isRecording = true;
_recordingThread.start();
}
private byte[] short2byte(short[] sData) {
int shortArrsize = sData.length;
byte[] bytes = new byte[shortArrsize * 2];
for (int i = 0; i < shortArrsize; i++) {
bytes[i * 2] = (byte) (sData[i] & 0x00FF);
bytes[(i * 2) + 1] = (byte) (sData[i] >> 8);
sData[i] = 0;
}
return bytes;
}
private void writeAudioDataToFile() {
// Write the output audio in byte
Log.i(MainActivity.LOG_PREFIX, "Recording started. Computing output file name");
File sampleDir = new File(getExternalFilesDir(null), "/TestRecordingDasa1");
if (!sampleDir.exists()) {
sampleDir.mkdirs();
}
String fileName = "Record-" + new SimpleDateFormat("dd-MM-yyyy-hh-mm-ss").format(new Date()) + ".pcm";
String filePath = sampleDir.getAbsolutePath() + "/" + fileName;
//String filePath = "/sdcard/voice8K16bitmono.pcm";
short sData[] = new short[BufferElements2Rec];
FileOutputStream os = null;
try {
os = new FileOutputStream(filePath);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
while (_isRecording) {
// gets the voice output from microphone to byte format
_recorder.read(sData, 0, BufferElements2Rec);
System.out.println("Short wirting to file" + sData.toString());
try {
// // writes the data to file from buffer
// // stores the voice buffer
byte bData[] = short2byte(sData);
os.write(bData, 0, BufferElements2Rec * BytesPerElement);
} catch (IOException e) {
e.printStackTrace();
}
}
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
Log.i(MainActivity.LOG_PREFIX, String.format("Recording finished. File saved to '%s'\nadb pull %s .", filePath, filePath));
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void stopRecording() {
// stops the recording activity
if (null != _recorder) {
_isRecording = false;
_recorder.stop();
_recorder.release();
_recorder = null;
}
_mediaProjection.stop();
stopSelf();
}
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(_actionReceiver);
}
BroadcastReceiver _actionReceiver = new BroadcastReceiver() {
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equalsIgnoreCase(ACTION_ALL)) {
String actionName = intent.getStringExtra(EXTRA_ACTION_NAME);
if (actionName != null && !actionName.isEmpty()) {
if (actionName.equalsIgnoreCase(ACTION_START)) {
startRecording(_callingIntent);
} else if (actionName.equalsIgnoreCase(ACTION_STOP)){
stopRecording();
}
}
}
}
};
}
This was tested in google pixel device with android 10. Just wanted to know weather this new api can be used in recording calls or media only. Here is the documentation of this new API.
Playback capture.
What would be the possible mistake im doing here?
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'm following a tutorial to download files using the Retrofit library.
My app's UI has several different buttons which download different files using the above method. The problem is when someone presses another button after pressing the first, it's queued and starts after the first finishes. I want it to start right away simultaneously.
Here's the code for the DownloadService:
public class DownloadService extends IntentService {
public DownloadService() {
super("Download Service");
}
private int totalFileSize;
private NotificationCompat.Builder notificationBuilder;
private NotificationManager notificationManager;
#Override
protected void onHandleIntent(Intent intent) {
MyApp x = (MyApp)getApplicationContext();
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_file_download_deep_orange_a400_18dp)
.setContentTitle("Downloading")
.setContentText("Please wait...")
.setAutoCancel(true);
notificationManager.notify(x.ID, notificationBuilder.build());
Log.i("Paras", "onHandleIntent: " + x.filename + x.url);
initDownload(x.filename,x.url,x.ID);
}
private void initDownload(String filename, String url, int id) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://dl.dropboxusercontent.com/")
.build();
RequestInterface.RetrofitInterface retrofitInterface = retrofit.create(RequestInterface.RetrofitInterface.class);
Call<ResponseBody> request = retrofitInterface.downloadFile(url);
try {
downloadFile(request.execute().body(),filename,id);
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
private void downloadFile(ResponseBody body, String filename,int id) throws IOException {
int count;
byte data[] = new byte[1024 * 4];
long fileSize = body.contentLength();
InputStream bis = new BufferedInputStream(body.byteStream(), 1024 * 8);
File outputFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), filename);
OutputStream output = new FileOutputStream(outputFile);
long total = 0;
long startTime = System.currentTimeMillis();
int timeCount = 1;
while ((count = bis.read(data)) != -1) {
total += count;
totalFileSize = (int) (fileSize / (Math.pow(1, 2))) / 1000;
double current = Math.round(total / (Math.pow(1, 2))) / 1000;
int progress = (int) ((total * 100) / fileSize);
long currentTime = System.currentTimeMillis() - startTime;
Download download = new Download();
download.setTotalFileSize(totalFileSize);
if (currentTime > 1000 * timeCount) {
download.setCurrentFileSize((int) current);
download.setProgress(progress);
sendNotification(download,id);
timeCount++;
}
output.write(data, 0, count);
}
onDownloadComplete(filename,id);
output.flush();
output.close();
bis.close();
}
private void sendNotification(Download download, int id) {
sendIntent(download);
notificationBuilder.setProgress(100, download.getProgress(), false);
notificationBuilder.setContentText("Downloading file " + download.getCurrentFileSize() + "/" + totalFileSize + " KB");
notificationManager.notify(id, notificationBuilder.build());
}
private void sendIntent(Download download) {
Intent intent = new Intent(subject.MESSAGE_PROGRESS);
intent.putExtra("download", download);
LocalBroadcastManager.getInstance(DownloadService.this).sendBroadcast(intent);
}
private void onDownloadComplete(String filename,int id) {
try {
Download download = new Download();
download.setProgress(100);
sendIntent(download);
notificationManager.cancel(id);
notificationBuilder.setProgress(0, 0, false);
notificationBuilder.setContentText("Tap to open");
notificationManager.notify(id, notificationBuilder.build());
String path1 = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/" + filename;
File file = new File(path1);
Uri uri_path = Uri.fromFile(file);
String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension
(MimeTypeMap.getFileExtensionFromUrl(path1));
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
intent.setType(mimeType);
intent.setDataAndType(uri_path, mimeType);
PendingIntent pIntent = PendingIntent.getActivity(this, (int) System.currentTimeMillis(), intent, 0);
String string = filename;
notificationBuilder
.setContentIntent(pIntent)
.setAutoCancel(true)
.setContentTitle(string + " Downloaded");
Log.i("Paras", "onDownloadComplete: " + string);
notificationManager.notify(id, notificationBuilder.build());
} catch (Exception ex) {
}
}
#Override
public void onTaskRemoved(Intent rootIntent) {
}
}
Then I read about IntentService and Service classes. Do Service classes allow simultaneous downloads? I tried something like this:
public class DownloadService extends Service {
public DownloadService() {
super();
}
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
MyApp x = (MyApp)getApplicationContext();
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationBuilder = new NotificationCompat.Builder(getBaseContext())
.setSmallIcon(R.drawable.ic_file_download_deep_orange_a400_18dp)
.setContentTitle("Downloading")
.setContentText("Please wait...")
.setAutoCancel(true);
notificationManager.notify(x.ID, notificationBuilder.build());
Log.i("Paras", "onHandleIntent: " + x.filename + x.url);
initDownload(x.filename,x.url,x.ID);
}
}
#Override
public void onCreate() {
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
MyApp x = (MyApp)getApplicationContext();
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj= intent.putExtra("ID",x.ID);
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
private int totalFileSize;
private NotificationCompat.Builder notificationBuilder;
private NotificationManager notificationManager;
private void initDownload(String filename, String url, int id) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://dl.dropboxusercontent.com/")
.build();
RequestInterface.RetrofitInterface retrofitInterface = retrofit.create(RequestInterface.RetrofitInterface.class);
Call<ResponseBody> request = retrofitInterface.downloadFile(url);
try {
downloadFile(request.execute().body(),filename,id);
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
private void downloadFile(ResponseBody body, String filename,int id) throws IOException {
int count;
byte data[] = new byte[1024 * 4];
long fileSize = body.contentLength();
InputStream bis = new BufferedInputStream(body.byteStream(), 1024 * 8);
File outputFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), filename);
OutputStream output = new FileOutputStream(outputFile);
long total = 0;
long startTime = System.currentTimeMillis();
int timeCount = 1;
while ((count = bis.read(data)) != -1) {
total += count;
totalFileSize = (int) (fileSize / (Math.pow(1, 2))) / 1000;
double current = Math.round(total / (Math.pow(1, 2))) / 1000;
int progress = (int) ((total * 100) / fileSize);
long currentTime = System.currentTimeMillis() - startTime;
Download download = new Download();
download.setTotalFileSize(totalFileSize);
if (currentTime > 1000 * timeCount) {
download.setCurrentFileSize((int) current);
download.setProgress(progress);
sendNotification(download,id);
timeCount++;
}
output.write(data, 0, count);
}
onDownloadComplete(filename,id);
output.flush();
output.close();
bis.close();
}
private void sendNotification(Download download, int id) {
sendIntent(download);
notificationBuilder.setProgress(100, download.getProgress(), false);
notificationBuilder.setContentText("Downloading file " + download.getCurrentFileSize() + "/" + totalFileSize + " KB");
notificationManager.notify(id, notificationBuilder.build());
}
private void sendIntent(Download download) {
Intent intent = new Intent(subject.MESSAGE_PROGRESS);
intent.putExtra("download", download);
LocalBroadcastManager.getInstance(DownloadService.this).sendBroadcast(intent);
}
private void onDownloadComplete(String filename,int id) {
try {
Download download = new Download();
download.setProgress(100);
sendIntent(download);
notificationManager.cancel(id);
notificationBuilder.setProgress(0, 0, false);
notificationBuilder.setContentText("Tap to open");
notificationManager.notify(id, notificationBuilder.build());
String path1 = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/" + filename;
File file = new File(path1);
Uri uri_path = Uri.fromFile(file);
String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension
(MimeTypeMap.getFileExtensionFromUrl(path1));
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
intent.setType(mimeType);
intent.setDataAndType(uri_path, mimeType);
PendingIntent pIntent = PendingIntent.getActivity(this, (int) System.currentTimeMillis(), intent, 0);
String string = filename;
notificationBuilder
.setContentIntent(pIntent)
.setAutoCancel(true)
.setContentTitle(string + " Downloaded");
Log.i("Paras", "onDownloadComplete: " + string);
notificationManager.notify(id, notificationBuilder.build());
} catch (Exception ex) {
}
}
#Override
public void onTaskRemoved(Intent rootIntent) {
}
}
But it didn't work. Any clues what I should do? I'm ready to give more details if required.
Edit 1: DownloadService runs on a function "startDownload" which is executed by various buttons. As you can see in 2nd code, class Extends Service. There is one thread which handles all those button clicks. If you look in comments, it's suggested that I should use Service and different threads for all those clicks. Now how can I make so many threads programmatically. There are almost 40 buttons which make use of DownloadService.
Thanks to #Lxu, I have got it working. So IntentServiceis meant to do one task at a time and can't do multiple tasks simultaneously. We should use Serviceinstead. It allows multiple tasks to be performed simultaneously. We can create multiple threads inside the Service which will be executed simultaneously. My problem got solved by putting all the code of onCreate() to onStartCommand(). When a service is called for the first time, onCreate() is called and after that, it's not called anymore no matter how many times service is called. On every service call, onStartCommand() is executed which creates new thread every time. That's it.
Here's the complete code:
public class DownloadService extends Service {
public DownloadService() {
super();
}
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
int id1;
int id2;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
MyApp x = (MyApp)getApplicationContext();
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationBuilder = new NotificationCompat.Builder(getApplicationContext())
.setSmallIcon(R.drawable.ic_file_download_deep_orange_a400_18dp)
.setContentTitle("Downloading")
.setContentText("Please wait...")
.setAutoCancel(true);
notificationManager.notify(x.ID, notificationBuilder.build());
Log.i("Paras", "onHandleIntent: " + x.filename + x.url + " " + x.ID);
initDownload(x.filename,x.url,x.ID);
}
}
#Override
public void onCreate() {
// Get the HandlerThread's Looper and use it for our Handler
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
MyApp x = (MyApp)getApplicationContext();
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
private int totalFileSize;
private NotificationCompat.Builder notificationBuilder;
private NotificationManager notificationManager;
private void initDownload(String filename, String url, int id) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://dl.dropboxusercontent.com/")
.build();
RequestInterface.RetrofitInterface retrofitInterface = retrofit.create(RequestInterface.RetrofitInterface.class);
Call<ResponseBody> request = retrofitInterface.downloadFile(url);
try {
downloadFile(request.execute().body(),filename,id);
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
private void downloadFile(ResponseBody body, String filename,int id) throws IOException {
int count;
byte data[] = new byte[1024 * 4];
long fileSize = body.contentLength();
InputStream bis = new BufferedInputStream(body.byteStream(), 1024 * 8);
File outputFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), filename);
OutputStream output = new FileOutputStream(outputFile);
long total = 0;
long startTime = System.currentTimeMillis();
int timeCount = 1;
while ((count = bis.read(data)) != -1) {
total += count;
totalFileSize = (int) (fileSize / (Math.pow(1, 2))) / 1000;
double current = Math.round(total / (Math.pow(1, 2))) / 1000;
int progress = (int) ((total * 100) / fileSize);
long currentTime = System.currentTimeMillis() - startTime;
Download download = new Download();
download.setTotalFileSize(totalFileSize);
if (currentTime > 1000 * timeCount) {
download.setCurrentFileSize((int) current);
download.setProgress(progress);
sendNotification(download,id);
timeCount++;
}
output.write(data, 0, count);
}
onDownloadComplete(filename,id);
output.flush();
output.close();
bis.close();
}
private void sendNotification(Download download, int id) {
sendIntent(download,id);
notificationBuilder.setProgress(100, download.getProgress(), false)
.setContentTitle("Downloading");
notificationBuilder.setContentText("Downloading file " + download.getCurrentFileSize() + "/" + totalFileSize + " KB");
notificationManager.notify(id, notificationBuilder.build());
}
private void sendIntent(Download download, int id) {
Intent intent = new Intent(subject.MESSAGE_PROGRESS);
intent.putExtra("download", download);
LocalBroadcastManager.getInstance(DownloadService.this).sendBroadcast(intent);
}
private void onDownloadComplete(String filename,int id) {
try {
Download download = new Download();
download.setProgress(100);
sendIntent(download,id);
notificationManager.cancel(id);
notificationBuilder.setProgress(0, 0, false);
notificationBuilder.setContentText("Tap to open");
notificationManager.notify(id, notificationBuilder.build());
String path1 = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/" + filename;
File file = new File(path1);
Uri uri_path = Uri.fromFile(file);
String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension
(MimeTypeMap.getFileExtensionFromUrl(path1));
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
intent.setType(mimeType);
intent.setDataAndType(uri_path, mimeType);
PendingIntent pIntent = PendingIntent.getActivity(this,(int) System.currentTimeMillis(), intent, 0);
String string = filename;
notificationBuilder
.setContentIntent(pIntent)
.setAutoCancel(true)
.setContentTitle(string + " Downloaded");
Log.i("Paras", "onDownloadComplete: " + string);
notificationManager.notify(id, notificationBuilder.build());
}catch (Exception ex){
}
}
#Override
public void onTaskRemoved(Intent rootIntent) {
}
}
I wrote a little android program, there is a main activity with a broadcast listener, and i create another thread. The thread searches for prime numbers, and loading them into a long arraylist, and after every 3 seconds, sends the filled array to the main activity via broadcast. Everythings ok, until i'm trying to get the long array extra from the intent. It causes every time a nullpointerexception.
I tried with a string arraylist, it worked, but i am curious because the intent has an "getlongarrayextra" method.
Here is my code:
public class MainActivity extends Activity {
public static String BROADCAST_THREAD_KEY = "broadcast_key";
public static String EXTRAARRAYID = "primes";
private static long MAXNUM = 2000000;
private PrimeCalculatorThread thread;
TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.numberstext);
}
private BroadcastReceiver receiver = new BroadcastReceiver() {
public void onReceive(android.content.Context context,
android.content.Intent intent) {
String origitext = textView.getText().toString();
long[] primes = intent.getExtras().getLongArray(EXTRAARRAYID);
Log.d("ASD", "broadcast received" + primes.toString());
StringBuilder builder = new StringBuilder();
if (primes != null) {
for (long prime : primes) {
builder.append(prime + " - ");
}
textView.setText(origitext + "\n" + builder.toString());
}
};
};
#Override
protected void onResume() {
Log.d("ASD", "ONRESUME");
initReceiverAndStartThread();
super.onResume();
}
private void initReceiverAndStartThread() {
IntentFilter filter = new IntentFilter(BROADCAST_THREAD_KEY);
registerReceiver(receiver, filter);
thread = new PrimeCalculatorThread(getBaseContext(), MAXNUM);
thread.start();
Log.d("ASD", "THREAD STARTED");
}
and the second thread:
public class PrimeCalculatorThread extends Thread {
private Context context;
private long maxnum;
List<Long> primes;
boolean isrunning;
public void setIsrunning(boolean isrunning) {
this.isrunning = isrunning;
}
private long counter = 0;
private long DELAYBETWEENBROADCAST = 3000;
public PrimeCalculatorThread(Context c, long maxnum) {
this.context = c;
this.maxnum = maxnum;
primes = new ArrayList<Long>();
}
#Override
public void run() {
long startTime = System.currentTimeMillis();
long estimatedTime;
isrunning = true;
for (long i = 0; i < maxnum; i++) {
Log.d("ASD", Boolean.toString(isrunning));
if (!isrunning)
break;
Log.d("ASD", i + "");
estimatedTime = System.currentTimeMillis() - startTime;
if (isPrime(i)) {
primes.add(i);
Log.d("ASD", i + "is a prime");
} else {
Log.d("ASD", i + "is not a prime");
}
if (estimatedTime > counter * DELAYBETWEENBROADCAST
+ DELAYBETWEENBROADCAST) { // elapsed another period
Log.d("ASD", primes.toString() + " will be sending.");
sendBroadCast();
primes.clear();
counter++;
}
try { //for debug purposes
Thread.sleep(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void sendBroadCast() {
Intent intent = new Intent(MainActivity.BROADCAST_THREAD_KEY);
intent.putExtra(MainActivity.EXTRAARRAYID, primes.toArray());
context.sendBroadcast(intent);
Log.d("ASD", "BROADCAST SENT" + primes.toString());
}
boolean isPrime(long n) {
if (n < 2)
return false;
if (n == 2 || n == 3)
return true;
if (n % 2 == 0 || n % 3 == 0)
return false;
long sqrtN = (long) Math.sqrt(n) + 1;
for (long i = 6L; i <= sqrtN; i += 6) {
if (n % (i - 1) == 0 || n % (i + 1) == 0)
return false;
}
return true;
}
}
The problem is that you are managing a list of Long objects and passing it in putExtra, which means you are invoking putExtra(String name, Serializable value). Then you try to get that value using getLongArray(), but you haven't put any long array extra, you see! To solve this, replace
intent.putExtra(MainActivity.EXTRAARRAYID, primes.toArray());
with
long[] primesArray = new long[primes.size()];
for (int i = 0; i < primes.size(); i++) {
primesArray[i] = primes.get(i);
}
intent.putExtra(MainActivity.EXTRAARRAYID, primesArray);
This will invoke the correct putExtra(String name, long[] value) method.
I am using DownloadManager to download the following url:
http://dj-videos.us/Music/XclusiveSinGleTrack/320%20Kbps/November%202013/Yo%20Yo%20Honey%20Singh%20-%20Blue%20Eyes-[DJKANG.Com].mp3
But the downloading is failed. I even hit the url on browser and it works properly. Is it the problem of url parsing?
Code: DDownloadService.java
public class DDownloadService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
Context conte;
// NotificationManager notificationManager;
// NotificationCompat.Builder mBuilder;
boolean playing = false;
Runnable runnable;
SharedPreferences pre;
static int countOfCurrent = 0;
String downloadName, downloadUrl;
NotificationManager notificationManager;
NotificationCompat.Builder mBuilder;
// ..
static int downloadNumber = 0;
DownloadManager mgr[] = new DownloadManager[100];
long downloadIds[] = new long[100];
BroadcastReceiver cancelDownload;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
try {
Thread.sleep(5000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
downloadNumber++;
downloadName = pre.getString("downloadname", "");
downloadName = viewSD(downloadName);
downloadUrl = pre.getString("downloadurl", "");
downloadName = downloadName.toLowerCase();
pre.edit()
.putString(
"songsInDownload",
pre.getString("songsInDownload", "") + "|"
+ downloadName).commit();
pre.edit().putInt(downloadName + "no", +downloadNumber).commit();
mgr[downloadNumber] = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
try {
countOfCurrent++;
downloadIds[downloadNumber] = mgr[downloadNumber]
.enqueue(new DownloadManager.Request(Uri
.parse(downloadUrl))
.setAllowedNetworkTypes(
DownloadManager.Request.NETWORK_WIFI
| DownloadManager.Request.NETWORK_MOBILE)
.setAllowedOverRoaming(false)
.setTitle("Downloading")
.setDescription(downloadName)
.setNotificationVisibility(
DownloadManager.Request.VISIBILITY_HIDDEN)
.setDestinationInExternalPublicDir(
Environment.DIRECTORY_MUSIC,
downloadName)
.setVisibleInDownloadsUi(false));
pre.edit()
.putLong(downloadName + "id",
downloadIds[downloadNumber]).commit();
Timer myTimer = new Timer();
myTimer.schedule(new RegrowCornAnimate(downloadNumber,
downloadName), 0, 10);
} catch (IllegalStateException e) {
Toast.makeText(getBaseContext(), "No storage found!",
Toast.LENGTH_SHORT).show();
e.printStackTrace();
} catch (Exception e) {
Toast.makeText(getBaseContext(), " Something wrong happened!",
Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
}
#Override
public void onCreate() {
conte = this;
pre = getSharedPreferences("download", 0);
downloadName = pre.getString("downloadname", "");
downloadUrl = pre.getString("downloadurl", "");
cancelDownload = new BroadcastReceiver() {
#Override
public void onReceive(Context arg0, Intent arg1) {
try {
mgr[pre.getInt(arg1.getExtras().getString("name") + "no", 0)]
.remove(pre.getLong(
arg1.getExtras().getString("name") + "id",
0));
} catch (Exception e) {
e.printStackTrace();
}
}
};
registerReceiver(cancelDownload, new IntentFilter("cancelIt"));
notificationManager = (NotificationManager) conte
.getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(conte)
.setSmallIcon(R.drawable.icon)
.setContentTitle("Downloading in progress").setContentText("");
startForeground(55, mBuilder.build());
notificationManager.cancel(55);
HandlerThread thread = new HandlerThread("ServiceStartArguments", 0);
// //..................
// notificationManager = (NotificationManager) conte
// .getSystemService(Context.NOTIFICATION_SERVICE);
// mBuilder = new NotificationCompat.Builder(conte);
// RemoteViews remoteViews = new RemoteViews(getPackageName(),
// R.layout.notification_layout);
// try {
// mBuilder.setSmallIcon(R.drawable.icon);
// mBuilder.setAutoCancel(false).setOngoing(true)
// .setContent(remoteViews);
// Uri uri = RingtoneManager
// .getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
// mBuilder.setSound(uri);
// notificationManager.notify(Mp3Constants.NOTIFICATION_NUMBER,
// mBuilder.build());
// } catch (Exception e) {
// e.printStackTrace();
// }
// //...................
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// online = intent.getExtras().getString("online");
// link = intent.getExtras().getString("link");
// name = intent.getExtras().getString("name");
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
return START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(cancelDownload);
}
class RegrowCornAnimate extends TimerTask {
private final int serial;
private final String name_of_da;
boolean startFlag = true, errorFlag = true;
RegrowCornAnimate(int serial, String name) {
this.serial = serial;
this.name_of_da = name;
}
public void run() {
// Do stuff
int dl_progress = 0;
try {
DownloadManager.Query q = new DownloadManager.Query();
q.setFilterById(downloadIds[serial]);
Cursor c = mgr[serial].query(q);
c.moveToFirst();
long bytes_downloaded = c
.getInt(c
.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
long bytes_total = c
.getInt(c
.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
dl_progress = (int) ((bytes_downloaded * 100) / bytes_total);
pre.edit().putInt(name_of_da, dl_progress).commit();
switch (c.getInt(c
.getColumnIndex(DownloadManager.COLUMN_STATUS))) {
case DownloadManager.STATUS_FAILED:
// msg = "Download failed!";
// Toast.makeText(getBaseContext(), "Url Broken!",
// Toast.LENGTH_SHORT).show();
sendNotification(1, serial, name_of_da, dl_progress);
this.cancel();
countOfCurrent--;
if (countOfCurrent == 0)
stopSelf();
break;
case DownloadManager.STATUS_PAUSED:
// msg = "Download paused!";
if (errorFlag) {
errorFlag = false;
sendNotification(7, serial, name_of_da, dl_progress);
}
break;
case DownloadManager.STATUS_PENDING:
// msg = "Download pending!";
sendNotification(0, serial, name_of_da, dl_progress);
break;
case DownloadManager.STATUS_RUNNING:
// msg = "Download in progress!";
errorFlag = true;
if (startFlag) {
if (verifyFromSD(name_of_da)) {
startFlag = false;
sendBroadcast(new Intent("start"));
}
}
sendNotification(0, serial, name_of_da, dl_progress);
break;
case DownloadManager.STATUS_SUCCESSFUL:
// msg = "Download complete!";
pre.edit()
.putString(
"songsInDownload",
pre.getString("songsInDownload", "")
.replace("|" + name_of_da, ""))
.commit();
pre.edit().putInt(name_of_da, 100);
sendNotification(0, serial, name_of_da, dl_progress);
this.cancel();
countOfCurrent--;
if (countOfCurrent == 0)
stopSelf();
break;
default:
// msg = "Download is nowhere in sight";
sendNotification(10, serial, name_of_da, dl_progress);
this.cancel();
countOfCurrent--;
if (countOfCurrent == 0)
stopSelf();
break;
}
c.close();
} catch (Exception e) {
e.printStackTrace();
sendNotification(7, serial, name_of_da, dl_progress);
cancel();
countOfCurrent--;
if (countOfCurrent == 0)
stopSelf();
}
}
}
public void sendNotification(int tmout, int nin, String name, int progress) {
if (tmout == 0) {
// notificationManager.notify(nin, mBuilder.build());
if (progress >= 100) {
// notificationManager.cancel(nin);
mBuilder.setSmallIcon(R.drawable.icon)
.setContentTitle("Completed").setContentText(name)
.setAutoCancel(true).setOngoing(false)
.setProgress(100, 100, false);
Uri ttt = Uri.parse(Environment.getExternalStorageDirectory()
.toString() + "/Music/" + name);
pre.edit().putInt("retry", 1).commit();
Intent inten = new Intent(Intent.ACTION_VIEW, ttt);
String arr[] = name.split("\\.");
inten.setDataAndType(ttt, "audio/" + arr[arr.length - 1]);
PendingIntent i = PendingIntent.getActivity(getBaseContext(),
0, inten, 0);
mBuilder.setContentIntent(i);
notificationManager.notify(nin, mBuilder.build());
} else {
mBuilder.setContentTitle("Downloading: " + name)
.setContentText(progress + " %")
.setSmallIcon(R.drawable.icon).setAutoCancel(false)
.setOngoing(true);
mBuilder.setProgress(100, progress, false);
notificationManager.notify(nin, mBuilder.build());
}
} else {
if (tmout == 1) {
mBuilder.setSmallIcon(R.drawable.icon)
.setContentTitle("Failed: " + name)
.setContentText(progress + " %").setAutoCancel(true)
.setProgress(100, progress, false).setOngoing(false);
// Intent intnt = new Intent(Mp3Constants.NOTIFICATION);
// intnt.putExtra("resume", "1");
// intnt.putExtra("url", urlD);
// intnt.putExtra("name", name);
// intnt.putExtra("nin", nin);
// PendingIntent i = PendingIntent
// .getBroadcast(conte, 0, intnt, 0);
// mBuilder.setContentIntent(i);
} else if (tmout == 7) {
mBuilder.setSmallIcon(R.drawable.icon)
.setContentTitle("Cancelled: " + name)
.setAutoCancel(true).setProgress(100, progress, false)
.setOngoing(false);
// Intent intnt = new Intent(Mp3Constants.NOTIFICATION);
// intnt.putExtra("resume", "1");
// intnt.putExtra("url", urlD);
// intnt.putExtra("name", name);
// intnt.putExtra("nin", nin);
// PendingIntent i = PendingIntent
// .getBroadcast(conte, 0, intnt, 0);
// mBuilder.setContentIntent(i);
} else {
mBuilder.setSmallIcon(R.drawable.icon)
.setContentTitle("Interrupted: " + name)
.setContentText("No storage found").setAutoCancel(true)
.setOngoing(false);
}
notificationManager.notify(nin, mBuilder.build());
}
}
private String viewSD(String naame) {
File f = new File(Environment.getExternalStorageDirectory().toString()
+ "/Music");
File[] files = f.listFiles();
if (files == null) {
return naame;
}
while (true) {
String newName = naame;
naame = relooper(files, newName);
if (newName.equals(naame))
break;
}
return naame;
}
public String relooper(File[] files, String name) {
int send = files.length;
for (int i = 0; i < send; i++) {
File file = files[i];
String myfile = file
.getPath()
.substring(file.getPath().lastIndexOf("/") + 1,
file.getPath().length()).toLowerCase();
if (name.equalsIgnoreCase(myfile))
return "copy_of_" + name;
}
return name;
}
private boolean verifyFromSD(String naame) {
File f = new File(Environment.getExternalStorageDirectory().toString()
+ "/Music");
File[] files = f.listFiles();
if (files == null) {
return false;
}
int send = files.length;
for (int i = 0; i < send; i++) {
File file = files[i];
String myfile = file
.getPath()
.substring(file.getPath().lastIndexOf("/") + 1,
file.getPath().length()).toLowerCase();
if (naame.equalsIgnoreCase(myfile))
return true;
}
return false;
}
}
EDIT: I found the problem from logcat:
01-07 11:47:37.313: W/DownloadManager(18893): Exception for id 285: Illegal character in path at index 115: http://dj-videos.us/Music/XclusiveSinGleTrack/320%20Kbps/November%202013/Yo%20Yo%20Honey%20Singh%20-%20Blue%20Eyes-[DJKANG.Com].mp3
01-07 11:47:37.313: W/DownloadManager(18893): java.lang.IllegalArgumentException: Illegal character in path at index 115: http://dj-videos.us/Music/XclusiveSinGleTrack/320%20Kbps/November%202013/Yo%20Yo%20Honey%20Singh%20-%20Blue%20Eyes-[DJKANG.Com].mp3
01-07 11:47:37.313: W/DownloadManager(18893): at java.net.URI.create(URI.java:727)
01-07 11:47:37.313: W/DownloadManager(18893): at android.net.Proxy.getProxy(Proxy.java:113)
01-07 11:47:37.313: W/DownloadManager(18893): at android.net.Proxy.getPreferredHttpHost(Proxy.java:218)
01-07 11:47:37.313: W/DownloadManager(18893): at com.android.providers.downloads.DownloadThread.run(DownloadThread.java:174)
But I still need to know which format to use to parse url for DownloadManager.
The IllegalArgumentException occurs when the URL contains illegal characters such as [ ]. As mentioned in the comments, you need to encode such characters using URLEncoder.
I implemented it this way in my code -
private String checkUrl(String url) {
if(url.contains("[")) {
String[] a = url.split("\\[");
String b = "[" + a[1]; //contains text after [ e.g. [DJKANG.Com].mp3
url = a[0] + URLEncoder.encode(b, "UTF-8"); // encodes illegal characters
}
return url;
}