package com.codegy.aerlink.utils;
import android.Manifest;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.os.IBinder;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.wearable.activity.WearableActivity;
import android.support.wearable.view.ProgressSpinner;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.codegy.aerlink.MainService;
import com.codegy.aerlink.R;
import com.codegy.aerlink.connection.ConnectionState;
/**
* Created by Guiye on 29/5/15.
*/
public abstract class AerlinkActivity extends WearableActivity implements ServiceObserver {
private static final String LOG_TAG = AerlinkActivity.class.getSimpleName();
private final int PERMISSIONS_REQUEST_CODE = 1;
protected MainService mService;
protected boolean mServiceBound = false;
protected ConnectionState state = ConnectionState.Disconnected;
protected View mDisconnectedLayout;
protected TextView mConnectionInfoTextView;
protected boolean mLoading;
protected View mLoadingLayout;
protected ProgressSpinner mLoadingSpinner;
protected boolean mShowingError;
protected View mConnectionErrorLayout;
public boolean isConnected() {
return state == ConnectionState.Ready;
}
/***
* Request for a specific service handler
* @param serviceHandlerClass the class of the service handler requested
* @return if the service is available this returns the correct service handler,
* if not, it returns null
*/
public ServiceHandler getServiceHandler(Class serviceHandlerClass) {
ServiceHandler serviceHandler = null;
if (mService != null) {
serviceHandler = mService.getServiceHandler(serviceHandlerClass);
}
return serviceHandler;
}
@Override
protected void onResume() {
super.onResume();
if (isServiceRunning()) {
if (!mServiceBound){
Intent intent = new Intent(this, MainService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
showErrorInterface(false);
}
else if (mServiceBound) {
stopService();
}
updateInterface();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mService != null) {
mService.removeObserver(this);
}
if (mServiceBound) {
try {
unbindService(serviceConnection);
} catch (Exception ignored) {}
}
}
public void startService() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{ Manifest.permission.ACCESS_COARSE_LOCATION },
PERMISSIONS_REQUEST_CODE);
return;
}
startService(new Intent(this, MainService.class));
Intent intent = new Intent(this, MainService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
public void stopService() {
try {
unbindService(serviceConnection);
} catch (Exception ignored) {}
stopService(new Intent(this, MainService.class));
mServiceBound = false;
onConnectionStateChanged(ConnectionState.Disconnected);
}
/***
* Called on connection to device, get everything ready here, set callbacks of service handlers
*/
public abstract void onConnectedToDevice();
/***
* Called on disconnection from device, clear everything on this method related to the previously connected device
*/
public void onDisconnectedFromDevice() {
setLoading(false);
showErrorInterface(false);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == PERMISSIONS_REQUEST_CODE) {
boolean success = true;
if (grantResults.length == permissions.length) {
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
success = false;
break;
}
}
}
else {
success = false;
}
if (success) {
startService();
}
else {
stopService();
}
}
}
/**
* Update interface on this method, for example: check for connection
*/
public void updateInterface() {
if (mDisconnectedLayout != null) {
mDisconnectedLayout.setVisibility(isConnected() ? View.GONE : View.VISIBLE);
}
if (mConnectionInfoTextView != null) {
switch (state) {
case Ready:
mConnectionInfoTextView.setText(R.string.general_connected);
mConnectionInfoTextView.setTextColor(ContextCompat.getColor(this, R.color.connected));
break;
case Connecting:
mConnectionInfoTextView.setText(R.string.general_connecting);
mConnectionInfoTextView.setTextColor(ContextCompat.getColor(this, R.color.connecting));
break;
default:
mConnectionInfoTextView.setText(R.string.general_disconnected);
mConnectionInfoTextView.setTextColor(ContextCompat.getColor(this, R.color.disconnected));
break;
}
}
}
public void setLoading(boolean loading) {
if (mLoading == loading) {
return;
}
mLoading = loading;
updateLoadingInterface();
}
public void updateLoadingInterface() {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (mLoadingLayout == null || mLoadingSpinner == null) {
return;
}
if (mLoading) {
mLoadingLayout.setVisibility(View.VISIBLE);
mLoadingSpinner.showWithAnimation();
}
else {
mLoadingSpinner.hideWithAnimation(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mLoadingLayout.setVisibility(View.GONE);
}
});
}
}
});
}
public void showErrorInterface(boolean showError) {
if (mShowingError == showError) {
return;
}
mShowingError = showError;
updateErrorInterface();
}
public void updateErrorInterface() {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (mConnectionErrorLayout != null) {
mConnectionErrorLayout.setVisibility(mShowingError ? View.VISIBLE : View.GONE);
}
}
});
}
public void restartConnectionAction(View view) {
restartConnection();
showErrorInterface(false);
onConnectionStateChanged(ConnectionState.Disconnected);
}
public void restartConnection() {
if (mService == null) {
startService();
return;
}
mService.restartConnection();
}
/***
* Check if Aerlink's main service is running
* @return boolean indicating if the service is running or not
*/
public boolean isServiceRunning() {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (MainService.class.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
@Override
public void onConnectionStateChanged(ConnectionState state) {
if (this.state == state) {
return;
}
if (state == ConnectionState.Ready) {
onConnectedToDevice();
}
else if (this.state == ConnectionState.Ready) {
onDisconnectedFromDevice();
}
this.state = state;
runOnUiThread(new Runnable() {
@Override
public void run() {
updateInterface();
}
});
}
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i(LOG_TAG, "Service disconnected");
if (mService != null) {
mService.removeObserver(AerlinkActivity.this);
}
mService = null;
mServiceBound = false;
onConnectionStateChanged(ConnectionState.Disconnected);
}
@Override
public void onServiceConnected(ComponentName name, IBinder serviceBinder) {
Log.i(LOG_TAG, "Service connected");
MainService.ServiceBinder binder = (MainService.ServiceBinder) serviceBinder;
mService = binder.getService();
mServiceBound = true;
mService.addObserver(AerlinkActivity.this);
}
};
private ScheduledTask mTimeOutTask;
protected int getTimeOutPeriod() {
return 3000;
}
protected void scheduleTimeOutTask() {
if (mTimeOutTask == null) {
mTimeOutTask = new ScheduledTask(getTimeOutPeriod(), getMainLooper(), new Runnable() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
setLoading(false);
showErrorInterface(true);
}
});
}
});
}
else {
mTimeOutTask.cancel();
}
mTimeOutTask.schedule();
}
protected void cancelTimeOutTask() {
if (mTimeOutTask != null) {
mTimeOutTask.cancel();
}
}
}