Fix memory leak in HotspotService

This commit is contained in:
Adeel Zafar 2019-08-07 20:39:33 +05:00
parent 9b5a4894ef
commit 7a3e5c980d
4 changed files with 73 additions and 43 deletions

View File

@ -9,4 +9,6 @@ public interface ServerStateListener {
void serverStopped(); void serverStopped();
void hotspotTurnedOn(WifiConfiguration wifiConfiguration); void hotspotTurnedOn(WifiConfiguration wifiConfiguration);
void hotspotState(Boolean state);
} }

View File

@ -2,18 +2,18 @@ package org.kiwix.kiwixmobile.webserver;
import android.Manifest; import android.Manifest;
import android.app.Activity; import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender; import android.content.IntentSender;
import android.content.ServiceConnection;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration;
import android.os.Build; import android.os.Build;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder;
import android.util.Log; import android.util.Log;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.View; import android.view.View;
@ -30,7 +30,6 @@ import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction; import androidx.fragment.app.FragmentTransaction;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.google.android.gms.common.api.ApiException; import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.common.api.ResolvableApiException; import com.google.android.gms.common.api.ResolvableApiException;
import com.google.android.gms.location.LocationRequest; import com.google.android.gms.location.LocationRequest;
@ -54,19 +53,19 @@ public class ZimHostActivity extends AppCompatActivity implements
Button startServerButton; Button startServerButton;
TextView serverTextView; TextView serverTextView;
private BroadcastReceiver broadcastReceiver; boolean bound;
private boolean bound;
public static final String ACTION_TURN_ON_AFTER_O = "Turn_on_hotspot_after_oreo"; public static final String ACTION_TURN_ON_AFTER_O = "Turn_on_hotspot_after_oreo";
public static final String ACTION_TURN_OFF_AFTER_O = "Turn_off_hotspot_after_oreo"; public static final String ACTION_TURN_OFF_AFTER_O = "Turn_off_hotspot_after_oreo";
public static final String ACTION_CHECK_HOTSPOT_STATE = "Check_hotspot_state";
private final String IP_STATE_KEY = "ip_state_key"; private final String IP_STATE_KEY = "ip_state_key";
private static final int MY_PERMISSIONS_ACCESS_FINE_LOCATION = 102; private static final int MY_PERMISSIONS_ACCESS_FINE_LOCATION = 102;
private Intent serviceIntent; private Intent serviceIntent;
private Task<LocationSettingsResponse> task; private Task<LocationSettingsResponse> task;
boolean flag = false; boolean flag = false;
HotspotService hotspotService;
String ip; String ip;
String TAG = ZimHostActivity.this.getClass().getSimpleName(); String TAG = ZimHostActivity.this.getClass().getSimpleName();
ServiceConnection serviceConnection;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -85,6 +84,21 @@ public class ZimHostActivity extends AppCompatActivity implements
startServerButton.setText(getString(R.string.stop_server_label)); startServerButton.setText(getString(R.string.stop_server_label));
} }
serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
HotspotService.HotspotBinder binder = (HotspotService.HotspotBinder) service;
hotspotService = binder.getService();
bound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
bound = false;
}
};
FragmentManager fragmentManager = getSupportFragmentManager(); FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ZimFileSelectFragment fragment = new ZimFileSelectFragment(); ZimFileSelectFragment fragment = new ZimFileSelectFragment();
@ -92,22 +106,8 @@ public class ZimHostActivity extends AppCompatActivity implements
fragmentTransaction.commit(); fragmentTransaction.commit();
serviceIntent = new Intent(this, HotspotService.class); serviceIntent = new Intent(this, HotspotService.class);
Context context = this;
broadcastReceiver = new BroadcastReceiver() { bindService();
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getBooleanExtra("hotspot_state", false)) {
startService(ACTION_TURN_OFF_AFTER_O);
} else //If hotspot is not already enabled, then turn it on.
{
setupLocationServices();
}
}
};
LocalBroadcastManager.getInstance(this)
.registerReceiver(broadcastReceiver, new IntentFilter(ACTION_CHECK_HOTSPOT_STATE));
startServerButton.setOnClickListener(new View.OnClickListener() { startServerButton.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) { @Override public void onClick(View v) {
@ -130,12 +130,32 @@ public class ZimHostActivity extends AppCompatActivity implements
}); });
} }
private void bindService() {
bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}
private void unbindService() {
if (bound) {
hotspotService.registerCallBack(null); // unregister
unbindService(serviceConnection);
bound = false;
}
}
@RequiresApi(api = Build.VERSION_CODES.O) @RequiresApi(api = Build.VERSION_CODES.O)
void toggleHotspot() { void toggleHotspot() {
//Check if location permissions are granted //Check if location permissions are granted
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) { == PackageManager.PERMISSION_GRANTED) {
startService(ACTION_CHECK_HOTSPOT_STATE);
if (hotspotService.checkHotspotState(this)) //If hotspot is already enabled, turn it off
{
startService(ACTION_TURN_OFF_AFTER_O);
} else //If hotspot is not already enabled, then turn it on.
{
setupLocationServices();
}
} else { } else {
//Ask location permission if not granted //Ask location permission if not granted
ActivityCompat.requestPermissions(this, ActivityCompat.requestPermissions(this,
@ -146,8 +166,6 @@ public class ZimHostActivity extends AppCompatActivity implements
@Override protected void onResume() { @Override protected void onResume() {
super.onResume(); super.onResume();
LocalBroadcastManager.getInstance(this)
.registerReceiver(broadcastReceiver, new IntentFilter(ACTION_CHECK_HOTSPOT_STATE));
} }
// This method checks if mobile data is enabled in user's device. // This method checks if mobile data is enabled in user's device.
@ -402,6 +420,10 @@ public class ZimHostActivity extends AppCompatActivity implements
dialog.show(); dialog.show();
} }
@Override public void hotspotState(Boolean state) {
}
@Override protected void onSaveInstanceState(Bundle outState) { @Override protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
if (flag) { if (flag) {

View File

@ -9,18 +9,18 @@ import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.os.Binder;
import android.os.Build; import android.os.Build;
import android.os.IBinder; import android.os.IBinder;
import android.util.Log; import android.util.Log;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import org.kiwix.kiwixmobile.R; import org.kiwix.kiwixmobile.R;
import org.kiwix.kiwixmobile.main.MainActivity; import org.kiwix.kiwixmobile.main.MainActivity;
import org.kiwix.kiwixmobile.utils.Constants; import org.kiwix.kiwixmobile.utils.Constants;
import org.kiwix.kiwixmobile.webserver.ServerStateListener;
import static org.kiwix.kiwixmobile.webserver.ZimHostActivity.ACTION_CHECK_HOTSPOT_STATE;
import static org.kiwix.kiwixmobile.webserver.ZimHostActivity.ACTION_TURN_OFF_AFTER_O; import static org.kiwix.kiwixmobile.webserver.ZimHostActivity.ACTION_TURN_OFF_AFTER_O;
import static org.kiwix.kiwixmobile.webserver.ZimHostActivity.ACTION_TURN_ON_AFTER_O; import static org.kiwix.kiwixmobile.webserver.ZimHostActivity.ACTION_TURN_ON_AFTER_O;
import static org.kiwix.kiwixmobile.webserver.WebServerHelper.stopAndroidWebServer; import static org.kiwix.kiwixmobile.webserver.WebServerHelper.stopAndroidWebServer;
@ -37,11 +37,12 @@ public class HotspotService extends Service {
private BroadcastReceiver stopReceiver; private BroadcastReceiver stopReceiver;
private NotificationManager notificationManager; private NotificationManager notificationManager;
private NotificationCompat.Builder builder; private NotificationCompat.Builder builder;
ServerStateListener serverStateListener;
IBinder serviceBinder = new HotspotBinder();
String TAG = HotspotService.this.getClass().getSimpleName(); String TAG = HotspotService.this.getClass().getSimpleName();
@Override public void onCreate() { @Override public void onCreate() {
hotspotManager = new WifiHotspotManager(this);
super.onCreate(); super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@ -63,12 +64,6 @@ public class HotspotService extends Service {
@Override public int onStartCommand(Intent intent, int flags, int startId) { @Override public int onStartCommand(Intent intent, int flags, int startId) {
switch (intent.getAction()) { switch (intent.getAction()) {
case ACTION_CHECK_HOTSPOT_STATE:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
sendBroadcast(hotspotManager.checkHotspotState());
}
break;
case ACTION_TURN_ON_AFTER_O: case ACTION_TURN_ON_AFTER_O:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
hotspotManager.turnOnHotspot(); hotspotManager.turnOnHotspot();
@ -88,17 +83,9 @@ public class HotspotService extends Service {
} }
@Nullable @Override public IBinder onBind(Intent intent) { @Nullable @Override public IBinder onBind(Intent intent) {
return null; return serviceBinder;
} }
private void sendBroadcast(boolean success) {
Intent intent = new Intent(
ACTION_CHECK_HOTSPOT_STATE); //put the same message as in the filter you used in the activity when registering the receiver
intent.putExtra("hotspot_state", success);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
private Notification buildForegroundNotification(String status, boolean showStopButton) { private Notification buildForegroundNotification(String status, boolean showStopButton) {
Log.v(TAG, "Building notification " + status); Log.v(TAG, "Building notification " + status);
builder = new NotificationCompat.Builder(this); builder = new NotificationCompat.Builder(this);
@ -154,4 +141,23 @@ public class HotspotService extends Service {
notificationManager.createNotificationChannel(hotspotServiceChannel); notificationManager.createNotificationChannel(hotspotServiceChannel);
} }
} }
@RequiresApi(api = Build.VERSION_CODES.O)
public boolean checkHotspotState(Context context) {
if (hotspotManager == null) {
hotspotManager = new WifiHotspotManager(context);
}
return hotspotManager.checkHotspotState();
}
public class HotspotBinder extends Binder {
public HotspotService getService() {
return HotspotService.this;
}
}
public void registerCallBack(ServerStateListener myCallback) {
serverStateListener = myCallback;
}
} }

View File

@ -24,7 +24,7 @@ public class WifiHotspotManager {
private WifiManager wifiManager; private WifiManager wifiManager;
Context context; Context context;
WifiManager.LocalOnlyHotspotReservation hotspotReservation; WifiManager.LocalOnlyHotspotReservation hotspotReservation;
boolean oreoenabled = false; boolean oreoenabled;
WifiConfiguration currentConfig; WifiConfiguration currentConfig;
ServerStateListener serverStateListener; ServerStateListener serverStateListener;
String TAG = WifiHotspotManager.this.getClass().getSimpleName(); String TAG = WifiHotspotManager.this.getClass().getSimpleName();