0

I am using a Sinch tutorial(https://github.com/sinch/android-app-app-calling-headers) as a framework for an app I am trying to develop. The following is the login class from the tutorial which I have updated and been successful in initializing the sinch client.

public class LoginActivity extends BaseActivity implements SinchService.StartFailedListener {

private Button mLoginButton;
private EditText mLoginName;
private static final int REQUEST_PERMISSION = 10;

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

    mLoginName = (EditText) findViewById(R.id.loginName);
    mLoginButton = (Button) findViewById(R.id.loginButton);
    mLoginButton.setEnabled(false);

    requestAppPermissions(new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.ACCESS_FINE_LOCATION}, R.string.msg,  REQUEST_PERMISSION);
    mLoginButton.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            loginClicked();
        }
    });

}

@Override
public void onPermissionGranted(int requestCode) {

}

@Override
protected void onServiceConnected() {
    mLoginButton.setEnabled(true);
    getSinchServiceInterface().setStartListener(this);
}

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

@Override
public void onStartFailed(SinchError error) {
    Toast.makeText(this, error.toString(), Toast.LENGTH_LONG).show();
}

@Override
public void onStarted() {
    openPlaceCallActivity();
}

private void loginClicked() {
    String userName = mLoginName.getText().toString();

    if (userName.isEmpty()) {
        Toast.makeText(this, "Please enter a name", Toast.LENGTH_LONG).show();
        return;
    }

    if (!getSinchServiceInterface().isStarted()) {
        getSinchServiceInterface().startClient(userName);
    } else {
        openPlaceCallActivity();
    }
}

private void openPlaceCallActivity() {
    Intent mainActivity = new Intent(this, PlaceCallActivity.class);
    startActivity(mainActivity);
    }

}

The instantiation of the client occurs in the SinchService Class which is as follows:

 private static final String APP_KEY = "";
private static final String APP_SECRET = "";
private static final String ENVIRONMENT = "sandbox.sinch.com";
public static final String LOCATION = "LOCATION";
public static final String CALL_ID = "CALL_ID";
static final String TAG = SinchService.class.getSimpleName();

private SinchServiceInterface mSinchServiceInterface = new SinchServiceInterface();
private SinchClient mSinchClient;
private String mUserId;

private StartFailedListener mListener;

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

@Override
public void onDestroy() {
    if (mSinchClient != null && mSinchClient.isStarted()) {
        mSinchClient.terminate();
    }
    super.onDestroy();
}

private void start(String userName) {

    if (mSinchClient == null) {
        mUserId = userName;
        mSinchClient = Sinch.getSinchClientBuilder().context(getApplicationContext()).userId(userName)
                .applicationKey(APP_KEY)
                .applicationSecret(APP_SECRET)
                .environmentHost(ENVIRONMENT).build();

        mSinchClient.setSupportCalling(true);
        mSinchClient.startListeningOnActiveConnection();

        mSinchClient.addSinchClientListener(new MySinchClientListener());
        mSinchClient.getCallClient().addCallClientListener(new SinchCallClientListener());
        mSinchClient.start();
    }
}

private void stop() {
    if (mSinchClient != null) {
        mSinchClient.terminate();
        mSinchClient = null;
    }
}

private boolean isStarted() {
    return (mSinchClient != null && mSinchClient.isStarted());
}

@Override
public IBinder onBind(Intent intent) {
    return mSinchServiceInterface;
}

public class SinchServiceInterface extends Binder {

    public Call callPhoneNumber(String phoneNumber) {
        return mSinchClient.getCallClient().callPhoneNumber(phoneNumber);
    }

    public Call callUser(String userId) {
        return mSinchClient.getCallClient().callUser(userId);
    }

    public Call callUser(String userId, Map<String, String> headers) {
        return mSinchClient.getCallClient().callUser(userId, headers);
    }

    public String getUserName() {
        return mUserId;
    }

    public boolean isStarted() {
        return SinchService.this.isStarted();
    }

    public void startClient(String userName) {
        start(userName);
    }

    public void stopClient() {
        stop();
    }

    public void setStartListener(StartFailedListener listener) {
        mListener = listener;
    }

    public Call getCall(String callId) {
        return mSinchClient.getCallClient().getCall(callId);
    }
}

public interface StartFailedListener {
    void onStartFailed(SinchError error);

    void onStarted();
}

private class MySinchClientListener implements SinchClientListener {

    @Override
    public void onClientFailed(SinchClient client, SinchError error) {
        if (mListener != null) {
            mListener.onStartFailed(error);
        }
        mSinchClient.terminate();
        mSinchClient = null;
    }

    @Override
    public void onClientStarted(SinchClient client) {
        Log.d(TAG, "SinchClient started");
        if (mListener != null) {
            mListener.onStarted();
        }
    }

    @Override
    public void onClientStopped(SinchClient client) {
        Log.d(TAG, "SinchClient stopped");
    }

    @Override
    public void onLogMessage(int level, String area, String message) {
        switch (level) {
            case Log.DEBUG:
                Log.d(area, message);
                break;
            case Log.ERROR:
                Log.e(area, message);
                break;
            case Log.INFO:
                Log.i(area, message);
                break;
            case Log.VERBOSE:
                Log.v(area, message);
                break;
            case Log.WARN:
                Log.w(area, message);
                break;
        }
    }

    @Override
    public void onRegistrationCredentialsRequired(SinchClient client,
            ClientRegistration clientRegistration) {
    }
}

private class SinchCallClientListener implements CallClientListener {

    @Override
    public void onIncomingCall(CallClient callClient, Call call) {
        Log.d(TAG, "Incoming call");
        Intent intent = new Intent(SinchService.this, IncomingCallScreenActivity.class);
        intent.putExtra(CALL_ID, call.getCallId());
        intent.putExtra(LOCATION, call.getHeaders().get("location"));
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        SinchService.this.startActivity(intent);
       }
   }

}

For my purposes, I need to derive the username for the client from my shared preferences folder. I made a dummy app that uses the same framework above with the addition of shared preferences but I always get a NullPointerException error. The following is my login class from my dummy app.

   public class LoginActivity extends BaseActivity implements SinchService.StartFailedListener {

private EditText mLoginName, recipientName, coordinateA, coordinateB;
private Button loginButton;
private static final int REQUEST_PERMISSION = 10;
public static final String DEFAULT = "N/A";


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_login);
    userName = (EditText) findViewById(R.id.userInput);
    recipientName = (EditText) findViewById(R.id.recipientInput);
    loginButton = (Button) findViewById(R.id.loginButton);
    requestAppPermissions(new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.ACCESS_FINE_LOCATION}, R.string.msg,  REQUEST_PERMISSION);

    SharedPreferences sharedPreferences = getSharedPreferences("MyData", MODE_PRIVATE);
    SharedPreferences.Editor editor = sharedPreferences.edit();
    editor.putString("user_name", mLoginName.getText().toString());
    editor.putString("recipient_name", recipientName.getText().toString());
    editor.commit();

    loginButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            loginClicked();
        }
    });

}

@Override
public void onPermissionGranted(int requestCode) {

}

@Override
protected void onServiceConnected() {
    getSinchServiceInterface().setStartListener(this);
}

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

@Override
public void onStartFailed(SinchError error) {
    Toast.makeText(this, error.toString(), Toast.LENGTH_LONG).show();
}

@Override
public void onStarted() {
    openPlaceCallActivity();
}

private void loginClicked() {
    SharedPreferences sharedPreferences = getSharedPreferences("MyData", MODE_PRIVATE);
    String userName = sharedPreferences.getString("user_name", DEFAULT);

     if (userName.isEmpty()) {
        Toast.makeText(this, "Please enter a name", 
        Toast.LENGTH_LONG).show();
        return;
    }  

    if (!getSinchServiceInterface().isStarted()) {
        getSinchServiceInterface().startClient(userName);
    } else {
        openPlaceCallActivity();

    }
}
private void openPlaceCallActivity() {
    Intent mainActivity = new Intent(LoginActivity.this, PlaceCallActivity.class);
    startActivity(mainActivity);
    }

}

When comparing my login class with the tutorial's login class-- the only difference is where the variable "userName" is derived. We both have a value attached to the username; however, only one client is able to establish while the other throws a NullPointerException Error. Anyone know why?

EDIT: The error message is as follows:

E/AndroidRuntime: FATAL EXCEPTION: main
              Process: com.example.dejon_000.sinchtest2, PID: 32470
              java.lang.NullPointerException: Attempt to invoke virtual method 'boolean com.example.dejon_000.sinchtest2.SinchService$SinchServiceInterface.isStarted()' on a null object reference
                  at com.example.dejon_000.sinchtest2.LoginActivity.loginClicked(LoginActivity.java:83)
                  at com.example.dejon_000.sinchtest2.LoginActivity.access$000(LoginActivity.java:17)
                  at com.example.dejon_000.sinchtest2.LoginActivity$1.onClick(LoginActivity.java:47)
                  at android.view.View.performClick(View.java:4802)
                  at android.view.View$PerformClick.run(View.java:20059)
                  at android.os.Handler.handleCallback(Handler.java:739)
                  at android.os.Handler.dispatchMessage(Handler.java:95)
                  at android.os.Looper.loop(Looper.java:135)
                  at android.app.ActivityThread.main(ActivityThread.java:5422)
                  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:914)
                  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:707)

SECOND EDIT: The getSinchServiceInterface() method is found in the BaseActivity class. It is as follows:

public abstract class BaseActivity extends Activity implements ServiceConnection {

private SparseIntArray mErrorString;
public static final String DEFAULT = "N/A";
private SinchService.SinchServiceInterface mSinchServiceInterface;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getApplicationContext().bindService(new Intent(this, SinchService.class), this,
            BIND_AUTO_CREATE);
    mErrorString = new SparseIntArray();
}

@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
    if (SinchService.class.getName().equals(componentName.getClassName())) {
        mSinchServiceInterface = (SinchService.SinchServiceInterface) iBinder;
        onServiceConnected();
    }
}

@Override
public void onServiceDisconnected(ComponentName componentName) {
    if (SinchService.class.getName().equals(componentName.getClassName())) {
        mSinchServiceInterface = null;
        onServiceDisconnected();
    }
}

protected void onServiceConnected() {
    // for subclasses
}

protected void onServiceDisconnected() {
    // for subclasses
}

protected SinchService.SinchServiceInterface getSinchServiceInterface() {
    return mSinchServiceInterface;
}

public abstract void onPermissionGranted(int requestCode);

public void requestAppPermissions(final String[] requestedPermissions, final int stringId, final int requestCode) {
    mErrorString.put(requestCode, stringId);

    int permissionCheck = PackageManager.PERMISSION_GRANTED;
    boolean showRequestPermissions = false;
    for (String permission : requestedPermissions) {
        permissionCheck = permissionCheck + ContextCompat.checkSelfPermission(this, permission);
        showRequestPermissions = showRequestPermissions || ActivityCompat.shouldShowRequestPermissionRationale(this, permission);
    }

    if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
        if (showRequestPermissions) {
            Snackbar.make(findViewById(android.R.id.content), stringId, Snackbar.LENGTH_INDEFINITE).setAction("GRANT", new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    ActivityCompat.requestPermissions(BaseActivity.this, requestedPermissions, requestCode);

                }
            }).show();
        } else {
            ActivityCompat.requestPermissions(this, requestedPermissions, requestCode);
        }

    } else {
        onPermissionGranted(requestCode);
    }

}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    int permissionCheck = PackageManager.PERMISSION_GRANTED;
    for(int permission : grantResults){
        permissionCheck = permissionCheck + permission;
    }
    if((grantResults.length > 0)&& PackageManager.PERMISSION_GRANTED == permissionCheck ){
        onPermissionGranted(requestCode);

    }else{
        Snackbar.make(findViewById(android.R.id.content), mErrorString.get(requestCode), Snackbar.LENGTH_INDEFINITE).setAction("ENABLE", new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent i = new Intent();
                i.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                i.setData(Uri.parse("package:"+ getPackageName()));
                i.addCategory(Intent.CATEGORY_DEFAULT);
                i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
                i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                startActivity(i);
            }
        }).show();
    }

   }

 }
Wdej
  • 1
  • 5
  • 1
    Possible duplicate of [What is a NullPointerException, and how do I fix it?](http://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it) – Pier Giorgio Misley Dec 23 '16 at 21:37
  • 1
    i'm kinda annoyed about all the nullpointerException which are not even tried to be solved reading what the exception says.. btw getSinchServiceInterface is null when u call the isStarted() method on it.. – Pier Giorgio Misley Dec 23 '16 at 21:38
  • I read the error message and see that the error is being thrown with the isStarted()method- I understand it is Null at that point, but I don't know why – Wdej Dec 23 '16 at 21:41
  • because your method getSinchServiceInterface() returns null – Pier Giorgio Misley Dec 23 '16 at 21:41
  • When I initialize the Sinch Client with a username straight from edittext layout getSinchServiceInterface is not null. I am asking why getSinchServiceInterface is null when I create a username through accessing my shared preferences. – Wdej Dec 23 '16 at 21:44
  • I can't tell you because you didn't post this method. anyway the nullpointer can be resolved by debugging.. if you stop debug inside the method you see all variables values.. – Pier Giorgio Misley Dec 23 '16 at 21:46
  • Thanks for your help, I am somewhat new to programming. The getSinchServiceInterface() is posted above in the second block of code. The different derivations of the username variable is found in the loginClicked() method in the first and third block of code. – Wdej Dec 23 '16 at 21:52
  • don't worry, it's a long day this one. anyway sorry but I don't really see this method getSinchServiceInterface() i'm using find in page but I don't see it.. – Pier Giorgio Misley Dec 23 '16 at 22:02
  • My apologies, the getSinchServiceInterface() is found in the BaseActivity class. I added it in the second edit. – Wdej Dec 23 '16 at 22:15

1 Answers1

0

Try this :

on your BaseActivity.java

instead of

protected void onServiceConnected() {
// for subclasses
}

put

protected void onServiceConnected(IBinder iBinder) {
mSinchServiceInterface = (SinchService.SinchServiceInterface) iBinder;
}

and in your LoginActivity.java

Override the function onServiceConnected(IBinder iBinder)

@Override
protected void onServiceConnected(IBinder iBinder) {
   super.onServiceConnected(iBinder);
   getSinchServiceInterface().setStartListener(this);
}