From 7a3e5c980dc6ddbc238ab22205d11d6732843445 Mon Sep 17 00:00:00 2001 From: Adeel Zafar Date: Wed, 7 Aug 2019 20:39:33 +0500 Subject: [PATCH] Fix memory leak in HotspotService --- .../webserver/ServerStateListener.java | 2 + .../webserver/ZimHostActivity.java | 70 ++++++++++++------- .../wifi_hotspot/HotspotService.java | 42 ++++++----- .../wifi_hotspot/WifiHotspotManager.java | 2 +- 4 files changed, 73 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/org/kiwix/kiwixmobile/webserver/ServerStateListener.java b/app/src/main/java/org/kiwix/kiwixmobile/webserver/ServerStateListener.java index 2819a11f6..15d13ed3a 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/webserver/ServerStateListener.java +++ b/app/src/main/java/org/kiwix/kiwixmobile/webserver/ServerStateListener.java @@ -9,4 +9,6 @@ public interface ServerStateListener { void serverStopped(); void hotspotTurnedOn(WifiConfiguration wifiConfiguration); + + void hotspotState(Boolean state); } diff --git a/app/src/main/java/org/kiwix/kiwixmobile/webserver/ZimHostActivity.java b/app/src/main/java/org/kiwix/kiwixmobile/webserver/ZimHostActivity.java index 6870c14ce..69bee17b3 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/webserver/ZimHostActivity.java +++ b/app/src/main/java/org/kiwix/kiwixmobile/webserver/ZimHostActivity.java @@ -2,18 +2,18 @@ package org.kiwix.kiwixmobile.webserver; import android.Manifest; import android.app.Activity; -import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; -import android.content.IntentFilter; import android.content.IntentSender; +import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.wifi.WifiConfiguration; import android.os.Build; import android.os.Handler; +import android.os.IBinder; import android.util.Log; import android.view.KeyEvent; import android.view.View; @@ -30,7 +30,6 @@ import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.fragment.app.FragmentManager; 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.ResolvableApiException; import com.google.android.gms.location.LocationRequest; @@ -54,19 +53,19 @@ public class ZimHostActivity extends AppCompatActivity implements Button startServerButton; TextView serverTextView; - private BroadcastReceiver broadcastReceiver; - private boolean bound; + boolean bound; 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_CHECK_HOTSPOT_STATE = "Check_hotspot_state"; private final String IP_STATE_KEY = "ip_state_key"; private static final int MY_PERMISSIONS_ACCESS_FINE_LOCATION = 102; private Intent serviceIntent; private Task task; boolean flag = false; + HotspotService hotspotService; String ip; String TAG = ZimHostActivity.this.getClass().getSimpleName(); + ServiceConnection serviceConnection; @Override protected void onCreate(Bundle savedInstanceState) { @@ -85,6 +84,21 @@ public class ZimHostActivity extends AppCompatActivity implements 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(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); ZimFileSelectFragment fragment = new ZimFileSelectFragment(); @@ -92,22 +106,8 @@ public class ZimHostActivity extends AppCompatActivity implements fragmentTransaction.commit(); serviceIntent = new Intent(this, HotspotService.class); - Context context = this; - broadcastReceiver = new BroadcastReceiver() { - - @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)); + bindService(); startServerButton.setOnClickListener(new View.OnClickListener() { @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) void toggleHotspot() { //Check if location permissions are granted if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == 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 { //Ask location permission if not granted ActivityCompat.requestPermissions(this, @@ -146,8 +166,6 @@ public class ZimHostActivity extends AppCompatActivity implements @Override protected void 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. @@ -402,6 +420,10 @@ public class ZimHostActivity extends AppCompatActivity implements dialog.show(); } + @Override public void hotspotState(Boolean state) { + + } + @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); if (flag) { diff --git a/app/src/main/java/org/kiwix/kiwixmobile/wifi_hotspot/HotspotService.java b/app/src/main/java/org/kiwix/kiwixmobile/wifi_hotspot/HotspotService.java index 21a8c5ed8..9aa0ed9ce 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/wifi_hotspot/HotspotService.java +++ b/app/src/main/java/org/kiwix/kiwixmobile/wifi_hotspot/HotspotService.java @@ -9,18 +9,18 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.os.Binder; import android.os.Build; import android.os.IBinder; import android.util.Log; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.core.app.NotificationCompat; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; import org.kiwix.kiwixmobile.R; import org.kiwix.kiwixmobile.main.MainActivity; 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_ON_AFTER_O; import static org.kiwix.kiwixmobile.webserver.WebServerHelper.stopAndroidWebServer; @@ -37,11 +37,12 @@ public class HotspotService extends Service { private BroadcastReceiver stopReceiver; private NotificationManager notificationManager; private NotificationCompat.Builder builder; + ServerStateListener serverStateListener; + IBinder serviceBinder = new HotspotBinder(); String TAG = HotspotService.this.getClass().getSimpleName(); @Override public void onCreate() { - hotspotManager = new WifiHotspotManager(this); super.onCreate(); 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) { 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: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { hotspotManager.turnOnHotspot(); @@ -88,17 +83,9 @@ public class HotspotService extends Service { } @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) { Log.v(TAG, "Building notification " + status); builder = new NotificationCompat.Builder(this); @@ -154,4 +141,23 @@ public class HotspotService extends Service { 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; + } } diff --git a/app/src/main/java/org/kiwix/kiwixmobile/wifi_hotspot/WifiHotspotManager.java b/app/src/main/java/org/kiwix/kiwixmobile/wifi_hotspot/WifiHotspotManager.java index 392c69050..eab6201c5 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/wifi_hotspot/WifiHotspotManager.java +++ b/app/src/main/java/org/kiwix/kiwixmobile/wifi_hotspot/WifiHotspotManager.java @@ -24,7 +24,7 @@ public class WifiHotspotManager { private WifiManager wifiManager; Context context; WifiManager.LocalOnlyHotspotReservation hotspotReservation; - boolean oreoenabled = false; + boolean oreoenabled; WifiConfiguration currentConfig; ServerStateListener serverStateListener; String TAG = WifiHotspotManager.this.getClass().getSimpleName();