从phonegap拨打电话后重新关注主要活动

时间:2012-04-25 14:33:34

标签: android cordova

我正在构建一个基于PhoneGAP的应用程序,在那里我需要拨打电话,然后在说5秒后返回我的应用程序。

关于拨打电话的部分可以正常工作。要通过呼叫而不仅仅是拨号盘打开Android,进行呼叫的代码将放在com.phonegap.api.Plugin中,看起来像

private void callNumber(String phoneNumber){
    Uri calling = Uri.parse("tel:" + phoneNumber);
    Intent callIntent = new Intent(Intent.ACTION_CALL, calling);
    this.ctx.startActivity(callIntent);
}

要重新启动应用程序,我在调用RestartTask之前启动AsyncTask。因为这段代码存在于插件中,所以我必须使用Activity.runOnUiThread来启动RestartTask,但除此之外没什么特别之处。

在RestartTask中,只实现了doInBackground方法并且它完成了所有方法,它正在休眠5秒钟,然后运行以下意图:

Intent restartIntent = new Intent(DialerPlugin.this.ctx.getBaseContext(), MainActivity.class);
restartIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
DialerPlugin.this.ctx.startActivity(restartIntent);

此处MainActivity是来自PhoneGAP的派生主类,它扩展了DroidGap

设置FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_SINGLE_TOP正是人们所说的herehere,如果活动要“重新激活”,这意味着活动当前实例化的任务是使用而不是创建新任务,并且活动将与其运行状态一起重用,而不是创建新的活动实例。当操作系统提供意图时,“旧”活动将被调用onNewIntent

然而,当电话呼叫变为活动状态时,没有任何反应,似乎意图未传递到MainActivity,直到我挂断其中一部电话。怪异。

如果我将标志更改为包含FLAG_ACTIVITY_CLEAR_TOP,则重新启动应用任务或主要活动。但是,因为这是PhoneGAP,两者都对应于重新启动应用程序,这不是我想要的。我还可以在另一项任务中将Android启动作为我的应用程序的全新实例,这是重点。

但是我无法让Android重点关注我的主要活动。我做错了什么?

谢谢!

1 个答案:

答案 0 :(得分:3)

经过多个小时的黑客攻击后,我设法解决了这个问题。 看来,一旦新的android任务获得控制权,这就是当使用内置拨号器进行呼叫时发生的事情,后台任务从任务开始,这使得调用也失去了开始新活动的特权,除非它正在开始一项新任务。

这意味着,就是AsyncTask是在调用之前从活动启动的,然后稍微睡一下以确保拨号器任务/活动是打开的,它必须启动一个新任务以获得后焦点。不能再次启动Cordova活动,因为这会有效地重启整个应用程序,因此解决方案是进行精简重启任务,立即完成。

在Cordova插件中,可以放置以下内部类:

protected class RestartTask extends AsyncTask<Void, Void, Void>{
    protected RestartTask() { }

    @Override
    protected Void doInBackground(Void... unused){
        try {
            // pass time so the built-in dialer app can make the call
            Thread.sleep(MyPlugin.restartDelay);
        }
        catch (InterruptedException localInterruptedException)
        {
            Log.d("MyPlugin", "RestartTask received an InterruptedException");
        }

        return null;
    }

    @Override
    protected void onPostExecute(Void justEyeCandy){
        super.onPostExecute(justEyeCandy);

        // Start the RestartActivity in a new task. This will snap the phone out of the built-in dialer app, which
        // has started in it's own task at this point in time. The RestartActivity gains control and finishes
        // immediately, leading control back to the activity at the top of the stack in the
        // app (where the user came from when making the call).
        Intent restartIntent = new Intent(MyPlugin.this.ctx.getApplicationContext(), RestartActivity.class);
        restartIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        MyPlugin.this.ctx.getApplicationContext().startActivity(restartIntent);
    }
}

可以通过调用:

在插件中启动此AsyncTask
this.ctx.runOnUiThread(new Runnable(){
    public void run(){
        try {
            RestartTask restartTask = new RestartTask();
            restartTask.execute();
        }
        catch (Exception e) {
            Log.d("MyPlugin", "Exploded when trying to start background task: " + e.getMessage());
        }
    }
});

AsyncTask在新任务中启动的类是:

public class RestartActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // the prototype RestartActivity there is a possibility that this will be the root activity of the app.
        // If that is the case, this activity will boot the main activity of the app in a new task, before signing off.
        // However, this is not the case for this app, as restarts are only used once a call diversion has taken place,
        // form within the app.
        if (isTaskRoot())
        {
            // Start the app before finishing
            String packageName = this.getBaseContext().getPackageName();
            Intent startAppIntent = this.getBaseContext().getPackageManager().getLaunchIntentForPackage(packageName);
            startAppIntent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
            startActivity(startAppIntent);
        }

        // Now finish, which will drop the user in to the activity that was at the top of the task stack
        finish();
    }
}