Skip to content

Commit

Permalink
Merge pull request #300 from ivpn/feature/split-tunneling-system-apps
Browse files Browse the repository at this point in the history
Split Tunneling for system-apps
  • Loading branch information
jurajhilje authored Dec 11, 2023
2 parents 398b6b3 + 5f5447b commit d47772d
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@
along with the IVPN Android app. If not, see <https://www.gnu.org/licenses/>.
*/

import android.Manifest;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.widget.CompoundButton;

import androidx.databinding.ObservableArrayList;
import androidx.databinding.ObservableBoolean;
Expand All @@ -45,10 +47,13 @@
public class SplitTunnelingViewModel {

public final ObservableBoolean dataLoading = new ObservableBoolean();
public final ObservableBoolean showSystemApps = new ObservableBoolean();
public final ObservableBoolean isAllItemsAllowed = new ObservableBoolean();
public final ObservableArrayList<ApplicationItem> apps = new ObservableArrayList<>();
public final ObservableArrayList<ApplicationItem> systemApps = new ObservableArrayList<>();
public final ObservableArrayList<String> disallowedApps = new ObservableArrayList<String>();
public final ObservableField<SplitTunnelingRecyclerViewAdapter> adapter = new ObservableField<>();
public CompoundButton.OnCheckedChangeListener toggleSystemApps = (compoundButton, value) -> toggleSystemApps(value);
public final OnApplicationItemSelectionChangedListener selectionChangedListener = new OnApplicationItemSelectionChangedListener() {
@Override
public void onApplicationItemSelectionChanged(ApplicationItem applicationItem, boolean isSelected) {
Expand All @@ -73,10 +78,7 @@ public void onItemsSelectionStateChanged(boolean isAllItemSelected) {
this.adapter.set(adapter);
this.menuHandler = adapter.getMenuHandler();
this.preference = preference;

disallowedApps.clear();
disallowedApps.addAll(getDisallowedPackages());

reloadDisallowedApps();
isAllItemsAllowed.set(disallowedApps.size() == 0);
}

Expand All @@ -87,11 +89,25 @@ public void getApplicationsList(PackageManager packageManager) {
public void selectAll() {
allowAllPackages();
menuHandler.selectAll();
reloadDisallowedApps();
}

public void deselectAll() {
disallowAllApps(new HashSet<>(apps));
ObservableArrayList<ApplicationItem> allApps = new ObservableArrayList<>();
allApps.addAll(apps);
allApps.addAll(systemApps);
disallowAllApps(new HashSet<>(allApps));
menuHandler.deselectAll();
reloadDisallowedApps();
}

private void reloadDisallowedApps() {
disallowedApps.clear();
disallowedApps.addAll(getDisallowedPackages());
}

private void toggleSystemApps(Boolean value) {
showSystemApps.set(value);
}

private void disallowAllApps(Set<ApplicationItem> applicationItems) {
Expand Down Expand Up @@ -145,29 +161,40 @@ protected void onPreExecute() {
@Override
protected List<ApplicationItem> doInBackground(Void... voids) {
List<ApplicationItem> items = new LinkedList<>();
List<ApplicationItem> systemItems = new LinkedList<>();
Set<String> packageNames = new HashSet<>();
Set<String> systemPackageNames = new HashSet<>();
for (ApplicationInfo info : applicationInfoList) {
try {
if (null != packageManager.getLaunchIntentForPackage(info.packageName) ||
null != packageManager.getLeanbackLaunchIntentForPackage(info.packageName) ||
null != packageManager.getInstallerPackageName(info.packageName)
) {
if (packageNames.add(info.loadLabel(packageManager).toString())) {
items.add(new ApplicationItem(info.loadLabel(packageManager).toString(), info.packageName,
if (PackageManager.PERMISSION_GRANTED == packageManager.checkPermission(Manifest.permission.INTERNET, info.packageName)) {
if ((null != packageManager.getLaunchIntentForPackage(info.packageName) ||
null != packageManager.getLeanbackLaunchIntentForPackage(info.packageName) ||
null != packageManager.getInstallerPackageName(info.packageName) &&
(info.flags & ApplicationInfo.FLAG_SYSTEM) == 0)
) {
if (packageNames.add(info.loadLabel(packageManager).toString())) {
items.add(new ApplicationItem(info.loadLabel(packageManager).toString(), info.packageName,
info.loadIcon(packageManager)));
}
}
if (systemPackageNames.add(info.loadLabel(packageManager).toString())) {
systemItems.add(new ApplicationItem(info.loadLabel(packageManager).toString(), info.packageName,
info.loadIcon(packageManager)));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
apps.clear();
apps.addAll(items);
systemApps.clear();
systemApps.addAll(systemItems);
return items;
}

@Override
protected void onPostExecute(List<ApplicationItem> applicationItems) {
apps.clear();
apps.addAll(applicationItems);
dataLoading.set(false);
}
}
Expand Down
44 changes: 40 additions & 4 deletions core/src/main/res/layout/content_split_tunneling.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,55 @@
android:textSize="14sp"
android:textStyle="normal" />

<View
<LinearLayout
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/split_line_color" />
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
android:orientation="horizontal">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif"
android:lineSpacingExtra="8sp"
android:text="@string/split_tunneling_show_system_apps"
android:textColor="@color/antitracker_text"
android:textSize="16sp"
android:textStyle="normal" />

<Space
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />

<androidx.appcompat.widget.SwitchCompat
android:id="@+id/show_system_apps"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:checked="@{viewmodel.showSystemApps}"
app:onChanged="@{viewmodel.toggleSystemApps}"
android:thumb="@drawable/common_thumb_selector"
app:track="@drawable/common_track_selector" />

</LinearLayout>

</LinearLayout>

<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/split_line_color" />

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adapter="@{viewmodel.adapter}"
app:apps="@{viewmodel.apps}"
app:apps="@{viewmodel.showSystemApps ? viewmodel.systemApps : viewmodel.apps}"
app:not_allowed_apps="@{viewmodel.disallowedApps}"
app:selection_listener="@{viewmodel.selectionChangedListener}"/>

Expand Down
1 change: 1 addition & 0 deletions core/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@
<string name="split_tunneling_description">Split tunnelling allows you to control which apps use the VPN tunnel. New apps that you install will automatically use the VPN tunnel.</string>
<string name="split_tunneling_turn_on_all">TURN ON ALL</string>
<string name="split_tunneling_turn_off_all">TURN OFF ALL</string>
<string name="split_tunneling_show_system_apps">Show system apps</string>

<!--Trusted wifi -->
<string name="network_mobile_data">Mobile data</string>
Expand Down

0 comments on commit d47772d

Please sign in to comment.