send the release v9 to tk women. fixed restart issue

qlline_design_update
Faiz Hashmi 3 weeks ago
parent f97fb5c78b
commit a6df0764fb

@ -2,10 +2,13 @@ package com.example.hmg_qline.hmg_qline
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import java.io.File
class MainActivity : FlutterActivity() {
private val CHANNEL = "com.example.hmg_qline/foreground"
@ -15,17 +18,353 @@ class MainActivity : FlutterActivity() {
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
Log.d("MainActivity", "MethodChannel call received: ${call.method}")
when (call.method) {
"reopenApp" -> {
Log.d("MainActivity", "reopenApp called, bringing app to foreground")
// Simply bring current activity to foreground
moveTaskToBack(false)
// Or trigger Flutter navigation if needed
result.success("App brought to foreground")
}
else -> result.notImplemented()
"restartApp" -> {
Log.d("MainActivity", "Restarting application")
restartApplication()
result.success("App restart initiated")
}
"restartDevice" -> {
Log.d("MainActivity", "Attempting device restart")
restartDevice(result)
}
"runShellScript" -> {
Log.d("MainActivity", "Executing shell restart command")
executeShellRestart(result)
}
"clearAudioCache" -> {
Log.d("MainActivity", "Clearing audio cache")
clearAudioResources()
result.success("Audio cache cleared")
}
"clearAllResources" -> {
Log.d("MainActivity", "Clearing all native resources")
clearAllNativeResources()
result.success("All resources cleared")
}
else -> {
Log.w("MainActivity", "Method not implemented: ${call.method}")
result.notImplemented()
}
}
}
}
private fun restartApplication() {
try {
Log.d("MainActivity", "Initiating app restart")
// Clear resources before restart
clearAllNativeResources()
// Create restart intent
val intent = packageManager.getLaunchIntentForPackage(packageName)?.apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
putExtra("restarted", true)
}
if (intent != null) {
// Use a shorter delay for faster restart
Handler(Looper.getMainLooper()).postDelayed({
startActivity(intent)
finishAffinity()
// Remove exitProcess() call if present
// android.os.Process.killProcess(android.os.Process.myPid())
}, 100) // Reduced delay
Log.d("MainActivity", "App restart initiated")
} else {
Log.e("MainActivity", "Could not create restart intent")
}
} catch (e: Exception) {
Log.e("MainActivity", "Error during restart: ${e.message}")
// Fallback - don't exit, just log the error
}
}
private fun restartDevice(result: MethodChannel.Result) {
try {
Log.d("MainActivity", "Attempting device restart (requires root)")
// Try different reboot commands
val rebootCommands = arrayOf(
arrayOf("su", "-c", "reboot"),
arrayOf("su", "-c", "reboot now"),
arrayOf("reboot")
)
var success = false
for (command in rebootCommands) {
try {
val process = Runtime.getRuntime().exec(command)
val exitCode = process.waitFor()
if (exitCode == 0) {
success = true
Log.d("MainActivity", "Device restart command executed successfully")
result.success("Device restart initiated")
break
}
} catch (e: Exception) {
Log.w("MainActivity", "Reboot command failed: ${command.joinToString(" ")}")
}
}
if (!success) {
Log.e("MainActivity", "All reboot commands failed - device may not have root access")
result.error("RESTART_ERROR", "Device restart failed - root access required", null)
}
} catch (e: Exception) {
Log.e("MainActivity", "Exception during device restart: ${e.message}")
result.error("RESTART_ERROR", "Device restart failed: ${e.message}", null)
}
}
private fun executeShellRestart(result: MethodChannel.Result) {
try {
Log.d("MainActivity", "Executing shell restart script")
// Copy script from assets to internal storage
val scriptFile = copyAssetToFile("scripts/restart_app.sh")
if (scriptFile != null && scriptFile.exists()) {
// Make script executable
Runtime.getRuntime().exec("chmod 755 ${scriptFile.absolutePath}")
// Execute the script
val process = Runtime.getRuntime().exec("su -c ${scriptFile.absolutePath}")
val exitCode = process.waitFor()
if (exitCode == 0) {
result.success("Shell restart executed successfully")
} else {
result.error("SHELL_ERROR", "Script execution failed with code: $exitCode", null)
}
} else {
result.error("SCRIPT_ERROR", "Could not copy script from assets", null)
}
} catch (e: Exception) {
Log.e("MainActivity", "Shell restart error: ${e.message}")
result.error("SHELL_EXCEPTION", e.message, null)
}
}
private fun copyAssetToFile(assetPath: String): File? {
return try {
val inputStream = assets.open(assetPath)
val file = File(filesDir, "restart_app.sh")
file.outputStream().use { output ->
inputStream.copyTo(output)
}
file
} catch (e: Exception) {
Log.e("MainActivity", "Error copying asset: ${e.message}")
null
}
}
private fun clearAudioResources() {
try {
Log.d("MainActivity", "Clearing audio resources")
// Force garbage collection
System.gc()
// Clear audio-related system caches
val commands = arrayOf(
"am force-stop com.google.android.tts",
"am force-stop com.android.providers.media"
)
for (command in commands) {
try {
Runtime.getRuntime().exec(command)
} catch (e: Exception) {
Log.w("MainActivity", "Failed to clear audio service: $command")
}
}
} catch (e: Exception) {
Log.e("MainActivity", "Error clearing audio resources: ${e.message}")
}
}
private fun clearAllNativeResources() {
try {
Log.d("MainActivity", "Clearing all native resources")
// Clear audio resources
clearAudioResources()
// Clear image caches
try {
Runtime.getRuntime().exec("am broadcast -a android.intent.action.MEDIA_MOUNTED")
} catch (e: Exception) {
Log.w("MainActivity", "Failed to clear media cache")
}
// Force garbage collection
System.gc()
System.runFinalization()
Log.d("MainActivity", "Native resources cleared")
} catch (e: Exception) {
Log.e("MainActivity", "Error clearing native resources: ${e.message}")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Log if app was restarted
if (intent.getBooleanExtra("restarted", false)) {
Log.d("MainActivity", "App restarted successfully")
}
// Log if launched from boot
if (intent.getBooleanExtra("launched_from_boot", false)) {
Log.d("MainActivity", "App launched from boot")
// Give system time to settle after boot
Thread.sleep(2000)
}
}
override fun onResume() {
super.onResume()
Log.d("MainActivity", "Activity resumed")
}
override fun onPause() {
super.onPause()
Log.d("MainActivity", "Activity paused - cleaning up resources")
// Light cleanup when app goes to background
System.gc()
}
override fun onDestroy() {
super.onDestroy()
Log.d("MainActivity", "Activity destroyed")
// Final cleanup
clearAllNativeResources()
}
}
//package com.example.hmg_qline.hmg_qline
//
//import android.content.Intent
//import android.os.Bundle
//import android.util.Log
//import io.flutter.embedding.android.FlutterActivity
//import io.flutter.embedding.engine.FlutterEngine
//import io.flutter.plugin.common.MethodChannel
//
//class MainActivity : FlutterActivity() {
// private val CHANNEL = "com.example.hmg_qline/foreground"
//
// override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
// super.configureFlutterEngine(flutterEngine)
//
// MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
// Log.d("MainActivity", "MethodChannel call received: ${call.method}")
// when (call.method) {
// "reopenApp" -> {
// Log.d("MainActivity", "reopenApp called, bringing app to foreground")
// // Simply bring current activity to foreground
// moveTaskToBack(false)
// // Or trigger Flutter navigation if needed
// result.success("App brought to foreground")
// }
//
// else -> result.notImplemented()
// }
//
//
// when (call.method) {
// "runShellScript" -> {
// Log.d("MainActivity", "reopenApp called, bringing app to foreground")
// // Simply bring current activity to foreground
// moveTaskToBack(false)
// // Or trigger Flutter navigation if needed
// result.success("App brought to foreground")
// }
//
// else -> result.notImplemented()
// }
//
//
// }
// }
//
//
//}
//
//
////}
////
//// private fun hasShellPermissions(): Boolean {
//// return try {
//// val process = Runtime.getRuntime().exec("id")
//// process.waitFor()
//// val exitCode = process.exitValue()
//// Log.d("MainActivity", "Shell permission check exit code: $exitCode")
//// exitCode == 0
//// } catch (e: Exception) {
//// Log.e("MainActivity", "Error checking shell permissions: ${e.message}")
//// false
//// }
//// }
////
//// private fun executeShellScript(result: MethodChannel.Result) {
//// try {
//// // Copy script from assets to internal storage
//// val assetManager = assets
//// val inputStream = assetManager.open("restart_app.sh")
//// val scriptFile = java.io.File(filesDir, "restart_app.sh")
////
//// scriptFile.outputStream().use { output ->
//// inputStream.copyTo(output)
//// }
////
//// // Make script executable
//// scriptFile.setExecutable(true)
////
//// // Execute the script
//// val process = Runtime.getRuntime().exec("sh ${scriptFile.absolutePath}")
//// val exitCode = process.waitFor()
////
//// if (exitCode == 0) {
//// Log.d("MainActivity", "Shell script executed successfully")
//// result.success("Script executed successfully")
//// } else {
//// val errorStream = process.errorStream.bufferedReader().readText()
//// Log.e("MainActivity", "Script execution failed with exit code: $exitCode, error: $errorStream")
//// result.error("SCRIPT_ERROR", "Script execution failed", errorStream)
//// }
////
//// } catch (e: Exception) {
//// Log.e("MainActivity", "Error executing shell script: ${e.message}")
//// result.error("EXECUTION_ERROR", "Failed to execute script: ${e.message}", null)
//// }
//// }

@ -42,7 +42,7 @@ class AppDependencies {
getIt.registerSingleton<ScreenDetailsRepo>(ScreenDetailsRepoImp(apiClientInstance: getIt.get<ApiClient>(), loggerService: getIt.get<LoggerService>()));
//repos
getIt.registerSingleton<NativeMethodChannelService>(NativeMethodChannelServiceImp(loggerService: getIt.get<LoggerService>(), platform: const MethodChannel('com.example.hmg_qline/foreground')));
getIt.registerSingleton<NativeMethodChannelService>(NativeMethodChannelServiceImp(loggerService: getIt.get<LoggerService>()));
//ThirdPartyServices
getIt.registerSingleton<ConnectivityService>(ConnectivityServiceImp(connectivityInstance: Connectivity()));

@ -1,3 +1,5 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:hmg_qline/view_models/screen_config_view_model.dart';
@ -11,8 +13,14 @@ import 'package:wakelock_plus/wakelock_plus.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
try {
await AppDependencies.addDependencies();
await WakelockPlus.enable();
} catch (e) {
log('Initialization error: $e');
}
runApp(const MyApp());
}
@ -25,12 +33,18 @@ class MyApp extends StatelessWidget {
builder: (context, constraints) {
return OrientationBuilder(builder: (context, orientation) {
SizeConfig().init(constraints, orientation);
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
return MultiProvider(
providers: [
ChangeNotifierProvider<ScreenConfigViewModel>(create: (context) => getIt.get<ScreenConfigViewModel>()),
ChangeNotifierProvider<QueuingViewModel>(create: (context) => getIt.get<QueuingViewModel>()),
ChangeNotifierProvider<ScreenConfigViewModel>(
create: (context) => getIt.get<ScreenConfigViewModel>(),
lazy: false,
),
ChangeNotifierProvider<QueuingViewModel>(
create: (context) => getIt.get<QueuingViewModel>(),
lazy: false,
),
],
child: MaterialApp(
showSemanticsDebugger: false,
@ -51,3 +65,5 @@ class MyApp extends StatelessWidget {
);
}
}
// vTJJHSbhMyeq04KfmM3KAg

@ -1,38 +1,95 @@
import 'package:flutter/services.dart';
import 'package:hmg_qline/constants/app_constants.dart';
import 'package:hmg_qline/services/logger_service.dart';
import 'package:hmg_qline/utilities/enums.dart';
import 'package:restart_app/restart_app.dart';
abstract class NativeMethodChannelService {
void reopenApp();
Future<void> restartApp();
Future<void> restartDevice();
Future<void> clearAllResources();
Future<void> smartRestart({bool forceRestart = false, bool cleanupFirst = true});
}
class NativeMethodChannelServiceImp implements NativeMethodChannelService {
MethodChannel platform;
static const MethodChannel _platform = MethodChannel('com.example.hmg_qline/foreground');
LoggerService loggerService;
NativeMethodChannelServiceImp({required this.platform, required this.loggerService});
NativeMethodChannelServiceImp({required this.loggerService});
@override
void reopenApp() async {
try {
await platform.invokeMethod(AppStrings.openAppNativeFunctionName);
loggerService.logInfo("Attempting to reopen app");
await _platform.invokeMethod('reopenApp');
loggerService.logInfo("App reopened successfully");
} catch (e) {
loggerService.logError("Error launching app: $e");
loggerService.logToFile(message: "Error launching app: $e", source: "reopenApp -> native_method_handler.dart ", type: LogTypeEnum.error);
loggerService.logToFile(message: "Error launching app: $e", source: "reopenApp -> native_method_handler.dart", type: LogTypeEnum.error);
}
}
@override
Future<void> restartApp() async {
try {
await Restart.restartApp();
loggerService.logInfo("Initiating app restart");
await _platform.invokeMethod('restartApp');
loggerService.logInfo("App restart command sent successfully");
} catch (e) {
loggerService.logError("Error restarting app: $e");
loggerService.logToFile(message: "Error restarting app: $e", source: "restartApp -> native_method_handler.dart", type: LogTypeEnum.error);
}
}
@override
Future<void> restartDevice() async {
try {
loggerService.logInfo("Attempting device restart (requires root)");
final result = await _platform.invokeMethod('restartDevice');
loggerService.logInfo("Device restart initiated: $result");
} catch (e) {
loggerService.logError("Error restarting App : $e");
loggerService.logToFile(message: "Error restarting app: $e", source: "restartApp -> native_method_handler.dart ", type: LogTypeEnum.error);
loggerService.logError("Device restart failed: $e");
loggerService.logToFile(message: "Device restart failed: $e", source: "restartDevice -> native_method_handler.dart", type: LogTypeEnum.error);
}
}
@override
Future<void> clearAllResources() async {
try {
loggerService.logInfo("Clearing all native resources");
final result = await _platform.invokeMethod('clearAllResources');
loggerService.logInfo("All resources cleared: $result");
} catch (e) {
loggerService.logError("Error clearing resources: $e");
loggerService.logToFile(message: "Error clearing resources: $e", source: "clearAllResources -> native_method_handler.dart", type: LogTypeEnum.error);
}
}
// Enhanced restart method with multiple fallback options
@override
Future<void> smartRestart({bool forceRestart = false, bool cleanupFirst = true}) async {
try {
loggerService.logInfo("Starting smart restart - forceRestart: $forceRestart, cleanupFirst: $cleanupFirst");
if (cleanupFirst) {
await clearAllResources();
await Future.delayed(const Duration(seconds: 1));
}
try {
loggerService.logInfo("Initiating app restart");
await _platform.invokeMethod('restartApp');
loggerService.logInfo("App restart command sent successfully");
} catch (e) {
loggerService.logError("Error restarting app: $e");
loggerService.logToFile(message: "Error restarting app: $e", source: "restartApp -> native_method_handler.dart", type: LogTypeEnum.error);
}
} catch (primaryError) {
loggerService.logError("Primary restart failed, trying fallback methods: $primaryError");
}
}
}

@ -113,11 +113,7 @@ class QueuingViewModel extends ChangeNotifier {
Future<void> onToneCompleted() async {
GlobalConfigurationsModel globalConfigurationsModel = getIt.get<ScreenConfigViewModel>().globalConfigurationsModel;
if (true) {
await textToSpeechService.speechText(globalConfigurationsModel: globalConfigurationsModel, ticket: currentTickets.first, isMute: !(globalConfigurationsModel.isVoiceReq));
} else {
waitAndCallNextTicketIfAvailable();
}
}
Future<void> onVoiceCompleted() async {
@ -214,15 +210,8 @@ class QueuingViewModel extends ChangeNotifier {
}
log("globalConfigurationsModel: ${globalConfigurationsModel.toString()}");
if (true) {
isCallingInProgress = true;
await audioService.playTone(path: AppAssets.callTone, isMute: !(globalConfigurationsModel.isToneReq));
} else if (globalConfigurationsModel.isVoiceReq) {
isCallingInProgress = true;
await textToSpeechService.speechText(globalConfigurationsModel: globalConfigurationsModel, ticket: currentTickets.first, isMute: !(globalConfigurationsModel.isVoiceReq));
} else {
waitAndCallNextTicketIfAvailable();
}
}
}
@ -249,3 +238,6 @@ class QueuingViewModel extends ChangeNotifier {
// waitAndCallNextTicketIfAvailable();
// }
// }
// jQ
//ucq

@ -54,12 +54,12 @@ class ScreenConfigViewModel extends ChangeNotifier {
Future<void> onAppPaused() async {
loggerService.logToFile(message: "[didChangeAppLifecycleState] : [onAppPaused]", source: "onAppPaused -> screen_config_view_model.dart", type: LogTypeEnum.data);
nativeMethodChannelService.restartApp();
// nativeMethodChannelService.restartApp();
}
Future<void> onAppDetached() async {
loggerService.logToFile(message: "[didChangeAppLifecycleState] : [onAppDetached]", source: "onAppDetached -> screen_config_view_model.dart", type: LogTypeEnum.data);
nativeMethodChannelService.restartApp();
// nativeMethodChannelService.restartApp();
}
Future<void> waitForIPAndInitializeConfigVM() async {
@ -333,15 +333,17 @@ class ScreenConfigViewModel extends ChangeNotifier {
// At midnight, update weather and prayer details if required
if (now.day != lastChecked.day) {
if (now.difference(now.copyWith(hour: 0, minute: 0, second: 0, millisecond: 0, microsecond: 0)).inMinutes >= 5) {
QueuingViewModel queuingViewModel = getIt.get<QueuingViewModel>();
await queuingViewModel.stopHubConnection();
nativeMethodChannelService.restartApp();
if (globalConfigurationsModel.isWeatherReq) {
await getWeatherDetailsFromServer();
}
if (globalConfigurationsModel.isPrayerTimeReq) {
await getPrayerDetailsFromServer();
}
await nativeMethodChannelService.smartRestart(forceRestart: true, cleanupFirst: true);
// if (globalConfigurationsModel.isRssFeedReq) {
// await getRssFeedDetailsFromServer();
// }
// if (globalConfigurationsModel.isWeatherReq) {
// await getWeatherDetailsFromServer();
// }
// if (globalConfigurationsModel.isPrayerTimeReq) {
// await getPrayerDetailsFromServer();
// }
lastChecked = now;
}
}

@ -2,8 +2,10 @@ import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:hmg_qline/config/dependency_injection.dart';
import 'package:hmg_qline/models/global_config_model.dart';
import 'package:hmg_qline/utilities/enums.dart';
import 'package:hmg_qline/utilities/native_method_handler.dart';
import 'package:hmg_qline/view_models/screen_config_view_model.dart';
import 'package:hmg_qline/views/common_widgets/app_general_widgets.dart';
import 'package:provider/provider.dart';
@ -30,10 +32,15 @@ class AppHeader extends StatelessWidget implements PreferredSizeWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
engArabicTextWithSeparatorWidget(
InkWell(
onTap: () async {
await getIt.get<NativeMethodChannelService>().smartRestart();
},
child: engArabicTextWithSeparatorWidget(
englishText: globalConfigurationsModel.currentServeTextEng ?? "",
arabicText: globalConfigurationsModel.currentServeTextArb ?? "",
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [

@ -488,14 +488,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.10+1"
restart_app:
dependency: "direct main"
description:
name: restart_app
sha256: "00d5ec3e9de871cedbe552fc41e615b042b5ec654385e090e0983f6d02f655ed"
url: "https://pub.dev"
source: hosted
version: "1.3.2"
rxdart:
dependency: transitive
description:

@ -54,7 +54,7 @@ dependencies:
qr_code_scanner_plus: ^2.0.10+1
path_provider: ^2.1.5
flutter_foreground_task: ^9.1.0
restart_app: ^1.3.2
# restart_app: ^1.3.2
zo_animated_border: ^1.0.1
animated_flip_counter: ^0.3.4
# smooth_corner: ^1.1.1

Loading…
Cancel
Save