diff --git a/app/build.gradle b/app/build.gradle index 36d520b..8dcb293 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,14 +4,14 @@ plugins { android { namespace 'com.vectras.vm' - compileSdk 36 + compileSdk = 36 defaultConfig { applicationId "com.vectras.vm" minSdk minApi targetSdk targetApi versionCode 21 - versionName "v2.9.5.6-3dfx" + versionName "v2.9.5.7-3dfx" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true } @@ -86,9 +86,9 @@ dependencies { implementation 'com.google.firebase:firebase-storage' implementation("com.google.android.gms:play-services-auth:21.4.0") implementation("com.google.firebase:firebase-crashlytics") - implementation 'com.google.android.gms:play-services-ads:24.5.0' + implementation 'com.google.android.gms:play-services-ads:24.6.0' implementation 'com.google.guava:guava:33.4.8-jre' - implementation 'com.google.code.gson:gson:2.13.1' + implementation 'com.google.code.gson:gson:2.13.2' implementation 'com.squareup.okhttp3:okhttp:5.1.0' implementation "androidx.window:window:1.4.0" implementation "commons-io:commons-io:2.20.0" @@ -96,7 +96,7 @@ dependencies { implementation 'com.airbnb.android:lottie:6.6.7' implementation 'org.apache.commons:commons-compress:1.28.0' implementation 'com.google.firebase:firebase-crashlytics-buildtools:3.0.6' - implementation 'androidx.activity:activity:1.10.1' + implementation 'androidx.activity:activity:1.11.0' implementation 'androidx.constraintlayout:constraintlayout:2.2.1' implementation 'androidx.preference:preference:1.2.1' compileOnly project(':shell-loader:stub') @@ -108,7 +108,7 @@ dependencies { // Glide implementation 'com.github.bumptech.glide:glide:5.0.4' - annotationProcessor 'com.github.bumptech.glide:compiler:5.0.4' + annotationProcessor 'com.github.bumptech.glide:compiler:5.0.5' // Test dependencies testImplementation 'junit:junit:4.13.2' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d7cbab5..0d266de 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -49,10 +49,18 @@ android:supportsRtl="true" android:theme="@style/AppTheme"> + android:windowSoftInputMode="adjustResize" /> + + + android:foregroundServiceType="mediaPlayback" /> { @@ -27,8 +24,7 @@ public class AdapterBlog extends RecyclerView.Adapter { List data = Collections.emptyList(); DataBlog current; int currentPos = 0; - - // create constructor to innitilize context and data sent from MainActivity + public AdapterBlog(Context context, List data) { this.context = context; inflater = LayoutInflater.from(context); @@ -52,9 +48,9 @@ public class AdapterBlog extends RecyclerView.Adapter { final DataBlog current = data.get(position); myHolder.textTitle.setText(current.postTitle); myHolder.textDate.setText("Date: " + current.postDate); - Glide.with(MainActivity.activity).load(current.postThumb).into(myHolder.ivThumb); + Glide.with(context).load(current.postThumb).into(myHolder.ivThumb); Animation animation; - animation = AnimationUtils.loadAnimation(MainActivity.activity, android.R.anim.slide_in_left); + animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left); animation.setDuration(300); myHolder.cdPost.startAnimation(animation); @@ -66,7 +62,7 @@ public class AdapterBlog extends RecyclerView.Adapter { PostActivity.content = current.postContent; PostActivity.date = current.postDate; PostActivity.thumb = current.postThumb; - MainActivity.activity.startActivity(new Intent(MainActivity.activity, PostActivity.class)); + context.startActivity(new Intent(context, PostActivity.class)); } }); } diff --git a/app/src/main/java/com/vectras/vm/CqcmActivity.java b/app/src/main/java/com/vectras/vm/CqcmActivity.java index c7f8fe7..0036dea 100644 --- a/app/src/main/java/com/vectras/vm/CqcmActivity.java +++ b/app/src/main/java/com/vectras/vm/CqcmActivity.java @@ -6,7 +6,6 @@ import android.net.Uri; import android.os.Bundle; import android.provider.Settings; import android.util.Log; -import android.view.View; import android.widget.Button; import android.widget.Toast; @@ -15,12 +14,12 @@ import androidx.core.app.ActivityCompat; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; +import com.vectras.vm.home.HomeActivity; import com.vectras.vm.utils.FileUtils; import com.vectras.vm.utils.JSONUtils; import com.vectras.vm.utils.PermissionUtils; import com.vectras.vm.utils.UIUtils; -import java.io.File; import java.util.HashMap; import java.util.Objects; @@ -86,7 +85,7 @@ public class CqcmActivity extends AppCompatActivity { } else { _map = Objects.requireNonNull(getIntent().getStringExtra("content")); } - if (JSONUtils.isMapValidFromString(_map)) { + if (JSONUtils.isValidFromString(_map)) { mapForCreateNewVM = new Gson().fromJson(_map, new TypeToken>(){}.getType()); if (mapForCreateNewVM.containsKey("imgName")) { imgName = Objects.requireNonNull(mapForCreateNewVM.get("imgName")).toString(); @@ -116,7 +115,7 @@ public class CqcmActivity extends AppCompatActivity { } else { Toast.makeText(getApplicationContext(), "The virtual machine list data is corrupted and new virtual machines cannot be added right now.", Toast.LENGTH_LONG).show(); } - if(!MainActivity.isActivate) { + if(!HomeActivity.isActivate) { Log.i("CqcmActivity", "Vectras VM is not opening."); gotoActivity.setClass(getApplicationContext(), SplashActivity.class); startActivity(gotoActivity); @@ -134,7 +133,7 @@ public class CqcmActivity extends AppCompatActivity { private void runCommand(String _command) { AppConfig.pendingCommand = _command; - if(!MainActivity.isActivate) { + if(!HomeActivity.isActivate) { Log.i("CqcmActivity", "Vectras VM is not opening."); gotoActivity.setClass(getApplicationContext(), SplashActivity.class); startActivity(gotoActivity); diff --git a/app/src/main/java/com/vectras/vm/CustomRomActivity.java b/app/src/main/java/com/vectras/vm/CustomRomActivity.java index a5f8d78..1fd64d4 100644 --- a/app/src/main/java/com/vectras/vm/CustomRomActivity.java +++ b/app/src/main/java/com/vectras/vm/CustomRomActivity.java @@ -21,6 +21,7 @@ import com.vectras.qemu.MainSettingsManager; import com.vectras.vm.Fragment.CreateImageDialogFragment; import com.vectras.vm.MainRoms.DataMainRoms; import com.vectras.vm.databinding.ActivityCustomRomBinding; +import com.vectras.vm.home.HomeActivity; import com.vectras.vm.utils.DeviceUtils; import com.vectras.vm.utils.DialogUtils; import com.vectras.vm.utils.FileUtils; @@ -525,10 +526,7 @@ public class CustomRomActivity extends AppCompatActivity { createNewVM(); } else { DialogUtils.twoDialog(this, getString(R.string.problem_has_been_detected), _contentDialog, getString(R.string.continuetext), getString(R.string.cancel), true, R.drawable.warning_48px, true, - () -> { - createNewVM(); - finish(); - }, null, null); + this::createNewVM, null, null); } } } @@ -567,7 +565,7 @@ public class CustomRomActivity extends AppCompatActivity { } modify = false; - if (!MainActivity.isActivate) { + if (!HomeActivity.isActivate) { startActivity(new Intent(this, SplashActivity.class)); } else { Intent openURL = new Intent(); diff --git a/app/src/main/java/com/vectras/vm/Fragment/CreateImageDialogFragment.java b/app/src/main/java/com/vectras/vm/Fragment/CreateImageDialogFragment.java index 39932dd..30b4dd2 100644 --- a/app/src/main/java/com/vectras/vm/Fragment/CreateImageDialogFragment.java +++ b/app/src/main/java/com/vectras/vm/Fragment/CreateImageDialogFragment.java @@ -102,7 +102,7 @@ public class CreateImageDialogFragment extends DialogFragment { } Terminal vterm = new Terminal(getActivity()); vterm.executeShellCommand("qemu-img create -f qcow2 \"" + folder + imageName.getText().toString() + ".qcow2\" " + - imageSize.getText().toString() + "G", true, getActivity()); + imageSize.getText().toString() + "G", true, true, getActivity()); if (customRom) { if(drive != null) drive.setText(folder + imageName.getText().toString() + ".qcow2"); diff --git a/app/src/main/java/com/vectras/vm/Fragment/HomeFragment.java b/app/src/main/java/com/vectras/vm/Fragment/HomeFragment.java index bc9f61e..c3c0e82 100644 --- a/app/src/main/java/com/vectras/vm/Fragment/HomeFragment.java +++ b/app/src/main/java/com/vectras/vm/Fragment/HomeFragment.java @@ -1,62 +1,27 @@ package com.vectras.vm.Fragment; -import android.app.Activity; -import android.app.ProgressDialog; -import android.content.Context; -import android.content.Intent; -import android.content.res.Resources; -import android.net.ConnectivityManager; -import android.net.Network; -import android.net.NetworkInfo; -import android.os.AsyncTask; -import android.net.NetworkRequest; import android.os.Bundle; -import android.telephony.NetworkScanRequest; -import android.util.Log; -import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.TextView; import android.widget.Toast; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.GridLayoutManager; -import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import com.vectras.qemu.MainSettingsManager; -import com.vectras.vm.RomsManagerActivity; import com.vectras.vm.MainRoms.AdapterMainRoms; import com.vectras.vm.MainRoms.DataMainRoms; import com.vectras.vm.R; -import com.vectras.vm.Blog.AdapterBlog; -import com.vectras.vm.Blog.DataBlog; import com.vectras.vm.AppConfig; -import com.vectras.vm.MainActivity; import com.vectras.vm.utils.FileUtils; -import com.vectras.vm.utils.UIUtils; -import java.io.BufferedReader; import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.io.InputStreamReader; -import java.net.MalformedURLException; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; import java.util.ArrayList; import java.util.List; -import java.util.Scanner; - -import javax.net.ssl.HttpsURLConnection; import org.json.JSONArray; import org.json.JSONException; @@ -68,7 +33,6 @@ public class HomeFragment extends Fragment { public static RecyclerView mRVMainRoms; public static LinearLayout romsLayout; public static AdapterMainRoms mMainAdapter; - public MainActivity activity; public static JSONArray jArray; public static List data; private SwipeRefreshLayout refreshRoms; @@ -79,33 +43,28 @@ public class HomeFragment extends Fragment { // TODO show the text view in @layout/home_fragment if list empty - activity = MainActivity.activity; - view = inflater.inflate(R.layout.home_fragment, container, false); romsLayout = view.findViewById(R.id.romsLayout); refreshRoms = view.findViewById(R.id.refreshRoms); - refreshRoms.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { - @Override - public void onRefresh() { - loadDataVbi(); - mMainAdapter.notifyItemRangeChanged(0, mMainAdapter.data.size()); - refreshRoms.setRefreshing(false); - } + refreshRoms.setOnRefreshListener(() -> { + loadDataVbi(); + mMainAdapter.notifyItemRangeChanged(0, mMainAdapter.data.size()); + refreshRoms.setRefreshing(false); }); loadDataVbi(); return view; } - public static void loadDataVbi() { + private void loadDataVbi() { data = new ArrayList<>(); try { - jArray = new JSONArray(FileUtils.readFromFile(MainActivity.activity, new File(AppConfig.maindirpath + jArray = new JSONArray(FileUtils.readFromFile(requireActivity(), new File(AppConfig.maindirpath + "roms-data.json"))); // Extract data from json and store into ArrayList as class objects @@ -127,7 +86,7 @@ public class HomeFragment extends Fragment { } romsMainData.itemExtra = json_data.getString("imgExtra"); try { - if (json_data.getString("imgArch").equals(MainSettingsManager.getArch(MainActivity.activity))) + if (json_data.getString("imgArch").equals(MainSettingsManager.getArch(requireActivity()))) data.add(romsMainData); } catch (JSONException ignored) { data.add(romsMainData); @@ -135,35 +94,12 @@ public class HomeFragment extends Fragment { } // Setup and Handover data to recyclerview - mRVMainRoms = (RecyclerView) HomeFragment.view.findViewById(R.id.mRVMainRoms); - mMainAdapter = new AdapterMainRoms(MainActivity.activity, data); + mRVMainRoms = HomeFragment.view.findViewById(R.id.mRVMainRoms); + mMainAdapter = new AdapterMainRoms(requireActivity(), data); mRVMainRoms.setAdapter(mMainAdapter); - mRVMainRoms.setLayoutManager(new GridLayoutManager(MainActivity.activity, 2)); + mRVMainRoms.setLayoutManager(new GridLayoutManager(getContext(), 2)); } catch (JSONException e) { - Toast.makeText(MainActivity.activity, e.toString(), Toast.LENGTH_LONG).show(); + Toast.makeText(requireActivity(), e.toString(), Toast.LENGTH_LONG).show(); } } - - /** - * CHECK WHETHER INTERNET CONNECTION IS AVAILABLE OR NOT - */ - public boolean checkConnection(Context context) { - final ConnectivityManager connMgr = (ConnectivityManager) context - .getSystemService(Context.CONNECTIVITY_SERVICE); - - if (connMgr != null) { - NetworkInfo activeNetworkInfo = connMgr.getActiveNetworkInfo(); - - if (activeNetworkInfo != null) { // connected to the internet - // connected to the mobile provider's data plan - if (activeNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI) { - // connected to wifi - return true; - } else - return activeNetworkInfo.getType() == ConnectivityManager.TYPE_MOBILE; - } - } - return false; - } - } diff --git a/app/src/main/java/com/vectras/vm/Fragment/LoggerFragment.java b/app/src/main/java/com/vectras/vm/Fragment/LoggerFragment.java index c77dd04..5bc40dc 100644 --- a/app/src/main/java/com/vectras/vm/Fragment/LoggerFragment.java +++ b/app/src/main/java/com/vectras/vm/Fragment/LoggerFragment.java @@ -1,48 +1,25 @@ package com.vectras.vm.Fragment; import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; import android.os.Bundle; -import android.text.Editable; -import android.text.TextWatcher; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemSelectedListener; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.CompoundButton; -import android.widget.EditText; -import android.widget.Spinner; -import android.widget.Switch; -import android.widget.TextView; import android.widget.Toast; -import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.vectras.vm.R; -import com.vectras.vm.RomsManagerActivity; -import com.vectras.vm.MainActivity; import com.vectras.vm.VectrasApp; import com.vectras.vm.adapter.LogsAdapter; import com.vectras.vm.logger.VectrasStatus; -import com.vectras.vm.utils.UIUtils; -import com.google.android.material.button.MaterialButton; -import com.google.android.material.snackbar.Snackbar; -import com.google.android.material.textfield.TextInputEditText; -import com.google.android.material.textfield.TextInputLayout; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; -import java.util.Objects; import java.util.Timer; import java.util.TimerTask; diff --git a/app/src/main/java/com/vectras/vm/MainActivity.java b/app/src/main/java/com/vectras/vm/MainActivity.java index e583afa..50778e7 100644 --- a/app/src/main/java/com/vectras/vm/MainActivity.java +++ b/app/src/main/java/com/vectras/vm/MainActivity.java @@ -13,10 +13,12 @@ import static com.vectras.vm.VectrasApp.getApp; import static com.vectras.vm.utils.LibraryChecker.isPackageInstalled2; import static com.vectras.vm.utils.UIUtils.UIAlert; +import com.vectras.vm.settings.UpdaterActivity; import com.vectras.vm.settings.VNCActivity; import com.vectras.vm.utils.DeviceUtils; import com.vectras.vm.utils.DialogUtils; import com.vectras.vm.utils.NetworkUtils; +import com.vectras.vm.utils.NotificationUtils; import com.vectras.vm.utils.PermissionUtils; import android.app.ActivityManager; @@ -26,8 +28,6 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.res.Configuration; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -62,8 +62,6 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import com.google.android.gms.ads.AdRequest; import com.google.android.gms.ads.LoadAdError; import com.google.android.gms.ads.MobileAds; -import com.google.android.gms.ads.initialization.InitializationStatus; -import com.google.android.gms.ads.initialization.OnInitializationCompleteListener; import com.google.android.gms.ads.interstitial.InterstitialAd; import com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback; import com.google.android.material.appbar.AppBarLayout; @@ -81,10 +79,10 @@ import com.vectras.vm.MainRoms.AdapterMainRoms; import com.vectras.vm.MainRoms.DataMainRoms; import com.vectras.vm.adapter.LogsAdapter; import com.vectras.vm.logger.VectrasStatus; -import com.vectras.vm.utils.AppUpdater; import com.vectras.vm.utils.FileUtils; import com.vectras.vm.utils.LibraryChecker; import com.vectras.vm.utils.PackageUtils; +import com.vectras.vm.utils.ServiceUtils; import com.vectras.vterm.Terminal; import org.json.JSONArray; @@ -100,6 +98,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -122,7 +121,7 @@ public class MainActivity extends AppCompatActivity { private InterstitialAd mInterstitialAd; private AdRequest adRequest; public DrawerLayout mainDrawer; - private String TAG = "MainActivity"; + private final String TAG = "MainActivity"; public static /**/ LinearLayout extVncLayout; public static AppBarLayout appbar; public TextView totalRam; @@ -164,27 +163,21 @@ public class MainActivity extends AppCompatActivity { tvLogin.setText(activity.getString(R.string.port_caption) + ": " + (Config.defaultVNCPort + 5900)/* + "\nPASSWORD --> " + Config.defaultVNCPasswd*/); Button stopBtn = findViewById(R.id.stopBtn); - stopBtn.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - // Stop the service - MainService.stopService(); + stopBtn.setOnClickListener(v -> { + // Stop the service + MainService.stopService(); - Terminal vterm = new Terminal(activity); - vterm.executeShellCommand2("killall qemu-system-*", false, activity); + Terminal vterm = new Terminal(activity); + vterm.executeShellCommand2("killall qemu-system-*", false, activity); - extVncLayout.setVisibility(View.GONE); - appbar.setExpanded(false); - } + extVncLayout.setVisibility(View.GONE); + appbar.setExpanded(false); }); - refreshRoms.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { - @Override - public void onRefresh() { - loadDataVbi(); - mMainAdapter.notifyItemRangeChanged(0, mMainAdapter.data.size()); - refreshRoms.setRefreshing(false); - } + refreshRoms.setOnRefreshListener(() -> { + loadDataVbi(); + mMainAdapter.notifyItemRangeChanged(0, mMainAdapter.data.size()); + refreshRoms.setRefreshing(false); }); /*bottomAppBar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() { @Override @@ -203,91 +196,53 @@ public class MainActivity extends AppCompatActivity { });*/ Button gotoromstore = findViewById(R.id.gotoromstorebutton); - gotoromstore.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Intent intent = new Intent(); - intent.setClass(getApplicationContext(), RomsManagerActivity.class); - startActivity(intent); - } + gotoromstore.setOnClickListener(v -> { + Intent intent = new Intent(); + intent.setClass(getApplicationContext(), RomsManagerActivity.class); + startActivity(intent); }); FloatingActionButton fabAdd = findViewById(R.id.fabAdd_AppBarBottomActivity); - fabAdd.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - startActivity(new Intent(activity, SetArchActivity.class)); - } - }); - Toolbar mainToolbar = (Toolbar) findViewById(R.id.toolbar); + fabAdd.setOnClickListener(view -> startActivity(new Intent(activity, SetArchActivity.class))); + + Toolbar mainToolbar = findViewById(R.id.toolbar); setSupportActionBar(mainToolbar); - mainDrawer = (DrawerLayout) findViewById(R.id.drawer_layout); + mainDrawer = findViewById(R.id.drawer_layout); ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, mainDrawer, mainToolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); mainDrawer.setDrawerListener(toggle); toggle.syncState(); - NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); + NavigationView navigationView = findViewById(R.id.nav_view); //Setting Navigation View Item Selected Listener to handle the item click of the navigation menu - navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { + // This method will trigger on item Click of navigation menu + navigationView.setNavigationItemSelectedListener(menuItem -> { + //Closing drawer on item click + mainDrawer.closeDrawers(); - // This method will trigger on item Click of navigation menu - @Override - public boolean onNavigationItemSelected(MenuItem menuItem) { - //Closing drawer on item click - mainDrawer.closeDrawers(); - - //Check to see which item was being clicked and perform appropriate action - int id = menuItem.getItemId(); - if (id == R.id.navigation_item_info) { - startActivity(new Intent(activity, AboutActivity.class)); - } - if (id == R.id.navigation_item_help) { - String tw = AppConfig.vectrasHelp; - Intent w = new Intent(ACTION_VIEW); - w.setData(Uri.parse(tw)); - startActivity(w); - } else if (id == R.id.navigation_item_website) { - String tw = AppConfig.vectrasWebsite; - Intent w = new Intent(ACTION_VIEW); - w.setData(Uri.parse(tw)); - startActivity(w); - } else if (id == R.id.navigation_item_import_iso) { - if (new File(AppConfig.maindirpath + "/drive.iso").exists()) { - AlertDialog ad; - ad = new AlertDialog.Builder(activity, R.style.MainDialogTheme).create(); - ad.setTitle("REPLACE ISO"); - ad.setMessage("there is iso imported you want to replace it?"); - ad.setButton(Dialog.BUTTON_POSITIVE, "REPLACE", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - Intent intent = new Intent(ACTION_OPEN_DOCUMENT); - intent.addCategory(Intent.CATEGORY_OPENABLE); - intent.setType("*/*"); - - // Optionally, specify a URI for the file that should appear in the - // system file picker when it loads. - if (SDK_INT >= Build.VERSION_CODES.O) { - intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.DIRECTORY_DOWNLOADS); - } - - startActivityForResult(intent, 1004); - return; - } - }); - ad.setButton(Dialog.BUTTON_NEGATIVE, "REMOVE", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - File isoFile = new File(AppConfig.maindirpath + "/drive.iso"); - try { - isoFile.delete(); - } catch (Exception e) { - throw new RuntimeException(e); - } - return; - } - }); - ad.show(); - } else { + //Check to see which item was being clicked and perform appropriate action + int id = menuItem.getItemId(); + if (id == R.id.navigation_item_info) { + startActivity(new Intent(activity, AboutActivity.class)); + } + if (id == R.id.navigation_item_help) { + String tw = AppConfig.vectrasHelp; + Intent w = new Intent(ACTION_VIEW); + w.setData(Uri.parse(tw)); + startActivity(w); + } else if (id == R.id.navigation_item_website) { + String tw = AppConfig.vectrasWebsite; + Intent w = new Intent(ACTION_VIEW); + w.setData(Uri.parse(tw)); + startActivity(w); + } else if (id == R.id.navigation_item_import_iso) { + if (new File(AppConfig.maindirpath + "/drive.iso").exists()) { + AlertDialog ad; + ad = new AlertDialog.Builder(activity, R.style.MainDialogTheme).create(); + ad.setTitle("REPLACE ISO"); + ad.setMessage("there is iso imported you want to replace it?"); + ad.setButton(Dialog.BUTTON_POSITIVE, "REPLACE", (dialog, which) -> { Intent intent = new Intent(ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("*/*"); @@ -299,125 +254,36 @@ public class MainActivity extends AppCompatActivity { } startActivityForResult(intent, 1004); - } - } else if (id == R.id.navigation_item_hdd1) { - if (new File(AppConfig.maindirpath + "/hdd1.qcow2").exists()) { - AlertDialog ad; - ad = new AlertDialog.Builder(activity, R.style.MainDialogTheme).create(); - ad.setTitle("REPLACE HDD1"); - ad.setMessage("there is hdd1 imported you want to replace it?"); - ad.setButton(Dialog.BUTTON_POSITIVE, "REPLACE", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - Intent intent = new Intent(ACTION_OPEN_DOCUMENT); - intent.addCategory(Intent.CATEGORY_OPENABLE); - intent.setType("*/*"); - - // Optionally, specify a URI for the file that should appear in the - // system file picker when it loads. - if (SDK_INT >= Build.VERSION_CODES.O) { - intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.DIRECTORY_DOWNLOADS); - } - - startActivityForResult(intent, 1006); - return; - } - }); - ad.setButton(Dialog.BUTTON_NEGATIVE, "REMOVE", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - File isoFile = new File(AppConfig.maindirpath + "/hdd1.qcow2"); - try { - isoFile.delete(); - } catch (Exception e) { - throw new RuntimeException(e); - } - return; - } - }); - ad.setButton(Dialog.BUTTON_NEUTRAL, "SHARE", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - Intent intentShareFile = new Intent(Intent.ACTION_SEND); - File fileWithinMyDir = new File(AppConfig.maindirpath + "/hdd1.qcow2"); - - if (fileWithinMyDir.exists()) { - intentShareFile.setType("*/*"); - intentShareFile.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + AppConfig.maindirpath + "/hdd1.qcow2")); - - intentShareFile.putExtra(Intent.EXTRA_SUBJECT, - "Sharing File..."); - intentShareFile.putExtra(Intent.EXTRA_TEXT, "Sharing File..."); - - startActivity(Intent.createChooser(intentShareFile, "Share File")); - } - } - }); - ad.show(); - } else { - Intent intent = new Intent(ACTION_OPEN_DOCUMENT); - intent.addCategory(Intent.CATEGORY_OPENABLE); - intent.setType("*/*"); - - // Optionally, specify a URI for the file that should appear in the - // system file picker when it loads. - if (SDK_INT >= Build.VERSION_CODES.O) { - intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.DIRECTORY_DOWNLOADS); + }); + ad.setButton(Dialog.BUTTON_NEGATIVE, "REMOVE", (dialog, which) -> { + File isoFile = new File(AppConfig.maindirpath + "/drive.iso"); + try { + if(!isoFile.delete()) Log.e(TAG, "Delete drive.iso failed!"); + } catch (Exception e) { + Log.e(TAG, "Delete drive.iso: ", e); } + }); + ad.show(); + } else { + Intent intent = new Intent(ACTION_OPEN_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("*/*"); - startActivityForResult(intent, 1005); + // Optionally, specify a URI for the file that should appear in the + // system file picker when it loads. + if (SDK_INT >= Build.VERSION_CODES.O) { + intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.DIRECTORY_DOWNLOADS); } - } else if (id == R.id.navigation_item_hdd2) { - if (new File(AppConfig.maindirpath + "/hdd2.qcow2").exists()) { - AlertDialog ad; - ad = new AlertDialog.Builder(activity, R.style.MainDialogTheme).create(); - ad.setTitle("REPLACE HDD2"); - ad.setMessage("there is hdd2 imported you want to replace it?"); - ad.setButton(Dialog.BUTTON_POSITIVE, "REPLACE", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - Intent intent = new Intent(ACTION_OPEN_DOCUMENT); - intent.addCategory(Intent.CATEGORY_OPENABLE); - intent.setType("*/*"); - // Optionally, specify a URI for the file that should appear in the - // system file picker when it loads. - if (SDK_INT >= Build.VERSION_CODES.O) { - intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.DIRECTORY_DOWNLOADS); - } - - startActivityForResult(intent, 1006); - return; - } - }); - ad.setButton(Dialog.BUTTON_NEGATIVE, "REMOVE", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - File isoFile = new File(AppConfig.maindirpath + "/hdd2.qcow2"); - try { - isoFile.delete(); - } catch (Exception e) { - throw new RuntimeException(e); - } - return; - } - }); - ad.setButton(Dialog.BUTTON_NEUTRAL, "SHARE", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - Intent intentShareFile = new Intent(Intent.ACTION_SEND); - File fileWithinMyDir = new File(AppConfig.maindirpath + "/hdd2.qcow2"); - - if (fileWithinMyDir.exists()) { - intentShareFile.setType("*/*"); - intentShareFile.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + AppConfig.maindirpath + "/hdd2.qcow2")); - - intentShareFile.putExtra(Intent.EXTRA_SUBJECT, - "Sharing File..."); - intentShareFile.putExtra(Intent.EXTRA_TEXT, "Sharing File..."); - - startActivity(Intent.createChooser(intentShareFile, "Share File")); - } - } - }); - ad.show(); - } else { + startActivityForResult(intent, 1004); + } + } else if (id == R.id.navigation_item_hdd1) { + if (new File(AppConfig.maindirpath + "/hdd1.qcow2").exists()) { + AlertDialog ad; + ad = new AlertDialog.Builder(activity, R.style.MainDialogTheme).create(); + ad.setTitle("REPLACE HDD1"); + ad.setMessage("there is hdd1 imported you want to replace it?"); + ad.setButton(Dialog.BUTTON_POSITIVE, "REPLACE", (dialog, which) -> { Intent intent = new Intent(ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("*/*"); @@ -429,84 +295,172 @@ public class MainActivity extends AppCompatActivity { } startActivityForResult(intent, 1006); + }); + ad.setButton(Dialog.BUTTON_NEGATIVE, "REMOVE", (dialog, which) -> { + File isoFile = new File(AppConfig.maindirpath + "/hdd1.qcow2"); + try { + if(!isoFile.delete()) Log.e(TAG, "Delete hdd1.qcow2 failed!"); + } catch (Exception e) { + Log.e(TAG, "Delete hdd1.qcow2: ", e); + } + }); + ad.setButton(Dialog.BUTTON_NEUTRAL, "SHARE", (dialog, which) -> { + Intent intentShareFile = new Intent(Intent.ACTION_SEND); + File fileWithinMyDir = new File(AppConfig.maindirpath + "/hdd1.qcow2"); + + if (fileWithinMyDir.exists()) { + intentShareFile.setType("*/*"); + intentShareFile.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + AppConfig.maindirpath + "/hdd1.qcow2")); + + intentShareFile.putExtra(Intent.EXTRA_SUBJECT, + "Sharing File..."); + intentShareFile.putExtra(Intent.EXTRA_TEXT, "Sharing File..."); + + startActivity(Intent.createChooser(intentShareFile, "Share File")); + } + }); + ad.show(); + } else { + Intent intent = new Intent(ACTION_OPEN_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("*/*"); + + // Optionally, specify a URI for the file that should appear in the + // system file picker when it loads. + if (SDK_INT >= Build.VERSION_CODES.O) { + intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.DIRECTORY_DOWNLOADS); } - } else if (id == R.id.navigation_item_desktop) { - launchX11(true); - } else if (id == R.id.navigation_item_terminal) { - /*com.vectras.vterm.TerminalBottomSheetDialog VTERM = new com.vectras.vterm.TerminalBottomSheetDialog(activity); - VTERM.showVterm();*/ - startActivity(new Intent(activity, TermuxActivity.class)); - } else if (id == R.id.navigation_item_view_logs) { - BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(activity); - View view = activity.getLayoutInflater().inflate(R.layout.bottomsheetdialog_logger, null); - bottomSheetDialog.setContentView(view); - bottomSheetDialog.show(); - final String CREDENTIAL_SHARED_PREF = "settings_prefs"; - Timer _timer = new Timer(); - TimerTask t; - - LinearLayoutManager layoutManager = new LinearLayoutManager(getApp()); - LogsAdapter mLogAdapter = new LogsAdapter(layoutManager, getApp()); - RecyclerView logList = (RecyclerView) view.findViewById(R.id.recyclerLog); - logList.setAdapter(mLogAdapter); - logList.setLayoutManager(layoutManager); - mLogAdapter.scrollToLastPosition(); - try { - Process process = Runtime.getRuntime().exec("logcat -e"); - BufferedReader bufferedReader = new BufferedReader( - new InputStreamReader(process.getInputStream())); - Process process2 = Runtime.getRuntime().exec("logcat -w"); - BufferedReader bufferedReader2 = new BufferedReader( - new InputStreamReader(process2.getInputStream())); - - t = new TimerTask() { - @Override - public void run() { - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - try { - if (bufferedReader.readLine() != null || bufferedReader2.readLine() != null) { - String logLine = bufferedReader.readLine(); - String logLine2 = bufferedReader2.readLine(); - VectrasStatus.logError("[E] " + logLine + ""); - VectrasStatus.logError("[W] " + logLine2 + ""); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - } - }); - } - }; - _timer.scheduleAtFixedRate(t, (int) (0), (int) (100)); - } catch (IOException e) { - Toast.makeText(activity, "There was an error: " + Log.getStackTraceString(e), Toast.LENGTH_LONG).show(); - e.printStackTrace(); - } - } else if (id == R.id.navigation_item_settings) { - startActivity(new Intent(activity, MainSettingsManager.class)); - } else if (id == R.id.navigation_item_store) { - startActivity(new Intent(activity, StoreActivity.class)); - } else if (id == R.id.navigation_data_explorer) { - startActivity(new Intent(activity, DataExplorerActivity.class)); - } else if (id == R.id.navigation_item_donate) { - String tw = "https://www.patreon.com/VectrasTeam"; - Intent w = new Intent(ACTION_VIEW); - w.setData(Uri.parse(tw)); - startActivity(w); - } else if (id == R.id.navigation_item_get_rom) { - Intent intent = new Intent(); - intent.setClass(getApplicationContext(), RomsManagerActivity.class); - startActivity(intent); - } else if (id == R.id.mini_tools) { - Intent intent = new Intent(); - intent.setClass(activity, Minitools.class); - startActivity(intent); + startActivityForResult(intent, 1005); } - return false; + } else if (id == R.id.navigation_item_hdd2) { + if (new File(AppConfig.maindirpath + "/hdd2.qcow2").exists()) { + AlertDialog ad; + ad = new AlertDialog.Builder(activity, R.style.MainDialogTheme).create(); + ad.setTitle("REPLACE HDD2"); + ad.setMessage("there is hdd2 imported you want to replace it?"); + ad.setButton(Dialog.BUTTON_POSITIVE, "REPLACE", (dialog, which) -> { + Intent intent = new Intent(ACTION_OPEN_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("*/*"); + + // Optionally, specify a URI for the file that should appear in the + // system file picker when it loads. + if (SDK_INT >= Build.VERSION_CODES.O) { + intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.DIRECTORY_DOWNLOADS); + } + + startActivityForResult(intent, 1006); + }); + ad.setButton(Dialog.BUTTON_NEGATIVE, "REMOVE", (dialog, which) -> { + File isoFile = new File(AppConfig.maindirpath + "/hdd2.qcow2"); + try { + if(!isoFile.delete()) Log.e(TAG, "Delete hdd2.qcow2 failed!"); + } catch (Exception e) { + Log.e(TAG, "Delete hdd2.qcow2: ", e); + } + }); + ad.setButton(Dialog.BUTTON_NEUTRAL, "SHARE", (dialog, which) -> { + Intent intentShareFile = new Intent(Intent.ACTION_SEND); + File fileWithinMyDir = new File(AppConfig.maindirpath + "/hdd2.qcow2"); + + if (fileWithinMyDir.exists()) { + intentShareFile.setType("*/*"); + intentShareFile.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + AppConfig.maindirpath + "/hdd2.qcow2")); + + intentShareFile.putExtra(Intent.EXTRA_SUBJECT, + "Sharing File..."); + intentShareFile.putExtra(Intent.EXTRA_TEXT, "Sharing File..."); + + startActivity(Intent.createChooser(intentShareFile, "Share File")); + } + }); + ad.show(); + } else { + Intent intent = new Intent(ACTION_OPEN_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("*/*"); + + // Optionally, specify a URI for the file that should appear in the + // system file picker when it loads. + if (SDK_INT >= Build.VERSION_CODES.O) { + intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.DIRECTORY_DOWNLOADS); + } + + startActivityForResult(intent, 1006); + } + } else if (id == R.id.navigation_item_desktop) { + launchX11(true); + } else if (id == R.id.navigation_item_terminal) { + /*com.vectras.vterm.TerminalBottomSheetDialog VTERM = new com.vectras.vterm.TerminalBottomSheetDialog(activity); + VTERM.showVterm();*/ + startActivity(new Intent(activity, TermuxActivity.class)); + } else if (id == R.id.navigation_item_view_logs) { + BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(activity); + View view = activity.getLayoutInflater().inflate(R.layout.bottomsheetdialog_logger, null); + bottomSheetDialog.setContentView(view); + bottomSheetDialog.show(); + + final String CREDENTIAL_SHARED_PREF = "settings_prefs"; + Timer _timer = new Timer(); + TimerTask t; + + LinearLayoutManager layoutManager = new LinearLayoutManager(getApp()); + LogsAdapter mLogAdapter = new LogsAdapter(layoutManager, getApp()); + RecyclerView logList = view.findViewById(R.id.recyclerLog); + logList.setAdapter(mLogAdapter); + logList.setLayoutManager(layoutManager); + mLogAdapter.scrollToLastPosition(); + try { + Process process = Runtime.getRuntime().exec("logcat -e"); + BufferedReader bufferedReader = new BufferedReader( + new InputStreamReader(process.getInputStream())); + Process process2 = Runtime.getRuntime().exec("logcat -w"); + BufferedReader bufferedReader2 = new BufferedReader( + new InputStreamReader(process2.getInputStream())); + + t = new TimerTask() { + @Override + public void run() { + runOnUiThread(() -> { + try { + if (bufferedReader.readLine() != null || bufferedReader2.readLine() != null) { + String logLine = bufferedReader.readLine(); + String logLine2 = bufferedReader2.readLine(); + VectrasStatus.logError("[E] " + logLine + ""); + VectrasStatus.logError("[W] " + logLine2 + ""); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } + }; + _timer.scheduleAtFixedRate(t, (int) (0), (int) (100)); + } catch (IOException e) { + Log.e(TAG, "Log: ", e); + } + } else if (id == R.id.navigation_item_settings) { + startActivity(new Intent(activity, MainSettingsManager.class)); + } else if (id == R.id.navigation_item_store) { + startActivity(new Intent(activity, StoreActivity.class)); + } else if (id == R.id.navigation_data_explorer) { + startActivity(new Intent(activity, DataExplorerActivity.class)); + } else if (id == R.id.navigation_item_donate) { + String tw = "https://www.patreon.com/VectrasTeam"; + Intent w = new Intent(ACTION_VIEW); + w.setData(Uri.parse(tw)); + startActivity(w); + } else if (id == R.id.navigation_item_get_rom) { + Intent intent = new Intent(); + intent.setClass(getApplicationContext(), RomsManagerActivity.class); + startActivity(intent); + } else if (id == R.id.mini_tools) { + Intent intent = new Intent(); + intent.setClass(activity, Minitools.class); + startActivity(intent); } + return false; }); getWindow().setNavigationBarColor(SurfaceColors.SURFACE_2.getColor(this)); @@ -517,10 +471,7 @@ public class MainActivity extends AppCompatActivity { //adRequest = new AdRequest.Builder().build(); //mAdView.loadAd(adRequest); - MobileAds.initialize(this, new OnInitializationCompleteListener() { - @Override - public void onInitializationComplete(InitializationStatus initializationStatus) { - } + MobileAds.initialize(this, initializationStatus -> { }); DialogUtils.joinTelegram(activity); @@ -547,61 +498,56 @@ public class MainActivity extends AppCompatActivity { TextView tvIsRunning = findViewById(R.id.tvIsRunning); - String vectrasMemory = String.valueOf(RamInfo.vectrasMemory()); + String vectrasMemory = String.valueOf(RamInfo.vectrasMemory(this)); TimerTask t = new TimerTask() { @Override public void run() { runOnUiThread( - new Runnable() { - @Override - public void run() { - boolean isMainServiceRunning = - isServiceRunning(MainService.class, activity); - if (isMainServiceRunning) - tvIsRunning.setText(R.string.running); - else tvIsRunning.setText(R.string.stopped); + () -> { + if (ServiceUtils.isServiceRunning(MainActivity.this, MainService.class)) + tvIsRunning.setText(R.string.running); + else tvIsRunning.setText(R.string.stopped); - ActivityManager.MemoryInfo miI = - new ActivityManager.MemoryInfo(); - ActivityManager activityManagerr = - (ActivityManager) - getSystemService(ACTIVITY_SERVICE); - activityManagerr.getMemoryInfo(miI); - long freeMemory = miI.availMem / 1048576L; - long totalMemory = miI.totalMem / 1048576L; - long usedMemory = totalMemory - freeMemory; + ActivityManager.MemoryInfo miI = + new ActivityManager.MemoryInfo(); + ActivityManager activityManagerr = + (ActivityManager) + getSystemService(ACTIVITY_SERVICE); + activityManagerr.getMemoryInfo(miI); + long freeMemory = miI.availMem / 1048576L; + long totalMemory = miI.totalMem / 1048576L; + long usedMemory = totalMemory - freeMemory; - totalRam.setText( - activity.getResources() - .getString(R.string.total_memory) - + " " - + totalMemory - + " MB"); - usedRam.setText( - activity.getResources() - .getString(R.string.used_memory) - + " " - + usedMemory - + " MB"); - freeRam.setText( - activity.getResources() - .getString(R.string.free_memory) - + " " - + freeMemory - + " MB (" - + vectrasMemory - + " " - + activity.getResources() - .getString(R.string.used) - + ")"); - LinearProgressIndicator progressBar = findViewById(R.id.progressBar); - progressBar.setMax((int) totalMemory); - if (SDK_INT >= Build.VERSION_CODES.N) { - progressBar.setProgress((int) usedMemory, true); - } else { - progressBar.setProgress((int) usedMemory); - } + totalRam.setText( + activity.getResources() + .getString(R.string.total_memory) + + " " + + totalMemory + + " MB"); + usedRam.setText( + activity.getResources() + .getString(R.string.used_memory) + + " " + + usedMemory + + " MB"); + freeRam.setText( + activity.getResources() + .getString(R.string.free_memory) + + " " + + freeMemory + + " MB (" + + vectrasMemory + + " " + + activity.getResources() + .getString(R.string.used) + + ")"); + LinearProgressIndicator progressBar = findViewById(R.id.progressBar); + progressBar.setMax((int) totalMemory); + if (SDK_INT >= Build.VERSION_CODES.N) { + progressBar.setProgress((int) usedMemory, true); + } else { + progressBar.setProgress((int) usedMemory); } }); } @@ -615,7 +561,7 @@ public class MainActivity extends AppCompatActivity { setupBottomAppBar(); if (MainSettingsManager.getPromptUpdateVersion(activity)) - updateApp(false); + updateApp(); String command = "qemu-system-x86_64 --version"; new Terminal(activity).extractQemuVersion(command, false, activity, (output, errors) -> { @@ -645,11 +591,6 @@ public class MainActivity extends AppCompatActivity { super.onDestroy(); } - public static void clearNotifications() { - NotificationManager notificationManager = (NotificationManager) activity.getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE); - notificationManager.cancelAll(); - } - public static int safeLongToInt(long l) { if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) { throw new IllegalArgumentException(l + " cannot be cast to int without changing its value."); @@ -657,98 +598,50 @@ public class MainActivity extends AppCompatActivity { return (int) l; } - public void updateApp(final boolean showDialog) { - new AppUpdater(this, new AppUpdater.OnUpdateListener() { + private void updateApp() { + int versionCode = PackageUtils.getThisVersionCode(getApplicationContext()); + String versionName = PackageUtils.getThisVersionName(getApplicationContext()); + + RequestNetwork requestNetwork = new RequestNetwork(this); + RequestNetwork.RequestListener requestNetworkListener = new RequestNetwork.RequestListener() { @Override - public void onUpdateListener(String result) { - try { - if (!result.contains("Error on getting data")) { - final JSONObject obj = new JSONObject(result); - int versionCode = PackageUtils.getThisVersionCode(getApplicationContext()); - String versionName = PackageUtils.getThisVersionName(getApplicationContext()); + public void onResponse(String tag, String response, HashMap responseHeaders) { + View _update = findViewById(R.id.update); + + if (!response.isEmpty()) { + try { + final JSONObject obj = new JSONObject(response); String versionNameonUpdate; + int versionCodeonUpdate; - if (obj.getString("versionNameBetas").equals(versionName) && !MainSettingsManager.getcheckforupdatesfromthebetachannel(activity) && !MainSettingsManager.getDontShowAgainJoinBetaUpdateChannelDialog(activity)) { - AlertDialog _alertDialog = new AlertDialog.Builder(activity, R.style.MainDialogTheme).create(); - _alertDialog.setTitle(getResources().getString(R.string.you_are_using_beta_version)); - _alertDialog.setMessage(getResources().getString(R.string.switch_to_check_for_updates_on_the_Beta_channel_now)); - _alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, getResources().getString(R.string.ok), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - MainSettingsManager.setcheckforupdatesfromthebetachannel(activity, true); - } - }); - _alertDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getResources().getString(R.string.cancel), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - _alertDialog.dismiss(); - } - }); - _alertDialog.setButton(DialogInterface.BUTTON_NEUTRAL, getResources().getString(R.string.dont_show_again), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - MainSettingsManager.setDontShowAgainJoinBetaUpdateChannelDialog(activity, true); - } - }); - _alertDialog.show(); - } - - if (MainSettingsManager.getcheckforupdatesfromthebetachannel(activity)) { + if (MainSettingsManager.getcheckforupdatesfromthebetachannel(MainActivity.this)) { versionNameonUpdate = obj.getString("versionNameBeta"); - - if (versionCode < obj.getInt("versionCode") || !versionNameonUpdate.equals(versionName)) { - if (showDialog) { - AlertDialog.Builder alert = new AlertDialog.Builder(activity, R.style.MainDialogTheme); - alert.setTitle("Install the latest version") - .setMessage(Html.fromHtml(obj.getString("MessageBeta") + "

Update size:
" + obj.getString("sizeBeta"))) - .setCancelable(obj.getBoolean("cancellableBeta")) - .setNegativeButton("Update", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - try { - startActivity(new Intent(ACTION_VIEW, Uri.parse(obj.getString("urlBeta")))); - } catch (JSONException e) { - - } - } - }).show(); - } else { - View _update = findViewById(R.id.update); - _update.setVisibility(View.VISIBLE); - } - } + versionCodeonUpdate = obj.getInt("versionCodeBeta"); } else { versionNameonUpdate = obj.getString("versionName"); - - if (versionCode < obj.getInt("versionCode") || !versionNameonUpdate.contains(versionName)) { - if (showDialog) { - AlertDialog.Builder alert = new AlertDialog.Builder(activity, R.style.MainDialogTheme); - alert.setTitle("Install the latest version") - .setMessage(Html.fromHtml(obj.getString("Message") + "

Update size:
" + obj.getString("size"))) - .setCancelable(obj.getBoolean("cancellable")) - .setNegativeButton("Update", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - try { - startActivity(new Intent(ACTION_VIEW, Uri.parse(obj.getString("url")))); - } catch (JSONException e) { - - } - } - }).show(); - } else { - View _update = findViewById(R.id.update); - _update.setVisibility(View.VISIBLE); - } - } + versionCodeonUpdate = obj.getInt("versionCode"); } - } else if (result.contains("Error on getting data") && showDialog) { - errorUpdateDialog(result); + + if (versionCode < versionCodeonUpdate || !versionNameonUpdate.equals(versionName)) { + _update.setVisibility(View.VISIBLE); + } else { + _update.setVisibility(View.GONE); + } + } catch (JSONException e) { + _update.setVisibility(View.GONE); } - } catch (Exception e) { - e.printStackTrace(); + } else { + _update.setVisibility(View.GONE); } } - }).start(showDialog); - } - private void errorUpdateDialog(String error) { - VectrasStatus.logInfo(String.format(error)); + @Override + public void onErrorResponse(String tag, String message) { + + } + }; + + requestNetwork.startRequestNetwork(RequestNetworkController.GET,AppConfig.updateJson,"maincheckupdate",requestNetworkListener); } private void loadDataVbi() { @@ -868,7 +761,7 @@ public class MainActivity extends AppCompatActivity { }); alertDialog.show(); } else if (id == R.id.backtothedisplay) { - if (VMManager.isQemuRunning()) { + if (VMManager.isQemuRunning(activity)) { if (MainSettingsManager.getVmUi(activity).equals("VNC")) activity.startActivity(new Intent(activity, MainVNCActivity.class)); else if (MainSettingsManager.getVmUi(activity).equals("X11")) @@ -881,54 +774,6 @@ public class MainActivity extends AppCompatActivity { return super.onOptionsItemSelected(item); } - /** - * CHECK WHETHER INTERNET CONNECTION IS AVAILABLE OR NOT - */ - public boolean checkConnection(Context context) { - final ConnectivityManager connMgr = (ConnectivityManager) context - .getSystemService(Context.CONNECTIVITY_SERVICE); - - if (connMgr != null) { - NetworkInfo activeNetworkInfo = connMgr.getActiveNetworkInfo(); - - if (activeNetworkInfo != null) { // connected to the internet - // connected to the mobile provider's data plan - if (activeNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI) { - // connected to wifi - return true; - } else - return activeNetworkInfo.getType() == ConnectivityManager.TYPE_MOBILE; - } - } - return false; - } - - private static boolean isMyServiceRunning(Class serviceClass) { - ActivityManager manager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE); - if (manager != null) { - for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { - if (serviceClass.getName().equals(service.service.getClassName())) { - return true; - } - } - } - return false; - } - - public static boolean checkSharedFolder() { //TODO: not work idk why - File folder = new File(AppConfig.sharedFolder); - File[] listOfFiles = folder.listFiles(); - - if (listOfFiles != null) { - for (File file : listOfFiles) { - if (file.isFile() && file.length() > 500 * 1024 * 1024) { // 500MB - return true; - } - } - } - return false; - } - public static void startVM(String vmName, String env, String itemExtra, String itemPath) { // timerTask = new TimerTask() { @@ -949,7 +794,10 @@ public class MainActivity extends AppCompatActivity { // timer.schedule(timerTask, 5000); File romDir = new File(Config.getCacheDir() + "/" + Config.vmID); - romDir.mkdirs(); + if(!romDir.mkdirs()) { + DialogUtils.oneDialog(activity, activity.getString(R.string.problem_has_been_detected), activity.getString(R.string.vm_cache_dir_failed_to_create_content) + " " + activity.getResources().getString(R.string.reason) + ": " + VMManager.latestUnsafeCommandReason, activity.getString(R.string.ok), true, R.drawable.warning_48px, true, null, null); + return; + } if (!VMManager.isthiscommandsafe(env, activity.getApplicationContext())) { DialogUtils.oneDialog(activity, activity.getString(R.string.problem_has_been_detected), activity.getString(R.string.harmful_command_was_detected) + " " + activity.getResources().getString(R.string.reason) + ": " + VMManager.latestUnsafeCommandReason, activity.getString(R.string.ok), true, R.drawable.verified_user_24px, true, null, null); @@ -958,7 +806,7 @@ public class MainActivity extends AppCompatActivity { VMManager.lastQemuCommand = env; - if (VMManager.isThisVMRunning(itemExtra, itemPath)) { + if (VMManager.isThisVMRunning(activity, itemExtra, itemPath)) { Toast.makeText(activity, "This VM is already running.", Toast.LENGTH_LONG).show(); if (MainSettingsManager.getVmUi(activity).equals("VNC")) activity.startActivity(new Intent(activity, MainVNCActivity.class)); @@ -1003,68 +851,65 @@ public class MainActivity extends AppCompatActivity { return; } - boolean isRunning = isMyServiceRunning(MainService.class); activity.showProgressDialog(activity.getString(R.string.booting_up)); Handler handler = new Handler(); handler.postDelayed( - new Runnable() { - public void run() { - if (isRunning) { - MainService.startCommand(env, activity); + () -> { + if (ServiceUtils.isServiceRunning(activity, MainService.class)) { + MainService.startCommand(env, activity); + } else { + Intent serviceIntent = new Intent(activity, MainService.class); + MainService.env = env; + MainService.CHANNEL_ID = vmName; + if (SDK_INT >= Build.VERSION_CODES.O) { + activity.startForegroundService(serviceIntent); } else { - Intent serviceIntent = new Intent(activity, MainService.class); - MainService.env = env; - MainService.CHANNEL_ID = vmName; - if (SDK_INT >= Build.VERSION_CODES.O) { - activity.startForegroundService(serviceIntent); - } else { - activity.startService(serviceIntent); - } + activity.startService(serviceIntent); } + } - if (MainSettingsManager.getVmUi(activity).equals("VNC")) { - if (MainSettingsManager.getVncExternal(MainActivity.activity)) { - extVncLayout.setVisibility(View.VISIBLE); - appbar.setExpanded(true); - activity.progressDialog.dismiss(); - } else { - Handler handler = new Handler(); - handler.postDelayed( - new Runnable() { - public void run() { - MainVNCActivity.started = true; - activity.startActivity( - new Intent( - activity, MainVNCActivity.class)); - activity.progressDialog.dismiss(); - } - }, - 2000); - } - } else if (MainSettingsManager.getVmUi(activity).equals("SPICE")) { - // activity.startActivity(new Intent(activity, - // RemoteCanvasActivity.class)); - } else if (MainSettingsManager.getVmUi(activity).equals("X11")) { - Handler handler = new Handler(); - handler.postDelayed( + if (MainSettingsManager.getVmUi(activity).equals("VNC")) { + if (MainSettingsManager.getVncExternal(MainActivity.activity)) { + extVncLayout.setVisibility(View.VISIBLE); + appbar.setExpanded(true); + activity.progressDialog.dismiss(); + } else { + Handler handler1 = new Handler(); + handler1.postDelayed( new Runnable() { public void run() { + MainVNCActivity.started = true; + activity.startActivity( + new Intent( + activity, MainVNCActivity.class)); activity.progressDialog.dismiss(); - activity.launchX11(false); } }, - 3000); + 2000); } + } else if (MainSettingsManager.getVmUi(activity).equals("SPICE")) { + // activity.startActivity(new Intent(activity, + // RemoteCanvasActivity.class)); + } else if (MainSettingsManager.getVmUi(activity).equals("X11")) { + Handler handler1 = new Handler(); + handler1.postDelayed( + new Runnable() { + public void run() { + activity.progressDialog.dismiss(); + activity.launchX11(false); + } + }, + 3000); } }, 2000); String[] params = env.split("\\s+"); VectrasStatus.logInfo("Params:"); - Log.d("StartVM", "Params:"); + Log.d("HomeStartVM", "Params:"); for (int i = 0; i < params.length; i++) { VectrasStatus.logInfo(i + ": " + params[i]); - Log.d("StartVM", i + ": " + params[i]); + Log.d("HomeStartVM", i + ": " + params[i]); } } @@ -1084,23 +929,11 @@ public class MainActivity extends AppCompatActivity { startActivity(new Intent(activity, MainVNCActivity.class)); } - public static boolean isServiceRunning(Class serviceClass, Context context) { - ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); - if (manager != null) { - for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { - if (serviceClass.getName().equals(service.service.getClassName())) { - return true; - } - } - } - return false; - } - public void onStart() { super.onStart(); Log.d(TAG, "onStart"); if (!MainSettingsManager.getVncExternal(activity)) - clearNotifications(); + NotificationUtils.clearAll(this); loadDataVbi(); Config.ui = MainSettingsManager.getVmUi(activity); @@ -1161,11 +994,14 @@ public class MainActivity extends AppCompatActivity { @Override public void onBackPressed() { - DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); + DrawerLayout drawer = findViewById(R.id.drawer_layout); if (drawer.isDrawerOpen(GravityCompat.START)) { drawer.closeDrawer(GravityCompat.START); } else { - super.onBackPressed(); + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_HOME); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); } } @@ -1178,148 +1014,116 @@ public class MainActivity extends AppCompatActivity { ProgressBar loading = findViewById(R.id.loading); if (selectedFilePath.toString().endsWith(".iso")) { loading.setVisibility(View.VISIBLE); - new Thread(new Runnable() { - @Override - public void run() { - FileInputStream File = null; + new Thread(() -> { + FileInputStream File; + try { + assert content_describer != null; + File = (FileInputStream) getContentResolver().openInputStream(content_describer); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + try { try { - File = (FileInputStream) getContentResolver().openInputStream(content_describer); - } catch (FileNotFoundException e) { - throw new RuntimeException(e); - } - try { - try { - OutputStream out = new FileOutputStream(new File(AppConfig.maindirpath + "/drive.iso")); - try { - // Transfer bytes from in to out - byte[] buf = new byte[1024]; - int len; - while ((len = File.read(buf)) > 0) { - out.write(buf, 0, len); - } - } finally { - out.close(); + try (OutputStream out = new FileOutputStream(AppConfig.maindirpath + "/drive.iso")) { + // Transfer bytes from in to out + byte[] buf = new byte[1024]; + int len; + while (true) { + assert File != null; + if (!((len = File.read(buf)) > 0)) break; + out.write(buf, 0, len); } - } finally { - Runnable runnable = new Runnable() { - @Override - public void run() { - loading.setVisibility(View.GONE); - } - }; - activity.runOnUiThread(runnable); - File.close(); } - } catch (IOException e) { - Runnable runnable = new Runnable() { - @Override - public void run() { - loading.setVisibility(View.GONE); - UIAlert(activity, e.toString(), "error"); - } - }; + } finally { + Runnable runnable = () -> loading.setVisibility(View.GONE); activity.runOnUiThread(runnable); + assert File != null; + File.close(); } + } catch (IOException e) { + Runnable runnable = () -> { + loading.setVisibility(View.GONE); + UIAlert(activity, e.toString(), "error"); + }; + activity.runOnUiThread(runnable); } }).start(); } else UIAlert(activity, "please select iso file", "INVALID FILE"); } else if (requestCode == 1005 && resultCode == RESULT_OK) { Uri content_describer = ReturnedIntent.getData(); - File selectedFilePath = new File(getPath(content_describer)); ProgressBar loading = findViewById(R.id.loading); loading.setVisibility(View.VISIBLE); - new Thread(new Runnable() { - @Override - public void run() { - FileInputStream File = null; + new Thread(() -> { + FileInputStream File; + try { + assert content_describer != null; + File = (FileInputStream) getContentResolver().openInputStream(content_describer); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + try { try { - File = (FileInputStream) getContentResolver().openInputStream(content_describer); - } catch (FileNotFoundException e) { - throw new RuntimeException(e); - } - try { - try { - OutputStream out = new FileOutputStream(new File(AppConfig.maindirpath + "/hdd1.qcow2")); - try { - // Transfer bytes from in to out - byte[] buf = new byte[1024]; - int len; - while ((len = File.read(buf)) > 0) { - out.write(buf, 0, len); - } - } finally { - out.close(); + try (OutputStream out = new FileOutputStream(AppConfig.maindirpath + "/hdd1.qcow2")) { + // Transfer bytes from in to out + byte[] buf = new byte[1024]; + int len; + while (true) { + assert File != null; + if (!((len = File.read(buf)) > 0)) break; + out.write(buf, 0, len); } - } finally { - Runnable runnable = new Runnable() { - @Override - public void run() { - loading.setVisibility(View.GONE); - } - }; - activity.runOnUiThread(runnable); - File.close(); } - } catch (IOException e) { - Runnable runnable = new Runnable() { - @Override - public void run() { - loading.setVisibility(View.GONE); - UIAlert(activity, e.toString(), "error"); - } - }; + } finally { + Runnable runnable = () -> loading.setVisibility(View.GONE); activity.runOnUiThread(runnable); + assert File != null; + File.close(); } + } catch (IOException e) { + Runnable runnable = () -> { + loading.setVisibility(View.GONE); + UIAlert(activity, e.toString(), "error"); + }; + activity.runOnUiThread(runnable); } }).start(); } else if (requestCode == 1006 && resultCode == RESULT_OK) { Uri content_describer = ReturnedIntent.getData(); - File selectedFilePath = new File(getPath(content_describer)); ProgressBar loading = findViewById(R.id.loading); loading.setVisibility(View.VISIBLE); - new Thread(new Runnable() { - @Override - public void run() { - FileInputStream File = null; + new Thread(() -> { + FileInputStream File = null; + try { + assert content_describer != null; + File = (FileInputStream) getContentResolver().openInputStream(content_describer); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + try { try { - File = (FileInputStream) getContentResolver().openInputStream(content_describer); - } catch (FileNotFoundException e) { - throw new RuntimeException(e); - } - try { - try { - OutputStream out = new FileOutputStream(new File(AppConfig.maindirpath + "/hdd2.qcow2")); - try { - // Transfer bytes from in to out - byte[] buf = new byte[1024]; - int len; - while ((len = File.read(buf)) > 0) { - out.write(buf, 0, len); - } - } finally { - out.close(); + try (OutputStream out = new FileOutputStream(AppConfig.maindirpath + "/hdd2.qcow2")) { + // Transfer bytes from in to out + byte[] buf = new byte[1024]; + int len; + while (true) { + assert File != null; + if (!((len = File.read(buf)) > 0)) break; + out.write(buf, 0, len); } - } finally { - Runnable runnable = new Runnable() { - @Override - public void run() { - loading.setVisibility(View.GONE); - } - }; - activity.runOnUiThread(runnable); - File.close(); } - } catch (IOException e) { - Runnable runnable = new Runnable() { - @Override - public void run() { - loading.setVisibility(View.GONE); - UIAlert(activity, e.toString(), "error"); - } - }; + } finally { + Runnable runnable = () -> loading.setVisibility(View.GONE); activity.runOnUiThread(runnable); + assert File != null; + File.close(); } + } catch (IOException e) { + Runnable runnable = () -> { + loading.setVisibility(View.GONE); + UIAlert(activity, e.toString(), "error"); + }; + activity.runOnUiThread(runnable); } }).start(); } else if (requestCode == 122 && resultCode == RESULT_OK) { @@ -1327,52 +1131,42 @@ public class MainActivity extends AppCompatActivity { File selectedFilePath = new File(getPath(content_describer)); ProgressBar loading = findViewById(R.id.loading); loading.setVisibility(View.VISIBLE); - new Thread(new Runnable() { - @Override - public void run() { - FileInputStream File = null; + new Thread(() -> { + FileInputStream File; + try { + assert content_describer != null; + File = (FileInputStream) getContentResolver().openInputStream(content_describer); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + try { try { - File = (FileInputStream) getContentResolver().openInputStream(content_describer); - } catch (FileNotFoundException e) { - throw new RuntimeException(e); - } - try { - try { - File romDir = new File(AppConfig.maindirpath + curRomName + "/"); - if (!romDir.exists()) { - romDir.mkdirs(); - } - OutputStream out = new FileOutputStream(new File(AppConfig.maindirpath + curRomName + "/" + "drv1-" + selectedFilePath.getName())); - try { - // Transfer bytes from in to out - byte[] buf = new byte[1024]; - int len; - while ((len = File.read(buf)) > 0) { - out.write(buf, 0, len); - } - } finally { - out.close(); - } - } finally { - Runnable runnable = new Runnable() { - @Override - public void run() { - loading.setVisibility(View.GONE); - } - }; - activity.runOnUiThread(runnable); - File.close(); + File romDir = new File(AppConfig.maindirpath + curRomName + "/"); + if (!romDir.exists()) { + if(!romDir.mkdirs()) return; } - } catch (IOException e) { - Runnable runnable = new Runnable() { - @Override - public void run() { - loading.setVisibility(View.GONE); - UIAlert(activity, e.toString(), "error"); + try (OutputStream out = new FileOutputStream(AppConfig.maindirpath + curRomName + "/" + "drv1-" + selectedFilePath.getName())) { + // Transfer bytes from in to out + byte[] buf = new byte[1024]; + int len; + while (true) { + assert File != null; + if (!((len = File.read(buf)) > 0)) break; + out.write(buf, 0, len); } - }; + } + } finally { + Runnable runnable = () -> loading.setVisibility(View.GONE); activity.runOnUiThread(runnable); + assert File != null; + File.close(); } + } catch (IOException e) { + Runnable runnable = () -> { + loading.setVisibility(View.GONE); + UIAlert(activity, e.toString(), "error"); + }; + activity.runOnUiThread(runnable); } }).start(); } @@ -1419,27 +1213,25 @@ public class MainActivity extends AppCompatActivity { private void setupBottomAppBar() { bottomAppBar = findViewById(R.id.bottomAppBar); - bottomAppBar.setOnMenuItemClickListener(new BottomAppBar.OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem item) { - if (item.getItemId() == R.id.update) { - updateApp(true); - } else if (item.getItemId() == R.id.shutdown) { - VMManager.requestKillAllQemuProcess(activity); - } else if (item.getItemId() == R.id.backtothedisplay) { - if (MainSettingsManager.getVmUi(activity).equals("VNC")) { - startActivity(new Intent(activity, MainVNCActivity.class)); - } else if (MainSettingsManager.getVmUi(activity).equals("X11")) { - launchX11(false); - } - } else if (item.getItemId() == R.id.importrom) { - Intent intent = new Intent(); - intent.setClass(getApplicationContext(), CustomRomActivity.class); - intent.putExtra("importcvbinow", ""); - startActivity(intent); + bottomAppBar.setOnMenuItemClickListener(item -> { + if (item.getItemId() == R.id.update) { + //updateApp(true); + startActivity(new Intent(this, UpdaterActivity.class)); + } else if (item.getItemId() == R.id.shutdown) { + VMManager.requestKillAllQemuProcess(activity, null); + } else if (item.getItemId() == R.id.backtothedisplay) { + if (MainSettingsManager.getVmUi(activity).equals("VNC")) { + startActivity(new Intent(activity, MainVNCActivity.class)); + } else if (MainSettingsManager.getVmUi(activity).equals("X11")) { + launchX11(false); } - return false; + } else if (item.getItemId() == R.id.importrom) { + Intent intent = new Intent(); + intent.setClass(getApplicationContext(), CustomRomActivity.class); + intent.putExtra("importcvbinow", ""); + startActivity(intent); } + return false; }); View _update = findViewById(R.id.update); _update.setVisibility(View.GONE); @@ -1471,7 +1263,7 @@ public class MainActivity extends AppCompatActivity { DialogUtils.twoDialog(activity, "Install XFCE4", "XFCE4 is not installed. Would you like to install it?", getString(R.string.install), getString(R.string.cancel), true, R.drawable.desktop_24px, true, () -> { String installCommand = "apk add " + xfce4Package; - new Terminal(activity).executeShellCommand(installCommand, true, activity); + new Terminal(activity).executeShellCommand(installCommand, true, true, activity); }, null, null); } else { if (isKillXFCE) diff --git a/app/src/main/java/com/vectras/vm/MainRoms/AdapterMainRoms.java b/app/src/main/java/com/vectras/vm/MainRoms/AdapterMainRoms.java index 7f4547d..c35234e 100644 --- a/app/src/main/java/com/vectras/vm/MainRoms/AdapterMainRoms.java +++ b/app/src/main/java/com/vectras/vm/MainRoms/AdapterMainRoms.java @@ -1,5 +1,6 @@ package com.vectras.vm.MainRoms; +import android.app.Activity; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; @@ -29,14 +30,15 @@ import java.util.List; public class AdapterMainRoms extends RecyclerView.Adapter { + private final Activity activity; private final Context context; private final LayoutInflater inflater; public List data = Collections.emptyList(); int currentPos = 0; - // create constructor to innitilize context and data sent from MainActivity - public AdapterMainRoms(Context context, List data) { - this.context = context; + public AdapterMainRoms(Activity activity, List data) { + this.activity = activity; + this.context = activity.getApplicationContext(); inflater = LayoutInflater.from(context); this.data = data; } @@ -69,15 +71,15 @@ public class AdapterMainRoms extends RecyclerView.Adapter { - BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(MainActivity.activity); - View v = MainActivity.activity.getLayoutInflater().inflate(R.layout.rom_options_dialog, null); + BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(context); + View v = activity.getLayoutInflater().inflate(R.layout.rom_options_dialog, null); bottomSheetDialog.setContentView(v); Button modifyRomBtn = v.findViewById(R.id.modifyRomBtn); modifyRomBtn.setOnClickListener(v3 -> { CustomRomActivity.current = data.get(position); - VMManager.setArch(current.itemArch, MainActivity.activity); - MainActivity.activity.startActivity(new Intent(MainActivity.activity, CustomRomActivity.class).putExtra("POS", position).putExtra("MODIFY", true).putExtra("VMID", current.vmID)); + VMManager.setArch(current.itemArch, activity); + context.startActivity(new Intent(context, CustomRomActivity.class).putExtra("POS", position).putExtra("MODIFY", true).putExtra("VMID", current.vmID)); bottomSheetDialog.cancel(); }); @@ -92,14 +94,14 @@ public class AdapterMainRoms extends RecyclerView.Adapter { - VMManager.deleteVMDialog(current.itemName, position, MainActivity.activity); + VMManager.deleteVMDialog(current.itemName, position, activity); bottomSheetDialog.cancel(); }); bottomSheetDialog.show(); }); myHolder.cdRoms.setOnClickListener(view -> { - VMManager.setArch(current.itemArch, MainActivity.activity); + VMManager.setArch(current.itemArch, activity); StartVM.cdrompath = current.imgCdrom; if (current.qmpPort == 0) { Config.setDefault(); @@ -107,12 +109,12 @@ public class AdapterMainRoms extends RecyclerView.Adapter { - VMManager.deleteVMDialog(current.itemName, position, MainActivity.activity); + VMManager.deleteVMDialog(current.itemName, position, activity); return false; }); } diff --git a/app/src/main/java/com/vectras/vm/MainService.java b/app/src/main/java/com/vectras/vm/MainService.java index 0f059da..d2dda33 100644 --- a/app/src/main/java/com/vectras/vm/MainService.java +++ b/app/src/main/java/com/vectras/vm/MainService.java @@ -28,6 +28,7 @@ public class MainService extends Service { public static String env = null; private String TAG = "MainService"; public static MainService service; + public static Activity activity; @Override public void onCreate() { @@ -49,10 +50,9 @@ public class MainService extends Service { if (env != null) { if (service != null) { - String filesDir = MainActivity.activity.getFilesDir().getAbsolutePath(); - Terminal vterm = new Terminal(this); - vterm.executeShellCommand2("dwm", false, MainActivity.activity); - vterm.executeShellCommand2(env, true, MainActivity.activity); + Terminal vterm = new Terminal(activity); + vterm.executeShellCommand2("dwm", false, activity); + vterm.executeShellCommand2(env, true, activity); } } else Log.e(TAG, "env is null"); @@ -69,12 +69,12 @@ public class MainService extends Service { //TODO: Not Work //Terminal.killQemuProcess(); - VMManager.killallqemuprocesses(MainActivity.activity); + VMManager.killallqemuprocesses(activity); } } }); - t.setName("StartVM"); + t.setName("HomeStartVM"); t.start(); } @@ -86,7 +86,7 @@ public class MainService extends Service { //TODO: Not Work //Terminal.killQemuProcess(); - VMManager.killallqemuprocesses(MainActivity.activity); + VMManager.killallqemuprocesses(this); return START_NOT_STICKY; } diff --git a/app/src/main/java/com/vectras/vm/Minitools.java b/app/src/main/java/com/vectras/vm/Minitools.java index 6840272..6bf1c4d 100644 --- a/app/src/main/java/com/vectras/vm/Minitools.java +++ b/app/src/main/java/com/vectras/vm/Minitools.java @@ -26,6 +26,7 @@ import androidx.appcompat.widget.Toolbar; import com.termux.app.TermuxService; import com.vectras.qemu.MainSettingsManager; +import com.vectras.vm.home.HomeActivity; import com.vectras.vm.utils.CommandUtils; import com.vectras.vm.utils.DialogUtils; import com.vectras.vm.utils.FileUtils; @@ -149,7 +150,7 @@ public class Minitools extends AppCompatActivity { reinstallsystem.setOnClickListener(v -> { DialogUtils.twoDialog(Minitools.this, getResources().getString(R.string.reinstall_system), getResources().getString(R.string.reinstall_system_content), getResources().getString(R.string.continuetext), getResources().getString(R.string.cancel), true, R.drawable.system_update_24px, true, () -> { - MainActivity.isActivate = false; + HomeActivity.isActivate = false; AppConfig.needreinstallsystem = true; VMManager.killallqemuprocesses(Minitools.this); FileUtils.deleteDirectory(getFilesDir().getAbsolutePath() + "/data"); diff --git a/app/src/main/java/com/vectras/vm/ProfileActivity.java b/app/src/main/java/com/vectras/vm/ProfileActivity.java index 19d7c5c..765c6cd 100644 --- a/app/src/main/java/com/vectras/vm/ProfileActivity.java +++ b/app/src/main/java/com/vectras/vm/ProfileActivity.java @@ -147,8 +147,8 @@ public class ProfileActivity extends AppCompatActivity { @Override public void onClick(View v) { FirebaseAuth.getInstance().signOut(); - MainActivity.activity.finish(); startActivity(new Intent(activity, SplashActivity.class)); + finishAffinity(); } }); } diff --git a/app/src/main/java/com/vectras/vm/Roms/AdapterRomStoreSearch.java b/app/src/main/java/com/vectras/vm/Roms/AdapterRomStoreSearch.java index f95d1aa..d36b63e 100644 --- a/app/src/main/java/com/vectras/vm/Roms/AdapterRomStoreSearch.java +++ b/app/src/main/java/com/vectras/vm/Roms/AdapterRomStoreSearch.java @@ -38,7 +38,6 @@ public class AdapterRomStoreSearch extends RecyclerView.Adapter dataRom = Collections.emptyList(); private final String TAG = "AdapterRomStoreSearch"; - // create constructor to innitilize context and data sent from MainActivity public AdapterRomStoreSearch(Context context, List data) { this.context = context; inflater = LayoutInflater.from(context); diff --git a/app/src/main/java/com/vectras/vm/Roms/AdapterRoms.java b/app/src/main/java/com/vectras/vm/Roms/AdapterRoms.java index ff3b641..8a0ff2b 100644 --- a/app/src/main/java/com/vectras/vm/Roms/AdapterRoms.java +++ b/app/src/main/java/com/vectras/vm/Roms/AdapterRoms.java @@ -38,7 +38,6 @@ public class AdapterRoms extends RecyclerView.Adapter { static List dataRom = Collections.emptyList(); private final String TAG = "AdapterRoms"; - // create constructor to innitilize context and data sent from MainActivity public AdapterRoms(Context context, List data) { this.context = context; inflater = LayoutInflater.from(context); diff --git a/app/src/main/java/com/vectras/vm/SetupQemuActivity.java b/app/src/main/java/com/vectras/vm/SetupQemuActivity.java index aaddb20..d14beda 100644 --- a/app/src/main/java/com/vectras/vm/SetupQemuActivity.java +++ b/app/src/main/java/com/vectras/vm/SetupQemuActivity.java @@ -43,6 +43,7 @@ import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import com.vectras.qemu.MainSettingsManager; import com.vectras.vm.databinding.ActivitySetupQemuBinding; +import com.vectras.vm.home.HomeActivity; import com.vectras.vm.utils.DeviceUtils; import com.vectras.vm.utils.DialogUtils; import com.vectras.vm.utils.JSONUtils; @@ -172,7 +173,7 @@ public class SetupQemuActivity extends AppCompatActivity implements View.OnClick public void onResponse(String tag, String response, HashMap responseHeaders) { linearload.setVisibility(GONE); contentJSON = response; - if (JSONUtils.isMapValidFromString(contentJSON)) { + if (JSONUtils.isValidFromString(contentJSON)) { mmap.clear(); mmap = new Gson().fromJson(contentJSON, new TypeToken>() { }.getType()); @@ -626,7 +627,7 @@ public class SetupQemuActivity extends AppCompatActivity implements View.OnClick " echo \"Starting setup...\";" + " apk update;" + " echo \"Installing packages...\";" + - " apk add " + AppConfig.neededPkgs.replaceAll(" mesa-vulkan-broadcom mesa-vulkan-freedreno mesa-vulkan-panfrost", "") + ";" + + " apk add " + AppConfig.neededPkgs32bit + ";" + //" tar -xzvf " + tarPath + " -C /;" + " echo \"Installing Qemu...\";" + " apk add qemu-system-x86_64 qemu-system-ppc qemu-system-i386 qemu-system-aarch64 qemu-pr-helper qemu-img qemu-audio-sdl pulseaudio mesa-dri-gallium;" + @@ -855,7 +856,7 @@ public class SetupQemuActivity extends AppCompatActivity implements View.OnClick @Override public void onClick(View v) { if (!AppConfig.needreinstallsystem) { - startActivity(new Intent(SetupQemuActivity.this, MainActivity.class)); + startActivity(new Intent(SetupQemuActivity.this, HomeActivity.class)); } else { AppConfig.needreinstallsystem = false; } diff --git a/app/src/main/java/com/vectras/vm/SplashActivity.java b/app/src/main/java/com/vectras/vm/SplashActivity.java index f7251e1..22c9fae 100644 --- a/app/src/main/java/com/vectras/vm/SplashActivity.java +++ b/app/src/main/java/com/vectras/vm/SplashActivity.java @@ -38,6 +38,7 @@ import androidx.core.content.ContextCompat; import androidx.preference.PreferenceManager; import com.vectras.qemu.MainSettingsManager; +import com.vectras.vm.home.HomeActivity; import com.vectras.vm.utils.FileUtils; import com.vectras.vm.utils.UIUtils; @@ -64,15 +65,11 @@ public class SplashActivity extends AppCompatActivity implements Runnable { setContentView(R.layout.activity_splash); UIUtils.setOnApplyWindowInsetsListener(findViewById(R.id.main)); - //TextView textversionname; - //textversionname = findViewById(R.id.versionname); - //PackageInfo pinfo = MainActivity.activity.getAppInfo(getApplicationContext()); - //textversionname.setText(pinfo.versionName); setupFolders(); SharedPreferences prefs = getSharedPreferences(CREDENTIAL_SHARED_PREF, Context.MODE_PRIVATE); try { - new Handler().postDelayed(activity, 3000); + new Handler().postDelayed(activity, 1000); } catch (Exception e) { throw new RuntimeException(e); }/* @@ -350,7 +347,7 @@ public class SplashActivity extends AppCompatActivity implements Runnable { String filesDir = activity.getFilesDir().getAbsolutePath(); SharedPreferences prefs = getSharedPreferences(CREDENTIAL_SHARED_PREF, Context.MODE_PRIVATE); if ((new File(filesDir, "/distro/usr/local/bin/qemu-system-x86_64").exists()) || (new File(filesDir, "/distro/usr/bin/qemu-system-x86_64").exists())) { - startActivity(new Intent(this, MainActivity.class)); + startActivity(new Intent(this, HomeActivity.class)); } else { startActivity(new Intent(this, SetupQemuActivity.class)); //For Android 14+ diff --git a/app/src/main/java/com/vectras/vm/StartVM.java b/app/src/main/java/com/vectras/vm/StartVM.java index 5add598..bfdcbd9 100644 --- a/app/src/main/java/com/vectras/vm/StartVM.java +++ b/app/src/main/java/com/vectras/vm/StartVM.java @@ -41,6 +41,9 @@ public class StartVM { else if (MainSettingsManager.getArch(activity).equals("PPC")) params.add("qemu-system-ppc"); + params.add("-qmp"); + params.add("unix:" + Config.getLocalQMPSocketPath() + ",server,nowait"); + String ifType; ifType= MainSettingsManager.getIfType(activity); @@ -150,10 +153,10 @@ public class StartVM { } String memoryStr = "-m "; - if (MainSettingsManager.getArch(activity).equals("PPC") && RamInfo.vectrasMemory() > 2048) { + if (MainSettingsManager.getArch(activity).equals("PPC") && RamInfo.vectrasMemory(activity) > 2048) { memoryStr += 2048; } else { - memoryStr += RamInfo.vectrasMemory(); + memoryStr += RamInfo.vectrasMemory(activity); } String boot = "-boot "; @@ -168,7 +171,7 @@ public class StartVM { //params.add(soundDevice); - if (MainSettingsManager.useDefaultBios(MainActivity.activity)) { + if (MainSettingsManager.useDefaultBios(activity)) { if (MainSettingsManager.getArch(activity).equals("PPC")) { bios = "-L "; bios += "pc-bios"; @@ -197,13 +200,13 @@ public class StartVM { params.add(machine); } - if (MainSettingsManager.useMemoryOvercommit(MainActivity.activity)) { + if (MainSettingsManager.useMemoryOvercommit(activity)) { params.add("-overcommit"); params.add("mem-lock=off"); } - if (MainSettingsManager.useLocalTime(MainActivity.activity)) { + if (MainSettingsManager.useLocalTime(activity)) { params.add("-rtc"); params.add("base=localtime"); } @@ -252,9 +255,9 @@ public class StartVM { params.add(vncParams); } else { - String qmpParams = "unix:"; - qmpParams += Config.getLocalVNCSocketPath(); - params.add(qmpParams); + String vncSocketParams = "unix:"; + vncSocketParams += Config.getLocalVNCSocketPath(); + params.add(vncSocketParams); } //if (!MainSettingsManager.getArch(activity).equals("PPC") || !MainSettingsManager.getArch(activity).equals("ARM64")) { @@ -272,9 +275,6 @@ public class StartVM { //params.add("-full-screen"); - params.add("-qmp"); - params.add("unix:" + Config.getLocalQMPSocketPath() + ",server,nowait"); - return String.join(" ", params); } diff --git a/app/src/main/java/com/vectras/vm/Store/AdapterStore.java b/app/src/main/java/com/vectras/vm/Store/AdapterStore.java index 52a915f..8cbb168 100644 --- a/app/src/main/java/com/vectras/vm/Store/AdapterStore.java +++ b/app/src/main/java/com/vectras/vm/Store/AdapterStore.java @@ -10,15 +10,11 @@ import android.view.animation.AnimationUtils; import android.widget.ImageView; import android.widget.TextView; import androidx.cardview.widget.CardView; -import androidx.fragment.app.FragmentTransaction; import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; import com.vectras.vm.R; -import com.vectras.vm.Fragment.HomeFragment; -import com.vectras.vm.PostActivity; import java.util.Collections; import java.util.List; -import com.vectras.vm.MainActivity; import com.vectras.vm.StoreActivity; import com.vectras.vm.StoreItemActivity; @@ -29,8 +25,7 @@ public class AdapterStore extends RecyclerView.Adapter List data = Collections.emptyList(); DataStore current; int currentPos = 0; - - // create constructor to innitilize context and data sent from MainActivity + public AdapterStore(Context context, List data) { this.context = context; inflater = LayoutInflater.from(context); @@ -53,10 +48,10 @@ public class AdapterStore extends RecyclerView.Adapter MyHolder myHolder = (MyHolder) holder; final DataStore current = data.get(position); myHolder.textName.setText(current.itemName); - myHolder.textSize.setText(MainActivity.activity.getString(R.string.size) + current.itemSize); + myHolder.textSize.setText(context.getString(R.string.size) + current.itemSize); Glide.with(StoreActivity.activity).load(current.itemIcon).into(myHolder.ivIcon); Animation animation; - animation = AnimationUtils.loadAnimation(MainActivity.activity, android.R.anim.slide_in_left); + animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left); animation.setDuration(300); myHolder.cdItem.startAnimation(animation); diff --git a/app/src/main/java/com/vectras/vm/VMManager.java b/app/src/main/java/com/vectras/vm/VMManager.java index 67ca759..f708f16 100644 --- a/app/src/main/java/com/vectras/vm/VMManager.java +++ b/app/src/main/java/com/vectras/vm/VMManager.java @@ -26,12 +26,15 @@ import androidx.recyclerview.widget.GridLayoutManager; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.textfield.TextInputLayout; import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; import com.vectras.qemu.Config; import com.vectras.qemu.MainSettingsManager; import com.vectras.qemu.MainVNCActivity; import com.vectras.qemu.utils.QmpClient; import com.vectras.vm.MainRoms.AdapterMainRoms; +import com.vectras.vm.home.HomeActivity; import com.vectras.vm.utils.DialogUtils; import com.vectras.vm.utils.FileUtils; import com.vectras.vm.utils.JSONUtils; @@ -39,6 +42,7 @@ import com.vectras.vm.utils.UIUtils; import com.vectras.vterm.Terminal; import org.jetbrains.annotations.Contract; +import org.json.JSONArray; import java.io.BufferedWriter; import java.io.File; @@ -142,24 +146,23 @@ public class VMManager { } public static void removeInRomsDataJson(Activity _activity, String _vmName, int _position) { - MainActivity.mMainAdapter = new AdapterMainRoms(MainActivity.activity, MainActivity.data); - MainActivity.data.remove(_position); - MainActivity.mRVMainRoms.setAdapter(MainActivity.mMainAdapter); - MainActivity.mRVMainRoms.setLayoutManager(new GridLayoutManager(MainActivity.activity, 2)); - MainActivity.jArray.remove(_position); try { + JSONArray jSONArray = new JSONArray(FileUtils.readFromFile(_activity, new File(AppConfig.maindirpath + + "roms-data.json"))); + jSONArray.remove(_position); + + Writer output = null; File jsonFile = new File(AppConfig.maindirpath + "roms-data" + ".json"); output = new BufferedWriter(new FileWriter(jsonFile)); - output.write(MainActivity.jArray.toString()); + output.write(jSONArray.toString()); output.close(); } catch (Exception e) { UIUtils.toastLong(_activity, e.toString()); } UIUtils.toastLong(_activity, _vmName + _activity.getString(R.string.are_removed_successfully)); - if (!FileUtils.readAFile(AppConfig.maindirpath + "roms-data.json").contains("{")) { - MainActivity.mdatasize2(); - } + + HomeActivity.refeshVMListNow(); } public static String idGenerator() { @@ -357,7 +360,7 @@ public class VMManager { if (_startRepeat < _filelist.size()) { if (!isFileExists(_filelist.get((int)(_startRepeat)) + "/vmID.txt")) { if (isFileExists(_filelist.get((int)(_startRepeat)) + "/rom-data.json")) { - if (JSONUtils.isMapValidFromString(FileUtils.readAFile(_filelist.get((int)(_startRepeat)) + "/rom-data.json"))) { + if (JSONUtils.isValidFromString(FileUtils.readAFile(_filelist.get((int)(_startRepeat)) + "/rom-data.json"))) { if (_resulttemp.toString().contains("}")) { _resulttemp.append(",").append(FileUtils.readAFile(_filelist.get((int) (_startRepeat)) + "/rom-data.json")); } else { @@ -428,67 +431,28 @@ public class VMManager { public static void startFixRomsDataJson() { int _startRepeat = 0; - StringBuilder _resulttemp = new StringBuilder(); - StringBuilder _result = new StringBuilder(); + String tempRomData; + JsonArray arr = new JsonArray(); restoredVMs = 0; ArrayList _filelist = new ArrayList<>(); FileUtils.getAListOfAllFilesAndFoldersInADirectory(AppConfig.vmFolder, _filelist); if (!_filelist.isEmpty()) { - for (int _repeat = 0; _repeat < (int)(_filelist.size()); _repeat++) { + for (int _repeat = 0; _repeat < _filelist.size(); _repeat++) { if (_startRepeat < _filelist.size()) { - if (isFileExists(_filelist.get((int)(_startRepeat)) + "/vmID.txt")) { - if (isFileExists(_filelist.get((int)(_startRepeat)) + "/rom-data.json")) { - if (JSONUtils.isMapValidFromString(FileUtils.readAFile(_filelist.get((int)(_startRepeat)) + "/rom-data.json"))) { - if (_resulttemp.toString().contains("}")) { - _resulttemp.append(",").append(FileUtils.readAFile(_filelist.get((int) (_startRepeat)) + "/rom-data.json")); - } else { - _resulttemp = new StringBuilder(FileUtils.readAFile(_filelist.get((int) (_startRepeat)) + "/rom-data.json")); - } - if (JSONUtils.isValidFromString(FileUtils.readAFile(AppConfig.maindirpath + "/roms-data.json").replaceAll("]", _resulttemp + "]"))) { - if (_result.toString().contains("}")) { - _result.append(",").append(FileUtils.readAFile(_filelist.get((int) (_startRepeat)) + "/rom-data.json")); - } else { - _result = new StringBuilder(FileUtils.readAFile(_filelist.get((int) (_startRepeat)) + "/rom-data.json")); - } - restoredVMs++; - } else if (JSONUtils.isValidFromString(FileUtils.readAFile(AppConfig.maindirpath + "/roms-data.json").replaceAll("]", "," + _resulttemp + "]"))) { - if (_result.toString().contains("}")) { - _result.append(",").append(FileUtils.readAFile(_filelist.get((int) (_startRepeat)) + "/rom-data.json")); - } else { - _result = new StringBuilder("," + FileUtils.readAFile(_filelist.get((int) (_startRepeat)) + "/rom-data.json")); - } - restoredVMs++; - } else { - Log.i("CqcmActivity", FileUtils.readAFile(AppConfig.maindirpath + "/roms-data.json").replaceAll("]", _resulttemp + "]")); - } + if (isFileExists(_filelist.get(_startRepeat) + "/vmID.txt")) { + if (isFileExists(_filelist.get(_startRepeat) + "/rom-data.json")) { + tempRomData = FileUtils.readAFile(_filelist.get(_startRepeat) + "/rom-data.json"); + if (JSONUtils.isValidFromString(tempRomData)) { + arr.add(JsonParser.parseString(tempRomData)); + restoredVMs++; } } } _startRepeat++; if (_startRepeat == _filelist.size()) { - if (_result.length() > 0) { - if (JSONUtils.isValidFromString("[" + _result + "]")) { - if (isFileExists(AppConfig.romsdatajson)) { - if (JSONUtils.isValidFromFile(AppConfig.romsdatajson)) { - String _JSONcontent = FileUtils.readAFile(AppConfig.romsdatajson); - String _JSONcontentnew = _JSONcontent.replaceAll("]", _result + "]"); - if (JSONUtils.isValidFromString(_JSONcontentnew)) { - FileUtils.writeToFile(AppConfig.maindirpath, "roms-data.json", _JSONcontentnew); - } else { - restoredVMs = 0; - } - } else { - restoredVMs = 0; - } - } else { - FileUtils.writeToFile(AppConfig.maindirpath, "roms-data.json", "[" + _result + "]"); - } - } else { - restoredVMs = 0; - } - } else { - restoredVMs = 0; + if (restoredVMs > 0) { + FileUtils.writeToFile(AppConfig.maindirpath, "roms-data.json", arr.toString()); } } } @@ -624,7 +588,7 @@ public class VMManager { if (_result.contains("proot\": error=2,")) { DialogUtils.twoDialog(_activity, _activity.getResources().getString(R.string.problem_has_been_detected), _activity.getResources().getString(R.string.error_PROOT_IS_MISSING_0), _activity.getString(R.string.continuetext), _activity.getString(R.string.cancel), true, R.drawable.build_24px, true, () -> { - MainActivity.isActivate = false; + HomeActivity.isActivate = false; FileUtils.deleteDirectory(_activity.getFilesDir().getAbsolutePath() + "/data"); FileUtils.deleteDirectory(_activity.getFilesDir().getAbsolutePath() + "/distro"); FileUtils.deleteDirectory(_activity.getFilesDir().getAbsolutePath() + "/usr"); @@ -650,7 +614,7 @@ public class VMManager { return true; } else if (_result.contains("No such file or directory")) { //Error code: NO_SUCH_FILE_OR_DIRECTORY - DialogUtils.oneDialog(_activity, _activity.getString(R.string.problem_has_been_detected), _activity.getString(R.string.error_NO_SUCH_FILE_OR_DIRECTORY), _activity.getString(R.string.ok),true, R.drawable.file_copy_24px, true,null, null); + DialogUtils.oneDialog(_activity, _activity.getString(R.string.problem_has_been_detected), _activity.getString(R.string.error_NO_SUCH_FILE_OR_DIRECTORY) + "\n\n" + _result, _activity.getString(R.string.ok),true, R.drawable.file_copy_24px, true,null, null); _activity.stopService(new Intent(_activity, MainService.class)); return true; } else { @@ -687,8 +651,7 @@ public class VMManager { } else { DialogUtils.oneDialog(_context, _context.getString(R.string.done), _context.getString(R.string.roms_data_json_fixed_successfully), _context.getString(R.string.ok),true, R.drawable.check_24px, true,null, null); } - MainActivity.mMainAdapter.notifyDataSetChanged(); - MainActivity.mdatasize2(); + HomeActivity.refeshVMListNow(); movetoRecycleBin(); } @@ -752,9 +715,9 @@ public class VMManager { return true; } - public static boolean isThisVMRunning(String intemExtra, String itemPath) { - Terminal vterm = new Terminal(MainActivity.activity); - vterm.executeShellCommand2("ps -e", false, MainActivity.activity); + public static boolean isThisVMRunning(Activity activity, String intemExtra, String itemPath) { + Terminal vterm = new Terminal(activity); + vterm.executeShellCommand2("ps -e", false, activity); if (AppConfig.temporaryLastedTerminalOutput.contains(intemExtra) && AppConfig.temporaryLastedTerminalOutput.contains(itemPath)) { Log.d("VMManager.isThisVMRunning", "Yes"); return true; @@ -764,9 +727,9 @@ public class VMManager { } } - public static boolean isQemuRunning() { - Terminal vterm = new Terminal(MainActivity.activity); - vterm.executeShellCommand2("ps -e", false, MainActivity.activity); + public static boolean isQemuRunning(Activity activity) { + Terminal vterm = new Terminal(activity); + vterm.executeShellCommand2("ps -e", false, activity); if (AppConfig.temporaryLastedTerminalOutput.contains("qemu-system")) { Log.d("VMManager.isQemuRunning", "Yes"); return true; @@ -795,15 +758,18 @@ public class VMManager { } } - public static void requestKillAllQemuProcess(Activity activity) { + public static void requestKillAllQemuProcess(Activity activity, Runnable runnable) { DialogUtils.twoDialog(activity, activity.getString(R.string.do_you_want_to_kill_all_qemu_processes), activity.getString(R.string.all_running_vms_will_be_forcibly_shut_down), activity.getString(R.string.kill_all), activity.getString(R.string.cancel), true, R.drawable.power_settings_new_24px, true, - () -> killallqemuprocesses(activity), null, null); + () -> { + killallqemuprocesses(activity); + if (runnable != null) runnable.run(); + }, null, null); } - public static void killcurrentqemuprocess(Context context) { - Terminal vterm = new Terminal(context); + public static void killcurrentqemuprocess(Activity activity) { + Terminal vterm = new Terminal(activity); String env = "killall -9 "; - switch (MainSettingsManager.getArch(MainActivity.activity)) { + switch (MainSettingsManager.getArch(activity)) { case "ARM64": env += "qemu-system-aarch64"; break; @@ -817,15 +783,15 @@ public class VMManager { env += "qemu-system-x86_64"; break; } - vterm.executeShellCommand2(env, false, MainActivity.activity); + vterm.executeShellCommand2(env, false, null); } public static void killallqemuprocesses(Context context) { Terminal vterm = new Terminal(context); - vterm.executeShellCommand2("killall -9 qemu-system-i386", false, MainActivity.activity); - vterm.executeShellCommand2("killall -9 qemu-system-x86_64", false, MainActivity.activity); - vterm.executeShellCommand2("killall -9 qemu-system-aarch64", false, MainActivity.activity); - vterm.executeShellCommand2("killall -9 qemu-system-ppc", false, MainActivity.activity); + vterm.executeShellCommand2("killall -9 qemu-system-i386", false, null); + vterm.executeShellCommand2("killall -9 qemu-system-x86_64", false, null); + vterm.executeShellCommand2("killall -9 qemu-system-aarch64", false, null); + vterm.executeShellCommand2("killall -9 qemu-system-ppc", false, null); } public static void shutdownCurrentVM() { @@ -1195,4 +1161,18 @@ public class VMManager { || _qemuCommand.contains("-M pc-q35") || _qemuCommand.contains("-machine pc-q35"); } + + public static boolean checkSharedFolder() { //TODO: not work idk why + File folder = new File(AppConfig.sharedFolder); + File[] listOfFiles = folder.listFiles(); + + if (listOfFiles != null) { + for (File file : listOfFiles) { + if (file.isFile() && file.length() > 500 * 1024 * 1024) { // 500MB + return true; + } + } + } + return false; + } } diff --git a/app/src/main/java/com/vectras/vm/VectrasApp.java b/app/src/main/java/com/vectras/vm/VectrasApp.java index 9531751..31fa34b 100644 --- a/app/src/main/java/com/vectras/vm/VectrasApp.java +++ b/app/src/main/java/com/vectras/vm/VectrasApp.java @@ -86,6 +86,7 @@ public class VectrasApp extends Application { public void onCreate() { super.onCreate(); vectrasapp = this; + context = new WeakReference<>(getApplicationContext()); CrashHandler.getInstance().registerGlobal(this); CrashHandler.getInstance().registerPart(this); try { diff --git a/app/src/main/java/com/vectras/vm/WidgetProvider.java b/app/src/main/java/com/vectras/vm/WidgetProvider.java index ab2210b..9f9d332 100644 --- a/app/src/main/java/com/vectras/vm/WidgetProvider.java +++ b/app/src/main/java/com/vectras/vm/WidgetProvider.java @@ -15,6 +15,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.vectras.vm.MainRoms.AdapterMainRoms; import com.vectras.vm.MainRoms.DataMainRoms; +import com.vectras.vm.home.HomeActivity; import com.vectras.vm.utils.FileUtils; import org.json.JSONArray; @@ -33,7 +34,7 @@ public class WidgetProvider extends AppWidgetProvider { for (int i=0; i < appWidgetIds.length; i++) { int appWidgetId = appWidgetIds[i]; // Create an Intent to launch ExampleActivity - Intent intent = new Intent(context, MainActivity.class); + Intent intent = new Intent(context, HomeActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity( /* context = */ context, /* requestCode = */ 0, diff --git a/app/src/main/java/com/vectras/vm/home/HomeActivity.java b/app/src/main/java/com/vectras/vm/home/HomeActivity.java new file mode 100644 index 0000000..a2fb7b6 --- /dev/null +++ b/app/src/main/java/com/vectras/vm/home/HomeActivity.java @@ -0,0 +1,844 @@ +package com.vectras.vm.home; + +import static android.content.Intent.ACTION_OPEN_DOCUMENT; +import static android.content.Intent.ACTION_VIEW; +import static android.os.Build.VERSION.SDK_INT; +import static com.vectras.vm.VectrasApp.getApp; +import static com.vectras.vm.utils.UIUtils.UIAlert; + +import android.annotation.SuppressLint; +import android.app.Dialog; +import android.content.Intent; +import android.content.res.Configuration; +import android.graphics.Color; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.os.StrictMode; +import android.provider.DocumentsContract; +import android.text.Editable; +import android.text.TextWatcher; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.ProgressBar; + +import androidx.activity.EdgeToEdge; +import androidx.activity.OnBackPressedCallback; +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBarDrawerToggle; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.view.GravityCompat; +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.google.android.material.bottomsheet.BottomSheetDialog; +import com.google.android.material.button.MaterialButton; +import com.google.gson.Gson; +import com.termux.app.TermuxActivity; +import com.vectras.qemu.Config; +import com.vectras.qemu.MainSettingsManager; +import com.vectras.vm.AboutActivity; +import com.vectras.vm.AppConfig; +import com.vectras.vm.CustomRomActivity; +import com.vectras.vm.DataExplorerActivity; +import com.vectras.vm.Minitools; +import com.vectras.vm.R; +import com.vectras.vm.RequestNetwork; +import com.vectras.vm.RequestNetworkController; +import com.vectras.vm.Roms.AdapterRomStoreSearch; +import com.vectras.vm.Roms.DataRoms; +import com.vectras.vm.RomsManagerActivity; +import com.vectras.vm.SetArchActivity; +import com.vectras.vm.StoreActivity; +import com.vectras.vm.VMManager; +import com.vectras.vm.adapter.LogsAdapter; +import com.vectras.vm.databinding.ActivityHomeBinding; +import com.vectras.vm.databinding.ActivityHomeContentBinding; +import com.vectras.vm.home.core.CallbackInterface; +import com.vectras.vm.home.core.DisplaySystem; +import com.vectras.vm.home.core.PendingCommand; +import com.vectras.vm.home.core.SharedData; +import com.vectras.vm.home.monitor.SystemMonitorFragment; +import com.vectras.vm.home.romstore.RomStoreFragment; +import com.vectras.vm.home.vms.VmsFragment; +import com.vectras.vm.home.vms.VmsHomeAdapter; +import com.vectras.vm.logger.VectrasStatus; +import com.vectras.vm.settings.UpdaterActivity; +import com.vectras.vm.utils.DialogUtils; +import com.vectras.vm.utils.FileUtils; +import com.vectras.vm.utils.LibraryChecker; +import com.vectras.vm.utils.NotificationUtils; +import com.vectras.vm.utils.PackageUtils; +import com.vectras.vm.utils.UIUtils; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; +import java.util.stream.Collectors; + +public class HomeActivity extends AppCompatActivity implements RomStoreFragment.RomStoreCallToHomeListener, VmsFragment.VmsCallToHomeListener { + + public static String curRomName; + private final String TAG = "HomeActivity"; + public static boolean isActivate = false; + ActivityHomeBinding binding; + ActivityHomeContentBinding bindingContent; + private AdapterRomStoreSearch adapterRomStoreSearch; + private final List dataRomStoreSearch = new ArrayList<>(); + + public static CallbackInterface.HomeCallToVmsListener homeCallToVmsListener; + + public static void refeshVMListNow() { + homeCallToVmsListener.refeshVMList(); + } + + @Override + public void updateDataStatus(boolean isReady) { + bindingContent.searchbar.setEnabled(isReady); + } + + @Override + public void openRomStore() { + bindingContent.bottomNavigation.setSelectedItemId(R.id.item_romstore); + } + + @Override + protected void onCreate(Bundle bundle) { + super.onCreate(bundle); + + StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); + StrictMode.setThreadPolicy(policy); + + VmsFragment.vmsCallToHomeListener = this; + RomStoreFragment.romStoreCallToHomeListener = this; + + EdgeToEdge.enable(this); + binding = ActivityHomeBinding.inflate(getLayoutInflater()); + bindingContent = binding.maincontent; + setContentView(binding.getRoot()); + isActivate = true; + + UIUtils.setOnApplyWindowInsetsListener(bindingContent.main); + UIUtils.setOnApplyWindowInsetsListenerLeftOnly(binding.navView); + UIUtils.setOnApplyWindowInsetsListenerBottomOnly(binding.rvRomstoresearch); + UIUtils.setOnApplyWindowInsetsListenerBottomOnly(binding.lnSearchempty); + + initialize(bundle); + } + + private void initialize(Bundle savedInstanceState) { + bindingContent.efabCreate.setOnClickListener(view -> startActivity(new Intent(this, SetArchActivity.class))); + + setSupportActionBar(bindingContent.toolbar); + if (getSupportActionBar() != null) { + getSupportActionBar().setDisplayShowTitleEnabled(false); + } + + ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, binding.drawerLayout, bindingContent.toolbar, + R.string.navigation_drawer_open, R.string.navigation_drawer_close); + binding.drawerLayout.addDrawerListener(toggle); + toggle.syncState(); + + if (savedInstanceState == null) { + getSupportFragmentManager().beginTransaction() + .replace(bindingContent.containerView.getId(), new VmsFragment()) + .commit(); + } + + binding.searchview.setupWithSearchBar(bindingContent.searchbar); + + bindingContent.searchbar.inflateMenu(R.menu.searchbar_menu); + bindingContent.searchbar.setOnMenuItemClickListener( + menuItem -> { + if (menuItem.getItemId() == R.id.importrom) { + Intent intent = new Intent(); + intent.setClass(getApplicationContext(), CustomRomActivity.class); + intent.putExtra("importcvbinow", ""); + startActivity(intent); + } else if (menuItem.getItemId() == R.id.backtothedisplay) { + DisplaySystem.launch(this); + } + return true; + }); + + bindingContent.searchbar.setEnabled(false); + + bindingContent.bottomNavigation.setOnItemSelectedListener(item -> { + Fragment selectedFragment; + + int id = item.getItemId(); + if (id == R.id.item_home) { + selectedFragment = new VmsFragment(); + bindingContent.efabCreate.setVisibility(View.VISIBLE); + bindingContent.searchbar.setHint(getText(R.string.home)); + bindingContent.searchbar.setEnabled(false); + } else if (id == R.id.item_romstore) { + selectedFragment = new RomStoreFragment(); + bindingContent.efabCreate.setVisibility(View.GONE); + bindingContent.searchbar.setEnabled(true); + bindingContent.searchbar.setHint(getText(R.string.search)); + } else if (id == R.id.item_monitor) { + selectedFragment = new SystemMonitorFragment(); + bindingContent.efabCreate.setVisibility(View.GONE); + bindingContent.searchbar.setHint(getText(R.string.system_monitor)); + bindingContent.searchbar.setEnabled(false); + } else { + selectedFragment = new VmsFragment(); + bindingContent.efabCreate.setVisibility(View.VISIBLE); + bindingContent.searchbar.setHint(getText(R.string.home)); + bindingContent.searchbar.setEnabled(false); + } + + if (selectedFragment != null) { + getSupportFragmentManager().beginTransaction() + .replace(bindingContent.containerView.getId(), selectedFragment) + .commit(); + return true; + } + return false; + }); + + getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) { + @Override + public void handleOnBackPressed() { + if (binding.drawerLayout.isDrawerOpen(GravityCompat.START)) { + binding.drawerLayout.closeDrawer(GravityCompat.START); + } else { + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_HOME); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + } + } + }); + + adapterRomStoreSearch = new AdapterRomStoreSearch(this, dataRomStoreSearch); + binding.rvRomstoresearch.setAdapter(adapterRomStoreSearch); + binding.rvRomstoresearch.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); + + binding.searchview.getEditText().addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void afterTextChanged(Editable s) { + search(s.toString()); + } + + @Override + public void onTextChanged(CharSequence newText, int start, int before, int count) { + } + }); + + new LibraryChecker(this).checkMissingLibraries(this); + + setupDrawer(); + DisplaySystem.startTermuxX11(); + DialogUtils.joinTelegram(this); + NotificationUtils.clearAll(this); + + if (MainSettingsManager.getPromptUpdateVersion(this)) + updateApp(); + } + + @Override + public void onConfigurationChanged(@NonNull Configuration newConfig) { + super.onConfigurationChanged(newConfig); + homeCallToVmsListener.configurationChanged(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE); + } + + @Override + public void onDestroy() { + isActivate = false; + super.onDestroy(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.home_toolbar_menu, menu); + return true; + + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + + // Menu items + int id = item.getItemId(); + if (id == R.id.shutdown) { + VMManager.requestKillAllQemuProcess(this, null); + } + + return super.onOptionsItemSelected(item); + } + + public void onResume() { + super.onResume(); + Log.d(TAG, "onResume"); + Config.ui = MainSettingsManager.getVmUi(this); + Config.defaultVNCPort = Integer.parseInt(MainSettingsManager.getVncExternalDisplay(this)); + + if (!MainSettingsManager.getVncExternal(this)) + NotificationUtils.clearAll(this); + Config.ui = MainSettingsManager.getVmUi(this); + + DisplaySystem.reLaunchVNC(this); + PendingCommand.runNow(this); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent ReturnedIntent) { + super.onActivityResult(requestCode, resultCode, ReturnedIntent); + if (requestCode == 1004 && resultCode == RESULT_OK) { + Uri content_describer = ReturnedIntent.getData(); + File selectedFilePath = new File(getPath(content_describer)); + ProgressBar loading = findViewById(R.id.loading); + if (selectedFilePath.toString().endsWith(".iso")) { + loading.setVisibility(View.VISIBLE); + new Thread(() -> { + FileInputStream File; + try { + assert content_describer != null; + File = (FileInputStream) getContentResolver().openInputStream(content_describer); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + try { + try { + try (OutputStream out = new FileOutputStream(AppConfig.maindirpath + "/drive.iso")) { + // Transfer bytes from in to out + byte[] buf = new byte[1024]; + int len; + while (true) { + assert File != null; + if (!((len = File.read(buf)) > 0)) break; + out.write(buf, 0, len); + } + } + } finally { + Runnable runnable = () -> loading.setVisibility(View.GONE); + runOnUiThread(runnable); + assert File != null; + File.close(); + } + } catch (IOException e) { + Runnable runnable = () -> { + loading.setVisibility(View.GONE); + UIAlert(this, e.toString(), "error"); + }; + runOnUiThread(runnable); + } + }).start(); + } else + UIAlert(this, "please select iso file", "INVALID FILE"); + } else if (requestCode == 1005 && resultCode == RESULT_OK) { + Uri content_describer = ReturnedIntent.getData(); + ProgressBar loading = findViewById(R.id.loading); + loading.setVisibility(View.VISIBLE); + new Thread(() -> { + FileInputStream File; + try { + assert content_describer != null; + File = (FileInputStream) getContentResolver().openInputStream(content_describer); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + try { + try { + try (OutputStream out = new FileOutputStream(AppConfig.maindirpath + "/hdd1.qcow2")) { + // Transfer bytes from in to out + byte[] buf = new byte[1024]; + int len; + while (true) { + assert File != null; + if (!((len = File.read(buf)) > 0)) break; + out.write(buf, 0, len); + } + } + } finally { + Runnable runnable = () -> loading.setVisibility(View.GONE); + runOnUiThread(runnable); + assert File != null; + File.close(); + } + } catch (IOException e) { + Runnable runnable = () -> { + loading.setVisibility(View.GONE); + UIAlert(this, e.toString(), "error"); + }; + runOnUiThread(runnable); + } + }).start(); + } else if (requestCode == 1006 && resultCode == RESULT_OK) { + Uri content_describer = ReturnedIntent.getData(); + ProgressBar loading = findViewById(R.id.loading); + loading.setVisibility(View.VISIBLE); + new Thread(() -> { + FileInputStream File; + try { + assert content_describer != null; + File = (FileInputStream) getContentResolver().openInputStream(content_describer); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + try { + try { + try (OutputStream out = new FileOutputStream(AppConfig.maindirpath + "/hdd2.qcow2")) { + // Transfer bytes from in to out + byte[] buf = new byte[1024]; + int len; + while (true) { + assert File != null; + if (!((len = File.read(buf)) > 0)) break; + out.write(buf, 0, len); + } + } + } finally { + Runnable runnable = () -> loading.setVisibility(View.GONE); + runOnUiThread(runnable); + assert File != null; + File.close(); + } + } catch (IOException e) { + Runnable runnable = () -> { + loading.setVisibility(View.GONE); + UIAlert(this, e.toString(), "error"); + }; + runOnUiThread(runnable); + } + }).start(); + } else if (requestCode == 122 && resultCode == RESULT_OK) { + Uri content_describer = ReturnedIntent.getData(); + File selectedFilePath = new File(getPath(content_describer)); + ProgressBar loading = findViewById(R.id.loading); + loading.setVisibility(View.VISIBLE); + new Thread(() -> { + FileInputStream File; + try { + assert content_describer != null; + File = (FileInputStream) getContentResolver().openInputStream(content_describer); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + try { + try { + File romDir = new File(AppConfig.maindirpath + curRomName + "/"); + if (!romDir.exists()) { + if(!romDir.mkdirs()) return; + } + try (OutputStream out = new FileOutputStream(AppConfig.maindirpath + curRomName + "/" + "drv1-" + selectedFilePath.getName())) { + // Transfer bytes from in to out + byte[] buf = new byte[1024]; + int len; + while (true) { + assert File != null; + if (!((len = File.read(buf)) > 0)) break; + out.write(buf, 0, len); + } + } + } finally { + Runnable runnable = () -> loading.setVisibility(View.GONE); + runOnUiThread(runnable); + assert File != null; + File.close(); + } + } catch (IOException e) { + Runnable runnable = () -> { + loading.setVisibility(View.GONE); + UIAlert(this, e.toString(), "error"); + }; + runOnUiThread(runnable); + } + }).start(); + } + } + + public String getPath(Uri uri) { + return FileUtils.getPath(this, uri); + } + + private void setupDrawer() { + binding.drawerLayout.setScrimColor(Color.parseColor("#40000000")); //25% + + //Setting Navigation View Item Selected Listener to handle the item click of the navigation menu + // This method will trigger on item Click of navigation menu + binding.navView.setNavigationItemSelectedListener(menuItem -> { + //Closing drawer on item click + binding.drawerLayout.closeDrawers(); + + //Check to see which item was being clicked and perform appropriate action + int id = menuItem.getItemId(); + if (id == R.id.navigation_item_info) { + startActivity(new Intent(this, AboutActivity.class)); + } + if (id == R.id.navigation_item_help) { + String tw = AppConfig.vectrasHelp; + Intent w = new Intent(ACTION_VIEW); + w.setData(Uri.parse(tw)); + startActivity(w); + } else if (id == R.id.navigation_item_website) { + String tw = AppConfig.vectrasWebsite; + Intent w = new Intent(ACTION_VIEW); + w.setData(Uri.parse(tw)); + startActivity(w); + } else if (id == R.id.navigation_item_import_iso) { + if (new File(AppConfig.maindirpath + "/drive.iso").exists()) { + AlertDialog ad; + ad = new AlertDialog.Builder(this, R.style.MainDialogTheme).create(); + ad.setTitle("REPLACE ISO"); + ad.setMessage("there is iso imported you want to replace it?"); + ad.setButton(Dialog.BUTTON_POSITIVE, "REPLACE", (dialog, which) -> { + Intent intent = new Intent(ACTION_OPEN_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("*/*"); + + // Optionally, specify a URI for the file that should appear in the + // system file picker when it loads. + if (SDK_INT >= Build.VERSION_CODES.O) { + intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.DIRECTORY_DOWNLOADS); + } + + startActivityForResult(intent, 1004); + }); + ad.setButton(Dialog.BUTTON_NEGATIVE, "REMOVE", (dialog, which) -> { + File isoFile = new File(AppConfig.maindirpath + "/drive.iso"); + try { + if(!isoFile.delete()) Log.e(TAG, "Delete drive.iso failed!"); + } catch (Exception e) { + Log.e(TAG, "Delete drive.iso: ", e); + } + }); + ad.show(); + } else { + Intent intent = new Intent(ACTION_OPEN_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("*/*"); + + // Optionally, specify a URI for the file that should appear in the + // system file picker when it loads. + if (SDK_INT >= Build.VERSION_CODES.O) { + intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.DIRECTORY_DOWNLOADS); + } + + startActivityForResult(intent, 1004); + } + } else if (id == R.id.navigation_item_hdd1) { + if (new File(AppConfig.maindirpath + "/hdd1.qcow2").exists()) { + AlertDialog ad; + ad = new AlertDialog.Builder(this, R.style.MainDialogTheme).create(); + ad.setTitle("REPLACE HDD1"); + ad.setMessage("there is hdd1 imported you want to replace it?"); + ad.setButton(Dialog.BUTTON_POSITIVE, "REPLACE", (dialog, which) -> { + Intent intent = new Intent(ACTION_OPEN_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("*/*"); + + // Optionally, specify a URI for the file that should appear in the + // system file picker when it loads. + if (SDK_INT >= Build.VERSION_CODES.O) { + intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.DIRECTORY_DOWNLOADS); + } + + startActivityForResult(intent, 1006); + }); + ad.setButton(Dialog.BUTTON_NEGATIVE, "REMOVE", (dialog, which) -> { + File isoFile = new File(AppConfig.maindirpath + "/hdd1.qcow2"); + try { + if(!isoFile.delete()) Log.e(TAG, "Delete hdd1.qcow2 failed!"); + } catch (Exception e) { + Log.e(TAG, "Delete hdd1.qcow2: ", e); + } + }); + ad.setButton(Dialog.BUTTON_NEUTRAL, "SHARE", (dialog, which) -> { + Intent intentShareFile = new Intent(Intent.ACTION_SEND); + File fileWithinMyDir = new File(AppConfig.maindirpath + "/hdd1.qcow2"); + + if (fileWithinMyDir.exists()) { + intentShareFile.setType("*/*"); + intentShareFile.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + AppConfig.maindirpath + "/hdd1.qcow2")); + + intentShareFile.putExtra(Intent.EXTRA_SUBJECT, + "Sharing File..."); + intentShareFile.putExtra(Intent.EXTRA_TEXT, "Sharing File..."); + + startActivity(Intent.createChooser(intentShareFile, "Share File")); + } + }); + ad.show(); + } else { + Intent intent = new Intent(ACTION_OPEN_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("*/*"); + + // Optionally, specify a URI for the file that should appear in the + // system file picker when it loads. + if (SDK_INT >= Build.VERSION_CODES.O) { + intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.DIRECTORY_DOWNLOADS); + } + + startActivityForResult(intent, 1005); + } + } else if (id == R.id.navigation_item_hdd2) { + if (new File(AppConfig.maindirpath + "/hdd2.qcow2").exists()) { + AlertDialog ad; + ad = new AlertDialog.Builder(this, R.style.MainDialogTheme).create(); + ad.setTitle("REPLACE HDD2"); + ad.setMessage("there is hdd2 imported you want to replace it?"); + ad.setButton(Dialog.BUTTON_POSITIVE, "REPLACE", (dialog, which) -> { + Intent intent = new Intent(ACTION_OPEN_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("*/*"); + + // Optionally, specify a URI for the file that should appear in the + // system file picker when it loads. + if (SDK_INT >= Build.VERSION_CODES.O) { + intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.DIRECTORY_DOWNLOADS); + } + + startActivityForResult(intent, 1006); + }); + ad.setButton(Dialog.BUTTON_NEGATIVE, "REMOVE", (dialog, which) -> { + File isoFile = new File(AppConfig.maindirpath + "/hdd2.qcow2"); + try { + if(!isoFile.delete()) Log.e(TAG, "Delete hdd2.qcow2 failed!"); + } catch (Exception e) { + Log.e(TAG, "Delete hdd2.qcow2: ", e); + } + }); + ad.setButton(Dialog.BUTTON_NEUTRAL, "SHARE", (dialog, which) -> { + Intent intentShareFile = new Intent(Intent.ACTION_SEND); + File fileWithinMyDir = new File(AppConfig.maindirpath + "/hdd2.qcow2"); + + if (fileWithinMyDir.exists()) { + intentShareFile.setType("*/*"); + intentShareFile.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + AppConfig.maindirpath + "/hdd2.qcow2")); + + intentShareFile.putExtra(Intent.EXTRA_SUBJECT, + "Sharing File..."); + intentShareFile.putExtra(Intent.EXTRA_TEXT, "Sharing File..."); + + startActivity(Intent.createChooser(intentShareFile, "Share File")); + } + }); + ad.show(); + } else { + Intent intent = new Intent(ACTION_OPEN_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("*/*"); + + // Optionally, specify a URI for the file that should appear in the + // system file picker when it loads. + if (SDK_INT >= Build.VERSION_CODES.O) { + intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.DIRECTORY_DOWNLOADS); + } + + startActivityForResult(intent, 1006); + } + } else if (id == R.id.navigation_item_desktop) { + DisplaySystem.launchX11(this, true); + } else if (id == R.id.navigation_item_terminal) { + /*com.vectras.vterm.TerminalBottomSheetDialog VTERM = new com.vectras.vterm.TerminalBottomSheetDialog(activity); + VTERM.showVterm();*/ + startActivity(new Intent(this, TermuxActivity.class)); + } else if (id == R.id.navigation_item_view_logs) { + BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(this); + View view = getLayoutInflater().inflate(R.layout.bottomsheetdialog_logger, null); + bottomSheetDialog.setContentView(view); + bottomSheetDialog.show(); + +// final String CREDENTIAL_SHARED_PREF = "settings_prefs"; + Timer _timer = new Timer(); + TimerTask t; + + LinearLayoutManager layoutManager = new LinearLayoutManager(getApp()); + LogsAdapter mLogAdapter = new LogsAdapter(layoutManager, getApp()); + RecyclerView logList = view.findViewById(R.id.recyclerLog); + logList.setAdapter(mLogAdapter); + logList.setLayoutManager(layoutManager); + mLogAdapter.scrollToLastPosition(); + try { + Process process = Runtime.getRuntime().exec("logcat -e"); + BufferedReader bufferedReader = new BufferedReader( + new InputStreamReader(process.getInputStream())); + Process process2 = Runtime.getRuntime().exec("logcat -w"); + BufferedReader bufferedReader2 = new BufferedReader( + new InputStreamReader(process2.getInputStream())); + + t = new TimerTask() { + @Override + public void run() { + runOnUiThread(() -> { + try { + if (bufferedReader.readLine() != null || bufferedReader2.readLine() != null) { + String logLine = bufferedReader.readLine(); + String logLine2 = bufferedReader2.readLine(); + VectrasStatus.logError("[E] " + logLine + ""); + VectrasStatus.logError("[W] " + logLine2 + ""); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } + }; + _timer.scheduleAtFixedRate(t, 0, 100); + } catch (IOException e) { + Log.e(TAG, "Log: ", e); + } + } else if (id == R.id.navigation_item_settings) { + startActivity(new Intent(this, MainSettingsManager.class)); + } else if (id == R.id.navigation_item_store) { + startActivity(new Intent(this, StoreActivity.class)); + } else if (id == R.id.navigation_data_explorer) { + startActivity(new Intent(this, DataExplorerActivity.class)); + } else if (id == R.id.navigation_item_donate) { + String tw = "https://www.patreon.com/VectrasTeam"; + Intent w = new Intent(ACTION_VIEW); + w.setData(Uri.parse(tw)); + startActivity(w); + } else if (id == R.id.navigation_item_get_rom) { + Intent intent = new Intent(); + intent.setClass(getApplicationContext(), RomsManagerActivity.class); + startActivity(intent); + } else if (id == R.id.mini_tools) { + Intent intent = new Intent(); + intent.setClass(this, Minitools.class); + startActivity(intent); + } + return false; + }); + } + + private void updateApp() { + int versionCode = PackageUtils.getThisVersionCode(getApplicationContext()); + String versionName = PackageUtils.getThisVersionName(getApplicationContext()); + + RequestNetwork requestNetwork = new RequestNetwork(this); + RequestNetwork.RequestListener requestNetworkListener = new RequestNetwork.RequestListener() { + @Override + public void onResponse(String tag, String response, HashMap responseHeaders) { + if (!response.isEmpty()) { + try { + final JSONObject obj = new JSONObject(response); + String versionNameonUpdate; + int versionCodeonUpdate; +// String message; +// String size; + + if (MainSettingsManager.getcheckforupdatesfromthebetachannel(HomeActivity.this)) { + versionNameonUpdate = obj.getString("versionNameBeta"); + versionCodeonUpdate = obj.getInt("versionCodeBeta"); +// message = obj.getString("MessageBeta"); +// size = obj.getString("sizeBeta"); + } else { + versionNameonUpdate = obj.getString("versionName"); + versionCodeonUpdate = obj.getInt("versionCode"); +// message = obj.getString("Message"); +// size = obj.getString("size"); + } + + if ((versionCode < versionCodeonUpdate || + !versionNameonUpdate.equals(versionName)) && + !MainSettingsManager.getSkipVersion(HomeActivity.this).equals(versionNameonUpdate)) { + + BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(HomeActivity.this); + View v = getLayoutInflater().inflate(R.layout.update_bottom_dialog_layout, null); + bottomSheetDialog.setContentView(v); + +// TextView tvContent = v.findViewById(R.id.tv_content); + MaterialButton skipButton = v.findViewById(R.id.bn_skip); + MaterialButton laterButton = v.findViewById(R.id.bn_later); + MaterialButton updateButton = v.findViewById(R.id.bn_update); + +// tvContent.setMovementMethod(LinkMovementMethod.getInstance()); +// tvContent.setText(Html.fromHtml(message + "

Update size:
" + size)); + + skipButton.setOnClickListener(view -> { + MainSettingsManager.setSkipVersion(HomeActivity.this, versionNameonUpdate); + bottomSheetDialog.dismiss(); + }); + + laterButton.setOnClickListener(view -> bottomSheetDialog.dismiss()); + + updateButton.setOnClickListener(view -> { + startActivity(new Intent(HomeActivity.this, UpdaterActivity.class)); + bottomSheetDialog.dismiss(); + }); + + bottomSheetDialog.show(); + } + } catch (JSONException e) { + Log.e(TAG, "updateApp: ", e); + } + } + } + + @Override + public void onErrorResponse(String tag, String message) { + + } + }; + + requestNetwork.startRequestNetwork(RequestNetworkController.GET,AppConfig.updateJson,"maincheckupdate",requestNetworkListener); + } + + @SuppressLint("NotifyDataSetChanged") + private void search(String keyword) { + try { + // Extract data from json and store into ArrayList as class objects + Gson gson = new Gson(); + List filteredData = new ArrayList<>(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + filteredData = SharedData.dataRomStore.stream() + .filter(rom -> { + String romName = (rom.romName != null) ? rom.romName : ""; + String romKernel = (rom.romKernel != null) ? rom.romKernel : ""; + + return romName.toLowerCase().contains(keyword.toLowerCase()) + || romKernel.toLowerCase().contains(keyword.toLowerCase()); + }) + .collect(Collectors.toList()); + } else { + for (DataRoms rom : SharedData.dataRomStore) { + if (rom.romName.toLowerCase().contains(keyword.toLowerCase()) || + rom.romKernel.toLowerCase().contains(keyword.toLowerCase())) { + filteredData.add(rom); + } + } + } + + dataRomStoreSearch.clear(); + dataRomStoreSearch.addAll(filteredData); + } catch (Exception e) { + Log.e("RomManagerActivity", "Json parsing error: " + e.getMessage()); + } + + if (dataRomStoreSearch.isEmpty()) + binding.rvRomstoresearch.setVisibility(View.GONE); + else + binding.rvRomstoresearch.setVisibility(View.VISIBLE); + + adapterRomStoreSearch.notifyDataSetChanged(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/vectras/vm/home/core/CallbackInterface.java b/app/src/main/java/com/vectras/vm/home/core/CallbackInterface.java new file mode 100644 index 0000000..482658c --- /dev/null +++ b/app/src/main/java/com/vectras/vm/home/core/CallbackInterface.java @@ -0,0 +1,9 @@ +package com.vectras.vm.home.core; + +public class CallbackInterface { + //Fix Cyclic. + public interface HomeCallToVmsListener { + void refeshVMList(); + void configurationChanged(boolean isLandscape); + } +} diff --git a/app/src/main/java/com/vectras/vm/home/core/DisplaySystem.java b/app/src/main/java/com/vectras/vm/home/core/DisplaySystem.java new file mode 100644 index 0000000..ef6e9da --- /dev/null +++ b/app/src/main/java/com/vectras/vm/home/core/DisplaySystem.java @@ -0,0 +1,105 @@ +package com.vectras.vm.home.core; + +import static android.os.Build.VERSION.SDK_INT; +import static com.vectras.vm.utils.LibraryChecker.isPackageInstalled2; + +import android.app.Activity; +import android.content.Intent; +import android.os.Build; + +import com.termux.app.TermuxService; +import com.vectras.qemu.Config; +import com.vectras.qemu.MainSettingsManager; +import com.vectras.qemu.MainVNCActivity; +import com.vectras.vm.R; +import com.vectras.vm.core.ShellExecutor; +import com.vectras.vm.utils.DialogUtils; +import com.vectras.vm.utils.FileUtils; +import com.vectras.vm.x11.X11Activity; +import com.vectras.vterm.Terminal; + +import java.util.HashSet; +import java.util.Set; + +public class DisplaySystem { + public static void launch(Activity activity) { + if (MainSettingsManager.getVmUi(activity).equals("VNC")) { + activity.startActivity(new Intent(activity, MainVNCActivity.class)); + } else if (MainSettingsManager.getVmUi(activity).equals("X11")) { + DisplaySystem.launchX11(activity, false); + } + } + + public static void reLaunchVNC(Activity activity) { + if (MainSettingsManager.getVmUi(activity).equals("VNC") && + FileUtils.isFileExists(Config.getLocalQMPSocketPath()) && + !activity.isFinishing() && + MainVNCActivity.started) + activity.startActivity(new Intent(activity, MainVNCActivity.class)); + } + + public static void launchX11(Activity activity, boolean isKillXFCE) { + if (SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + DialogUtils.oneDialog( + activity, + activity.getString(R.string.x11_feature_not_supported), + activity.getString(R.string.the_x11_feature_is_currently_not_supported_on_android_14_and_above_please_use_a_device_with_android_13_or_below_for_x11_functionality), + activity.getString(R.string.ok), + true, R.drawable.error_96px, + true, + null, + null + ); + } else { + // XFCE4 meta-package + String xfce4Package = "xfce4"; + + // Check if XFCE4 is installed + isPackageInstalled2(activity, xfce4Package, (output, errors) -> { + boolean isInstalled = false; + + // Check if the package exists in the installed packages output + if (output != null) { + Set installedPackages = new HashSet<>(); + for (String installedPackage : output.split("\n")) { + installedPackages.add(installedPackage.trim()); + } + + isInstalled = installedPackages.contains(xfce4Package.trim()); + } + + // If not installed, show a dialog to install it + if (!isInstalled) { + DialogUtils.twoDialog( + activity, + "Install XFCE4", + "XFCE4 is not installed. Would you like to install it?", + activity.getString(R.string.install), + activity.getString(R.string.cancel), + true, + R.drawable.desktop_24px, + true, + () -> { + String installCommand = "apk add " + xfce4Package; + new Terminal(activity).executeShellCommand(installCommand, true, true, activity); + }, + null, + null + ); + } else { + if (isKillXFCE) + new Terminal(activity).executeShellCommand2("killall xfce4-session", false, activity); + activity.startActivity(new Intent(activity, X11Activity.class)); + new Terminal(activity).executeShellCommand2("xfce4-session", false, activity); + } + }); + } + } + + public static void startTermuxX11() { + if (Build.VERSION.SDK_INT < 34) { + ShellExecutor shellExec = new ShellExecutor(); + shellExec.exec(TermuxService.PREFIX_PATH + "/bin/termux-x11 :0"); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/vectras/vm/home/core/HomeStartVM.java b/app/src/main/java/com/vectras/vm/home/core/HomeStartVM.java new file mode 100644 index 0000000..b6bf902 --- /dev/null +++ b/app/src/main/java/com/vectras/vm/home/core/HomeStartVM.java @@ -0,0 +1,184 @@ +package com.vectras.vm.home.core; + +import static android.os.Build.VERSION.SDK_INT; + +import android.app.Activity; +import android.content.Intent; +import android.os.Build; +import android.os.Handler; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.appcompat.app.AlertDialog; + +import com.google.android.material.appbar.AppBarLayout; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.vectras.qemu.Config; +import com.vectras.qemu.MainSettingsManager; +import com.vectras.qemu.MainVNCActivity; +import com.vectras.vm.AppConfig; +import com.vectras.vm.MainService; +import com.vectras.vm.R; +import com.vectras.vm.VMManager; +import com.vectras.vm.logger.VectrasStatus; +import com.vectras.vm.settings.VNCActivity; +import com.vectras.vm.utils.DialogUtils; +import com.vectras.vm.utils.NetworkUtils; +import com.vectras.vm.utils.ServiceUtils; + +import java.io.File; + +public class HomeStartVM { + public static AlertDialog progressDialog; + + public static boolean skipIDEwithARM64DialogInStartVM = false; + + public static void startNow( + Activity activity, + String vmName, + String env, + String itemExtra, + String itemPath, + AppBarLayout appbar, + LinearLayout extVncLayout + ) { + File romDir = new File(Config.getCacheDir() + "/" + Config.vmID); + if (!romDir.exists()) { + if (!romDir.mkdirs()) { + DialogUtils.oneDialog(activity, activity.getString(R.string.problem_has_been_detected), activity.getString(R.string.vm_cache_dir_failed_to_create_content), activity.getString(R.string.ok), true, R.drawable.warning_48px, true, null, null); + return; + } + } + + if (!VMManager.isthiscommandsafe(env, activity.getApplicationContext())) { + DialogUtils.oneDialog(activity, activity.getString(R.string.problem_has_been_detected), activity.getString(R.string.harmful_command_was_detected) + " " + activity.getResources().getString(R.string.reason) + ": " + VMManager.latestUnsafeCommandReason, activity.getString(R.string.ok), true, R.drawable.verified_user_24px, true, null, null); + return; + } + + VMManager.lastQemuCommand = env; + + if (VMManager.isThisVMRunning(activity, itemExtra, itemPath)) { + Toast.makeText(activity, "This VM is already running.", Toast.LENGTH_LONG).show(); + if (MainSettingsManager.getVmUi(activity).equals("VNC")) + activity.startActivity(new Intent(activity, MainVNCActivity.class)); + else if (MainSettingsManager.getVmUi(activity).equals("X11")) + DisplaySystem.launchX11(activity, false); + return; + } + + if (AppConfig.getSetupFiles().contains("arm") && !AppConfig.getSetupFiles().contains("arm64")) { + if (env.contains("tcg,thread=multi")) { + DialogUtils.twoDialog(activity, activity.getResources().getString(R.string.problem_has_been_detected), activity.getResources().getString(R.string.can_not_use_mttcg), activity.getString(R.string.ok), activity.getString(R.string.cancel), true, R.drawable.warning_48px, true, + () -> startNow(activity, vmName, env.replace("tcg,thread=multi", "tcg,thread=single"), itemExtra, itemPath, appbar, extVncLayout), null, null); + return; + } + } + + if (MainSettingsManager.getArch(activity).equals("ARM64") && MainSettingsManager.getIfType(activity).equals("ide") && skipIDEwithARM64DialogInStartVM) { + DialogUtils.twoDialog(activity, activity.getString(R.string.problem_has_been_detected), activity.getString(R.string.you_cannot_use_IDE_hard_drive_type_with_ARM64), activity.getString(R.string.continuetext), activity.getString(R.string.cancel), true, R.drawable.warning_48px, true, + () -> { + skipIDEwithARM64DialogInStartVM = true; + startNow(activity, vmName, env, itemExtra, itemPath, appbar, extVncLayout); + }, null, null); + return; + } else if (skipIDEwithARM64DialogInStartVM) { + skipIDEwithARM64DialogInStartVM = false; + } + + if (MainSettingsManager.getSharedFolder(activity) && MainSettingsManager.getArch(activity).equals("I386")) { + Toast.makeText(activity, R.string.shared_folder_is_not_used_because_i386_does_not_support_it, Toast.LENGTH_LONG).show(); + } + + if (MainSettingsManager.getVncExternal(activity) && + NetworkUtils.isPortOpen("localhost", Config.defaultVNCPort + Config.defaultVNCPort, 500)) { + DialogUtils.twoDialog(activity, activity.getString(R.string.problem_has_been_detected), + activity.getString(R.string.the_vnc_server_port_you_set_is_currently_in_use_by_other), + activity.getString(R.string.go_to_settings), + activity.getString(R.string.close), + true, R.drawable.warning_48px, true, + () -> activity.startActivity(new Intent(activity, VNCActivity.class)), + null, + null); + return; + } + + showProgressDialog(activity, activity.getString(R.string.booting_up)); + Handler handler = new Handler(); + handler.postDelayed( + () -> { + if (ServiceUtils.isServiceRunning(activity, MainService.class)) { + MainService.startCommand(env, activity); + } else { + Intent serviceIntent = new Intent(activity, MainService.class); + MainService.env = env; + MainService.CHANNEL_ID = vmName; + MainService.activity = activity; + if (SDK_INT >= Build.VERSION_CODES.O) { + activity.startForegroundService(serviceIntent); + } else { + activity.startService(serviceIntent); + } + } + + + if (MainSettingsManager.getVmUi(activity).equals("VNC")) { + if (MainSettingsManager.getVncExternal(activity)) { + if (extVncLayout != null) extVncLayout.setVisibility(View.VISIBLE); + if (appbar != null) appbar.setExpanded(true); + progressDialog.dismiss(); + } else { + Handler handler1 = new Handler(); + handler1.postDelayed( + () -> { + MainVNCActivity.started = true; + activity.startActivity( + new Intent( + activity, MainVNCActivity.class)); + progressDialog.dismiss(); + }, + 2000); + } +// } else if (MainSettingsManager.getVmUi(activity).equals("SPICE")) { +// //This feature is not available yet. + } else if (MainSettingsManager.getVmUi(activity).equals("X11")) { + Handler handler1 = new Handler(); + handler1.postDelayed( + () -> { + progressDialog.dismiss(); + DisplaySystem.launchX11(activity, false); + }, + 3000); + } + + if (MainSettingsManager.getVncExternal(activity)) { + Config.currentVNCServervmID = Config.vmID; + DialogUtils.oneDialog(activity, activity.getString(R.string.vnc_server), activity.getString(R.string.running_vm_with_vnc_server_content) + " " + (Integer.parseInt(MainSettingsManager.getVncExternalDisplay(activity)) + 5900) + ".", activity.getString(R.string.ok), true, R.drawable.cast_24px, true, null, null); + } + }, + 2000); + String[] params = env.split("\\s+"); + VectrasStatus.logInfo("Params:"); + Log.d("HomeStartVM", "Params:"); + for (int i = 0; i < params.length; i++) { + VectrasStatus.logInfo(i + ": " + params[i]); + Log.d("HomeStartVM", i + ": " + params[i]); + } + + } + + public static void showProgressDialog(Activity activity, String _content) { + View progressView = LayoutInflater.from(activity).inflate(R.layout.dialog_progress_style, null); + TextView progress_text = progressView.findViewById(R.id.progress_text); + progress_text.setText(_content); + progressDialog = new MaterialAlertDialogBuilder(activity, R.style.CenteredDialogTheme) + .setView(progressView) + .setCancelable(false) + .create(); + + progressDialog.show(); + } +} diff --git a/app/src/main/java/com/vectras/vm/home/core/PendingCommand.java b/app/src/main/java/com/vectras/vm/home/core/PendingCommand.java new file mode 100644 index 0000000..8e67dbf --- /dev/null +++ b/app/src/main/java/com/vectras/vm/home/core/PendingCommand.java @@ -0,0 +1,57 @@ +package com.vectras.vm.home.core; + +import android.app.Activity; +import android.widget.Toast; + +import com.vectras.vm.AppConfig; +import com.vectras.vm.R; +import com.vectras.vm.StartVM; +import com.vectras.vm.VMManager; +import com.vectras.vm.utils.DialogUtils; +import com.vectras.vterm.Terminal; + +public class PendingCommand { + public static void runNow(Activity activity) { + if (!AppConfig.pendingCommand.isEmpty()) { + if (!VMManager.isthiscommandsafe(AppConfig.pendingCommand, activity)) { + AppConfig.pendingCommand = ""; + DialogUtils.oneDialog( + activity, + activity.getString(R.string.problem_has_been_detected), + activity.getString(R.string.harmful_command_was_detected) + " " + activity.getResources().getString(R.string.reason) + ": " + VMManager.latestUnsafeCommandReason, + activity.getString(R.string.ok), + true, + R.drawable.verified_user_24px, + true, + null, + null + ); + } else { + if (AppConfig.pendingCommand.startsWith("qemu-img")) { + if (!VMManager.isthiscommandsafeimg(AppConfig.pendingCommand, activity)) { + DialogUtils.oneDialog(activity, + activity.getString(R.string.problem_has_been_detected), + activity.getString(R.string.size_too_large_try_qcow2_format), + activity.getString(R.string.ok), + true, + R.drawable.warning_48px, + true, + null, + null + ); + } else { + Terminal _vterm = new Terminal(activity); + _vterm.executeShellCommand2(AppConfig.pendingCommand, false, activity); + Toast.makeText(activity, activity.getResources().getString(R.string.done), Toast.LENGTH_LONG).show(); + } + } else { + com.vectras.vm.StartVM.cdrompath = ""; + String env = StartVM.env(activity, AppConfig.pendingCommand, "", "1"); + HomeStartVM.startNow(activity, "Quick run", env, AppConfig.pendingCommand, "", null, null); + VMManager.lastQemuCommand = AppConfig.pendingCommand; + } + } + AppConfig.pendingCommand = ""; + } + } +} diff --git a/app/src/main/java/com/vectras/vm/home/core/RomOptionsDialog.java b/app/src/main/java/com/vectras/vm/home/core/RomOptionsDialog.java new file mode 100644 index 0000000..aad146a --- /dev/null +++ b/app/src/main/java/com/vectras/vm/home/core/RomOptionsDialog.java @@ -0,0 +1,47 @@ +package com.vectras.vm.home.core; + +import android.app.Activity; +import android.content.Intent; +import android.view.View; +import android.widget.Button; + +import com.google.android.material.bottomsheet.BottomSheetDialog; +import com.vectras.vm.CustomRomActivity; +import com.vectras.vm.ExportRomActivity; +import com.vectras.vm.MainRoms.DataMainRoms; +import com.vectras.vm.R; +import com.vectras.vm.VMManager; + +import java.util.List; + +public class RomOptionsDialog { + public static void showNow(Activity activity, List data, int position, String vmID, String vmName, String arch) { + BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(activity); + View v = activity.getLayoutInflater().inflate(R.layout.rom_options_dialog, null); + bottomSheetDialog.setContentView(v); + + Button modifyRomBtn = v.findViewById(R.id.modifyRomBtn); + modifyRomBtn.setOnClickListener(v3 -> { + CustomRomActivity.current = data.get(position); + VMManager.setArch(arch, activity); + activity.startActivity(new Intent(activity, CustomRomActivity.class).putExtra("POS", position).putExtra("MODIFY", true).putExtra("VMID", vmID)); + bottomSheetDialog.cancel(); + }); + + Button exportRomBtn = v.findViewById(R.id.exportRomBtn); + exportRomBtn.setOnClickListener(v2 -> { + ExportRomActivity.pendingPosition = position; + Intent intent = new Intent(); + intent.setClass(activity, ExportRomActivity.class); + activity.startActivity(intent); + bottomSheetDialog.cancel(); + }); + + Button removeRomBtn = v.findViewById(R.id.removeRomBtn); + removeRomBtn.setOnClickListener(v1 -> { + VMManager.deleteVMDialog(vmName, position, activity); + bottomSheetDialog.cancel(); + }); + bottomSheetDialog.show(); + } +} diff --git a/app/src/main/java/com/vectras/vm/home/core/SharedData.java b/app/src/main/java/com/vectras/vm/home/core/SharedData.java new file mode 100644 index 0000000..81530df --- /dev/null +++ b/app/src/main/java/com/vectras/vm/home/core/SharedData.java @@ -0,0 +1,10 @@ +package com.vectras.vm.home.core; + +import com.vectras.vm.Roms.DataRoms; + +import java.util.ArrayList; +import java.util.List; + +public class SharedData { + public static List dataRomStore = new ArrayList<>(); +} diff --git a/app/src/main/java/com/vectras/vm/home/monitor/SystemMonitorFragment.java b/app/src/main/java/com/vectras/vm/home/monitor/SystemMonitorFragment.java new file mode 100644 index 0000000..6444529 --- /dev/null +++ b/app/src/main/java/com/vectras/vm/home/monitor/SystemMonitorFragment.java @@ -0,0 +1,242 @@ +package com.vectras.vm.home.monitor; + +import static android.content.Context.ACTIVITY_SERVICE; +import static android.os.Build.VERSION.SDK_INT; + +import android.annotation.SuppressLint; +import android.app.ActivityManager; +import android.os.Build; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import android.os.Environment; +import android.os.Handler; +import android.os.Looper; +import android.os.StatFs; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.google.android.material.transition.MaterialFadeThrough; +import com.vectras.qemu.Config; +import com.vectras.qemu.MainSettingsManager; +import com.vectras.vm.R; +import com.vectras.vm.VMManager; +import com.vectras.vm.databinding.FragmentHomeSystemMonitorBinding; +import com.vectras.vm.utils.DialogUtils; +import com.vectras.vterm.Terminal; + +import java.util.Locale; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +public class SystemMonitorFragment extends Fragment { + final String TAG = "SystemMonitorFragment"; + FragmentHomeSystemMonitorBinding binding; + ExecutorService executor = Executors.newSingleThreadExecutor(); + boolean isStopUpdateMonitor = false; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setEnterTransition(new MaterialFadeThrough()); + setReturnTransition(new MaterialFadeThrough()); + setExitTransition(new MaterialFadeThrough()); + setReenterTransition(new MaterialFadeThrough()); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + binding = FragmentHomeSystemMonitorBinding.inflate(getLayoutInflater()); + return binding.getRoot(); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + startMonitor(); + getQemuInfo(); + initialize(); + } + + @Override + public void onResume() { + super.onResume(); + if(isStopUpdateMonitor) { + startMonitor(); + getQemuInfo(); + } + } + + @Override + public void onPause() { + super.onPause(); + stopMonitor(); + } + + private void initialize() { + binding.btStopqemu.setOnClickListener(v -> VMManager.requestKillAllQemuProcess(requireActivity(), () -> { + ScheduledExecutorService executorUpdate = Executors.newSingleThreadScheduledExecutor(); + executorUpdate.schedule(() -> { + if (getContext() != null) { + requireActivity().runOnUiThread(this::getQemuInfo); + } + }, 500, TimeUnit.MILLISECONDS); + })); + + binding.btStopvmvnc.setOnClickListener(v -> { + if (Config.currentVNCServervmID.isEmpty()) { + binding.btStopvmvnc.setVisibility(View.GONE); + } else { + DialogUtils.threeDialog( + requireActivity(), + getString(R.string.shutdown), + getString(R.string.shutdown_or_reset_content), + getString(R.string.shutdown), + getString(R.string.cancel), + getString(R.string.reset), + true, + R.drawable.power_settings_new_24px, + true, + () -> { + Config.vmID = Config.currentVNCServervmID; + VMManager.shutdownCurrentVM(); + Config.currentVNCServervmID = ""; + binding.btStopvmvnc.setVisibility(View.GONE); + getQemuInfo(); + }, + null, + () -> { + Config.vmID = Config.currentVNCServervmID; + VMManager.resetCurrentVM(); + }, + null); + } + }); + } + + private final Handler handler = new Handler(Looper.getMainLooper()); + private final Runnable monitorTask = new Runnable() { + @Override + public void run() { + if (isStopUpdateMonitor) return; + updateSystemMonitor(); + handler.postDelayed(this, 1000); + } + }; + + private void startMonitor() { + isStopUpdateMonitor = false; + handler.post(monitorTask); + } + + private void stopMonitor() { + isStopUpdateMonitor = true; + handler.removeCallbacks(monitorTask); + } + + @SuppressLint("SetTextI18n") + private void updateSystemMonitor() { + ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo(); + ActivityManager activityManager = (ActivityManager) requireActivity().getSystemService(ACTIVITY_SERVICE); + activityManager.getMemoryInfo(mi); + + double totalMemory = mi.totalMem * Math.pow(10, -9); + double freeMemory = mi.availMem * Math.pow(10, -9); + double usedMemory = totalMemory - freeMemory; + double percentageOfRam = (100 / totalMemory) * usedMemory; + + binding.tvTotalram.setText(getString(R.string.total_memory) + " " + String.format(Locale.US, "%.1f", totalMemory) + " GB"); + binding.tvUsedram.setText(getString(R.string.used_memory) + " " + String.format(Locale.US, "%.1f", usedMemory) + " GB"); + binding.tvPercentageofram.setText((int) percentageOfRam + "%"); + if (SDK_INT >= Build.VERSION_CODES.N) { + binding.cpiMemory.setProgress((int) percentageOfRam, true); + } else { + binding.cpiMemory.setProgress((int) percentageOfRam); + } + + + StatFs externalStatFs = new StatFs( Environment.getExternalStorageDirectory().getAbsolutePath() ); + + double totalStorage = (externalStatFs.getBlockCountLong() * externalStatFs.getBlockSizeLong()) * Math.pow(10, -9); + double freeStorage = (externalStatFs.getAvailableBlocksLong() * externalStatFs.getBlockSizeLong()) * Math.pow(10, -9); + double usedStorage = totalStorage - freeStorage; + double percentageOfStorage = (100 / totalStorage) * usedStorage; + + binding.tvTotalstorage.setText(getString(R.string.total_memory) + " " + String.format(Locale.US, "%.1f", totalStorage) + " GB"); + binding.tvUsedstorage.setText(getString(R.string.used_memory) + " " + String.format(Locale.US, "%.1f", usedStorage) + " GB"); + binding.tvPercentageofstorage.setText((int) percentageOfStorage + "%"); + if (SDK_INT >= Build.VERSION_CODES.N) { + binding.cpiStorage.setProgress((int) percentageOfStorage, true); + } else { + binding.cpiStorage.setProgress((int) percentageOfStorage); + } + } + + @SuppressLint("SetTextI18n") + private void getQemuInfo() { + String currentArch = MainSettingsManager.getArch(requireActivity()); + String command = "qemu-system-x86_64 --version"; + new Terminal(requireActivity()).extractQemuVersion(command, false, requireActivity(), (output, errors) -> { + if (errors.isEmpty()) { + binding.tvQemuversion.setText(getString(R.string.version) + " " + (output.equals("8.2.1") ? output + " - 3dfx" : getString(R.string.unknow)) + "."); + } else { + Log.e(TAG, "Errors: " + errors); + } + }); + + binding.tvQemuarch.setText(getString(R.string.arch) + " " + currentArch + "."); + + executor.execute(() -> { + String result = Terminal.executeShellCommandWithResult("ps -e", requireActivity()); + requireActivity().runOnUiThread(() -> { + if (!result.isEmpty()) { + switch (currentArch) { + case "X86_64" -> + binding.tvQemustatus.setText(getString(R.string.status_qemu) + " " + (result.contains("qemu-system-x86_64 -qmp") ? getString(R.string.running) : getString(R.string.stopped)) + "."); + case "I386" -> + binding.tvQemustatus.setText(getString(R.string.status_qemu) + " " + (result.contains("qemu-system-i386 -qmp") ? getString(R.string.running) : getString(R.string.stopped)) + "."); + case "ARM64" -> + binding.tvQemustatus.setText(getString(R.string.status_qemu) + " " + (result.contains("qemu-system-aarch64 -qmp") ? getString(R.string.running) : getString(R.string.stopped)) + "."); + case "PPC" -> + binding.tvQemustatus.setText(getString(R.string.status_qemu) + " " + (result.contains("qemu-system-ppc -qmp") ? getString(R.string.running) : getString(R.string.stopped)) + "."); + default -> binding.tvQemustatus.setText(getString(R.string.status_qemu) + " " + getString(R.string.stopped) + "."); + } + + if (result.contains("qemu-system") && result.contains("-qmp")) { + binding.btStopqemu.setVisibility(View.VISIBLE); + } else { + binding.btStopqemu.setVisibility(View.GONE); + } + } else { + binding.tvQemustatus.setText(getString(R.string.status_qemu) + " " + getString(R.string.stopped) + "."); + binding.btStopqemu.setVisibility(View.GONE); + Log.i(TAG, "Errors: " + result); + } + + getVNCServerStatus(result); + }); + }); + } + + @SuppressLint("SetTextI18n") + private void getVNCServerStatus(String resultCommand) { + binding.tvVncport.setText(getString(R.string.port_qemu) + " " + (Integer.parseInt(MainSettingsManager.getVncExternalDisplay(requireActivity())) + 5900) + "."); + + if (resultCommand.contains(Config.defaultVNCHost + ":" + Config.defaultVNCPort)) { + binding.tvVncstatus.setText(getString(R.string.status_qemu) + " " + getString(R.string.running) + "."); + binding.btStopvmvnc.setVisibility(View.VISIBLE); + } else { + binding.tvVncstatus.setText(getString(R.string.status_qemu) + " " + getString(R.string.stopped) + "."); + binding.btStopvmvnc.setVisibility(View.GONE); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/vectras/vm/home/romstore/HomeRomStoreViewModel.java b/app/src/main/java/com/vectras/vm/home/romstore/HomeRomStoreViewModel.java new file mode 100644 index 0000000..b912d5f --- /dev/null +++ b/app/src/main/java/com/vectras/vm/home/romstore/HomeRomStoreViewModel.java @@ -0,0 +1,23 @@ +package com.vectras.vm.home.romstore; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; + +import com.vectras.vm.Roms.DataRoms; + +import java.util.ArrayList; +import java.util.List; + +public class HomeRomStoreViewModel extends ViewModel { + private final MutableLiveData> romsList = new MutableLiveData<>(new ArrayList<>()); + + public LiveData> getRomsList() { + return romsList; + } + + public void setRomsList(List data) { + romsList.setValue(data); + } +} + diff --git a/app/src/main/java/com/vectras/vm/home/romstore/RomStoreFragment.java b/app/src/main/java/com/vectras/vm/home/romstore/RomStoreFragment.java new file mode 100644 index 0000000..4797954 --- /dev/null +++ b/app/src/main/java/com/vectras/vm/home/romstore/RomStoreFragment.java @@ -0,0 +1,131 @@ +package com.vectras.vm.home.romstore; + +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProvider; +import androidx.recyclerview.widget.LinearLayoutManager; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.google.android.material.transition.MaterialFadeThrough; +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import com.vectras.vm.AppConfig; +import com.vectras.vm.RequestNetwork; +import com.vectras.vm.RequestNetworkController; +import com.vectras.vm.Roms.AdapterRoms; +import com.vectras.vm.Roms.DataRoms; +import com.vectras.vm.databinding.FragmentHomeRomStoreBinding; +import com.vectras.vm.home.HomeActivity; +import com.vectras.vm.home.core.SharedData; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class RomStoreFragment extends Fragment { + + FragmentHomeRomStoreBinding binding; + private RequestNetwork net; + private RequestNetwork.RequestListener _net_request_listener; + private String contentJSON = "[]"; + HomeRomStoreViewModel homeRomStoreViewModel; + RomStoreHomeAdpater mAdapter; + List data = new ArrayList<>(); + + public static RomStoreCallToHomeListener romStoreCallToHomeListener; + public interface RomStoreCallToHomeListener { + void updateDataStatus(boolean isReady); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setEnterTransition(new MaterialFadeThrough()); + setReturnTransition(new MaterialFadeThrough()); + setExitTransition(new MaterialFadeThrough()); + setReenterTransition(new MaterialFadeThrough()); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + binding = FragmentHomeRomStoreBinding.inflate(inflater, container, false); + return binding.getRoot(); + } + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + mAdapter = new RomStoreHomeAdpater(getContext(), data); + binding.rvRomlist.setAdapter(mAdapter); + binding.rvRomlist.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false)); + + homeRomStoreViewModel = new ViewModelProvider(requireActivity()).get(HomeRomStoreViewModel.class); + homeRomStoreViewModel.getRomsList().observe(getViewLifecycleOwner(), roms -> { + if (roms == null || roms.isEmpty()) { + loadFromServer(); + } else { + binding.linearload.setVisibility(View.GONE); + data.clear(); + data.addAll(roms); + mAdapter.notifyDataSetChanged(); + } + }); + } + + private void loadFromServer() { + romStoreCallToHomeListener.updateDataStatus(false); + + net = new RequestNetwork(requireActivity()); + _net_request_listener = new RequestNetwork.RequestListener() { + @Override + public void onResponse(String tag, String response, HashMap responseHeaders) { + if (!response.isEmpty()) + contentJSON = response; + loadData(); + binding.linearload.setVisibility(View.GONE); + } + + @Override + public void onErrorResponse(String tag, String message) { + binding.linearload.setVisibility(View.GONE); + binding.linearnothinghere.setVisibility(View.VISIBLE); + } + }; + + binding.buttontryagain.setOnClickListener(v -> { + binding.linearload.setVisibility(View.VISIBLE); + net.startRequestNetwork(RequestNetworkController.GET,AppConfig.vectrasRaw + "vroms-store.json","",_net_request_listener); + }); + + net.startRequestNetwork(RequestNetworkController.GET, AppConfig.vectrasRaw + "vroms-store.json","",_net_request_listener); + } + + private void loadData() { + List dataRoms = new ArrayList<>(); + + try { + Gson gson = new Gson(); + Type listType = new TypeToken>() {}.getType(); + dataRoms = gson.fromJson(contentJSON, listType); + } catch (Exception e) { + binding.linearload.setVisibility(View.GONE); + binding.linearnothinghere.setVisibility(View.VISIBLE); + } + + homeRomStoreViewModel.setRomsList(dataRoms); + data.clear(); + data.addAll(dataRoms); + mAdapter.notifyDataSetChanged(); + SharedData.dataRomStore.addAll(dataRoms); + romStoreCallToHomeListener.updateDataStatus(true); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/vectras/vm/home/romstore/RomStoreHomeAdpater.java b/app/src/main/java/com/vectras/vm/home/romstore/RomStoreHomeAdpater.java new file mode 100644 index 0000000..d8466cd --- /dev/null +++ b/app/src/main/java/com/vectras/vm/home/romstore/RomStoreHomeAdpater.java @@ -0,0 +1,116 @@ +package com.vectras.vm.home.romstore; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; +import android.graphics.Color; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.appcompat.content.res.AppCompatResources; +import androidx.recyclerview.widget.RecyclerView; + +import com.bumptech.glide.Glide; +import com.vectras.vm.R; +import com.vectras.vm.RomInfo; +import com.vectras.vm.Roms.DataRoms; + +import java.util.Collections; +import java.util.List; + +public class RomStoreHomeAdpater extends RecyclerView.Adapter { + Context context; + private final LayoutInflater inflater; + static List dataRom = Collections.emptyList(); + + public RomStoreHomeAdpater(Context context, List data) { + this.context = context; + inflater = LayoutInflater.from(context); + dataRom = data; + } + + // Inflate the layout when viewholder created + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = inflater.inflate(R.layout.container_roms, parent, false); + return new MyHolder(view); + } + + // Bind data + @SuppressLint("SetTextI18n") + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position) { + + // Get current position of item in recyclerview to bind data and assign values from list + final MyHolder myHolder = (MyHolder) holder; + final DataRoms current = dataRom.get(position); + Glide.with(context).load(current.romIcon).placeholder(R.drawable.ic_computer_180dp_with_padding).error(R.drawable.ic_computer_180dp_with_padding).into(myHolder.ivIcon); + myHolder.textName.setText(current.romName); + myHolder.textSize.setText(current.romArch + " - " + current.fileSize); + if (current.romAvail) { + myHolder.linearItem.setOnClickListener(v -> { + notifyItemRangeChanged(0, dataRom.size()); + + Intent intent = new Intent(); + intent.setClass(context, RomInfo.class); + intent.putExtra("title", current.romName); + intent.putExtra("shortdesc", current.romSize); + intent.putExtra("getrom", current.romUrl); + intent.putExtra("desc", current.desc); + intent.putExtra("icon", current.romIcon); + intent.putExtra("filename", current.romPath); + intent.putExtra("finalromfilename", current.finalromfilename); + intent.putExtra("extra", current.romExtra); + intent.putExtra("arch", current.romArch); + intent.putExtra("verified", current.verified); + intent.putExtra("creator", current.creator); + intent.putExtra("size", current.fileSize); + context.startActivity(intent); + }); + } else { + myHolder.textAvail.setText(context.getString(R.string.unavailable)); + myHolder.textAvail.setTextColor(Color.RED); + } + + if (dataRom.size() == 1) { + myHolder.linearItem.setBackground(AppCompatResources.getDrawable(context, R.drawable.object_shape_single)); + } else if (position == 0) { + myHolder.linearItem.setBackground(AppCompatResources.getDrawable(context, R.drawable.object_shape_top)); + } else if (position == dataRom.size() - 1) { + myHolder.linearItem.setBackground(AppCompatResources.getDrawable(context, R.drawable.object_shape_bottom)); + } else { + myHolder.linearItem.setBackground(AppCompatResources.getDrawable(context, R.drawable.object_shape_middle)); + } + } + + // return total item from List + @Override + public int getItemCount() { + return dataRom == null ? 0 : dataRom.size(); + } + + static class MyHolder extends RecyclerView.ViewHolder { + + TextView textName, textAvail, textSize; + ImageView ivIcon; + LinearLayout linearItem; + + // create constructor to get widget reference + public MyHolder(View itemView) { + super(itemView); + textName = itemView.findViewById(R.id.textName); + ivIcon = itemView.findViewById(R.id.ivIcon); + textSize = itemView.findViewById(R.id.textSize); + textAvail = itemView.findViewById(R.id.textAvail); + + linearItem = itemView.findViewById(R.id.linearItem); + } + + } +} diff --git a/app/src/main/java/com/vectras/vm/home/vms/VmsDiffUtil.java b/app/src/main/java/com/vectras/vm/home/vms/VmsDiffUtil.java new file mode 100644 index 0000000..b5aa7e2 --- /dev/null +++ b/app/src/main/java/com/vectras/vm/home/vms/VmsDiffUtil.java @@ -0,0 +1,42 @@ +package com.vectras.vm.home.vms; + +import androidx.recyclerview.widget.DiffUtil; + +import com.vectras.vm.MainRoms.DataMainRoms; + +import java.util.List; + +public class VmsDiffUtil extends DiffUtil.Callback { + private final List oldList; + private final List newList; + + public VmsDiffUtil(List oldList, List newList) { + this.oldList = oldList; + this.newList = newList; + } + + @Override + public int getOldListSize() { + return oldList.size(); + } + + @Override + public int getNewListSize() { + return newList.size(); + } + + @Override + public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { + // So sánh bằng khóa duy nhất (vd: vmID) + return oldList.get(oldItemPosition).vmID.equals(newList.get(newItemPosition).vmID); + } + + @Override + public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { + // So sánh nội dung, nếu khác thì update item đó + DataMainRoms oldItem = oldList.get(oldItemPosition); + DataMainRoms newItem = newList.get(newItemPosition); + return oldItem.equals(newItem); // Nếu bạn override equals trong DataMainRoms thì dùng cách này + } +} + diff --git a/app/src/main/java/com/vectras/vm/home/vms/VmsFragment.java b/app/src/main/java/com/vectras/vm/home/vms/VmsFragment.java new file mode 100644 index 0000000..96c4e53 --- /dev/null +++ b/app/src/main/java/com/vectras/vm/home/vms/VmsFragment.java @@ -0,0 +1,199 @@ +package com.vectras.vm.home.vms; + +import android.content.res.Configuration; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.GridLayoutManager; + +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.google.android.material.transition.MaterialFadeThrough; +import com.vectras.vm.AppConfig; +import com.vectras.vm.MainRoms.DataMainRoms; +import com.vectras.vm.R; +import com.vectras.vm.VMManager; +import com.vectras.vm.databinding.FragmentHomeVmsBinding; +import com.vectras.vm.home.HomeActivity; +import com.vectras.vm.home.core.CallbackInterface; +import com.vectras.vm.utils.DeviceUtils; +import com.vectras.vm.utils.DialogUtils; +import com.vectras.vm.utils.FileUtils; +import com.vectras.vm.utils.PermissionUtils; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class VmsFragment extends Fragment implements CallbackInterface.HomeCallToVmsListener { + private final String TAG = "VmsFragment"; + FragmentHomeVmsBinding binding; + private JSONArray jArray; + private final List data = new ArrayList<>(); + private VmsHomeAdapter vmsHomeAdapter; + private int spanCount = 0; + ExecutorService executor = Executors.newSingleThreadExecutor(); + + public static VmsCallToHomeListener vmsCallToHomeListener; + public interface VmsCallToHomeListener { + void openRomStore(); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setEnterTransition(new MaterialFadeThrough()); + setReturnTransition(new MaterialFadeThrough()); + setExitTransition(new MaterialFadeThrough()); + setReenterTransition(new MaterialFadeThrough()); + } + + @Override + public void onResume() { + super.onResume(); + checkAndLoad(); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + binding = FragmentHomeVmsBinding.inflate(inflater, container, false); + spanCount = requireActivity().getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 3 : 2; + return binding.getRoot(); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + HomeActivity.homeCallToVmsListener = this; + + binding.rvRomlist.setLayoutManager(new GridLayoutManager(getContext(), spanCount)); + vmsHomeAdapter = new VmsHomeAdapter(requireActivity(), data); + binding.rvRomlist.setAdapter(vmsHomeAdapter); + + binding.bnRomstore.setOnClickListener(v -> { + vmsCallToHomeListener.openRomStore(); + }); + + binding.bnRepair.setOnClickListener(V -> { + VMManager.startFixRomsDataJson(); + VMManager.fixRomsDataJsonResult(requireActivity()); + }); + + binding.wrlRomlist.setOnRefreshListener(() -> { + checkAndLoad(); + binding.wrlRomlist.setRefreshing(false); + }); + + checkAndLoad(); + } + + private void loadDataVbi() { + + if (!FileUtils.isFileExists(AppConfig.romsdatajson)) + FileUtils.writeToFile(AppConfig.maindirpath, "roms-data.json", "[]"); + + executor.execute(() -> { + List tempdata = new ArrayList<>(); + + try { + jArray = new JSONArray(FileUtils.readFromFile(requireActivity(), new File(AppConfig.maindirpath + + "roms-data.json"))); + + // Extract data from json and store into ArrayList as class objects + for (int i = 0; i < jArray.length(); i++) { + JSONObject json_data = jArray.getJSONObject(i); + DataMainRoms romsMainData = new DataMainRoms(); + romsMainData.itemName = json_data.getString("imgName"); + romsMainData.itemIcon = json_data.getString("imgIcon"); + try { + romsMainData.itemArch = json_data.getString("imgArch"); + } catch (JSONException ignored) { + romsMainData.itemArch = "unknown"; + } + romsMainData.itemPath = json_data.getString("imgPath"); + try { + romsMainData.imgCdrom = json_data.getString("imgCdrom"); + } catch (JSONException ignored) { + romsMainData.imgCdrom = ""; + } + try { + romsMainData.vmID = json_data.getString("vmID"); + } catch (JSONException ignored) { + romsMainData.vmID = ""; + } + try { + romsMainData.qmpPort = json_data.getInt("qmpPort"); + } catch (JSONException ignored) { + romsMainData.qmpPort = 0; + } + try { + romsMainData.itemDrv1 = json_data.getString("imgDrv1"); + } catch (JSONException ignored) { + romsMainData.itemDrv1 = ""; + } + romsMainData.itemExtra = json_data.getString("imgExtra"); + tempdata.add(romsMainData); + } + requireActivity().runOnUiThread(() -> binding.lnError.setVisibility(View.GONE)); + } catch (JSONException e) { + requireActivity().runOnUiThread(() -> binding.lnError.setVisibility(View.VISIBLE)); + Log.e(TAG, "loadDataVbi: ", e); + } + + requireActivity().runOnUiThread(() -> { + binding.lnLoad.setVisibility(View.GONE); + if (tempdata.isEmpty()) { + binding.lnNothinghere.setVisibility(View.VISIBLE); + } else { + binding.lnNothinghere.setVisibility(View.GONE); + vmsHomeAdapter.updateData(tempdata); + } + }); + }); + } + + private void checkAndLoad() { + if (PermissionUtils.storagepermission(requireActivity(), true)) { + loadDataVbi(); + if (DeviceUtils.isStorageLow(requireActivity())) { + DialogUtils.oneDialog(requireActivity(), + getResources().getString(R.string.oops), + getResources().getString(R.string.very_low_available_storage_space_content), + getResources().getString(R.string.ok), + true, + R.drawable.warning_48px, + true, + null, + () -> { + if (DeviceUtils.isStorageLow(requireActivity())) + requireActivity().finish(); + }); + } + } + } + + @Override + public void refeshVMList() { + requireActivity().runOnUiThread(this::checkAndLoad); + } + + @Override + public void configurationChanged(boolean isLandscape) { + spanCount = isLandscape ? 3 : 2; + binding.rvRomlist.setLayoutManager(new GridLayoutManager(getContext(), spanCount)); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/vectras/vm/home/vms/VmsHomeAdapter.java b/app/src/main/java/com/vectras/vm/home/vms/VmsHomeAdapter.java new file mode 100644 index 0000000..06069b1 --- /dev/null +++ b/app/src/main/java/com/vectras/vm/home/vms/VmsHomeAdapter.java @@ -0,0 +1,119 @@ +package com.vectras.vm.home.vms; + +import android.app.Activity; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.cardview.widget.CardView; +import androidx.recyclerview.widget.DiffUtil; +import androidx.recyclerview.widget.RecyclerView; + +import com.vectras.qemu.Config; +import com.vectras.vm.MainRoms.DataMainRoms; +import com.vectras.vm.R; +import com.vectras.vm.StartVM; +import com.vectras.vm.VMManager; +import com.vectras.vm.home.core.HomeStartVM; +import com.vectras.vm.home.core.RomOptionsDialog; + +import java.util.Collections; +import java.util.List; + +public class VmsHomeAdapter extends RecyclerView.Adapter{ + private final Activity activity; + private final LayoutInflater inflater; + public List data = Collections.emptyList(); + + public VmsHomeAdapter(Activity activity, List data) { + this.activity = activity; + inflater = LayoutInflater.from(activity); + this.data = data; + } + + // Inflate the layout when viewholder created + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = inflater.inflate(R.layout.container_main_roms, parent, false); + return new MyHolder(view); + } + + // Bind data + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int _position) { + + int position = holder.getBindingAdapterPosition(); + if (position == RecyclerView.NO_POSITION) return; + + // Get current position of item in recyclerview to bind data and assign values from list + final MyHolder myHolder = (MyHolder) holder; + final DataMainRoms current = data.get(position); + myHolder.textName.setText(current.itemName); + myHolder.textArch.setText(current.itemArch); + if (current.itemIcon.isEmpty()){ + VMManager.setIconWithName(myHolder.ivIcon, current.itemName); + } else { + Bitmap bmImg = BitmapFactory.decodeFile(current.itemIcon); + myHolder.ivIcon.setImageBitmap(bmImg); + } + myHolder.optionsBtn.setOnClickListener(view -> RomOptionsDialog.showNow(activity, data, position, current.vmID, current.itemName, current.itemArch)); + + myHolder.cdRoms.setOnClickListener(view -> { + VMManager.setArch(current.itemArch, activity); + StartVM.cdrompath = current.imgCdrom; + if (current.qmpPort == 0) { + Config.setDefault(); + } else { + Config.QMPPort = current.qmpPort; + } + Config.vmID = current.vmID; + String env = StartVM.env(activity, current.itemExtra, current.itemPath, ""); + HomeStartVM.startNow(activity, current.itemName, env, current.itemExtra, current.itemPath, null, null); + }); + + myHolder.cdRoms.setOnLongClickListener(v -> { + VMManager.deleteVMDialog(current.itemName, position, activity); + return false; + }); + } + + // return total item from List + @Override + public int getItemCount() { + return data.size(); + } + + static class MyHolder extends RecyclerView.ViewHolder { + + CardView cdRoms; + TextView textName, textArch; + ImageView ivIcon; + ImageButton optionsBtn; + + // create constructor to get widget reference + public MyHolder(View itemView) { + super(itemView); + cdRoms = itemView.findViewById(R.id.cdItem); + textName = itemView.findViewById(R.id.textName); + textArch = itemView.findViewById(R.id.textArch); + ivIcon = itemView.findViewById(R.id.ivIcon); + optionsBtn = itemView.findViewById(R.id.optionsButton); + } + + } + + public void updateData(List newData) { + DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new VmsDiffUtil(this.data, newData)); + this.data.clear(); + this.data.addAll(newData); + diffResult.dispatchUpdatesTo(this); + } + +} diff --git a/app/src/main/java/com/vectras/vm/settings/UpdaterActivity.java b/app/src/main/java/com/vectras/vm/settings/UpdaterActivity.java new file mode 100644 index 0000000..29a411e --- /dev/null +++ b/app/src/main/java/com/vectras/vm/settings/UpdaterActivity.java @@ -0,0 +1,162 @@ +package com.vectras.vm.settings; + +import static android.content.Intent.ACTION_VIEW; + +import android.app.Activity; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.text.Html; +import android.text.method.LinkMovementMethod; +import android.view.View; + +import androidx.activity.EdgeToEdge; +import androidx.appcompat.app.AppCompatActivity; + +import com.vectras.qemu.MainSettingsManager; +import com.vectras.vm.AppConfig; +import com.vectras.vm.R; +import com.vectras.vm.RequestNetwork; +import com.vectras.vm.RequestNetworkController; +import com.vectras.vm.databinding.ActivityUpdaterBinding; +import com.vectras.vm.utils.DialogUtils; +import com.vectras.vm.utils.PackageUtils; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.HashMap; +import java.util.Objects; + +public class UpdaterActivity extends AppCompatActivity { + + ActivityUpdaterBinding binding; + String downloadUrl = ""; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + EdgeToEdge.enable(this); + setContentView(R.layout.activity_vncactivity); + binding = ActivityUpdaterBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); + setSupportActionBar(binding.toolbar); + Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true); + binding.toolbar.setNavigationOnClickListener(view -> finish()); + initialize(); + } + + private void initialize() { + binding.bnUpdate.setOnClickListener(v -> { + if (downloadUrl.isEmpty()) { + finish(); + } else { + startActivity(new Intent(ACTION_VIEW, Uri.parse(downloadUrl))); + } + }); + + check(); + } + + private void whenUpToDate() { + binding.lpiProgressbar.setVisibility(View.GONE); + binding.collapsingToolbarLayout.setTitle(getText(R.string.you_are_up_to_date)); + binding.collapsingToolbarLayout.setSubtitle(PackageUtils.getThisVersionName(getApplicationContext())); + binding.bnUpdate.setText(getString(R.string.close)); + } + + private void checkAgain() { + binding.lpiProgressbar.setVisibility(View.VISIBLE); + binding.mcvWhatsnew.setVisibility(View.GONE); + binding.lnBottombar.setVisibility(View.GONE); + binding.collapsingToolbarLayout.setTitle(getText(R.string.checking_for_updates)); + binding.collapsingToolbarLayout.setSubtitle(getText(R.string.just_a_sec)); + binding.bnUpdate.setText(getString(R.string.update)); + downloadUrl = ""; + check(); + } + + private void check() { + int versionCode = PackageUtils.getThisVersionCode(getApplicationContext()); + String versionName = PackageUtils.getThisVersionName(getApplicationContext()); + + RequestNetwork requestNetwork = new RequestNetwork(this); + RequestNetwork.RequestListener requestNetworkListener = new RequestNetwork.RequestListener() { + @Override + public void onResponse(String tag, String response, HashMap responseHeaders) { + binding.lpiProgressbar.setVisibility(View.GONE); + binding.lnBottombar.setVisibility(View.VISIBLE); + + if (!response.isEmpty()) { + try { + final JSONObject obj = new JSONObject(response); + String versionNameonUpdate; + int versionCodeonUpdate; + String whatsnew; + String size; + String url; + + if (MainSettingsManager.getcheckforupdatesfromthebetachannel(UpdaterActivity.this)) { + versionNameonUpdate = obj.getString("versionNameBeta"); + versionCodeonUpdate = obj.getInt("versionCodeBeta"); + whatsnew = obj.getString("MessageBeta"); + size = obj.getString("sizeBeta"); + url = obj.getString("urlBeta"); + } else { + versionNameonUpdate = obj.getString("versionName"); + versionCodeonUpdate = obj.getInt("versionCode"); + whatsnew = obj.getString("Message"); + size = obj.getString("size"); + url = obj.getString("url"); + } + + if (versionCode < versionCodeonUpdate || !versionNameonUpdate.equals(versionName)) { + binding.collapsingToolbarLayout.setTitle(getText(R.string.new_update_available)); + binding.collapsingToolbarLayout.setSubtitle(getString(R.string.whats_new)); + binding.mcvWhatsnew.setVisibility(View.VISIBLE); + binding.tvWhatsnewcontent.setMovementMethod(LinkMovementMethod.getInstance()); + binding.tvWhatsnewcontent.setText(Html.fromHtml(whatsnew + "

Update size:
" + size)); + downloadUrl = url; + } else { + whenUpToDate(); + } + + if (obj.getString("versionNameBetas").contains(versionName) + && !MainSettingsManager.getcheckforupdatesfromthebetachannel(UpdaterActivity.this) + && !MainSettingsManager.getDontShowAgainJoinBetaUpdateChannelDialog(UpdaterActivity.this)) { + Activity activity = UpdaterActivity.this; + + DialogUtils.threeDialog(activity, + activity.getResources().getString(R.string.you_are_using_beta_version), + activity.getResources().getString(R.string.switch_to_check_for_updates_on_the_Beta_channel_now), + activity.getResources().getString(R.string.ok), + activity.getResources().getString(R.string.cancel), + activity.getResources().getString(R.string.dont_show_again), + true, + R.drawable.science_24px, + true, + () -> { + MainSettingsManager.setcheckforupdatesfromthebetachannel(activity, true); + checkAgain(); + }, + null, + () -> MainSettingsManager.setDontShowAgainJoinBetaUpdateChannelDialog(activity, true), + null); + } + } catch (JSONException e) { + whenUpToDate(); + } + } else { + whenUpToDate(); + } + } + + @Override + public void onErrorResponse(String tag, String message) { + whenUpToDate(); + } + }; + + requestNetwork.startRequestNetwork(RequestNetworkController.GET,AppConfig.updateJson,"checkupdate",requestNetworkListener); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/vectras/vm/utils/DeviceUtils.java b/app/src/main/java/com/vectras/vm/utils/DeviceUtils.java index 199348d..b1c9491 100644 --- a/app/src/main/java/com/vectras/vm/utils/DeviceUtils.java +++ b/app/src/main/java/com/vectras/vm/utils/DeviceUtils.java @@ -59,4 +59,8 @@ public class DeviceUtils { return false; } + + public static boolean is64bit() { + return Build.SUPPORTED_ABIS[0].contains("arm64"); + } } diff --git a/app/src/main/java/com/vectras/vm/utils/FileUtils.java b/app/src/main/java/com/vectras/vm/utils/FileUtils.java index 103a525..93e626d 100644 --- a/app/src/main/java/com/vectras/vm/utils/FileUtils.java +++ b/app/src/main/java/com/vectras/vm/utils/FileUtils.java @@ -3,7 +3,6 @@ package com.vectras.vm.utils; import android.annotation.SuppressLint; import android.content.ContentUris; import android.content.Context; -import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.Build; @@ -15,7 +14,6 @@ import android.system.ErrnoException; import android.system.Os; import android.text.TextUtils; import android.util.Log; -import android.webkit.MimeTypeMap; import android.widget.Toast; import java.io.File; @@ -27,31 +25,21 @@ import java.util.LinkedList; import java.util.List; import android.app.Activity; -import android.content.Context; -import android.content.Intent; import android.content.pm.PackageManager; -import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.os.ParcelFileDescriptor; -import android.util.Log; -import android.widget.Toast; import androidx.annotation.NonNull; -import com.vectras.vm.MainActivity; -import com.vectras.vm.AppConfig; import com.vectras.vm.R; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; -import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; -import java.io.InputStream; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Objects; @@ -486,11 +474,11 @@ public class FileUtils { } - public static String getDataDir() { + public static String getDataDir(Context context) { - String dataDir = MainActivity.activity.getApplicationInfo().dataDir; - PackageManager m = MainActivity.activity.getPackageManager(); - String packageName = MainActivity.activity.getPackageName(); + String dataDir = context.getApplicationInfo().dataDir; + PackageManager m = context.getPackageManager(); + String packageName = context.getPackageName(); Log.v("VMExecutor", "Found packageName: " + packageName); if (dataDir == null) { diff --git a/app/src/main/java/com/vectras/vm/utils/JSONUtils.java b/app/src/main/java/com/vectras/vm/utils/JSONUtils.java index 1ea2948..9f63a9b 100644 --- a/app/src/main/java/com/vectras/vm/utils/JSONUtils.java +++ b/app/src/main/java/com/vectras/vm/utils/JSONUtils.java @@ -1,6 +1,8 @@ package com.vectras.vm.utils; import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; import java.util.ArrayList; @@ -9,41 +11,17 @@ import java.util.Objects; public class JSONUtils { public static boolean isValidFromString(String _content) { - ArrayList> mmap = new ArrayList<>(); try { - mmap.clear(); - mmap = new Gson().fromJson(_content, new TypeToken>>() { - }.getType()); - return true; - } catch (Exception e) { - return false; - } - } - - public static boolean isMapValidFromString(String _content) { - HashMap mmap = new HashMap<>(); - try { - mmap.clear(); - mmap= new Gson().fromJson(_content, new TypeToken>(){}.getType()); - return true; + JsonElement element = JsonParser.parseString(_content); + return element != null; } catch (Exception e) { return false; } } public static boolean isValidFromFile(String _filepath) { - ArrayList> mmap = new ArrayList<>(); - String contentjson = ""; if (FileUtils.isFileExists(_filepath)) { - contentjson = FileUtils.readAFile(_filepath); - try { - mmap.clear(); - mmap = new Gson().fromJson(contentjson, new TypeToken>>() { - }.getType()); - return true; - } catch (Exception e) { - return false; - } + return isValidFromString(FileUtils.readAFile(_filepath)); } else { return false; } diff --git a/app/src/main/java/com/vectras/vm/utils/LibraryChecker.java b/app/src/main/java/com/vectras/vm/utils/LibraryChecker.java index a61858a..2692003 100644 --- a/app/src/main/java/com/vectras/vm/utils/LibraryChecker.java +++ b/app/src/main/java/com/vectras/vm/utils/LibraryChecker.java @@ -22,7 +22,7 @@ public class LibraryChecker { public void checkMissingLibraries(Activity activity) { // List of required libraries - String[] requiredLibraries = AppConfig.neededPkgs.split(" "); + String[] requiredLibraries = DeviceUtils.is64bit() ? AppConfig.neededPkgs.split(" ") : AppConfig.neededPkgs32bit.split(" "); // Get the list of installed packages isPackageInstalled(null, (output, errors) -> { @@ -61,7 +61,7 @@ public class LibraryChecker { .setPositiveButton("Install", (dialog, which) -> { // Create the install command String installCommand = "apk add " + missingLibraries.replace("\n", " "); - new Terminal(context).executeShellCommand(installCommand, true, activity); + new Terminal(context).executeShellCommand(installCommand, true, true, activity); }) .setNegativeButton("Cancel", (dialog, which) -> dialog.dismiss()) .show(); @@ -81,7 +81,7 @@ public class LibraryChecker { String command = "apk info"; Terminal terminal = new Terminal(context); - terminal.executeShellCommand(command, (Activity) context, (output, errors) -> { + terminal.executeShellCommand(command, (Activity) context, false, (output, errors) -> { if (callback != null) { callback.onCommandCompleted(output, errors); } @@ -93,7 +93,7 @@ public class LibraryChecker { String command = "apk info"; Terminal terminal = new Terminal(activity); - terminal.executeShellCommand(command, activity, (output, errors) -> { + terminal.executeShellCommand(command, activity, false, (output, errors) -> { if (callback != null) { callback.onCommandCompleted(output, errors); } @@ -134,7 +134,7 @@ public class LibraryChecker { .setCancelable(false) .setPositiveButton("Install", (dialog, which) -> { String installCommand = "apk add " + packageName; - new Terminal(context).executeShellCommand(installCommand, true, activity); + new Terminal(context).executeShellCommand(installCommand, true, true, activity); }) .setNegativeButton("Cancel", (dialog, which) -> dialog.dismiss()) .show(); diff --git a/app/src/main/java/com/vectras/vm/utils/NetworkUtils.java b/app/src/main/java/com/vectras/vm/utils/NetworkUtils.java index 5512741..75d66cc 100644 --- a/app/src/main/java/com/vectras/vm/utils/NetworkUtils.java +++ b/app/src/main/java/com/vectras/vm/utils/NetworkUtils.java @@ -1,5 +1,9 @@ package com.vectras.vm.utils; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; + import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; @@ -20,4 +24,26 @@ public class NetworkUtils { } } } + + /** + * CHECK WHETHER INTERNET CONNECTION IS AVAILABLE OR NOT + */ + public boolean checkConnection(Context context) { + final ConnectivityManager connMgr = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); + + if (connMgr != null) { + NetworkInfo activeNetworkInfo = connMgr.getActiveNetworkInfo(); + + if (activeNetworkInfo != null) { // connected to the internet + // connected to the mobile provider's data plan + if (activeNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI) { + // connected to wifi + return true; + } else + return activeNetworkInfo.getType() == ConnectivityManager.TYPE_MOBILE; + } + } + return false; + } } diff --git a/app/src/main/java/com/vectras/vm/utils/NotificationUtils.java b/app/src/main/java/com/vectras/vm/utils/NotificationUtils.java new file mode 100644 index 0000000..2518867 --- /dev/null +++ b/app/src/main/java/com/vectras/vm/utils/NotificationUtils.java @@ -0,0 +1,11 @@ +package com.vectras.vm.utils; + +import android.app.NotificationManager; +import android.content.Context; + +public class NotificationUtils { + public static void clearAll(Context context) { + NotificationManager notificationManager = (NotificationManager) context.getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.cancelAll(); + } +} diff --git a/app/src/main/java/com/vectras/vm/utils/NumberUtils.java b/app/src/main/java/com/vectras/vm/utils/NumberUtils.java new file mode 100644 index 0000000..e2e4f92 --- /dev/null +++ b/app/src/main/java/com/vectras/vm/utils/NumberUtils.java @@ -0,0 +1,10 @@ +package com.vectras.vm.utils; + +public class NumberUtils { + public static int safeLongToInt(long l) { + if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) { + return 0; + } + return (int) l; + } +} diff --git a/app/src/main/java/com/vectras/vm/utils/ServiceUtils.java b/app/src/main/java/com/vectras/vm/utils/ServiceUtils.java new file mode 100644 index 0000000..7d1474c --- /dev/null +++ b/app/src/main/java/com/vectras/vm/utils/ServiceUtils.java @@ -0,0 +1,18 @@ +package com.vectras.vm.utils; + +import android.app.ActivityManager; +import android.content.Context; + +public class ServiceUtils { + public static boolean isServiceRunning(Context context, Class serviceClass) { + ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + if (manager != null) { + for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { + if (serviceClass.getName().equals(service.service.getClassName())) { + return true; + } + } + } + return false; + } +} diff --git a/app/src/main/java/com/vectras/vm/utils/UIUtils.java b/app/src/main/java/com/vectras/vm/utils/UIUtils.java index 2d4a7fc..ee6c274 100644 --- a/app/src/main/java/com/vectras/vm/utils/UIUtils.java +++ b/app/src/main/java/com/vectras/vm/utils/UIUtils.java @@ -26,7 +26,6 @@ import android.text.Html; import android.text.InputType; import android.text.Spannable; import android.text.SpannableString; -import android.text.method.LinkMovementMethod; import android.text.style.ForegroundColorSpan; import android.util.Log; import android.view.Display; @@ -41,7 +40,6 @@ import android.widget.Toast; import com.vectras.qemu.Config; import com.vectras.qemu.MainSettingsManager; import com.vectras.qemu.utils.FileUtils; -import com.vectras.vm.MainActivity; import com.vectras.vm.R; import com.vectras.vm.logger.VectrasStatus; @@ -461,4 +459,44 @@ public class UIUtils { return insets; }); } + public static void setOnApplyWindowInsetsListenerBottomOnly(View _view) { + int originalPaddingLeft = _view.getPaddingLeft(); + int originalPaddingTop = _view.getPaddingTop(); + int originalPaddingRight = _view.getPaddingRight(); + int originalPaddingBottom = _view.getPaddingBottom(); + + ViewCompat.setOnApplyWindowInsetsListener(_view, (v, insets) -> { + Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout() | WindowInsetsCompat.Type.ime()); + v.setPadding(originalPaddingLeft, originalPaddingTop, originalPaddingRight, systemBars.bottom + originalPaddingBottom); + return insets; + }); + } + + + public static void setOnApplyWindowInsetsListenerLeftOnly(View _view) { + int originalPaddingLeft = _view.getPaddingLeft(); + int originalPaddingTop = _view.getPaddingTop(); + int originalPaddingRight = _view.getPaddingRight(); + int originalPaddingBottom = _view.getPaddingBottom(); + + + ViewCompat.setOnApplyWindowInsetsListener(_view, (v, insets) -> { + Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout() | WindowInsetsCompat.Type.ime()); + v.setPadding(systemBars.left + originalPaddingLeft , originalPaddingTop, originalPaddingRight, originalPaddingBottom); + return insets; + }); + } + + public static void setOnApplyWindowInsetsListenerHorizontalOnly(View _view) { + int originalPaddingLeft = _view.getPaddingLeft(); + int originalPaddingTop = _view.getPaddingTop(); + int originalPaddingRight = _view.getPaddingRight(); + int originalPaddingBottom = _view.getPaddingBottom(); + + ViewCompat.setOnApplyWindowInsetsListener(_view, (v, insets) -> { + Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout() | WindowInsetsCompat.Type.ime()); + v.setPadding(systemBars.left + originalPaddingLeft, originalPaddingTop, systemBars.right + originalPaddingRight, originalPaddingBottom); + return insets; + }); + } } diff --git a/app/src/main/java/com/vectras/vm/widgets/JoystickView.java b/app/src/main/java/com/vectras/vm/widgets/JoystickView.java index c0a2ed4..d3462fe 100644 --- a/app/src/main/java/com/vectras/vm/widgets/JoystickView.java +++ b/app/src/main/java/com/vectras/vm/widgets/JoystickView.java @@ -28,7 +28,7 @@ public class JoystickView extends View /** - * Interface definition for a callback to be invoked when a + * CallbackInterface definition for a callback to be invoked when a * JoystickView's button is moved */ public interface OnMoveListener { @@ -43,7 +43,7 @@ public class JoystickView extends View /** - * Interface definition for a callback to be invoked when a JoystickView + * CallbackInterface definition for a callback to be invoked when a JoystickView * is touched and held by multiple pointers. */ public interface OnMultipleLongPressListener { diff --git a/app/src/main/java/com/vectras/vm/widgets/RadioGroupPlus.java b/app/src/main/java/com/vectras/vm/widgets/RadioGroupPlus.java index c4cd5c8..aede6ba 100644 --- a/app/src/main/java/com/vectras/vm/widgets/RadioGroupPlus.java +++ b/app/src/main/java/com/vectras/vm/widgets/RadioGroupPlus.java @@ -269,7 +269,7 @@ public class RadioGroupPlus extends LinearLayout { } /** - *

Interface definition for a callback to be invoked when the checked + *

CallbackInterface definition for a callback to be invoked when the checked * radio button changed in this group.

*/ public interface OnCheckedChangeListener { diff --git a/app/src/main/java/com/vectras/vm/x11/X11Activity.java b/app/src/main/java/com/vectras/vm/x11/X11Activity.java index 0874ea1..8af99b7 100644 --- a/app/src/main/java/com/vectras/vm/x11/X11Activity.java +++ b/app/src/main/java/com/vectras/vm/x11/X11Activity.java @@ -599,7 +599,7 @@ public class X11Activity extends AppCompatActivity implements View.OnApplyWindow // Stop the service MainService.stopService(); //Terminal.killQemuProcess(); - VMManager.killcurrentqemuprocess(getApplicationContext()); + VMManager.killcurrentqemuprocess(X11Activity.this); finish(); }) .setNegativeButton(getString(R.string.no), null) diff --git a/app/src/main/java/com/vectras/vm/x11/input/TouchInputHandler.java b/app/src/main/java/com/vectras/vm/x11/input/TouchInputHandler.java index c3305ed..efabb68 100644 --- a/app/src/main/java/com/vectras/vm/x11/input/TouchInputHandler.java +++ b/app/src/main/java/com/vectras/vm/x11/input/TouchInputHandler.java @@ -757,7 +757,7 @@ public class TouchInputHandler { /** - * Interface with a set of functions to control the behavior of the remote host renderer. + * CallbackInterface with a set of functions to control the behavior of the remote host renderer. */ public interface RenderStub { /** diff --git a/app/src/main/java/com/vectras/vterm/Terminal.java b/app/src/main/java/com/vectras/vterm/Terminal.java index c52f182..90cc451 100644 --- a/app/src/main/java/com/vectras/vterm/Terminal.java +++ b/app/src/main/java/com/vectras/vterm/Terminal.java @@ -1,9 +1,7 @@ package com.vectras.vterm; import android.app.Activity; -import android.app.ProgressDialog; import android.content.Context; -import android.content.DialogInterface; import android.os.Build; import android.os.Handler; import android.os.Looper; @@ -32,18 +30,18 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import com.vectras.qemu.MainVNCActivity; -import com.vectras.vm.MainActivity; -import com.vectras.vm.MainService; import com.vectras.vm.R; import com.vectras.vm.VMManager; import com.vectras.vm.AppConfig; +import com.vectras.vm.VectrasApp; import com.vectras.vm.utils.ClipboardUltils; import com.vectras.vm.utils.DialogUtils; +import com.vectras.vm.utils.NotificationUtils; public class Terminal { private static final String TAG = "Vterm"; private Context context; - private String user = "root"; + private static String user = "root"; public static Process qemuProcess; public static String DISPLAY = ":0"; @@ -74,12 +72,12 @@ public class Terminal { if (VMManager.isExecutedCommandError(usercommand, message, activity)) return; - DialogUtils.twoDialog(activity, "Execution Result", message, activity.getString(R.string.copy), activity.getString(R.string.close),true, R.drawable.round_terminal_24, true, - () -> ClipboardUltils.copyToClipboard(activity, message), null,null); + DialogUtils.twoDialog(activity, "Execution Result", message, activity.getString(R.string.copy), activity.getString(R.string.close), true, R.drawable.round_terminal_24, true, + () -> ClipboardUltils.copyToClipboard(activity, message), null, null); } // Method to execute the shell command - public void executeShellCommand(String userCommand, boolean showResultDialog, Activity dialogActivity) { + public void executeShellCommand(String userCommand, boolean showResultDialog, boolean showProgressDialog, Activity dialogActivity) { StringBuilder output = new StringBuilder(); StringBuilder errors = new StringBuilder(); Log.d(TAG, userCommand); @@ -94,7 +92,7 @@ public class Terminal { .setCancelable(false) .create(); - progressDialog.show(); + if (showProgressDialog) progressDialog.show(); new Thread(() -> { try { @@ -272,7 +270,7 @@ public class Terminal { } catch (IOException | InterruptedException e) { output.append(e.getMessage()); errors.append(Log.getStackTraceString(e)); - MainActivity.clearNotifications(); + NotificationUtils.clearAll(VectrasApp.getContext()); } finally { // Switch to main thread after execution new Handler(Looper.getMainLooper()).post(() -> { @@ -289,6 +287,82 @@ public class Terminal { }).start(); } + public static String executeShellCommandWithResult(String userCommand, Activity activity) { + StringBuilder output = new StringBuilder(); + StringBuilder errors = new StringBuilder(); + Log.d(TAG, userCommand); + com.vectras.vm.logger.VectrasStatus.logError("VTERM: >" + userCommand + ""); + + try { + ProcessBuilder processBuilder = new ProcessBuilder(); + + String filesDir = Objects.requireNonNull(activity.getFilesDir().getAbsolutePath()); + File tmpDir = new File(Objects.requireNonNull(activity.getFilesDir()), "usr/tmp"); + + processBuilder.environment().put("PROOT_TMP_DIR", tmpDir.getAbsolutePath()); + processBuilder.environment().put("HOME", "/root"); + processBuilder.environment().put("USER", user); + processBuilder.environment().put("TERM", "xterm-256color"); + processBuilder.environment().put("TMPDIR", tmpDir.getAbsolutePath()); + processBuilder.environment().put("SHELL", "/bin/sh"); + processBuilder.environment().put("DISPLAY", DISPLAY); + processBuilder.environment().put("PULSE_SERVER", "127.0.0.1"); + + String[] prootCommand = { + TermuxService.PREFIX_PATH + "/bin/proot", + "--kill-on-exit", + "--link2symlink", + "-0", + "-r", filesDir + "/distro", + "-b", "/dev", + "-b", "/proc", + "-b", "/sys", + "-b", "/data/data/com.vectras.vm/files/distro/root:/dev/shm", + "-b", "/sdcard", + "-b", "/storage", + "-b", "/data", + "-b", "/data/data/com.vectras.vm/files/usr/tmp:/tmp", + "-w", "/root", + "/bin/sh", + "--login" + }; + + processBuilder.command(prootCommand); + qemuProcess = processBuilder.start(); + + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(qemuProcess.getOutputStream())); + BufferedReader reader = new BufferedReader(new InputStreamReader(qemuProcess.getInputStream())); + BufferedReader errorReader = new BufferedReader(new InputStreamReader(qemuProcess.getErrorStream())); + + writer.write(userCommand); + writer.newLine(); + writer.flush(); + writer.close(); + + String line; + while ((line = reader.readLine()) != null) { + Log.d(TAG, line); + com.vectras.vm.logger.VectrasStatus.logError("VTERM: >" + line + ""); + output.append(line).append("\n"); + } + + while ((line = errorReader.readLine()) != null) { + Log.w(TAG, line); + com.vectras.vm.logger.VectrasStatus.logError("VTERM ERROR: >" + line + ""); + output.append(line).append("\n"); + } + + int exitCode = qemuProcess.waitFor(); + if (exitCode != 0) { + output.append("Execution finished with exit code: ").append(exitCode).append("\n"); + } + } catch (IOException | InterruptedException e) { + output.append(e.getMessage()); + errors.append(Log.getStackTraceString(e)); + } + return output.toString(); + } + public void extractQemuVersion(String userCommand, boolean showResultDialog, Activity dialogActivity, CommandCallback callback) { StringBuilder output = new StringBuilder(); StringBuilder errors = new StringBuilder(); @@ -396,7 +470,7 @@ public class Terminal { void onCommandCompleted(String output, String errors); } - public String executeShellCommand(String userCommand, Activity dialogActivity, CommandCallback callback) { + public String executeShellCommand(String userCommand, Activity dialogActivity, boolean isShowProgressDialog, CommandCallback callback) { StringBuilder output = new StringBuilder(); StringBuilder errors = new StringBuilder(); Log.d(TAG, userCommand); @@ -412,7 +486,7 @@ public class Terminal { .create(); // Make sure to show the dialog on the main thread - new Handler(Looper.getMainLooper()).post(progressDialog::show); + if (isShowProgressDialog) new Handler(Looper.getMainLooper()).post(progressDialog::show); new Thread(() -> { try { diff --git a/app/src/main/res/drawable/add_24px.xml b/app/src/main/res/drawable/add_24px.xml new file mode 100644 index 0000000..d6fd3d3 --- /dev/null +++ b/app/src/main/res/drawable/add_24px.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/home_24px.xml b/app/src/main/res/drawable/home_24px.xml new file mode 100644 index 0000000..16b0538 --- /dev/null +++ b/app/src/main/res/drawable/home_24px.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/home_filled_24px.xml b/app/src/main/res/drawable/home_filled_24px.xml new file mode 100644 index 0000000..333f1ed --- /dev/null +++ b/app/src/main/res/drawable/home_filled_24px.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/home_storage_filled_24px.xml b/app/src/main/res/drawable/home_storage_filled_24px.xml new file mode 100644 index 0000000..eeea8b0 --- /dev/null +++ b/app/src/main/res/drawable/home_storage_filled_24px.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_home_selector.xml b/app/src/main/res/drawable/ic_home_selector.xml new file mode 100644 index 0000000..7a31bcb --- /dev/null +++ b/app/src/main/res/drawable/ic_home_selector.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_home_storage_selector.xml b/app/src/main/res/drawable/ic_home_storage_selector.xml new file mode 100644 index 0000000..027d3f2 --- /dev/null +++ b/app/src/main/res/drawable/ic_home_storage_selector.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_monitor_heart_selector.xml b/app/src/main/res/drawable/ic_monitor_heart_selector.xml new file mode 100644 index 0000000..23ece28 --- /dev/null +++ b/app/src/main/res/drawable/ic_monitor_heart_selector.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/monitor_heart_filled_24px.xml b/app/src/main/res/drawable/monitor_heart_filled_24px.xml new file mode 100644 index 0000000..e0efd94 --- /dev/null +++ b/app/src/main/res/drawable/monitor_heart_filled_24px.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/activity_home.xml b/app/src/main/res/layout/activity_home.xml new file mode 100644 index 0000000..947f86f --- /dev/null +++ b/app/src/main/res/layout/activity_home.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_home_content.xml b/app/src/main/res/layout/activity_home_content.xml new file mode 100644 index 0000000..5284bfe --- /dev/null +++ b/app/src/main/res/layout/activity_home_content.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_updater.xml b/app/src/main/res/layout/activity_updater.xml new file mode 100644 index 0000000..297b704 --- /dev/null +++ b/app/src/main/res/layout/activity_updater.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_home_rom_store.xml b/app/src/main/res/layout/fragment_home_rom_store.xml new file mode 100644 index 0000000..645096d --- /dev/null +++ b/app/src/main/res/layout/fragment_home_rom_store.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home_system_monitor.xml b/app/src/main/res/layout/fragment_home_system_monitor.xml new file mode 100644 index 0000000..1461043 --- /dev/null +++ b/app/src/main/res/layout/fragment_home_system_monitor.xml @@ -0,0 +1,265 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home_vms.xml b/app/src/main/res/layout/fragment_home_vms.xml new file mode 100644 index 0000000..f4a2f5f --- /dev/null +++ b/app/src/main/res/layout/fragment_home_vms.xml @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/update_bottom_dialog_layout.xml b/app/src/main/res/layout/update_bottom_dialog_layout.xml new file mode 100644 index 0000000..3d2053d --- /dev/null +++ b/app/src/main/res/layout/update_bottom_dialog_layout.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/menu/bottom_navigation_home_menu.xml b/app/src/main/res/menu/bottom_navigation_home_menu.xml new file mode 100644 index 0000000..898ea99 --- /dev/null +++ b/app/src/main/res/menu/bottom_navigation_home_menu.xml @@ -0,0 +1,17 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/home_drawer_menu.xml b/app/src/main/res/menu/home_drawer_menu.xml index 45a0260..1c14b46 100644 --- a/app/src/main/res/menu/home_drawer_menu.xml +++ b/app/src/main/res/menu/home_drawer_menu.xml @@ -8,11 +8,8 @@ - + - - + android:visible="true" + app:showAsAction="always"/> diff --git a/app/src/main/res/menu/searchbar_menu.xml b/app/src/main/res/menu/searchbar_menu.xml new file mode 100644 index 0000000..68d4149 --- /dev/null +++ b/app/src/main/res/menu/searchbar_menu.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 42403c2..ceac2b1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3,7 +3,7 @@ Vectras VM - v2.9.5.6-3dfx + v2.9.5.7-3dfx Stable Home Logger @@ -224,9 +224,9 @@ IMAGE NAME MAKE IMAGE IMPORTED ROMS WILL BE SHOWN HERE - VERSION: + Version: QEMU - ARCH: + Arch: Running Stopped SERVICE: @@ -530,6 +530,27 @@ Unable to process thumbnail. The available storage space on your device is too low. Please clean up. The virtual machine list data is corrupted, do you want to repair it? + The virtual machine cache directory failed to create. Please try again later. + Checking for updates + Just a sec… + What\'s new? + New update available + You\'re up to date + Check for updates + See if there are any new updates. + Home + Skip this version + Update now to experience the latest features and fix issues. + More + Storage + System monitor + Status: + Port: + You can shut down this virtual machine by clicking the Stop button in the System monitor. To control it, connect to this port: + Action needed + Data about the virtual machines has been corrupted and needs to be repaired. + Start repair + diff --git a/app/src/main/res/xml/settings.xml b/app/src/main/res/xml/settings.xml index bade35b..97cacf0 100644 --- a/app/src/main/res/xml/settings.xml +++ b/app/src/main/res/xml/settings.xml @@ -26,16 +26,6 @@ android:title="@string/join_the_beta_channel" app:icon="@drawable/science_24px" /> - - + + + + + + \ No newline at end of file diff --git a/web/data/UpdateConfig.json b/web/data/UpdateConfig.json index 764790d..a2039a8 100644 --- a/web/data/UpdateConfig.json +++ b/web/data/UpdateConfig.json @@ -1,15 +1,15 @@ { "versionCode":"21", - "versionName":"v2.9.5-3dfx,v2.9.5-3dfx-almondcake,v2.9.5-3dfx-bread,v2.9.5-3dfx-churro,v2.9.5-3dfx-doughnut,v2.9.5-3dfx-empanada,v2.9.5-3dfx-flan,v2.9.5-3dfx-gugelhupf,v2.9.5-3dfx-hamentaschen,v2.9.5-3dfx-italianice,v2.9.5-3dfx-ladyfingers,v2.9.5-3dfx-madeleine,v2.9.5-3dfx-neapolitanicecream,v2.9.5-3dfx-orangecake,v2.9.5-3dfx-profiterole,v2.9.5-3dfx-quincejelly,v2.9.5-3dfx-rugelach,v2.9.5-3dfx-scone,v2.9.5-3dfx-tart,v2.9.5-3dfx-ube-halaya,v2.9.5-3dfx-victoria-sponge,v2.9.5-3dfx-waffle,v2.9.5-3dfx-xangos,v2.9.5-3dfx-yorkshire-pudding,v2.9.5-3dfx-zeppole,v2.9.5.1-3dfx,v2.9.5.2-3dfx,v2.9.5.3-3dfx,v2.9.5.4-3dfx,v2.9.5.5-3dfx,v2.9.5.6-3dfx", + "versionName":"v2.9.5-3dfx,v2.9.5-3dfx-almondcake,v2.9.5-3dfx-bread,v2.9.5-3dfx-churro,v2.9.5-3dfx-doughnut,v2.9.5-3dfx-empanada,v2.9.5-3dfx-flan,v2.9.5-3dfx-gugelhupf,v2.9.5-3dfx-hamentaschen,v2.9.5-3dfx-italianice,v2.9.5-3dfx-ladyfingers,v2.9.5-3dfx-madeleine,v2.9.5-3dfx-neapolitanicecream,v2.9.5-3dfx-orangecake,v2.9.5-3dfx-profiterole,v2.9.5-3dfx-quincejelly,v2.9.5-3dfx-rugelach,v2.9.5-3dfx-scone,v2.9.5-3dfx-tart,v2.9.5-3dfx-ube-halaya,v2.9.5-3dfx-victoria-sponge,v2.9.5-3dfx-waffle,v2.9.5-3dfx-xangos,v2.9.5-3dfx-yorkshire-pudding,v2.9.5-3dfx-zeppole,v2.9.5.1-3dfx,v2.9.5.2-3dfx,v2.9.5.3-3dfx,v2.9.5.4-3dfx,v2.9.5.5-3dfx,v2.9.5.6-3dfx,v2.9.5.7-3dfx", "size": "46 MB", "url": "https://github.com/xoureldeen/Vectras-VM-Android/releases/v2.9.5", "Message": "

v2.9.5-3dfx

  • Bring back 3dfx support.
  • Enhance app execution.
  • Added some linux programs in x11 display.
  • Added alpine linux (x11).
  • Russian language by @OFGING


New updates are live!", "cancellable": true, "versionCodeBeta":"21", - "versionNameBeta":"v2.9.5.6-3dfx", - "versionNameBetas":"v2.9.5-3dfx-madeleine,v2.9.5-3dfx-neapolitanicecream,v2.9.5-3dfx-orangecake,v2.9.5-3dfx-profiterole,v2.9.5-3dfx-quincejelly,v2.9.5-3dfx-rugelach,v2.9.5-3dfx-scone,v2.9.5-3dfx-tart,v2.9.5-3dfx-victoria-sponge,v2.9.5-3dfx-waffle,v2.9.5-3dfx-xangos,v2.9.5-3dfx-yorkshire-pudding,v2.9.5-3dfx-zeppole,v2.9.5.1-3dfx,v2.9.5.2-3dfx,v2.9.5.3-3dfx,v2.9.5.4-3dfx,v2.9.5.5-3dfx,v2.9.5.6-3dfx", + "versionNameBeta":"v2.9.5.7-3dfx", + "versionNameBetas":"v2.9.5-3dfx-madeleine,v2.9.5-3dfx-neapolitanicecream,v2.9.5-3dfx-orangecake,v2.9.5-3dfx-profiterole,v2.9.5-3dfx-quincejelly,v2.9.5-3dfx-rugelach,v2.9.5-3dfx-scone,v2.9.5-3dfx-tart,v2.9.5-3dfx-victoria-sponge,v2.9.5-3dfx-waffle,v2.9.5-3dfx-xangos,v2.9.5-3dfx-yorkshire-pudding,v2.9.5-3dfx-zeppole,v2.9.5.1-3dfx,v2.9.5.2-3dfx,v2.9.5.3-3dfx,v2.9.5.4-3dfx,v2.9.5.5-3dfx,v2.9.5.6-3dfx,v2.9.5.7-3dfx", "sizeBeta": "50 MB", "urlBeta": "https://github.com/AnBui2004/Vectras-VM-Emu-Android/releases", - "MessageBeta": "

v2.9.5.6-3dfx

Bugs fixed.", + "MessageBeta": "

v2.9.5.7-3dfx

Bugs fixed.", "cancellableBeta": true } diff --git a/web/data/vroms-store.json b/web/data/vroms-store.json index 3ddaf4a..3ecdd45 100644 --- a/web/data/vroms-store.json +++ b/web/data/vroms-store.json @@ -335,6 +335,22 @@ "creator": "Nguyen Bao An Bui", "verified": true }, + { + "rom_name":"Windows 8 build 8432", + "rom_icon":"https://vuetiwuvbyxywfukompp.supabase.co/storage/v1/object/public/getmyos/v1/files/2018/09/17/windows-logo_1_926ed76111646acbbe332bc5af0cf2ce.png", + "rom_url":"https://youtu.be/wH8n87pPJ2k", + "rom_path":"Windows 8 build 8432.cvbi", + "rom_avail":true, + "rom_size":"Preview build", + "rom_arch":"X86_64", + "rom_kernel":"windows", + "rom_extra":"", + "final_rom_file_name":"", + "desc":"This Rom is from Nguyen Bao An Bui. You can get it on An Bui app: https://play.google.com/store/apps/details?id=com.anbui.app\n\nWindows 8.1 build 9431 is the official Preview build of Windows 8.1, also known as the Milestone Preview. This build was released on 26 June 2013 with the occasion of the Build 2013 conference taking place. At the time of its release, it was possible to upgrade to this build from a Windows 8 copy by using the Windows Store or by downloading an ISO from TechNet or MSDN. The ISOs were made publicly available the day after, on 27 June 2013 in multiple languages, when the day 2 keynote started. An ARM version of the build was also available, but it was only obtainable through the Microsoft Store (repair content packages were also made available).", + "file_size": "7 GB", + "creator": "Nguyen Bao An Bui", + "verified": true + }, { "rom_name":"Windows 8", "rom_icon":"https://vuetiwuvbyxywfukompp.supabase.co/storage/v1/object/public/getmyos/v1/files/2018/09/17/windows-logo_1_926ed76111646acbbe332bc5af0cf2ce.png",