0

I have a fragment that shouldn't be opened if a user does NOT approve activation of Bluetooth, which is requested via this piece of code

    Intent mIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
        mIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 240);
            startActivityForResult(mIntent, 1);
    //Here I want to exit the method in case result is denied
getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.content,new ServerFragment()).addToBackStack(null).commit();

I've been looking in quite a few places and the only thing I've found is to use the setResult from a new activity (in my case, the onActivityResult is overridden in the calling activity since this code is within a fragment)

Any ideas?

Thanks!

EDIT: Here's a stack trace

java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=131073, result=240, data=null} to activity {bt.bt/bt.bt.MainActivity}: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
                                                                               at android.app.ActivityThread.deliverResults(ActivityThread.java:3659)
                                                                               at android.app.ActivityThread.handleSendResult(ActivityThread.java:3702)
                                                                               at android.app.ActivityThread.access$1300(ActivityThread.java:155)
                                                                               at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1366)
                                                                               at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                               at android.os.Looper.loop(Looper.java:135)
                                                                               at android.app.ActivityThread.main(ActivityThread.java:5343)
                                                                               at java.lang.reflect.Method.invoke(Native Method)
                                                                               at java.lang.reflect.Method.invoke(Method.java:372)
                                                                               at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
                                                                               at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)
                                                                            Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
Stefan
  • 700
  • 10
  • 22

3 Answers3

0

You should just return in your function after launching the intent. You then wait for the callback in onActivityResult. In this method, if the result is RESULT_OK, then you would start your fragment.

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == your_request_code_here) {
        if (resultCode != Activity.RESULT_CANCELED) {
            // start fragment
        }
    }
}

Full activity:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent mIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
                mIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 240);
                startActivityForResult(mIntent, 1);
            }
        });
    }

    @Override
    public void onPause() {
        super.onPause();
    }

    @Override
    public void onResume() {
        super.onResume();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == 1) {
            if (resultCode != Activity.RESULT_CANCELED) {

            }
        }
    }
}
Francesc
  • 25,014
  • 10
  • 66
  • 84
  • This won't work because onActivityResult is asynchronous, meaning the calling fragment won't wait for the result, it continues the execution. If I try to add a new fragment to the screen, from onActivityResult, the IllegalStateException is generated. – Stefan Mar 04 '16 at 00:43
  • Please post your code and stack trace. This is the standard way to handle these requests. – Francesc Mar 04 '16 at 00:50
  • Posted it, take a look – Stefan Mar 04 '16 at 00:57
  • Try this: in onActivityResult set a boolean to true (to indicate that you should start the fragment). Then in onResume you check that boolean, if it is true, you start the fragment, and reset the value to false. – Francesc Mar 04 '16 at 01:01
  • The problem is that I call startActivityForResult from a fragment, so onSaveInstance or onResume are not called(since the view is not paused) – Stefan Mar 04 '16 at 01:06
  • How can the view not be paused if you are starting a new activity? I'm not sure I follow. Could you post more of your code so we see the flow? – Francesc Mar 04 '16 at 01:16
  • startActivityForResult uses the built in function, it starts a dialog via Intent asking for Bluetooth to be discoverable. It's ASYNCHRONOUS, so it doesn't pause anything. It's part of the activity that hosts a fragment which calls the startActivityForResult . – Stefan Mar 04 '16 at 02:01
  • I have built a test app (see updated response above). When I click the button, onPause is called (the activity is paused while the dialog is shown). When I accept to turn on BT, onActivityResult is called, followed by onResume, as expected. If you see something different, you'll have to post your code so we can help you. – Francesc Mar 04 '16 at 02:35
  • I guess I didn't see this. Nevertheless, after trying to call replace fragment in onResume, the same IllegalStateException occurs – Stefan Mar 04 '16 at 03:06
  • Without the whole code, I can't be of any more help, maybe others will chip in. – Francesc Mar 04 '16 at 03:09
0

As in the code pasted by you, you are instantiating the fragment as soon as you called startActivityForResult(), you don't need to do it - that is causing the issue. You just have to startActivityForResult() and then in your onActivityResult() method in your activity you can instantiate your fragment if the resultCode is RESULT_OK

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == your_request_code_here) {
        if (resultCode == Activity.RESULT_OK) {

getSupportFragmentManager().beginTransaction().replace(R.id.content,new ServerFragment()).addToBackStack(null).commit();
        }
    }
}
Shadab Ansari
  • 7,022
  • 2
  • 27
  • 45
0

I think you should use BroadcastReceiver to register an event Bluetooth. In your Manifest.xml, you need to add two statement:

<uses-permission android:name="android.permission.BLUETOOTH" />
<receiver android:name=".BluetoothBroadcastReceiver"
              android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
 </intent-filter>
    </receiver>

Then you need to implement onReceive() method :

public void onReceive(Context context, Intent intent) {

    String action = intent.getAction();
    Log.d("BroadcastActions", "Action "+action+"received");
    int state;
    BluetoothDevice bluetoothDevice;

    switch(action)
    {
        case BluetoothAdapter.ACTION_STATE_CHANGED:
            state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
            if (state == BluetoothAdapter.STATE_OFF)
            {
                Toast.makeText(context, "Bluetooth is off", Toast.LENGTH_SHORT).show();
                Log.d("BroadcastActions", "Bluetooth is off");
            }
            else if (state == BluetoothAdapter.STATE_TURNING_OFF)
            {
                Toast.makeText(context, "Bluetooth is turning off", Toast.LENGTH_SHORT).show();
                Log.d("BroadcastActions", "Bluetooth is turning off");
            }
            else if(state == BluetoothAdapter.STATE_ON)
            {
getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.content,new ServerFragment()).addToBackStack(null).commit();
                Log.d("BroadcastActions", "Bluetooth is on");
            }
            break;

....
}

You can see more in this link: Android Broadcast Receiver bluetooth events catching

Community
  • 1
  • 1
NhatVM
  • 1,964
  • 17
  • 25