Skip to content

Commit 9fd7a40

Browse files
DanielcoderXmarkpash
authored andcommitted
Fixed battery issue, improved VpnService performance
1 parent d2bd505 commit 9fd7a40

11 files changed

+246
-72
lines changed

app/build.gradle

-7
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,6 @@ android {
3333
kotlinOptions {
3434
jvmTarget = '1.8'
3535
}
36-
buildFeatures {
37-
compose true
38-
}
39-
composeOptions {
40-
kotlinCompilerExtensionVersion '1.4.3'
41-
}
4236
packagingOptions {
4337
resources.excludes.add("META-INF/*")
4438
}
@@ -54,7 +48,6 @@ configurations {
5448
}
5549

5650
dependencies {
57-
implementation 'androidx.activity:activity-compose:1.9.0'
5851
implementation 'androidx.appcompat:appcompat:1.7.0'
5952
implementation 'com.google.android.material:material:1.12.0'
6053
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package org.bepass.oblivion
2+
3+
import android.annotation.SuppressLint
4+
import android.app.AlertDialog
5+
import android.content.Context
6+
import android.content.Intent
7+
import android.net.Uri
8+
import android.os.Build
9+
import android.os.PowerManager
10+
import android.provider.Settings
11+
import android.view.LayoutInflater
12+
import android.widget.Button
13+
import android.widget.TextView
14+
15+
/**
16+
* Checks if the app is running in restricted background mode.
17+
* Returns true if running in restricted mode, false otherwise.
18+
*/
19+
fun isBatteryOptimizationEnabled(context: Context): Boolean {
20+
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
21+
val powerManager = context.getSystemService(Context.POWER_SERVICE) as? PowerManager
22+
powerManager?.isIgnoringBatteryOptimizations(context.packageName) == false
23+
} else {
24+
false
25+
}
26+
}
27+
28+
/**
29+
* Directly requests to ignore battery optimizations for the app.
30+
*/
31+
@SuppressLint("BatteryLife")
32+
fun requestIgnoreBatteryOptimizations(context: Context) {
33+
val intent = Intent().apply {
34+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
35+
action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
36+
data = Uri.parse("package:${context.packageName}")
37+
}
38+
}
39+
context.startActivity(intent)
40+
}
41+
42+
43+
/**
44+
* Shows a dialog explaining the need for disabling battery optimization and navigates to the app's settings.
45+
*/
46+
fun showBatteryOptimizationDialog(context: Context) {
47+
val dialogView = LayoutInflater.from(context).inflate(R.layout.dialog_battery_optimization, null)
48+
49+
val dialog = AlertDialog.Builder(context).apply {
50+
setView(dialogView)
51+
}.create()
52+
53+
dialogView.findViewById<TextView>(R.id.dialog_title).text = context.getString(R.string.batteryOpL)
54+
dialogView.findViewById<TextView>(R.id.dialog_message).text = context.getString(R.string.dialBtText)
55+
56+
dialogView.findViewById<Button>(R.id.dialog_button_positive).setOnClickListener {
57+
requestIgnoreBatteryOptimizations(context)
58+
dialog.dismiss()
59+
}
60+
61+
dialogView.findViewById<Button>(R.id.dialog_button_negative).setOnClickListener {
62+
dialog.dismiss()
63+
}
64+
65+
dialog.show()
66+
}

app/src/main/java/org/bepass/oblivion/MainActivity.java

+2-40
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
11
package org.bepass.oblivion;
22

3+
import static org.bepass.oblivion.OblivionVpnService.startVpnService;
34
import static org.bepass.oblivion.OblivionVpnService.stopVpnService;
45

56
import android.Manifest;
6-
import android.annotation.SuppressLint;
77
import android.content.Context;
88
import android.content.Intent;
99
import android.content.pm.PackageManager;
1010
import android.net.ConnectivityManager;
1111
import android.net.Network;
1212
import android.net.NetworkCapabilities;
1313
import android.net.NetworkInfo;
14-
import android.net.Uri;
1514
import android.os.Build;
1615
import android.os.Bundle;
1716
import android.os.Handler;
18-
import android.os.PowerManager;
19-
import android.provider.Settings;
2017
import android.view.View;
2118
import android.widget.FrameLayout;
2219
import android.widget.ImageView;
@@ -28,7 +25,6 @@
2825
import androidx.activity.result.ActivityResultLauncher;
2926
import androidx.activity.result.contract.ActivityResultContracts;
3027
import androidx.annotation.NonNull;
31-
import androidx.annotation.RequiresApi;
3228

3329
import com.google.android.material.floatingactionbutton.FloatingActionButton;
3430

@@ -43,12 +39,6 @@ public class MainActivity extends StateAwareBaseActivity {
4339
private long backPressedTime;
4440
private Toast backToast;
4541
private LocaleHandler localeHandler;
46-
private final ActivityResultLauncher<Intent> batteryOptimizationLauncher = registerForActivityResult(
47-
new ActivityResultContracts.StartActivityForResult(),
48-
result -> {
49-
// Do nothing, as no return value is expected
50-
});
51-
5242
private final Handler handler = new Handler();
5343

5444
@Override
@@ -70,11 +60,6 @@ protected void onCreate(Bundle savedInstanceState) {
7060
FloatingActionButton floatingActionButton = findViewById(R.id.floatingActionButton);
7161
floatingActionButton.setOnClickListener(v -> localeHandler.showLanguageSelectionDialog(()->
7262
localeHandler.restartActivity(this)));
73-
if (!isIgnoringBatteryOptimizations()) {
74-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
75-
requestIgnoreBatteryOptimizations();
76-
}
77-
}
7863
// Views
7964
ImageView infoIcon = findViewById(R.id.info_icon);
8065
ImageView logIcon = findViewById(R.id.bug_icon);
@@ -119,7 +104,7 @@ protected void onCreate(Bundle savedInstanceState) {
119104
}
120105
// Start the VPN service if it's disconnected
121106
if (lastKnownConnectionState.isDisconnected()) {
122-
OblivionVpnService.startVpnService(this);
107+
startVpnService(this);
123108
}
124109
// To check is Internet Connection is available
125110
handler.postDelayed(new Runnable() {
@@ -190,29 +175,6 @@ private void checkInternetConnectionAndDisconnectVPN() {
190175
stopVpnService(this);
191176
}
192177
}
193-
private boolean isIgnoringBatteryOptimizations() {
194-
String packageName = getPackageName();
195-
PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
196-
if (pm != null) {
197-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
198-
return pm.isIgnoringBatteryOptimizations(packageName);
199-
}
200-
}
201-
return false;
202-
}
203-
@SuppressLint("BatteryLife")
204-
@RequiresApi(api = Build.VERSION_CODES.M)
205-
private void requestIgnoreBatteryOptimizations() {
206-
try {
207-
Intent intent = new Intent();
208-
String packageName = getPackageName();
209-
intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
210-
intent.setData(Uri.parse("package:" + packageName));
211-
batteryOptimizationLauncher.launch(intent);
212-
} catch (Exception e) {
213-
Toast.makeText(this, "Unable to request ignore battery optimizations", Toast.LENGTH_SHORT).show();
214-
}
215-
}
216178
protected void cleanOrMigrateSettings() {
217179
// Get the global FileManager instance
218180
FileManager fileManager = FileManager.getInstance(getApplicationContext());

app/src/main/java/org/bepass/oblivion/OblivionVpnService.java

+38-24
Original file line numberDiff line numberDiff line change
@@ -373,53 +373,67 @@ public void onDestroy() {
373373
public void onRevoke() {
374374
setLastKnownState(ConnectionState.DISCONNECTED);
375375
Log.i(TAG, "Stopping VPN");
376+
376377
// Stop foreground service and notification
377-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
378-
NotificationManager notificationManager = getSystemService(NotificationManager.class);
379-
if (notificationManager != null) {
380-
notificationManager.deleteNotificationChannel("oblivion");
381-
}
382-
}
383378
try {
384379
stopForeground(true);
380+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
381+
NotificationManager notificationManager = getSystemService(NotificationManager.class);
382+
if (notificationManager != null) {
383+
notificationManager.deleteNotificationChannel("oblivion");
384+
}
385+
}
385386
} catch (Exception e) {
386-
e.printStackTrace();
387+
Log.e(TAG, "Error stopping foreground service and notification", e);
387388
}
388389

389390
// Release the wake lock if held
390-
if (wLock != null && wLock.isHeld()) {
391-
wLock.release();
392-
wLock = null;
391+
try {
392+
if (wLock != null && wLock.isHeld()) {
393+
wLock.release();
394+
wLock = null;
395+
}
396+
} catch (Exception e) {
397+
Log.e(TAG, "Error releasing wake lock", e);
393398
}
394399

395400
// Close the VPN interface
396-
if (mInterface != null) {
397-
try {
401+
try {
402+
if (mInterface != null) {
398403
mInterface.close();
399-
} catch (IOException e) {
400-
Log.e(TAG, "Error closing the VPN interface", e);
401404
}
405+
} catch (IOException e) {
406+
Log.e(TAG, "Error closing the VPN interface", e);
402407
}
403408

404409
// Stop Tun2socks
405-
Tun2socks.stop();
410+
try {
411+
Tun2socks.stop();
412+
} catch (Exception e) {
413+
Log.e(TAG, "Error stopping Tun2socks", e);
414+
}
406415

407416
// Shutdown executor service
408417
if (executorService instanceof ExecutorService) {
409-
((ExecutorService) executorService).shutdownNow();
410-
}
411-
412-
// Ensure all tasks are completed or terminated
413-
try {
414-
if (!((ExecutorService) executorService).awaitTermination(1, TimeUnit.SECONDS)) {
415-
Log.e(TAG, "Executor service did not terminate in the specified time.");
418+
ExecutorService service = (ExecutorService) executorService;
419+
service.shutdown(); // Attempt to gracefully shutdown
420+
try {
421+
// Wait a certain amount of time for tasks to complete
422+
if (!service.awaitTermination(500, TimeUnit.MILLISECONDS)) {
423+
service.shutdownNow(); // Forcefully terminate if tasks are not completed
424+
}
425+
} catch (InterruptedException e) {
426+
service.shutdownNow(); // Forcefully terminate if interrupted
427+
Thread.currentThread().interrupt(); // Restore interrupted status
428+
Log.e(TAG, "Executor service termination interrupted", e);
416429
}
417-
} catch (InterruptedException e) {
418-
Log.e(TAG, "Executor service termination interrupted.", e);
419430
}
431+
432+
Log.i(TAG, "VPN stopped successfully");
420433
}
421434

422435

436+
423437
private void publishConnectionState(ConnectionState state) {
424438
if (!connectionStateObservers.isEmpty()) {
425439
for (String observerKey : connectionStateObservers.keySet())

app/src/main/java/org/bepass/oblivion/SettingsActivity.java

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package org.bepass.oblivion;
22

3+
import static org.bepass.oblivion.BatteryOptimizationKt.isBatteryOptimizationEnabled;
4+
import static org.bepass.oblivion.BatteryOptimizationKt.showBatteryOptimizationDialog;
5+
36
import android.content.Context;
47
import android.content.Intent;
58
import android.os.Bundle;
6-
import android.util.Log;
79
import android.util.Pair;
810
import android.view.View;
911
import android.widget.AdapterView;
@@ -38,6 +40,16 @@ protected void onCreate(Bundle savedInstanceState) {
3840
context = this;
3941
fileManager = FileManager.getInstance(this);
4042

43+
LinearLayout batteryOptLayout = findViewById(R.id.battery_optimization_layout);
44+
LinearLayout batteryOptLine = findViewById(R.id.battery_opt_line);
45+
if(isBatteryOptimizationEnabled(this)){
46+
batteryOptLayout.setOnClickListener(view -> {
47+
showBatteryOptimizationDialog(this);
48+
});
49+
}else{
50+
batteryOptLayout.setVisibility(View.GONE);
51+
batteryOptLine.setVisibility(View.GONE);
52+
}
4153
LinearLayout endpointLayout = findViewById(R.id.endpoint_layout);
4254
LinearLayout portLayout = findViewById(R.id.port_layout);
4355
LinearLayout splitTunnelLayout = findViewById(R.id.split_tunnel_layout);

app/src/main/res/layout/activity_settings.xml

+47
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,53 @@
5757
android:layout_height="wrap_content"
5858
android:orientation="vertical">
5959

60+
<LinearLayout
61+
android:id="@+id/battery_optimization_layout"
62+
android:layout_width="match_parent"
63+
android:layout_height="80dp"
64+
android:background="?android:selectableItemBackground"
65+
android:gravity="center"
66+
android:paddingHorizontal="16dp"
67+
android:orientation="vertical">
68+
69+
<LinearLayout
70+
android:layout_width="match_parent"
71+
android:layout_height="wrap_content"
72+
android:gravity="end">
73+
74+
<TextView
75+
android:layout_width="wrap_content"
76+
android:layout_height="wrap_content"
77+
android:fontFamily="@font/shabnam"
78+
android:minWidth="100dp"
79+
android:text="@string/batteryOpL"
80+
android:textAlignment="viewEnd"
81+
android:textColor="@color/black"
82+
android:textSize="20sp" />
83+
</LinearLayout>
84+
85+
<TextView
86+
android:layout_width="match_parent"
87+
android:layout_height="wrap_content"
88+
android:layout_marginTop="4dp"
89+
android:fontFamily="@font/shabnam"
90+
android:text="@string/batteryOpLText"
91+
android:textColor="#9A9A9A"
92+
android:textSize="16sp" />
93+
94+
</LinearLayout>
95+
<LinearLayout
96+
android:id="@+id/battery_opt_line"
97+
android:layout_width="match_parent"
98+
android:layout_height="10dp"
99+
android:gravity="center"
100+
android:orientation="vertical"
101+
>
102+
<View
103+
android:layout_width="match_parent"
104+
android:layout_height="1dp"
105+
android:background="@android:color/darker_gray" />
106+
</LinearLayout>
60107
<LinearLayout
61108
android:id="@+id/endpoint_layout"
62109
android:layout_width="match_parent"

0 commit comments

Comments
 (0)