How Android 5.1 and below run applications in the foreground
I have implemented a small timer application and it is starting whenever I received a call, Like after receiving an incoming call I am starting my timer application and displaying timer in foreground.
But it works in the lollipop 5.1 version, in the low-end version running in the background.
I need to run the app in the foreground of all devices, how do I do this?
My code:
Intent it = new Intent("intent.my.action");
it.setComponent(new ComponentName(context.getPackageName(), timer.class.getName()));
it.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.getApplicationContext().startActivity(it);
My Recipients:
public class CallerToActivity extends BroadcastReceiver {
static boolean wasRinging = false;
static boolean finish = false;
SessionManager session;
private boolean enable;
public void onReceive(Context context, Intent intent) {
session = new SessionManager(context);
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
enable = session. Is_Enabled();
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
Log.d("Status", "Phone is Ringing");
} else if (state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
Intent it = new Intent("intent.my.action");
it.putExtra("Call", "true");
it.setComponent(new ComponentName(context.getPackageName(), timer.class.getName()));
it.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.getApplicationContext().startActivity(it);
} else if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
Call Dropped or rejected
Toast.makeText(context, "phone is neither ringing nor in a call",
Toast.LENGTH_SHORT).show();
wasRinging = false;
finish = true;
System.exit(0);
Log.d("Status", "Phone is dropped");
}
}
}
Solution
Here are the steps to
resolve the issue
1) Create a Receiver listener call (PhoneStatReceiver.java
).
2) Create a service to display View (such as a timer View
) above your phone call View (HBFloatingHead.java).
3) Also create a timer in the HBFloatingHead service and update the window layout based on the timer.
4) Update your AndroidManifest .xml
Sample code:
1) PhoneStatReceiver.java
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import android.util.Log;
public class PhoneStatReceiver extends BroadcastReceiver{
private static final String TAG = "PhoneStatReceiver";
private static MyPhoneStateListener phoneListener = new MyPhoneStateListener();
private static boolean incomingFlag = false;
private static String incoming_number = null;
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)){
incomingFlag = false;
String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Log.i(TAG, "call OUT:"+phoneNumber);
startService(context);
}else{
TelephonyManager tm =
(TelephonyManager)context.getSystemService(Service.TELEPHONY_SERVICE);
switch (tm.getCallState()) {
case TelephonyManager.CALL_STATE_RINGING:
incomingFlag = true;
incoming_number = intent.getStringExtra("incoming_number");
Log.i(TAG, "RINGING :"+ incoming_number);
startService(context);
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
if(incomingFlag){
Log.i(TAG, "incoming ACCEPT :"+ incoming_number);
}
break;
case TelephonyManager.CALL_STATE_IDLE:
if(incomingFlag){
Log.i(TAG, "incoming IDLE");
}
break;
}
}
}
public void startService(Context context){
Intent intent = new Intent(context, HBFloatingHead.class);
context.startService(intent);
}
}
2) **Update HBFloatingHead.java**
import android.app.Service;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.Binder;
import android.os.CountDownTimer;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.widget.TextView;
public class HBFloatingHead extends Service {
private WindowManager mhbWindow;
private TextView mfloatingHead;
private Intent intent;
public static final String BROADCAST_ACTION = "com.fragmentsample";
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
HBFloatingHead getService() {
return HBFloatingHead.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onDestroy() {
super.onDestroy();
if (mfloatingHead != null) {
mhbWindow.removeView(mfloatingHead);
countDownTimer.cancel();
}
}
WindowManager.LayoutParams params;
@Override
public void onCreate() {
super.onCreate();
intent = new Intent(BROADCAST_ACTION);
mhbWindow = (WindowManager) getSystemService(WINDOW_SERVICE);
mfloatingHead = new TextView(this);
mfloatingHead.setBackgroundResource(R.drawable.floating4);
mfloatingHead.setTextColor(Color.WHITE);
mfloatingHead.setTextSize(20f);
mfloatingHead.setHint("00.00 sec");
mfloatingHead.setGravity(Gravity.CENTER);
mfloatingHead.setPadding(20, 20, 20, 20);
params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.TOP | Gravity.LEFT;
params.x = 0;
params.y = 100;
mhbWindow.addView(mfloatingHead, params);
try {
mfloatingHead.setOnTouchListener(new View.OnTouchListener() {
private WindowManager.LayoutParams paramsF = params;
private int initialX;
private int initialY;
private float initialTouchX;
private float initialTouchY;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_DOWN:
initialX = paramsF.x;
initialY = paramsF.y;
initialTouchX = event.getRawX();
initialTouchY = event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
paramsF.x = initialX
+ (int) (event.getRawX() - initialTouchX);
paramsF.y = initialY
+ (int) (event.getRawY() - initialTouchY);
mhbWindow.updateViewLayout(mfloatingHead, paramsF);
break;
default:
break;
}
return false;
}
});
} catch (Exception e) {
Log.e("#HB#", e.getMessage().toString());
}
mfloatingHead.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
HBFloatingHead.this.stopSelf();
}
});
startTimer(1);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
android.os.Handler handler = new android.os.Handler(new android.os.Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
try {
long seconds = msg.what;
String text = String.format("%02d", seconds / 60) + ":"
+ String.format("%02d", seconds % 60);
Log.e("TAG", "Updated text : " + text);
mfloatingHead.setText(text);
mhbWindow.updateViewLayout(mfloatingHead, params);
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
});
CountDownTimer countDownTimer;
private void startTimer(final int minuti) {
countDownTimer = new CountDownTimer(60 * minuti * 1000, 500) {
@Override
public void onTick(long millisUntilFinished) {
int seconds = (int) (millisUntilFinished / 1000);
if (seconds > 0)
handler.sendEmptyMessage(seconds);
else
HBFloatingHead.this.stopSelf();
Log.d("TIME", mTvTime.getText().toString());
}
@Override
public void onFinish() {
}
};
countDownTimer.start();
}
}
3) Create your layout as annotated in the HBFloatingService class
4) Update your AndroidManifest .xml
Add permissions
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"> </uses-permission>
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"></uses-permission>
Declare your Android components
<receiver android:name=". PhoneStatReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
<service
android:name=". HBFloatingHead"
android:exported="true" />