get Intent Extra from clicking notification through Firebase - java

Notification come up in notification center with image (even app is closed | app is in background) and whenever I click notification, the activity open it but no intent data.
I always get null whenever I try to get intent extra. No matter I try hard to pass data through Bundle or directly passing in intent.setExtra, I always get null.
I have a Firebase handler class
public class MyFirebaseInstanceService extends FirebaseMessagingService {
#Override
public void onNewToken(String s) {
super.onNewToken(s);
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
//super.onMessageReceived(remoteMessage);
String msg = remoteMessage.getNotification().getBody();
String title = remoteMessage.getNotification().getTitle();
String channel = remoteMessage.getNotification().getChannelId();
Holder holder = new Holder();
holder.setTitle(title);
holder.setMsg(msg);
holder.setChannel(channel);
if (remoteMessage.getData().size() > 0) {
Map<String, String> params = remoteMessage.getData();
holder.setId(params.get("id"));
holder.setImgUrl(params.get("imgurl"));
holder.setType(params.get("type"));
} else {
int r = new Random().nextInt();
holder.setId(r + "");
holder.setType("bigtext");
}
sendMyNotification(holder, remoteMessage);
}
private void sendMyNotification(Holder holder, RemoteMessage remoteMessage) {
String clickAction = remoteMessage.getNotification().getClickAction();
Intent intent = new Intent(this, NotificationReadActivity.class);
if (clickAction != null) {
if (!clickAction.isEmpty() && clickAction.length() > 5)
intent = new Intent(clickAction);
}
intent.putExtra("obj", holder);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.setAction(holder.getId() + "");
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, holder.getChannel());
notificationBuilder.setSmallIcon(R.mipmap.ic_launcher);
notificationBuilder.setAutoCancel(true);
notificationBuilder.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));
notificationBuilder.setChannelId(holder.getChannel());
if (holder.getType().equals("bigpic")) {
notificationBuilder.setStyle(new NotificationCompat.BigPictureStyle());
Bitmap bitmap = getBitmapfromUrl(holder.getImgUrl());
if (bitmap != null) {
notificationBuilder.setLargeIcon(bitmap);
}
} else {
notificationBuilder.setStyle(new NotificationCompat.BigTextStyle());
}
notificationBuilder.setContentTitle(holder.getTitle());
notificationBuilder.setContentText(holder.getMsg());
PendingIntent pendingIntent = PendingIntent.getActivity(this, holder.getId(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
notificationBuilder.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(holder.getChannel(), "Default", NotificationManager.IMPORTANCE_DEFAULT);
channel.enableLights(true);
channel.enableVibration(true);
channel.setLightColor(Color.RED);
channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
notificationManager.createNotificationChannel(channel);
}
notificationManager.notify(holder.getId(), notificationBuilder.build());
} catch (Exception ignored) {
}
}
private Bitmap getBitmapfromUrl(String imageUrl) {
try {
URL url = new URL(imageUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
return BitmapFactory.decodeStream(input);
} catch (Exception ignored) {
return null;
}
}
}
then I have a one activity
public class NotificationReadActivity extends AppCompatActivity {
TextView title, desc;
AppCompatImageView img;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_notification_read);
title = findViewById(R.id.title);
desc = findViewById(R.id.desc);
img = findViewById(R.id.img);
handleIntent(getIntent());
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
handleIntent(intent);
}
private void handleIntent(Intent intent) {
Bundle bundle = intent.getExtras();
if (intent.hasExtra("obj")) {
Holder holder = (Holder) intent.getSerializableExtra("obj");
if (holder.getType().equals("bigpic")) {
Glide.with(this).load(holder.getImgUrl()).into(img);
} else
img.setVisibility(View.GONE);
title.setText(holder.getTitle());
desc.setText(holder.getMsg());
} else if (bundle.containsKey("obj")) {
Holder holder = (Holder) bundle.getSerializable("obj");
if (holder.getType().equals("bigpic")) {
Glide.with(this).load(holder.getImgUrl()).into(img);
} else
img.setVisibility(View.GONE);
title.setText(holder.getTitle());
desc.setText(holder.getMsg());
} else {
title.setText("Null");
//finish();
}
}
}
in manifest I have also set properly
<activity
android:name=".NotificationReadActivity"
android:excludeFromRecents="true"
android:label="#string/notification_center"
android:launchMode="singleTop">
<intent-filter>
<action android:name="com.full_package.NotificationReadActivity.TARGET_NOTIFICATION" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<service
android:name=".Fcm.MyFirebaseInstanceService"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>

I have come up with the only solution is a passing string or int or any type of data other than an object in the intent will work. intent.putExtra can not handle or pass an object.
Intent intent = new Intent(this, NotificationReadActivity.class);
intent.putExtra("key1", "some string"); //this is correct
intent.putExtra("key2", 123); //this is correct
intent.putExtra("key3", any type of data); //this is correct
intent.putExtra("object", some_object); //this is in-correct

Related

After pressing record button recording starts and instantly stops in Android App

I am making my first Android App where I need to take a video of 45 secs to calculate pulse from it.
Recording video is coded the simple way, using startActivityForResult()(something similar to record video using intent). The activity to record video successfully starts but when the record button is pressed recording starts and instantly stops. I have no clue as to why. Logcat displays no error output with respect to the activity. Even, there is no mention of any of my source files in any info or error Logs in Logcat.
Here are my files
MainActivity.java
public class MainActivity extends AppCompatActivity implements SensorEventListener {
private Camera c;
private CameraView cv1;
private FrameLayout view_camera;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (!(getApplicationContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA))) {
this.finish();
System.exit(0);
}
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
VideoCapture video_capture;
Button button_symptoms = (Button)findViewById(R.id.button_symptoms);
Button button_upload_signs = (Button)findViewById(R.id.button_upload_signs);
Button button_measure_heart_rate = (Button)findViewById(R.id.button_measure_heart_rate);
Button button_measure_respiratory_rate = (Button)findViewById(R.id.button_measure_respiratory_rate);
cv1 = new CameraView(getApplicationContext(), this);
view_camera = (FrameLayout)findViewById(R.id.view_camera);
view_camera.addView(cv1);
TextView finger_on_sensor = (TextView)findViewById(R.id.text_finger_on_sensor);
finger_on_sensor.setVisibility(View.INVISIBLE);
finger_on_sensor.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View arg_view, MotionEvent arg_me) {
finger_on_sensor.setVisibility(View.INVISIBLE);
File file_video = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/video_finger.mp4");
final int VIDEO_CAPTURE = 1;
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
Intent intent_record_video = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
intent_record_video.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 45);
Uri fileUri = FileProvider.getUriForFile(MainActivity.this, "com.example.cse535a1.provider", file_video);
List<ResolveInfo> resInfoList = getApplicationContext().getPackageManager().queryIntentActivities(intent_record_video, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
String packageName = resolveInfo.activityInfo.packageName;
getApplicationContext().grantUriPermission(packageName, fileUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
intent_record_video.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
startActivityForResult(intent_record_video, VIDEO_CAPTURE);
return false;
}
});
button_symptoms.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg_view) {
Intent intent = new Intent(getApplicationContext(), Loggin_symptoms.class);
startActivity(intent);
}
});
button_upload_signs.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg_view) {
}
});
button_measure_heart_rate.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg_view) {
finger_on_sensor.setVisibility(View.VISIBLE);
}
});
button_measure_respiratory_rate.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg_view) {
SensorManager manager_sensor = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
Sensor sensor_accelerometer = manager_sensor.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
manager_sensor.registerListener(MainActivity.this, sensor_accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
}
});
}
public void setCam(Camera arg_camera) {
c = arg_camera;
}
#Override
public void onSensorChanged(SensorEvent arg_event) {
float x = arg_event.values[0];
float y = arg_event.values[1];
float z = arg_event.values[2];
Log.i("ACCELEROMETER", String.valueOf(x) + ' ' + String.valueOf(y) + ' ' + String.valueOf(z));
}
#Override
public void onAccuracyChanged(Sensor arg_sensor, int arg_accuracy) {
}
public Camera getcam() {
Camera c = null;
try { c = Camera.open(0); }
catch (Exception e) {
}
return c;
}
#Override
protected void onPause() {
super.onPause();
c.unlock();
// if (c != null) {
// c.stopPreview();
// c.release();
// c = null;
// }
}
#Override
protected void onResume() {
super.onResume();
// if (c != null) {
// c.stopPreview();
// c.release();
// c = null;
// }
// cv1 = new CameraView(getApplicationContext(), this);
// view_camera.addView(cv1);
}
#Override
protected void onDestroy() {
if (c != null) {
c.stopPreview();
c.release();
c = null;
}
super.onDestroy();
}
}
CameraView.java
public class CameraView extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder holder_surface;
private Camera camera_selected;
MainActivity act1;
public CameraView(Context arg_context, MainActivity arg_activity) {
super(arg_context);
// camera_selected = arg_camera;
act1 = arg_activity;
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
holder_surface = getHolder();
holder_surface.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
holder_surface.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder arg_holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
// Log.i("CAMNULL", "CAM IS : " + String.valueOf(camera_selected == null));
Camera c = null;
try {
c = Camera.open(0);
} catch (Exception e) {
Log.e("CAMERA", "Camera not opened");
}
act1.setCam(c);
camera_selected = c;
camera_selected.setPreviewDisplay(arg_holder);
// camera_selected.startPreview();
// Log.i("Cam", "surface creator");
} catch (IOException e) {
// Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
// if (camera_selected != null) {
// camera_selected.stopPreview();
// camera_selected.release();
// camera_selected = null;
// }
}
public void surfaceChanged(SurfaceHolder arg_holder, int arg_format, int arg_width, int arg_height) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (holder_surface.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
camera_selected.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
// start preview with new settings
try {
camera_selected.setPreviewDisplay(holder_surface);
camera_selected.startPreview();
} catch (Exception e){
// Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.cse535a1">
<uses-feature android:name="android.hardware.camera" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<application
android:requestLegacyExternalStorage="true"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.CSE535A1">
<activity android:name=".Loggin_symptoms"></activity>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.cse535a1.provider"
android:exported="false"
android:grantUriPermissions="true">
<!-- ressource file to create -->
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths">
</meta-data>
</provider>
</application>
</manifest>
I am attaching images for you convenience.
Activity started and record button is pressed (i want to record a video for 45 secs).
The next instant recording stops
File file_video = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/video_finger.mp4");
final int VIDEO_CAPTURE = 1;
// StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
// StrictMode.setVmPolicy(builder.build());
Intent intent_record_video = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
intent_record_video.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 45);
Uri fileUri = FileProvider.getUriForFile(MainActivity.this, "com.example.cse535a1.provider", file_video);
// List<ResolveInfo> resInfoList = getApplicationContext().getPackageManager().queryIntentActivities(intent_record_video, PackageManager.MATCH_DEFAULT_ONLY);
// for (ResolveInfo resolveInfo : resInfoList) {
// String packageName = resolveInfo.activityInfo.packageName;
// getApplicationContext().grantUriPermission(packageName, fileUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
// }
intent_record_video.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
startActivityForResult(intent_record_video, VIDEO_CAPTURE);
This code(in my MainActivity.java file) is similar to videobasics on Android Developers. With my experience, I will say that it will work for API level 28 and not for API level 30, don't know about API 29.

ProtocolException in MediaPlayer streaming Service (MediaHTTPConnection: readAt 20709376 / 32768 => java.net.ProtocolException)

I've made an Android app that main feature is to play audio stream from my server. But for some reason music stops playing after about 20 minutes and the app is throwing ProtocolException (logs from app on Android Studio logcat image).
Android Studio logcat
This error is even more weird because it occurs only on some devices. Error occurs on multiple Xiaomi devices (all with Android 10) and Samsung Galaxy S9 (also with Android 10) but on Samsung Galaxy S10 (Android 10) and Huawai tablet that error doesn't occur and music is being played as long as user does not stop it.
This is my PlayerService class code that is responsible for running MediaPlayer as a service:
public class PlayerService extends Service {
private static final String CHANNEL_ID = "PlayerServiceChannel";
private static final int SERVICE_ID = 1;
private MediaPlayer player;
private Notification notification;
private JsonObjectHandler jsonObjectHandler;
private int streamIndex = 9999;
private Messenger messenger;
private PendingIntent pendingIntent;
private NotificationManager notificationManager;
private PendingIntent closeApp;
private WifiManager.WifiLock wifiLock;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
JSONObject jsonObject = new JSONObject(Objects.requireNonNull(intent.getStringExtra("JsonInfo")));
jsonObjectHandler = new JsonObjectHandler(jsonObject);
} catch (JSONException e) {
jsonObjectHandler = null;
}
return START_REDELIVER_INTENT;
}
#Override
public void onCreate() {
super.onCreate();
wifiLock = ((WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE))
.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "playerServiceWiFiLock");
HandlerThread thread = new HandlerThread("ServiceStartArgument", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
Looper mServiceLooper = thread.getLooper();
ServiceHandler mServiceHandler = new ServiceHandler(mServiceLooper);
messenger = new Messenger(mServiceHandler);
PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
case TelephonyManager.CALL_STATE_OFFHOOK:
stopForeground(true);
stopSelf();
break;
case TelephonyManager.CALL_STATE_IDLE:
break;
}
super.onCallStateChanged(state, incomingNumber);
}
};
TelephonyManager mgr = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
if (mgr != null) {
mgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
}
createNotificationChannel();
Intent notificationIntent = new Intent(this, LoginActivity.class);
pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
stopSelf();
unregisterReceiver(this);
System.exit(0);
}
};
IntentFilter intentFilter = new IntentFilter("android.intent.CLOSE_APP");
registerReceiver(broadcastReceiver, intentFilter);
Intent intentClose = new Intent("android.intent.CLOSE_APP");
closeApp = PendingIntent.getBroadcast(this, 0, intentClose, 0);
updateNotification(streamIndex);
startForeground(SERVICE_ID, notification);
}
private NotificationCompat.Builder createNotification(int streamIndex) {
String defaultValue;
if (jsonObjectHandler == null || streamIndex == 9999) {
defaultValue = "";
} else {
defaultValue =
jsonObjectHandler.getPlaylistButtons().get(streamIndex).getButtonName();
}
return new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ikonastream48)
.setContentIntent(pendingIntent)
.setContentTitle(getString(R.string.app_name))
.setContentText(defaultValue)
.setDefaults(0)
.setSound(null)
.addAction(R.drawable.ic_close_black, getString(R.string.close), closeApp);
}
private void updateNotification(int streamIndex) {
notification = createNotification(streamIndex).build();
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
assert notificationManager != null;
notificationManager.notify(SERVICE_ID, notification);
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID, "Example Service Channel", NotificationManager.IMPORTANCE_DEFAULT);
serviceChannel.setSound(null, null);
notificationManager = getSystemService(NotificationManager.class);
if (notificationManager != null) {
notificationManager.createNotificationChannel(serviceChannel);
}
}
}
private void stopServicePlayer() {
if (player != null) {
player.stop();
player.reset();
player.release();
player = null;
}
stopForeground(true);
}
#Override
public void onDestroy() {
super.onDestroy();
stopServicePlayer();
if (wifiLock.isHeld()) wifiLock.release();
}
private void sendMessageBroadcast(Intent intent) {
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
if (streamIndex != 9999) {
Intent intent1 = new Intent("streamIndex");
intent1.putExtra("INDEX", streamIndex);
sendMessageBroadcast(intent1);
}
return messenger.getBinder();
}
private final class ServiceHandler extends Handler {
ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 0) {
player = new MediaPlayer();
player.setOnErrorListener((mp, what, extra) -> false);
player.setAudioAttributes(new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.setUsage(AudioAttributes.USAGE_MEDIA)
.build());
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
streamIndex = msg.arg1;
updateNotification(streamIndex);
try {
player.setOnPreparedListener(mediaPlayer -> {
mediaPlayer.start();
Intent intent = new Intent("streamIndex");
intent.putExtra("INDEX", streamIndex);
sendMessageBroadcast(intent);
});
player.setDataSource(jsonObjectHandler
.getPlaylistButtons()
.get(streamIndex)
.getButtonStreamAddress());
} catch (IOException e) {
e.printStackTrace();
}
player.prepareAsync();
if (!wifiLock.isHeld()) wifiLock.acquire();
} else if (msg.what == 1) {
Intent intent2 = new Intent("streamIndex");
intent2.putExtra("INDEX", streamIndex);
sendMessageBroadcast(intent2);
}
}
}
}
Thank you for all responses in advance!
P.S. The code was written few years ago (at the beginning of my programming journey), so I'm aware that it looks bad and need to be rewritten in better way.
Disable caches and retry :
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "audio/mp3");
headers.put("Accept-Ranges", "bytes");
headers.put("Status", "206");
headers.put("Cache-control", "no-cache");
Uri uri = Uri.parse(yourContentUrl);
player.setDataSource(getApplicationContext(), uri, headers);
The problem was on the server side. When the stream was switched from CBR to the VBR in the Lame encoder, the problem stop occurring.

Android send data to broadcast receiver

I am creating an Android app that notify the users when they received a SMS from selected numbers using Foreground Service. The program only notify the user when the Service is running. My Main Activity has 3 buttons: Start Service, Stop Service and Setting which lead to another Activity that let the user change their information such as password and selected number. Currently the application can read and write data to JSON fine and the data get pass to other activities through Intent, also the Broadcast Receiver for detecting SMS also work when a message in received, and since I want it to work with Foreground Service, I register it in onStartCommand and unregister it in onDestroy in the Service and not register it in Manifest. My problem is on how to pass the user data to the Broadcast Receiver, since it is register to listen to android.provider.Telephony.SMS_RECEIVED and when I try to pass Intent to it through sentBroadcast() in my Service, it does not receive any value of the user. I tried to settle in making the user public static and it worked, but not sure if this the right way to do it. Here is my current code:
MainActivity.java
Button btnStartService, btnStopService;
TextView lblStatus;
JSONHandler jsonHandler;//for handling JSON file and data
public static User user;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnStartService = findViewById(R.id.buttonStartService);
btnStopService = findViewById(R.id.buttonStopService);
jsonHandler = new JSONHandler(this);
boolean isFilePresent = isFilePresent(this, "user.json");
if(isFilePresent) {
try {
user = jsonHandler.readFromFile();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
} else {
user = new User();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestSmsPermission();
requestPermissions(new String[]{WRITE_EXTERNAL_STORAGE,READ_EXTERNAL_STORAGE}, 1);
}
else {
startService();
}
}
public boolean isFilePresent(Context context, String fileName) {
String path = context.getFilesDir().getAbsolutePath() + "/" + fileName;
File file = new File(path);
return file.exists();
}
public void setBtnStartService(View view)
{
startService();
}
public void setBtnStopService(View view)
{
stopService();
}
public void startService() {
Intent serviceIntent = new Intent(this, ForegroundService.class);
serviceIntent.putExtra("inputExtra", "Message Service is running");
serviceIntent.putExtra("user", user);
ContextCompat.startForegroundService(this, serviceIntent);
Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
}
public void stopService() {
Intent serviceIntent = new Intent(this, ForegroundService.class);
stopService(serviceIntent);
Toast.makeText(this, "Service Stopped", Toast.LENGTH_LONG).show();
}
public void setBtnSetting(View view) {
Intent intent = new Intent(this, AuthenticateActivity.class);
intent.putExtra("user", user);
intent.putExtra("action", "setting");
startActivity(intent);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 1) {
startService();
}
}
private void requestSmsPermission() {
String permission = Manifest.permission.RECEIVE_SMS;
int grant = ContextCompat.checkSelfPermission(this, permission);
if ( grant != PackageManager.PERMISSION_GRANTED) {
String[] permission_list = new String[1];
permission_list[0] = permission;
ActivityCompat.requestPermissions(this, permission_list, 1);
}
}
ForegroundService.java
public class ForegroundService extends Service {
public static final String CHANNEL_ID = "ForegroundServiceChannel";
SMSReceiver smsListener;
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String input = intent.getStringExtra("inputExtra");
User user = (User) intent.getSerializableExtra("user");
createNotificationChannel();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Foreground Service")
.setContentText(input)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
//do heavy work on a background thread
if(smsListener == null)
{
smsListener = new SMSReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
Intent i = new Intent(this, SMSReceiver.class);
i.putExtra("user", user);
sendBroadcast(i);
registerReceiver(smsListener, intentFilter);
}
//stopSelf();
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
if(null!=smsListener)
{
unregisterReceiver(smsListener);
smsListener = null;
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID,
"Foreground Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(serviceChannel);
}
}
}
SMSReceiver.java
public class SMSReceiver extends BroadcastReceiver {
private String msgBody;
private String text = "";
private SharedPreferences preferences;
private String sender = "";
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
// User user = (User) intent.getExtras().getSerializable("user"); not working
User user = MainActivity.user;
ArrayList<String> banks = user.getBankList();
if (intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) {
Toast.makeText(context, "message received", Toast.LENGTH_SHORT).show();
Bundle bundle = intent.getExtras();
try {
if (bundle != null) {
final Object[] pdus = (Object[]) bundle.get("pdus");
SmsMessage smsMessage;
for (int i = 0; i < pdus.length; i++) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
smsMessage = SmsMessage.createFromPdu((byte[]) pdus[i], bundle.getString("format"));
else smsMessage = SmsMessage.createFromPdu((byte[]) pdus[i]);
msgBody = smsMessage.getMessageBody();
sender = smsMessage.getOriginatingAddress();
if(banks.contains(sender)) {
if (msgBody.contains(user.getPattern())) {
String[] tokens = msgBody.split(" ");
for (int j = 0; j < tokens.length; j++) {
if (tokens[j].contains("API")) {
text = tokens[j];
break;
}
}
}
}
}
//MainActivity.message = msgBody;
if(!text.isEmpty()) {
Toast.makeText(context, "message is: " + text, Toast.LENGTH_SHORT).show();
}
}
} catch (Exception e) {
Log.d("Exception caught", e.getMessage());
}
}
else {
Log.i("cs.fsu", "smsReceiver : NULL");
}
}
}
Is this the right way to maintain user data throughout the application lifecycle? By making public static for every class accessible? Or is there away to pass it through Intent? Please help me out

BOOT_COMPLETED not worknig

I want to run my android application always in background like whatsapp,truecaller i have used all things but when device is reboot the application is stop running in background for that i have used broadcast receiver to listen boot. here is my code.
My Service
public class Myservice extends Service {
File file;
private static String fileName = null;
private MediaRecorder recorder = null;
boolean mStartRecording = true;
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
super.onDestroy();
Intent intent = new Intent("RestartService");
}
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public int onStartCommand(final Intent intent, int flags, int startId) {
onTaskRemoved(intent);
file = new File(Environment.getExternalStorageDirectory(), "pranay");
if (!file.exists()) {
boolean mkdir = file.mkdirs();
if (!mkdir) {
Toast.makeText(this, "Fialed", Toast.LENGTH_SHORT).show();
}
}
fileName = Environment.getExternalStorageDirectory().getAbsolutePath() + "/pranay/" + UUID.randomUUID().toString() + "sample.mp3";
Log.i("msg", "running");
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent =
PendingIntent.getActivity(this, 0, notificationIntent, 0);
String channel = "pranay";
NotificationChannel notificationChannel = new NotificationChannel("id", channel, NotificationManager.IMPORTANCE_NONE);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.createNotificationChannel(notificationChannel);
Notification notification = new NotificationCompat.Builder(this, "id")
.setContentTitle("sa")
.setContentText("ssa")
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
recorder.setOutputFile(fileName);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
TelephonyManager manager1 = (TelephonyManager) getApplicationContext().getSystemService(getApplicationContext().TELEPHONY_SERVICE);
manager1.listen(new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String phoneNumber) {
super.onCallStateChanged(state, phoneNumber);
if (TelephonyManager.EXTRA_STATE_IDLE.equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE))) {
cleanup();
} else if (TelephonyManager.CALL_STATE_OFFHOOK == state) {
try {
recorder.prepare();
} catch (IOException e) {
Log.e("msg", "prepare() failed");
}
recorder.start();
mStartRecording = true;
}
}
}, PhoneStateListener.LISTEN_CALL_STATE);
return super.onStartCommand(intent,flags,startId);
}
private void startForeground(Notification notification, String id) {
startForeground(notification, id);
}
private void cleanup(){
if(recorder!=null)
{
try {
recorder.stop();
}catch (Exception e){
Log.e("msg",String.valueOf(e.getMessage()));
}finally {
recorder.release();
recorder=null;
}
stopSelf();
mStartRecording = false;
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
Intent restartServiceIntent = new Intent(getApplicationContext(),this.getClass());
restartServiceIntent.setPackage(getPackageName());
startService(restartServiceIntent);
super.onTaskRemoved(rootIntent);
}
}
Broad cast receiver
public class Receiver extends BroadcastReceiver {
static final String ACTION = "android.intent.action.BOOT_COMPLETED";
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
Toast.makeText(context,"Booted",Toast.LENGTH_SHORT).show();
Intent serviceIntent = new Intent(context, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startService(serviceIntent);
}
}
Manifest
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<receiver android:name=".Receiver"
android:enabled="true"
android:exported="true"
>
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE"/>
<action android:name="RestartService"/>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<category android:name="android.intent.category.DEFAULT"/>
<action android:name="android.intent.action.QUICKBOOT_POWERON"/>
<action android:name="android.intent.action.REBOOT"/>
</intent-filter>
</receiver>
<service android:name=".Myservice"/>
I am using android 10 and pie is it working on this versions?
You can use JobService android.intent.action.BOOT_COMPLETED this method is not worked on latest version of Android.
JobService
public MyJobService extends JobService {
private Handler myHandler = new Handler(new Handler.Callback() {
#Override
public boolean handler(Message msg) {
Log.e("TAG", "Does it run after reboot? ");
return true;
}
});
#Override
public boolean onStartJob(JobParameters params) {
myHandler.sendMessage(Message.obtain(myHandler, 1, params));
return true;
}
#Override
public boolean onStopJob(JobParameters params) {
myHandler.removeMessages(1);
}
}
MainActivity
MainActivity extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle saveInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout);
ComponentName serviceComponent = new ComponentName(this,MyJobService.class);
JobInfo.Builder builder = new JobInfo.Builder(0, serviceComponent);
builder.setMinimumLatency(1 * 1000);
builder.setOverrideDeadline(5 * 1000);
builder.setPersisted(true);
JobScheduler jobScheduler = (JobScheduler) getSystemService(this.JOB_SCHEDULER_SERVICE);
jobScheduler.schedule(builder.build());
}
}
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="you.package.name">
<application
..............
>
<service
android:name=".your.package.MyJobService"
android:permission="android.permission.BIND_JOB_SERVICE" />
</mainfest>

My app keeps crashing in android 9 version throwing java.lang.SecurityException

I recently developed an android app that streams radio online using a URL. It has been working well in other android versions that is 6,7and 8 the ones i tested in emulators.
But last week i published the app to play store, and my reports show that it crashes in android 9 phones. It keeps on throwing java.lang.SecurityException.
I have tried what i could to resolve the error but i have failed.
The users keep reporting multiple app crashes on their phones
This is the stack trace from the play console
java.lang.RuntimeException:
at android.app.ActivityThread.handleServiceArgs (ActivityThread.java:3903)
at android.app.ActivityThread.access$1700 (ActivityThread.java:236)
at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1815)
at android.os.Handler.dispatchMessage (Handler.java:106)
at android.os.Looper.loop (Looper.java:214)
at android.app.ActivityThread.main (ActivityThread.java:7032)
at java.lang.reflect.Method.invoke (Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:965)
Caused by: java.lang.SecurityException:
at android.os.Parcel.createException (Parcel.java:1966)
at android.os.Parcel.readException (Parcel.java:1934)
at android.os.Parcel.readException (Parcel.java:1884)
at android.app.IActivityManager$Stub$Proxy.setServiceForeground (IActivityManager.java:5043)
at android.app.Service.startForeground (Service.java:695)
at com.premar.radiomunabuddu.RadioMediaPlayerService.play (RadioMediaPlayerService.java:120)
at com.premar.radiomunabuddu.RadioMediaPlayerService.onStartCommand (RadioMediaPlayerService.java:50)
at android.app.ActivityThread.handleServiceArgs (ActivityThread.java:3884)
Caused by: android.os.RemoteException:
at com.android.server.am.ActivityManagerService.enforcePermission (ActivityManagerService.java:12159)
at com.android.server.am.ActiveServices.setServiceForegroundInnerLocked (ActiveServices.java:1289)
at com.android.server.am.ActiveServices.setServiceForegroundLocked (ActiveServices.java:969)
at com.android.server.am.ActivityManagerService.setServiceForeground (ActivityManagerService.java:24839)
at android.app.IActivityManager$Stub.onTransact$setServiceForeground$ (IActivityManager.java:11378)
This is the HomeActivity.java
public class HomeActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
FancyButton listenRadio;
ImageView facebook, twitter, instagram, linkedin;
RadioSettings settings;
Context context;
public static final int REQUEST_CODE =123;
private Button stopButton = null;
private Button playButton = null;
private Button phoneCall;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ButterKnife.bind(this);
settings = new RadioSettings();
//views
phoneCall = (Button)this.findViewById(R.id.phoneBtn);
//Allow hardware audio buttons to control volume
setVolumeControlStream(AudioManager.STREAM_MUSIC);
clickListeners(); //Start click listeners
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
}
private void openFacebookProfile() {
try {
String facebookURL = getFacebookPageUrl();
Intent facebookIntent = new Intent(Intent.ACTION_VIEW);
facebookIntent.setData(Uri.parse(facebookURL));
startActivity(facebookIntent);
} catch (Exception e){
e.printStackTrace();
}
}
private String getFacebookPageUrl() {
final String facebookUrl = settings.getFacebookAddress();
String fbURL = null;
PackageManager packageManager = getPackageManager();
try {
if (packageManager != null){
Intent fbIntent = packageManager.getLaunchIntentForPackage("com.facebook.katana");
if (fbIntent != null){
int versionCode = packageManager.getPackageInfo("com.facebook.katana",0).versionCode;
if (versionCode >= 3002850){
fbURL = "fb://page/1993598950880589";
}
} else {
fbURL = facebookUrl;
}
}
else {
fbURL = facebookUrl;
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
fbURL = facebookUrl;
}
return fbURL;
}
private void openTwitterProfile(){
Intent intent = null;
try {
this.getPackageManager().getPackageInfo("com.twitter.android", 0);
intent = new Intent(Intent.ACTION_VIEW, Uri.parse("twitter://user?user_id=USERID"));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
} catch (Exception e){
intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://twitter.com/profilename"));
}
this.startActivity(intent);
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.home, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.watch_webcam: {
launchWebcam();
break;
}
case R.id.playstore_share: {
/*
Uri uri = Uri.parse("market://details?id=" + context.getPackageName());
Intent goToMarket = new Intent(Intent.ACTION_VIEW, uri);
// To count with Play market backstack, After pressing back button,
// to taken back to our application, we need to add following flags to intent.
goToMarket.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY |
Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
try {
startActivity(goToMarket);
} catch (ActivityNotFoundException e) {
startActivity(new Intent(Intent.ACTION_VIEW,
Uri.parse("http://play.google.com/store/apps/details?id=" + context.getPackageName())));
}
break;
*/
}
}
return super.onOptionsItemSelected(item);
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_share) {
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
String shareMessage= "\nPlease download our Radiomunnabuddu USA app from the Play Store\n\n";
shareMessage = shareMessage + "https://play.google.com/store/apps/details?id=" + BuildConfig.APPLICATION_ID +"\n\n";
shareIntent.putExtra(Intent.EXTRA_TEXT , shareMessage);
shareIntent.putExtra(Intent.EXTRA_SUBJECT, "Radio Munnabuddu USA");
startActivity(Intent.createChooser(shareIntent, "Share via..."));
}
else if (id == R.id.nav_email){
Intent emailIntent = new Intent(Intent.ACTION_SENDTO);
emailIntent.setData(Uri.parse("mailto: "+settings.getEmailAddress()));
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Radio Munnabuddu USA");
if (emailIntent.resolveActivity(getPackageManager()) != null){
startActivity(Intent.createChooser(emailIntent, "Send email via"));
}
}
else if(id == R.id.nav_report){
Intent emailIntent = new Intent(Intent.ACTION_SENDTO);
emailIntent.setData(Uri.parse("mailto: denis#premar.tech"));
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Crash or Bug report");
if (emailIntent.resolveActivity(getPackageManager()) != null){
startActivity(Intent.createChooser(emailIntent, "Send email via."));
}
}
else if(id == R.id.nav_about){
Intent aboutIntent = new Intent(HomeActivity.this, AboutActivity.class);
startActivity(aboutIntent);
}
else if(id == R.id.nav_fb){
openFacebookProfile();
}
else if(id == R.id.nav_twitter){
openTwitterProfile();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
/**
* Listens for contact button clicks
*/
private void clickListeners(){
//Play button
playButton = (Button)findViewById(R.id.PlayButton);
playButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(),
RadioMediaPlayerService.class);
intent.putExtra(RadioMediaPlayerService.START_PLAY, true);
startService(intent);
}
});
//Stop button
stopButton = (Button)findViewById(R.id.StopButton);
stopButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
//Get new MediaPlayerService activity
Intent intent = new Intent(getApplicationContext(),
RadioMediaPlayerService.class);
stopService(intent);
}
});
//Email Button click list
final View EmailPress = (Button)this.findViewById(R.id.emailBtn);
EmailPress.setOnClickListener(new View.OnClickListener() {
public void onClick(View view){
Intent emailIntent = new Intent(Intent.ACTION_SENDTO);
emailIntent.setData(Uri.parse("mailto: "+settings.getEmailAddress()));
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Radio Munnabuddu");
if (emailIntent.resolveActivity(getPackageManager()) != null){
try {
startActivity(Intent.createChooser(emailIntent, "Send email..."));
} catch (android.content.ActivityNotFoundException ex) {
Toast.makeText(HomeActivity.this, "There are no email clients installed.", Toast.LENGTH_SHORT).show();
}
}
}
});
//Website Button
final View WWWPress = (Button)this.findViewById(R.id.websiteBtn);
WWWPress.setOnClickListener(new View.OnClickListener() {
public void onClick(View view){
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(settings.getWebsiteURL())); //URL
startActivity (browserIntent);
}
});
//SMS Button
final View TxtPress = (Button)this.findViewById(R.id.txtBtn);
TxtPress.setOnClickListener(new View.OnClickListener() {
public void onClick(View view){
Uri uri = Uri.parse(settings.getSmsNumber());
Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
intent.putExtra("sms_body", "Hello Presenter,");
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
/*
if (ActivityCompat.checkSelfPermission(HomeActivity.this, Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED){
Toast.makeText(HomeActivity.this, "Please grant the permission to call", Toast.LENGTH_SHORT).show();
requestSMSPermission();
}
else {
startActivity (smsIntent);
}*/
}
});
}
/**
* Launches webcam from external URL
*/
public void launchWebcam(){
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(settings.getRadioWebcamURL()));
startActivity (browserIntent);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
switch (requestCode) {
case REQUEST_CODE:
if ((grantResults.length > 0) && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
onCall();
} else {
Log.d("TAG", "Call Permission Not Granted");
//Toast.makeText(this, "Call Permission Not Granted", Toast.LENGTH_SHORT).show();
}
return;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
public void onCall() {
int permissionCheck = ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE);
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
this,
new String[]{Manifest.permission.CALL_PHONE},
REQUEST_CODE);
} else {
phoneCall.setOnClickListener(new View.OnClickListener() {
public void onClick(View view){
/*
String phoneNum = settings.getPhoneNumber();
Intent phoneIntent = new Intent(Intent.ACTION_CALL);
phoneIntent.setData(Uri.parse("tel:"+ phoneNum));
if (phoneIntent.resolveActivity(getPackageManager()) != null) {
startActivity(phoneIntent);
}
*/
startActivity(new Intent(Intent.ACTION_CALL).setData(Uri.parse("tel:" + settings.getPhoneNumber())));
}
});
}
}
This is the RadioMediaPlayerService.java
public class RadioMediaPlayerService extends Service implements
AudioManager.OnAudioFocusChangeListener {
//Variables
private boolean isPlaying = false;
private MediaPlayer radioPlayer; //The media player instance
private static int classID = 579; // just a number
public static String START_PLAY = "START_PLAY";
AudioManager audioManager;
//Media session
MediaSession mSession;
//Settings
RadioSettings settings = new RadioSettings();
#Override
public IBinder onBind(Intent intent) {
return null;
}
/**
* Starts the streaming service
*/
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent.getBooleanExtra(START_PLAY, false)) {
play();
}
//Request audio focus
if (!requestAudioFocus()) {
//Could not gain focus
stopSelf();
}
return Service.START_STICKY;
}
#Override
public void onCreate() {
super.onCreate();
}
/**
* Starts radio URL stream
*/
private void play() {
//Check connectivity status
if (isOnline()) {
//Check if player already streaming
if (!isPlaying) {
isPlaying = true;
//Return to the current activity
Intent intent = new Intent(this, HomeActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|
Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// mSession.setSessionActivity(pi);
//Build and show notification for radio playing
Bitmap largeIcon = BitmapFactory.decodeResource(getResources(),
R.drawable.buddu3);
Notification notification = new NotificationCompat.Builder(this, "ID")
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setTicker("Radio Munnabuddu USA")
.setContentTitle(settings.getRadioName())
.setContentText(settings.getMainNotificationMessage())
.setSmallIcon(R.drawable.ic_radio_black_24dp)
//.addAction(R.drawable.ic_play_arrow_white_64dp, "Play", pi)
// .addAction(R.drawable.ic_pause_black_24dp, "Pause", pi)
.setLargeIcon(largeIcon)
.setContentIntent(pi)
.build();
//Get stream URL
radioPlayer = new MediaPlayer();
try {
radioPlayer.setDataSource(settings.getRadioStreamURL()); //Place URL here
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
radioPlayer.prepareAsync();
radioPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
radioPlayer.start(); //Start radio stream
}
});
startForeground(classID, notification);
//Display toast notification
Toast.makeText(getApplicationContext(), settings.getPlayNotificationMessage(),
Toast.LENGTH_LONG).show();
}
}
else {
//Display no connectivity warning
Toast.makeText(getApplicationContext(), "No internet connection",
Toast.LENGTH_LONG).show();
}
}
/**
* Stops the stream if activity destroyed
*/
#Override
public void onDestroy() {
stop();
removeAudioFocus();
}
/**
* Stops audio from the active service
*/
private void stop() {
if (isPlaying) {
isPlaying = false;
if (radioPlayer != null) {
radioPlayer.release();
radioPlayer = null;
}
stopForeground(true);
}
Toast.makeText(getApplicationContext(), "Radio stopped",
Toast.LENGTH_LONG).show();
}
/**
* Checks if there is a data or internet connection before starting the stream.
* Displays Toast warning if there is no connection
* #return online status boolean
*/
public boolean isOnline() {
ConnectivityManager cm =
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnectedOrConnecting()) {
return true;
}
return false;
}
#Override
public void onAudioFocusChange(int focusChange) {
//Invoked when the audio focus of the system is updated.
switch (focusChange) {
/*
case AudioManager.AUDIOFOCUS_GAIN:
// resume playback
// if (radioPlayer == null) initMediaPlayer();
if (radioPlayer.isPlaying()){
radioPlayer.release();
stopForeground(true);
}
radioPlayer.setVolume(1.0f, 1.0f);
break;*/
case AudioManager.AUDIOFOCUS_LOSS:
// Lost focus for an unbounded amount of time: stop playback and release media player
if (radioPlayer.isPlaying()) radioPlayer.stop();
radioPlayer.release();
//radioPlayer = null;
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
// Lost focus for a short time, but we have to stop
// playback. We don't release the media player because playback
// is likely to resume
if (radioPlayer.isPlaying()) radioPlayer.pause();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
// Lost focus for a short time, but it's ok to keep playing
// at an attenuated level
if (radioPlayer.isPlaying()) radioPlayer.setVolume(0.1f, 0.1f);
break;
}
}
/**
* AudioFocus
*/
private boolean requestAudioFocus() {
audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
//Focus gained
return true;
}
//Could not gain focus
return false;
}
private boolean removeAudioFocus() {
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED ==
audioManager.abandonAudioFocus(this);
}
}
This is the Manifest.xml
<!--uses-permission android:name="android.permission.SEND_SMS" /-->
<uses-permission android:name="android.permission.INTERNET" />
<!--uses-permission android:name="android.permission.CALL_PHONE" /-->
<!--tools:node="remove"-->
<uses-feature
android:name="android.hardware.telephony"
android:required="false" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<service
android:name="com.premar.radiomunabuddu.RadioMediaPlayerService"
android:enabled="true" >
</service>
<receiver android:name="com.premar.radiomunabuddu.IntentReceiver">
<intent-filter>
<action android:name="android.media.AUDIO_BECOMING_NOISY" />
</intent-filter>
</receiver>
<activity
android:name="com.premar.radiomunabuddu.HomeActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.premar.radiomunabuddu.AboutActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.premar.radiomunabuddu.HomeActivity" />
</activity>
</application>
Android 9 introduced a new FOREGROUND_SERVICE permission. From the docs:
Note: Apps that target Android 9 (API level 28) or higher and use foreground services must request the FOREGROUND_SERVICE permission. This is a normal permission, so the system automatically grants it to the requesting app.
If an app that targets API level 28 or higher attempts to create a foreground service without requesting FOREGROUND_SERVICE, the system throws a SecurityException.
Just add that permission to your manifest and you should be good to go.
The setServiceForegroundInnerLocked method will check based on the targetSdkVersion level。lack FOREGROUND_SERVICE permission
code:
if (r.appInfo.targetSdkVersion >= Build.VERSION_CODES.P) {
mAm.enforcePermission(
android.Manifest.permission.FOREGROUND_SERVICE,
r.app.pid, r.appInfo.uid, "startForeground");
}

Categories