Fixing bugs
This commit is contained in:
parent
a6ab9fda8b
commit
d668b7f6c3
@ -5,9 +5,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
@ToString
|
@ToString
|
||||||
|
@ -4,7 +4,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
@ -5,13 +5,9 @@ import android.content.Intent;
|
|||||||
import android.net.VpnService;
|
import android.net.VpnService;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
|
||||||
import android.widget.CompoundButton;
|
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.PopupMenu;
|
import android.widget.PopupMenu;
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.activity.EdgeToEdge;
|
import androidx.activity.EdgeToEdge;
|
||||||
@ -21,21 +17,15 @@ import androidx.appcompat.app.AppCompatActivity;
|
|||||||
import androidx.core.graphics.Insets;
|
import androidx.core.graphics.Insets;
|
||||||
import androidx.core.view.ViewCompat;
|
import androidx.core.view.ViewCompat;
|
||||||
import androidx.core.view.WindowInsetsCompat;
|
import androidx.core.view.WindowInsetsCompat;
|
||||||
import androidx.room.Room;
|
|
||||||
|
|
||||||
import com.alterdekim.fridaapp.R;
|
import com.alterdekim.fridaapp.R;
|
||||||
import com.alterdekim.fridaapp.controller.ControllerId;
|
import com.alterdekim.fridaapp.controller.ControllerId;
|
||||||
import com.alterdekim.fridaapp.controller.ControllerManager;
|
import com.alterdekim.fridaapp.controller.ControllerManager;
|
||||||
import com.alterdekim.fridaapp.controller.MainActivityController;
|
import com.alterdekim.fridaapp.controller.MainActivityController;
|
||||||
import com.alterdekim.fridaapp.util.Util;
|
import com.alterdekim.fridaapp.util.Util;
|
||||||
import com.alterdekim.fridaapp.room.AppDatabase;
|
|
||||||
import com.alterdekim.fridaapp.room.Config;
|
|
||||||
import com.alterdekim.fridaapp.service.FridaService;
|
import com.alterdekim.fridaapp.service.FridaService;
|
||||||
import com.google.android.material.switchmaterial.SwitchMaterial;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.alterdekim.fridaapp.activity;
|
package com.alterdekim.fridaapp.activity;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import androidx.activity.EdgeToEdge;
|
import androidx.activity.EdgeToEdge;
|
||||||
@ -17,25 +18,46 @@ public class SingleConfigActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
private static final String TAG = SingleConfigActivity.class.getSimpleName();
|
private static final String TAG = SingleConfigActivity.class.getSimpleName();
|
||||||
|
|
||||||
private SingleConfigActivityController controller;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
EdgeToEdge.enable(this);
|
EdgeToEdge.enable(this);
|
||||||
setContentView(R.layout.activity_single_config);
|
setContentView(R.layout.activity_single_config);
|
||||||
|
|
||||||
ControllerManager.putController(new SingleConfigActivityController());
|
ControllerManager.putController(new SingleConfigActivityController());
|
||||||
this.controller = (SingleConfigActivityController) ControllerManager.getController(ControllerId.SingleConfigActivityController);
|
SingleConfigActivityController controller = (SingleConfigActivityController) ControllerManager.getController(ControllerId.SingleConfigActivityController);
|
||||||
|
|
||||||
|
Intent intent = getIntent();
|
||||||
|
String config_title = intent.getStringExtra("config_title");
|
||||||
|
byte[] config_data = intent.getByteArrayExtra("config_data");
|
||||||
|
|
||||||
|
controller.onConfigDataAppeared(config_title, config_data);
|
||||||
|
controller.onCreateGUI(this);
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
|
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
|
||||||
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
|
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
|
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
|
||||||
return insets;
|
return insets;
|
||||||
});
|
});
|
||||||
|
/*
|
||||||
|
this.findViewById(R.id.add_app).setOnClickListener(view -> {
|
||||||
|
final PackageManager pm = this.getPackageManager();
|
||||||
|
List<PackageInfo> apps = pm.getInstalledPackages(0);
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(SingleConfigActivity.this)
|
||||||
|
.setTitle(R.string.choose_app);
|
||||||
|
|
||||||
|
View mRowList = getLayoutInflater().inflate(R.layout.row, null);
|
||||||
|
ListView mListView = mRowList.findViewById(R.id.list_view);
|
||||||
|
|
||||||
|
final ArrayAdapter<String> names = new ArrayAdapter<>(SingleConfigActivity.this, android.R.layout.simple_list_item_1);
|
||||||
|
for( int i = 0; i < apps.size(); i++ ) {
|
||||||
|
names.add(pm.getApplicationLabel(apps.get(i).applicationInfo).toString());
|
||||||
|
}
|
||||||
|
mListView.setAdapter(names);
|
||||||
|
names.notifyDataSetChanged();
|
||||||
|
builder.setView(mRowList);
|
||||||
|
builder.create().show();
|
||||||
|
}); */
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -22,7 +22,9 @@ import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
|||||||
import com.google.android.material.switchmaterial.SwitchMaterial;
|
import com.google.android.material.switchmaterial.SwitchMaterial;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||||
@ -44,6 +46,11 @@ public class MainActivityController implements IController {
|
|||||||
public void onCreateGUI(AppCompatActivity activity) {
|
public void onCreateGUI(AppCompatActivity activity) {
|
||||||
this.db = Room.databaseBuilder(activity.getApplicationContext(), AppDatabase.class, "def-db").build();
|
this.db = Room.databaseBuilder(activity.getApplicationContext(), AppDatabase.class, "def-db").build();
|
||||||
this.mainActivity = (MainActivity) activity;
|
this.mainActivity = (MainActivity) activity;
|
||||||
|
Intent intent = new Intent(this.mainActivity, FridaService.class);
|
||||||
|
intent.putExtra("vpn_data", new byte[0]);
|
||||||
|
intent.putExtra("vpn_uid", -1);
|
||||||
|
intent.putExtra("vpn_state", false);
|
||||||
|
this.mainActivity.startService(intent);
|
||||||
this.initConfigListGUI();
|
this.initConfigListGUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,17 +66,31 @@ public class MainActivityController implements IController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Iterator<Config> iter = cl.iterator();
|
Iterator<Config> iter = cl.iterator();
|
||||||
|
List<SwitchMaterial> switches = new ArrayList<>();
|
||||||
while( iter.hasNext() ) {
|
while( iter.hasNext() ) {
|
||||||
Config config = iter.next();
|
Config config = iter.next();
|
||||||
View cfg_instance = inflater.inflate(R.layout.single_config, this.mainActivity.getCfg_list(), false);
|
View cfg_instance = inflater.inflate(R.layout.single_config, this.mainActivity.getCfg_list(), false);
|
||||||
this.mainActivity.getCfg_list().addView(cfg_instance);
|
this.mainActivity.getCfg_list().addView(cfg_instance);
|
||||||
TextView view_name = cfg_instance.findViewById(R.id.config_name);
|
TextView view_name = cfg_instance.findViewById(R.id.config_name);
|
||||||
SwitchMaterial view_switch = cfg_instance.findViewById(R.id.config_switch);
|
SwitchMaterial view_switch = cfg_instance.findViewById(R.id.config_switch);
|
||||||
|
switches.add(view_switch);
|
||||||
view_switch.setUseMaterialThemeColors(true);
|
view_switch.setUseMaterialThemeColors(true);
|
||||||
view_switch.setOnCheckedChangeListener((compoundButton, b) -> toggleVpn(view_switch, config, b));
|
view_switch.setOnCheckedChangeListener((compoundButton, b) -> {
|
||||||
|
if( b ) {
|
||||||
|
for (SwitchMaterial ss : switches) {
|
||||||
|
if (!ss.equals(view_switch)) {
|
||||||
|
Log.i(TAG, "DEACTIVATED");
|
||||||
|
ss.setChecked(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
toggleVpn(config, b);
|
||||||
|
});
|
||||||
view_name.setText(config.getTitle());
|
view_name.setText(config.getTitle());
|
||||||
view_name.setOnClickListener(view -> {
|
view_name.setOnClickListener(view -> {
|
||||||
Intent intent = new Intent(this.mainActivity, SingleConfigActivity.class);
|
Intent intent = new Intent(this.mainActivity, SingleConfigActivity.class);
|
||||||
|
intent.putExtra("config_data", config.getData_raw());
|
||||||
|
intent.putExtra("config_title", config.getTitle());
|
||||||
this.mainActivity.startActivity(intent);
|
this.mainActivity.startActivity(intent);
|
||||||
});
|
});
|
||||||
if( iter.hasNext() ) this.mainActivity.getCfg_list().addView(inflater.inflate(R.layout.single_divider, this.mainActivity.getCfg_list(), false));
|
if( iter.hasNext() ) this.mainActivity.getCfg_list().addView(inflater.inflate(R.layout.single_divider, this.mainActivity.getCfg_list(), false));
|
||||||
@ -81,11 +102,8 @@ public class MainActivityController implements IController {
|
|||||||
|
|
||||||
public void insertNewConfig(String name, byte[] config) {
|
public void insertNewConfig(String name, byte[] config) {
|
||||||
try {
|
try {
|
||||||
com.alterdekim.frida.config.Config cfg = new ObjectMapper(new YAMLFactory()).setAnnotationIntrospector(new JacksonAnnotationIntrospector()).readValue(config, com.alterdekim.frida.config.Config.class);
|
new ObjectMapper(new YAMLFactory()).setAnnotationIntrospector(new JacksonAnnotationIntrospector()).readValue(config, com.alterdekim.frida.config.Config.class);
|
||||||
Log.i(TAG, cfg.toString());
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(TAG, "Can't parse config");
|
|
||||||
e.printStackTrace();
|
|
||||||
Toast.makeText(this.mainActivity, R.string.config_adding_error, Toast.LENGTH_LONG).show();
|
Toast.makeText(this.mainActivity, R.string.config_adding_error, Toast.LENGTH_LONG).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -97,7 +115,7 @@ public class MainActivityController implements IController {
|
|||||||
.subscribe();
|
.subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void toggleVpn(SwitchMaterial view, Config config, boolean val) {
|
private void toggleVpn(Config config, boolean val) {
|
||||||
Intent intent = new Intent(this.mainActivity, FridaService.class);
|
Intent intent = new Intent(this.mainActivity, FridaService.class);
|
||||||
intent.putExtra("vpn_data", config.getData_raw());
|
intent.putExtra("vpn_data", config.getData_raw());
|
||||||
intent.putExtra("vpn_uid", config.getUid());
|
intent.putExtra("vpn_uid", config.getUid());
|
||||||
|
@ -1,11 +1,31 @@
|
|||||||
package com.alterdekim.fridaapp.controller;
|
package com.alterdekim.fridaapp.controller;
|
||||||
|
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
|
import com.alterdekim.frida.config.Config;
|
||||||
|
import com.alterdekim.fridaapp.R;
|
||||||
|
import com.alterdekim.fridaapp.activity.SingleConfigActivity;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
|
||||||
|
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
public class SingleConfigActivityController implements IController {
|
public class SingleConfigActivityController implements IController {
|
||||||
|
|
||||||
private static final String TAG = SingleConfigActivityController.class.getSimpleName();
|
private static final String TAG = SingleConfigActivityController.class.getSimpleName();
|
||||||
|
|
||||||
|
private String config_title;
|
||||||
|
private Config config_data;
|
||||||
|
private SingleConfigActivity activity;
|
||||||
|
//private List<String> appsList;
|
||||||
|
//private boolean isAllowedApps;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ControllerId getControllerId() {
|
public ControllerId getControllerId() {
|
||||||
return ControllerId.SingleConfigActivityController;
|
return ControllerId.SingleConfigActivityController;
|
||||||
@ -13,6 +33,47 @@ public class SingleConfigActivityController implements IController {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateGUI(AppCompatActivity activity) {
|
public void onCreateGUI(AppCompatActivity activity) {
|
||||||
|
this.activity = (SingleConfigActivity) activity;
|
||||||
|
//this.isAllowedApps = true;
|
||||||
|
TextView config_name = this.activity.findViewById(R.id.interface_name);
|
||||||
|
TextView public_key_text = this.activity.findViewById(R.id.public_key);
|
||||||
|
TextView address_text = this.activity.findViewById(R.id.address);
|
||||||
|
TextView endpoint = this.activity.findViewById(R.id.endpoint);
|
||||||
|
|
||||||
|
config_name.setText(this.config_title);
|
||||||
|
public_key_text.setText(this.config_data.getServer().getPublic_key());
|
||||||
|
address_text.setText(this.config_data.getClient().getAddress());
|
||||||
|
endpoint.setText(this.config_data.getServer().getEndpoint());
|
||||||
|
|
||||||
|
LinearLayout switch_allowed = this.activity.findViewById(R.id.switch_all);
|
||||||
|
LinearLayout switch_disallowed = this.activity.findViewById(R.id.switch_dis);
|
||||||
|
|
||||||
|
Resources resources = this.activity.getResources();
|
||||||
|
|
||||||
|
switch_allowed.setOnClickListener(view -> {
|
||||||
|
view.setBackground(resources.getDrawable(R.drawable.layout_swl));
|
||||||
|
( (TextView) activity.findViewById(R.id.btn_text_dis) ).setTextColor(resources.getColor(R.color.switch_deselected));
|
||||||
|
( (TextView) activity.findViewById(R.id.btn_text_all) ).setTextColor(resources.getColor(R.color.switch_selected));
|
||||||
|
switch_disallowed.setBackground(null);
|
||||||
|
//this.isAllowedApps = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
switch_disallowed.setOnClickListener(view -> {
|
||||||
|
view.setBackground(resources.getDrawable(R.drawable.layout_swr));
|
||||||
|
( (TextView) activity.findViewById(R.id.btn_text_dis) ).setTextColor(resources.getColor(R.color.switch_selected));
|
||||||
|
( (TextView) activity.findViewById(R.id.btn_text_all) ).setTextColor(resources.getColor(R.color.switch_deselected));
|
||||||
|
switch_allowed.setBackground(null);
|
||||||
|
//this.isAllowedApps = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onConfigDataAppeared(String title, byte[] data) {
|
||||||
|
this.config_title = title;
|
||||||
|
try {
|
||||||
|
this.config_data = new ObjectMapper(new YAMLFactory()).setAnnotationIntrospector(new JacksonAnnotationIntrospector()).readValue(data, Config.class);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Toast.makeText(this.activity, R.string.config_open_error, Toast.LENGTH_LONG).show();
|
||||||
|
this.activity.finish();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ import java.util.List;
|
|||||||
|
|
||||||
import io.reactivex.rxjava3.core.Completable;
|
import io.reactivex.rxjava3.core.Completable;
|
||||||
import io.reactivex.rxjava3.core.Flowable;
|
import io.reactivex.rxjava3.core.Flowable;
|
||||||
import io.reactivex.rxjava3.core.Observable;
|
|
||||||
import io.reactivex.rxjava3.core.Single;
|
import io.reactivex.rxjava3.core.Single;
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
|
@ -34,6 +34,8 @@ public class FridaService extends VpnService {
|
|||||||
|
|
||||||
private final FridaLib lib = new FridaLib();
|
private final FridaLib lib = new FridaLib();
|
||||||
|
|
||||||
|
private int uid = -1;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
Log.i(TAG, "Created");
|
Log.i(TAG, "Created");
|
||||||
@ -100,14 +102,19 @@ public class FridaService extends VpnService {
|
|||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
if( intent.getExtras() == null ) return START_STICKY;
|
if( intent.getExtras() == null ) return START_STICKY;
|
||||||
byte[] config = intent.getExtras().getByteArray("vpn_data");
|
byte[] config = intent.getExtras().getByteArray("vpn_data");
|
||||||
int uid = intent.getExtras().getInt("vpn_uid");
|
int cfg_uid = intent.getExtras().getInt("vpn_uid");
|
||||||
boolean state = intent.getExtras().getBoolean("vpn_state");
|
boolean state = intent.getExtras().getBoolean("vpn_state");
|
||||||
if(!state) {
|
if(!state) {
|
||||||
this.lib.stop();
|
this.lib.stop();
|
||||||
return START_STICKY;
|
return START_STICKY;
|
||||||
}
|
}
|
||||||
|
if(cfg_uid != this.uid && this.uid != -1) {
|
||||||
|
this.lib.stop();
|
||||||
|
turnOff();
|
||||||
|
}
|
||||||
|
this.uid = cfg_uid;
|
||||||
setupVPN(config);
|
setupVPN(config);
|
||||||
// TODO: different configs
|
|
||||||
this.vpnProcess = Flowable.fromRunnable(new NativeBinaryConnection(vpnInterface.detachFd(), Util.bytesToHex(config), lib, logPath))
|
this.vpnProcess = Flowable.fromRunnable(new NativeBinaryConnection(vpnInterface.detachFd(), Util.bytesToHex(config), lib, logPath))
|
||||||
.subscribeOn(Schedulers.newThread())
|
.subscribeOn(Schedulers.newThread())
|
||||||
.observeOn(Schedulers.newThread())
|
.observeOn(Schedulers.newThread())
|
||||||
|
@ -5,12 +5,9 @@ import android.database.Cursor;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.provider.OpenableColumns;
|
import android.provider.OpenableColumns;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class Util {
|
public class Util {
|
||||||
public static String readTextFromUri(Context context, Uri uri) throws IOException {
|
public static String readTextFromUri(Context context, Uri uri) throws IOException {
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="start"
|
android:layout_gravity="start"
|
||||||
android:text="Name"
|
android:text="Name"
|
||||||
|
android:maxLines="1"
|
||||||
android:textAllCaps="false"
|
android:textAllCaps="false"
|
||||||
android:textColor="@color/grey"
|
android:textColor="@color/grey"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
@ -49,8 +50,10 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="start"
|
android:layout_gravity="start"
|
||||||
android:text="8x6qHHHgsa5nq82nd=="
|
android:text="8x6qHHHgsa5nq82nd=="
|
||||||
|
android:textAlignment="viewStart"
|
||||||
android:textAllCaps="false"
|
android:textAllCaps="false"
|
||||||
android:textColor="@color/black"
|
android:textColor="@color/black"
|
||||||
|
android:maxLines="1"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
android:textStyle="normal" />
|
android:textStyle="normal" />
|
||||||
<TextView
|
<TextView
|
||||||
@ -96,6 +99,7 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:visibility="invisible"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="20dp"
|
android:layout_marginTop="20dp"
|
||||||
@ -118,6 +122,7 @@
|
|||||||
android:background="@drawable/layout_swl">
|
android:background="@drawable/layout_swl">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/btn_text_all"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
@ -136,6 +141,7 @@
|
|||||||
android:layout_weight="1">
|
android:layout_weight="1">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/btn_text_dis"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
|
12
src/main/res/layout/row.xml
Normal file
12
src/main/res/layout/row.xml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<ListView
|
||||||
|
android:id="@+id/list_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"/>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -4,4 +4,6 @@
|
|||||||
<color name="grey">#FFa9a9a9</color>
|
<color name="grey">#FFa9a9a9</color>
|
||||||
<color name="white">#FFFFFFFF</color>
|
<color name="white">#FFFFFFFF</color>
|
||||||
<color name="colorPrimary">#731DD8</color>
|
<color name="colorPrimary">#731DD8</color>
|
||||||
|
<color name="switch_deselected">#75757F</color>
|
||||||
|
<color name="switch_selected">@color/white</color>
|
||||||
</resources>
|
</resources>
|
@ -3,5 +3,7 @@
|
|||||||
<string name="create_config">Create from scratch</string>
|
<string name="create_config">Create from scratch</string>
|
||||||
<string name="import_config">Import from file</string>
|
<string name="import_config">Import from file</string>
|
||||||
<string name="config_adding_error">Cannot add new config</string>
|
<string name="config_adding_error">Cannot add new config</string>
|
||||||
<string name="config_adding_success">SUCCESS!</string>
|
<string name="config_adding_success">Success!</string>
|
||||||
|
<string name="config_open_error">Error occurred</string>
|
||||||
|
<string name="choose_app">Choose app</string>
|
||||||
</resources>
|
</resources>
|
Loading…
x
Reference in New Issue
Block a user