Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 98 additions & 11 deletions app/src/main/java/com/hyperion/grabber/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
import android.widget.Toast;

import com.hyperion.grabber.common.BootActivity;
import com.hyperion.grabber.common.HyperionActivityHelper;
import com.hyperion.grabber.common.HyperionScreenService;
import com.hyperion.grabber.common.util.PermissionHelper;
import com.hyperion.grabber.common.util.Preferences;
Expand All @@ -49,7 +48,16 @@ public class MainActivity extends AppCompatActivity implements ImageView.OnClick

@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(HyperionActivityHelper.updateBaseContextLocale(newBase));
Preferences prefs = new Preferences(newBase);
String languageString = prefs.getLocale();
Locale locale = new Locale(languageString);
Locale.setDefault(locale);

Resources res = newBase.getResources();
Configuration config = new Configuration(res.getConfiguration());
config.setLocale(locale);

super.attachBaseContext(newBase.createConfigurationContext(config));
}
public static final int REQUEST_MEDIA_PROJECTION = 1;
private static final int REQUEST_NOTIFICATION_PERMISSION = 2;
Expand All @@ -63,6 +71,7 @@ protected void attachBaseContext(Context newBase) {
private boolean mTclWarningShown = false;
private String mLastError = null;
private Spinner languageSpinner;
private boolean initialLanguageLoad = true;

private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
@Override
Expand All @@ -88,6 +97,42 @@ public void onReceive(Context context, Intent intent) {
}
};

private void setupLanguageSpinner() {
String[] languages = {"English", "Russian", "German", "Spanish", "French", "Italian", "Dutch", "Norwegian", "Czech", "Arabic"};
final String[] languageCodes = {"en", "ru", "de", "es", "fr", "it", "nl", "no", "cs", "ar"};

ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, languages);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
languageSpinner.setAdapter(adapter);

Preferences prefs = new Preferences(this);
String currentLang = prefs.getLocale();
for (int i = 0; i < languageCodes.length; i++) {
if (languageCodes[i].equals(currentLang)) {
languageSpinner.setSelection(i);
break;
}
}

languageSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (initialLanguageLoad) {
initialLanguageLoad = false;
return;
}
String selectedLang = languageCodes[position];
if (!selectedLang.equals(prefs.getLocale())) {
prefs.setLocale(selectedLang);
recreate();
}
}

@Override
public void onNothingSelected(AdapterView<?> parent) {}
});
}

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onCreate(Bundle savedInstanceState) {
Expand Down Expand Up @@ -115,7 +160,7 @@ protected void onCreate(Bundle savedInstanceState) {

languageSpinner = findViewById(R.id.languageSpinner);
if (languageSpinner != null) {
HyperionActivityHelper.setupLanguageSpinner(this, languageSpinner);
setupLanguageSpinner();
}

setImageViews(mRecorderRunning, false);
Expand All @@ -125,7 +170,9 @@ protected void onCreate(Bundle savedInstanceState) {
checkForInstance();

// Request notification permission for Android 13+
HyperionActivityHelper.requestNotificationPermission(this, REQUEST_NOTIFICATION_PERMISSION);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
requestNotificationPermission();
}
}

@Override
Expand All @@ -135,6 +182,17 @@ protected void onResume() {
checkForUpdates();
}

private void requestNotificationPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.POST_NOTIFICATIONS},
REQUEST_NOTIFICATION_PERMISSION);
}
}
}

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public void onClick(View view) {
Expand Down Expand Up @@ -281,19 +339,23 @@ public boolean onOptionsItemSelected(MenuItem item) {
}

private void checkForInstance() {
if (HyperionActivityHelper.isServiceRunning(this)) {
if (isServiceRunning()) {
Intent intent = new Intent(this, HyperionScreenService.class);
intent.setAction(HyperionScreenService.GET_STATUS);
startService(intent);
}
}

public void startScreenRecorder(int resultCode, Intent data) {
HyperionActivityHelper.startScreenRecorder(this, resultCode, data);
BootActivity.startScreenRecorder(this, resultCode, data);
}

public void stopScreenRecorder() {
HyperionActivityHelper.stopScreenRecorder(this, mRecorderRunning);
if (mRecorderRunning) {
Intent intent = new Intent(this, HyperionScreenService.class);
intent.setAction(HyperionScreenService.ACTION_EXIT);
startService(intent);
}
}

private void setImageViews(boolean running, boolean animated) {
Expand All @@ -302,17 +364,17 @@ private void setImageViews(boolean running, boolean animated) {
View buttonImage = findViewById(R.id.power_toggle);
if (running) {
if (animated){
HyperionActivityHelper.fadeView(rainbow, true);
HyperionActivityHelper.fadeView(message, true);
fadeView(rainbow, true);
fadeView(message, true);
} else {
rainbow.setVisibility(View.VISIBLE);
message.setVisibility(View.VISIBLE);
}
buttonImage.setAlpha((float) 1);
} else {
if (animated){
HyperionActivityHelper.fadeView(rainbow, false);
HyperionActivityHelper.fadeView(message, false);
fadeView(rainbow, false);
fadeView(message, false);
} else {
rainbow.setVisibility(View.INVISIBLE);
message.setVisibility(View.INVISIBLE);
Expand Down Expand Up @@ -357,4 +419,29 @@ private void showUpdateDialog(com.hyperion.grabber.common.util.GithubRelease rel
);
}

private boolean isServiceRunning() {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
assert manager != null;
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (HyperionScreenService.class.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
Comment on lines +422 to +430

Copilot AI Feb 15, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isServiceRunning() uses assert manager != null; but Java/Kotlin assertions are typically disabled in production builds, so this can still NPE. Prefer a real null-check and a safe default (return false) when ActivityManager is unavailable.

Copilot uses AI. Check for mistakes.
}

private void fadeView(View view, boolean visible){
float alpha = visible ? 1f : 0f;
int endVisibility = visible ? View.VISIBLE : View.INVISIBLE;
view.setVisibility(View.VISIBLE);
view.animate()
.alpha(alpha)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
view.setVisibility(endVisibility);
}
})
.start();
}
}
5 changes: 1 addition & 4 deletions app/src/main/java/com/hyperion/grabber/UpdateDialog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@ package com.hyperion.grabber

import android.app.AlertDialog
import android.content.Context
import android.util.Log
import android.view.LayoutInflater
import android.widget.TextView
import com.hyperion.grabber.common.util.GithubRelease

private const val TAG = "UpdateDialog"

class UpdateDialog(private val context: Context) {

fun show(release: GithubRelease, onUpdate: () -> Unit, onDismiss: () -> Unit) {
Expand All @@ -35,7 +32,7 @@ class UpdateDialog(private val context: Context) {
.setCancelable(true)
.show()
} catch (e: Exception) {
Log.e(TAG, "Error showing update dialog", e)
e.printStackTrace()
onDismiss()
Comment on lines 34 to 36

Copilot AI Feb 15, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

printStackTrace() should be avoided here; use Log.e(..., e) so the failure is properly captured in logcat and consistent with the rest of the app's error logging.

Copilot uses AI. Check for mistakes.
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com.hyperion.grabber.tv.activities;

import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;
import com.hyperion.grabber.common.HyperionActivityHelper;
import com.hyperion.grabber.common.util.Preferences;
import java.util.Locale;

public abstract class LeanbackActivity extends FragmentActivity {

Expand All @@ -15,7 +18,16 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {

@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(HyperionActivityHelper.updateBaseContextLocale(newBase));
Preferences prefs = new Preferences(newBase);
String languageString = prefs.getLocale();
Locale locale = new Locale(languageString);
Locale.setDefault(locale);

Resources res = newBase.getResources();
Configuration config = new Configuration(res.getConfiguration());
config.setLocale(locale);

super.attachBaseContext(newBase.createConfigurationContext(config));
}

@Override
Expand Down
Loading
Loading