package info.walltime.bitcast;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.MediaRouteButton;
import android.support.v7.media.MediaRouteSelector;
import android.support.v7.media.MediaRouter;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import com.google.android.gms.cast.ApplicationMetadata;
import com.google.android.gms.cast.Cast;
import com.google.android.gms.cast.CastDevice;
import com.google.android.gms.cast.CastMediaControlIntent;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import java.io.IOException;
public class Bitcast extends FragmentActivity {
private static final String TAG = "BITCAST";
public static final String APP_ID = "BBD7D49F";
private MediaRouter mMediaRouter;
private MediaRouteSelector mMediaRouteSelector;
private CastDevice mSelectedDevice;
private RouterCallback mMediaRouterCallback;
private GoogleApiClient mApiClient;
private boolean mWaitingForReconnect;
private GoogleApiClient.OnConnectionFailedListener mConnectionFailedListener;
private GoogleApiClient.ConnectionCallbacks mConnectionCallbacks;
private CastListener mCastClientListener;
private boolean mApplicationStarted;
private MainChannel mMainChannel;
private String mSessionId;
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mMediaRouter = MediaRouter.getInstance(getApplicationContext());
mMediaRouteSelector = new MediaRouteSelector.Builder()
.addControlCategory(CastMediaControlIntent.categoryForCast(APP_ID))
.build();
final android.support.v7.app.MediaRouteButton button
= (MediaRouteButton) findViewById(R.id.main_button);
mMediaRouterCallback = new RouterCallback();
mConnectionFailedListener = new ConnectionFailedListener();
mConnectionCallbacks = new ConnectionCallbacks();
mCastClientListener = new CastListener();
button.setRouteSelector(mMediaRouteSelector);
Button otherButton = (Button) findViewById(R.id.start);
otherButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
button.showDialog();
}
});
}
@Override
protected void onResume() {
super.onResume();
mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback,
MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
}
@Override
protected void onPause() {
if (isFinishing()) {
mMediaRouter.removeCallback(mMediaRouterCallback);
}
super.onPause();
}
private class RouterCallback extends MediaRouter.Callback {
@Override
public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) {
mSelectedDevice = CastDevice.getFromBundle(info.getExtras());
String routeId = info.getId();
Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions
.builder(mSelectedDevice, mCastClientListener);
apiOptionsBuilder.setVerboseLoggingEnabled(true);
mApiClient = new GoogleApiClient.Builder(Bitcast.this)
.addApi(Cast.API, apiOptionsBuilder.build())
.addConnectionCallbacks(mConnectionCallbacks)
.addOnConnectionFailedListener(mConnectionFailedListener)
.build();
mApiClient.connect();
}
@Override
public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) {
teardown();
mSelectedDevice = null;
}
}
private void teardown() {
Log.d(TAG, "teardown");
if (mApiClient != null) {
if (mApplicationStarted) {
if (mApiClient.isConnected()) {
try {
Cast.CastApi.stopApplication(mApiClient, mSessionId);
if (mMainChannel != null) {
Cast.CastApi.removeMessageReceivedCallbacks(
mApiClient,
mMainChannel.getNamespace());
mMainChannel = null;
}
} catch (IOException e) {
Log.e(TAG, "Exception while removing channel", e);
}
mApiClient.disconnect();
}
mApplicationStarted = false;
}
mApiClient = null;
}
mSelectedDevice = null;
mWaitingForReconnect = false;
mSessionId = null;
}
private class ConnectionCallbacks implements
GoogleApiClient.ConnectionCallbacks {
@Override
public void onConnected(Bundle connectionHint) {
if (mWaitingForReconnect) {
mWaitingForReconnect = false;
reconnectChannels();
} else {
try {
Cast.CastApi.launchApplication(mApiClient, APP_ID, false)
.setResultCallback(
new ResultCallback<Cast.ApplicationConnectionResult>() {
@Override
public void onResult(Cast.ApplicationConnectionResult result) {
Status status = result.getStatus();
if (status.isSuccess()) {
ApplicationMetadata applicationMetadata =
result.getApplicationMetadata();
mSessionId = result.getSessionId();
String applicationStatus = result.getApplicationStatus();
boolean wasLaunched = result.getWasLaunched();
launch();
} else {
teardown();
}
}
});
} catch (Exception e) {
Log.e(TAG, "Failed to launch application", e);
}
}
}
@Override
public void onConnectionSuspended(int cause) {
mWaitingForReconnect = true;
}
}
private void launch() {
mApplicationStarted = true;
mMainChannel = new MainChannel();
try {
Cast.CastApi.setMessageReceivedCallbacks(mApiClient,
mMainChannel.getNamespace(),
mMainChannel);
} catch (IOException e) {
Log.e(TAG, "Exception while creating channel", e);
}
}
private void reconnectChannels() {
// TODO
}
private class ConnectionFailedListener implements
GoogleApiClient.OnConnectionFailedListener {
@Override
public void onConnectionFailed(ConnectionResult result) {
teardown();
}
}
private class CastListener extends Cast.Listener {
@Override
public void onApplicationStatusChanged() {
if (mApiClient != null) {
Log.d(TAG, "onApplicationStatusChanged: "
+ Cast.CastApi.getApplicationStatus(mApiClient));
}
}
@Override
public void onVolumeChanged() {
if (mApiClient != null) {
Log.d(TAG, "onVolumeChanged: " + Cast.CastApi.getVolume(mApiClient));
}
}
@Override
public void onApplicationDisconnected(int errorCode) {
teardown();
}
}
class MainChannel implements Cast.MessageReceivedCallback {
public String getNamespace() {
return "urn:x-cast:info.walltime.bitcast.main";
}
@Override
public void onMessageReceived(CastDevice castDevice, String namespace,
String message) {
Log.d(TAG, "onMessageReceived: " + message);
}
}
private void sendMessage(String message) {
if (mApiClient != null && mMainChannel != null) {
try {
Cast.CastApi.sendMessage(mApiClient, mMainChannel.getNamespace(), message)
.setResultCallback(
new ResultCallback<Status>() {
@Override
public void onResult(Status result) {
if (!result.isSuccess()) {
Log.e(TAG, "Sending message failed");
}
}
});
} catch (Exception e) {
Log.e(TAG, "Exception while sending message", e);
}
}
}
}