Piku
Piku

Reputation: 259

How to run a application in the foreground on Android versions below 5.1

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 is working in lollipop 5.1 version in lower end version it is running in background.

I need to run application in foreground in all devices, how to achieve 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 reciever:

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");

        }

    }
}

Upvotes: 4

Views: 718

Answers (1)

Hitesh Bhalala
Hitesh Bhalala

Reputation: 2870

Here are the steps to solve your problem
1) Create Receiver to listen call (PhoneStatReceiver.java)
2) Create service to show view (Ex. Timer View) above your phone call view (HBFloatingHead.java)
3) Also create timer inside HBFloatingHead service and update window layout as per timer.
4) Update your AndroidManifest.xml

Example 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) **Updated 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 commented in 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" />

Upvotes: 4

Related Questions