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(); } } }