// // Copyright 2017, 2018 Filippo "Fil" Bergamo // // This file is part of RepWifiApp. // // RepWifiApp is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // RepWifiApp is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with RepWifiApp. If not, see . // // ******************************************************************** package fil.libre.repwifiapp.activities; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.preference.PreferenceManager; import fil.libre.repwifiapp.Prefs; import fil.libre.repwifiapp.helpers.Logger; import fil.libre.repwifiapp.network.AccessPointInfo; import fil.libre.repwifiapp.network.ConnectionResult; import fil.libre.repwifiapp.network.ConnectionStatus; import fil.libre.repwifiapp.service.Channel; import fil.libre.repwifiapp.service.ConnectionManagementService; /** * Provides a base class for all activities that need to bind to the * ConnectionManagementService. */ public class ConnectionBoundActivity extends MenuEnabledActivity implements OnSharedPreferenceChangeListener { private IBinder svcBinder = null; private Channel channel = null; private ServiceConnection svcConn = null; @Override public void onStart() { super.onStart(); startConnectionService(); registerPreferenceChangeListener(); } protected boolean isServiceBound() { return (channel != null); } private void startConnectionService() { Intent startIntent = new Intent(this, ConnectionManagementService.class); startIntent.setAction(ConnectionManagementService.ACTION_VOID); startService(startIntent); if (channel != null) { Logger.logDebug("ConnectionManagementService already bound"); return; } try { if (svcConn == null) { svcConn = new ServiceConnection() { public void onServiceConnected(ComponentName className, android.os.IBinder service) { ConnectionBoundActivity.this.initChannel(service); } public void onServiceDisconnected(ComponentName className) { ConnectionBoundActivity.this.channel = null; ConnectionBoundActivity.this.svcBinder = null; } }; } Intent intentGetService = new Intent(this, ConnectionManagementService.class); if (!this.bindService(intentGetService, svcConn, Context.BIND_AUTO_CREATE)) { Logger.logError("Failed to bind to ConnectionManagementService (bindService returned false)"); return; } } catch (Exception ex) { Logger.logError("Exception while bounding to inner connectivity management service.", ex); } } private void initChannel(IBinder service) { ConnectionBoundActivity.this.svcBinder = service; ConnectionBoundActivity.this.channel = new Channel(this, new Messenger(service), new Messenger(new ResponseHandler())); ConnectionBoundActivity.this.onManagementServiceConnected(); } protected void onManagementServiceConnected() { sendCmdPrefChanged(Prefs.PREF_MONITOR_NET_STATE); } protected boolean sendCmdStartConnect(AccessPointInfo network) { if (channel == null) { return false; } return channel.sendMsg(ConnectionManagementService.CMD_START_CONNECT, network, Channel.PAYLOAD_APINFO); } protected boolean sendCmdAbortConnection() { return sendMsgIfChannelConnected(ConnectionManagementService.CMD_ABORT_CONNECTION); } protected boolean sendCmdDisconnect() { return sendMsgIfChannelConnected(ConnectionManagementService.CMD_DISCONNECT); } protected boolean sendCmdGetAvailableNetworks() { return sendMsgIfChannelConnected(ConnectionManagementService.CMD_GET_AVAILABLE_NETWORKS); } protected boolean sendCmdStartMonitoringConnectionStatus() { return sendMsgIfChannelConnected(ConnectionManagementService.CMD_START_MONITOR_CONNECTION_STATUS); } protected boolean sendCmdStopMonitoringConnectionStatus() { return sendMsgIfChannelConnected(ConnectionManagementService.CMD_STOP_MONITOR_CONNECTION_STATUS); } protected boolean requestStatusUpdate() { return sendMsgIfChannelConnected(ConnectionManagementService.CMD_STATUS_UPDATE); } protected boolean sendCmdAutoconnect() { return sendMsgIfChannelConnected(ConnectionManagementService.CMD_AUTOCONNECT); } private boolean sendCmdPrefChanged(String prefname){ if (channel == null){ return false; } Bundle b = new Bundle(); b.putString(Channel.PAYLOAD_PREFKEY, prefname); return channel.sendMsg(ConnectionManagementService.CMD_PREF_CHANGED, b, 0); } private void sendCmdUnbind() { sendMsgIfChannelConnected(ConnectionManagementService.CMD_CLIENT_UNBINDING); } private boolean sendMsgIfChannelConnected(int what) { return sendMsgIfChannelConnected(what, 0); } private boolean sendMsgIfChannelConnected(int what, int arg1) { if (channel == null) { return false; } return channel.sendMsg(what, null, arg1); } protected void onMsgStatusChange(ConnectionStatus status) { } protected void onMsgConnectionResult(ConnectionResult connres) { } protected void onMsgAvailableNetworks(AccessPointInfo[] infos) { } protected void onMsgAutoconnectReport(AccessPointInfo[] infos) { } protected void onMsgDisconnectReport(ConnectionStatus status) { } private class ResponseHandler extends Handler { public void handleMessage(Message msg) { switch (msg.what) { case ConnectionManagementService.MSG_STATUS_CHANGE: Logger.logDebug("Received status update from the management service"); ConnectionStatus c = channel.getConnectionStatusPayload(msg); onMsgStatusChange(c); break; case ConnectionManagementService.MSG_CONNECTION_RESULT: Logger.logDebug("Received connection result from management service"); ConnectionResult r = channel.getConnectionResultPayload(msg); onMsgConnectionResult(r); break; case ConnectionManagementService.MSG_AVAILABLE_NETWORKS: Logger.logDebug("Received available networks from management service"); onMsgAvailableNetworks(channel.getApinfoArrayPayload(msg)); break; case ConnectionManagementService.MSG_AUTOCONNECT_REPORT: Logger.logDebug("Received autoconnect report from management service"); onMsgAutoconnectReport(channel.getApinfoArrayPayload(msg)); break; case ConnectionManagementService.MSG_DISCONNECT_REPORT: Logger.logDebug("Received disconnect report from management service"); onMsgDisconnectReport(channel.getConnectionStatusPayload(msg)); break; default: Logger.logError("Received response from connection management service with unknown what: " + msg.what); } } } private void registerPreferenceChangeListener() { SharedPreferences prefs = PreferenceManager .getDefaultSharedPreferences(getApplicationContext()); prefs.registerOnSharedPreferenceChangeListener(this); } private void unregisterPreferenceChangeListener() { SharedPreferences prefs = PreferenceManager .getDefaultSharedPreferences(getApplicationContext()); prefs.unregisterOnSharedPreferenceChangeListener(this); } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (sharedPreferences == null) { return; } sharedPreferences.edit().commit(); Prefs.commit(getApplicationContext()); sendCmdPrefChanged(key); } protected void unbindFromService() { sendCmdUnbind(); if (svcBinder != null && svcConn != null && channel != null) { unbindService(svcConn); } } @Override protected void onStop() { super.onStop(); } @Override public void onDestroy() { unregisterPreferenceChangeListener(); unbindFromService(); super.onDestroy(); } }