6

I'm trying to override the incoming call screen - I know I can't change it so I'm trying to popup an activity ontop.

My code works fine except when the phone has been idle for a few minutes.

My code:

AndroidManifest.xml :

<?xml version="1.0" encoding="utf-8" ?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.example.myfirstapp"
      android:versionCode="7"
      android:versionName="7">
    <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="10"></uses-sdk>
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE"/>
    <uses-permission android:name="android.permission.CALL_PHONE" />

    <application android:label="@string/app_name" android:icon="@drawable/ic_launcher">
        <receiver android:name=".MyPhoneBroadcastReceiver" android:enabled="true">
            <intent-filter android:priority="99999">
                <action android:name="android.intent.action.PHONE_STATE" />
            </intent-filter>
        </receiver>
        <activity
            android:name=".Call" >
        </activity>
    </application>
</manifest>

MyPhoneBroadcastReceiver.java:

public class MyPhoneBroadcastReceiver extends BroadcastReceiver{

    public void onReceive(final Context context, Intent intent) {

        Thread pageTimer = new Thread(){
            public void run(){
                try{
                    sleep(700);
                } catch (InterruptedException e){
                    e.printStackTrace();
                } finally {
                    Intent i = new Intent();
                    i.setClass(context, Call.class);
                    i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    i.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);  
                    i.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
                    i.putExtra("INCOMING_NUMBER", incomingNumber);
                    i.setAction(Intent.ACTION_MAIN);
                    i.addCategory(Intent.CATEGORY_LAUNCHER);
                    context.startActivity(i);
                }
            }
        };
        pageTimer.start();
    }
}

Call.java:

package com.example.myfirstapp;

import android.app.Activity;
import android.os.Bundle;

public class Call extends Activity{
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow(). addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
        getWindow().addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
        getWindow().addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        setContentView(R.layout.main);
    }
}

BTW - I tried waiting for the screen to wake up before the sleep(700) and it didn't help (in MyPhoneBroadcastReceiver.java)

...
try {      
    if (pm.isScreenOn()) {
        sleep(700);
    } else {
        while (!pm.isScreenOn()) {
            // Do nothing...
        }
        sleep(700);
    }
}
...
Julian Gorfer
  • 141
  • 1
  • 9
Erez
  • 2,615
  • 2
  • 21
  • 27

1 Answers1

6

When the phone screen is off and there is an incoming call, there are more work to do (waking up, dealing with the keyguard view...) so the in-call activity take longer to show up and this lead to the case your Call activity starts earlier than the in-call activity starts --> the in-call activity is on top
There is no exact time that the in-call activity need to displays (you have tried and see that 700 miliseconds is not enough)

My solution: keep tracking the state of Call activity:

  • If it's still on top and user has not dismiss it (or any condition to dismiss), just keep tracking using the handler
  • If there is any other activity go to foreground then Call activity try to get the back to top

My sample activity:

public class MainActivity extends Activity {
    private ActivityManager mActivityManager;
    private boolean mDismissed = false;

    private static final int MSG_ID_CHECK_TOP_ACTIVITY = 1;
    private static final long DELAY_INTERVAL = 100;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Window window = getWindow();
        window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);

        mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        mHandler.sendEmptyMessageDelayed(MSG_ID_CHECK_TOP_ACTIVITY,
                DELAY_INTERVAL);
    }

    private Handler mHandler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            if (msg.what == MSG_ID_CHECK_TOP_ACTIVITY && !mDismissed) {
                List<RunningTaskInfo> tasks = mActivityManager
                        .getRunningTasks(1);
                String topActivityName = tasks.get(0).topActivity
                        .getClassName();
                if (!topActivityName.equals(MainActivity.this
                        .getComponentName().getClassName())) {
                    // Try to show on top until user dismiss this activity
                    Intent i = new Intent();
                    i.setClass(MainActivity.this, MainActivity.class);
                    i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                    i.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
                    startActivity(i);
                }
                sendEmptyMessageDelayed(MSG_ID_CHECK_TOP_ACTIVITY,
                        DELAY_INTERVAL);
            }
        };
    };

}
Binh Tran
  • 2,478
  • 1
  • 21
  • 18
  • I use your code and it works almost well. On this activity I added answering button, but when I accept call (successfully) this activity doesn't disappear. How to manage this? Thanks – Aleksandar May 06 '15 at 15:18
  • You can use this api: http://developer.android.com/reference/android/os/Handler.html#removeMessages(int) --> mHandler.removeMessage(MSG_ID_CHECK_TOP_ACTIVITY); – Binh Tran May 06 '15 at 19:03
  • This is not working. It opens the dialog activity once and the value of mDismissed becomes true then again handler is not called, and then the activity goes behind the calling screen. – Rakesh Yadav Mar 08 '17 at 11:14
  • @R.Y It depends on where you set mDismissed to true. In my answer above, it only becomes true in case user dismiss the dialog. – Binh Tran Mar 08 '17 at 13:08