[FEAT] 新增 CMUH 客製初始畫面跳轉與多處頁面重啟邏輯優化

1. 新增 AppEntry 工具類別,集中管理 Cmuh 專案判斷與動態初始 Activity 的獲取邏輯。
2. 於 HomeActivity 中新增 Cmuh 專案判斷,若為 CMUH 則直接導向至 FontendActivity 以跳過一般首頁。
3. 將 MainActivity、MqttService 與 FontendActivity 中的硬編碼 HomeActivity 導向重構為呼叫 AppEntry.initialActivity()。
4. 新增 Cmuh 專屬之 activity_fontend.xml 佈局檔案。
5. 遞增 app/build.gradle 中的修補版號 verPatch 至 35。
This commit is contained in:
sky121113 2026-05-29 15:15:24 +08:00
parent f3867dcb4b
commit 7b9b96ce66
7 changed files with 307 additions and 16 deletions

View File

@ -9,7 +9,7 @@ plugins {
//
// =========================================================================
def verMinor = 1
def verPatch = 34
def verPatch = 35
android {

View File

@ -0,0 +1,267 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/light_gray"
>
<LinearLayout
android:id="@+id/linearLayout5"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="@color/red"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingLeft="20dp"
android:paddingRight="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/textVersion"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:text="20250108ver1"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/textThreadCount"
android:layout_width="60dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:text="TC:0"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/btnswitchlanTW"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:text="中"
android:visibility="gone"
android:textSize="30sp"
android:textColor="@color/white"
android:textStyle="bold"
/>
<TextView
android:id="@+id/btnswitchlanEn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:text="En"
android:visibility="gone"
android:textSize="30sp"
android:textColor="@color/white"
android:textStyle="bold"
/>
<TextView
android:id="@+id/btnswitchlanJa"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:text="日"
android:visibility="gone"
android:textSize="30sp"
android:textColor="@color/white"
android:textStyle="bold"
/>
<TextView
android:id="@+id/textTemperature"
android:layout_width="60dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="end"
android:text="0 ℃"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/textTime"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="end"
android:text="1911/01/01 01:01:01"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/textNetwork"
android:layout_width="150dp"
android:layout_height="match_parent"
android:gravity="center_vertical|end"
android:text="@string/no_internet"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
<RelativeLayout
android:id="@+id/relativeLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="2dp"
android:background="@color/black"
app:layout_constraintBottom_toTopOf="@+id/fragment_container"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/linearLayout5">
<androidx.media3.ui.PlayerView
android:id="@+id/videoView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:show_subtitle_button="true"
app:use_artwork="true"
app:use_controller="false" />
<ImageView
android:id="@+id/imageAd"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
android:visibility="gone"
/>
</RelativeLayout>
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="500dp"
app:layout_constraintBottom_toTopOf="@id/bottom_navigation"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/relativeLayout" />
<LinearLayout
android:id="@+id/bottom_navigation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone"
android:paddingStart="10dp"
android:paddingEnd="10dp">
<com.google.android.material.button.MaterialButton
android:id="@+id/buttonVmc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/drinksale"
app:cornerRadius="12dp"
android:backgroundTint="@android:color/transparent"
app:strokeColor="@color/gray"
android:textSize="38sp"
app:strokeWidth="2dp"
android:visibility="gone"
android:layout_margin="4dp"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/buttonElectric"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/board_games"
app:cornerRadius="12dp"
android:backgroundTint="@android:color/transparent"
app:strokeColor="@color/gray"
android:textSize="38sp"
android:visibility="gone"
app:strokeWidth="2dp"
android:layout_margin="4dp"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/buttonOther"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:visibility="gone"
android:text="@string/other"
app:cornerRadius="12dp"
android:backgroundTint="@android:color/transparent"
app:strokeColor="@color/gray"
android:textSize="38sp"
app:strokeWidth="2dp"
android:layout_margin="4dp"/>
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/floatButtonPickupCode"
android:layout_width="50dp"
android:layout_height="150dp"
android:text="取\n貨\n碼"
android:textSize="28sp"
android:layout_marginEnd="24dp"
android:layout_marginBottom="80dp"
android:backgroundTint="@color/gray"
android:textColor="@color/black"
android:alpha="0.8"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@+id/floatButtonShoppingCart"
app:layout_constraintEnd_toEndOf="@+id/bottom_navigation"
android:textStyle="bold"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/floatButtonShoppingCart"
android:layout_width="58dp"
android:layout_height="51dp"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_marginEnd="24dp"
android:layout_marginBottom="80dp"
android:contentDescription="TODO"
android:visibility="gone"
app:backgroundTint="@color/gray"
app:layout_constraintBottom_toBottomOf="@+id/fragment_container"
app:layout_constraintEnd_toEndOf="@+id/bottom_navigation"
app:maxImageSize="60dp"
app:srcCompat="@drawable/baseline_add_shopping_cart_24" />
<Button
android:id="@+id/btnTopRight"
android:layout_width="200dp"
android:layout_height="100dp"
android:text="進入後台"
android:textSize="24sp"
android:backgroundTint="@color/red"
android:textColor="@android:color/white"
android:alpha="1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:visibility="gone"
android:layout_marginTop="60dp"
android:layout_marginEnd="8dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,16 @@
package com.unibuy.smartdevice;
import com.unibuy.smartdevice.ui.FontendActivity;
public final class AppEntry {
private AppEntry() {
}
public static boolean isCmuh() {
return "Cmuh".equalsIgnoreCase(BuildConfig.FLAVOR_project);
}
public static Class<?> initialActivity() {
return isCmuh() ? FontendActivity.class : HomeActivity.class;
}
}

View File

@ -239,6 +239,14 @@ public class HomeActivity extends AppCompatActivityAbstract {
}
settingsDao.close();
if (AppEntry.isCmuh()) {
Intent intent = new Intent(this, FontendActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finish();
return;
}
binding = ActivityHomeBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
@ -312,7 +320,7 @@ public class HomeActivity extends AppCompatActivityAbstract {
getLogs().info("🔄HomeActivity - Scheduled Hard App restarting via gracefulDisconnect...");
com.unibuy.smartdevice.external.mqtt.MqttManager.getInstance().gracefulDisconnect(() -> {
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
Intent intent = new Intent(getApplicationContext(), HomeActivity.class);
Intent intent = new Intent(getApplicationContext(), AppEntry.initialActivity());
// 清空所有 Task重新啟動
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);

View File

@ -649,7 +649,7 @@ public class MainActivity extends AppCompatActivityAbstract {
getLogs().info("🔄MainActivity - Manual App restarting via gracefulDisconnect...");
com.unibuy.smartdevice.external.mqtt.MqttManager.getInstance().gracefulDisconnect(() -> {
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
Intent intent = new Intent(getApplicationContext(), HomeActivity.class);
Intent intent = new Intent(getApplicationContext(), AppEntry.initialActivity());
// 清空所有 Task重新啟動
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);

View File

@ -15,7 +15,7 @@ import android.util.Log;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import com.unibuy.smartdevice.HomeActivity;
import com.unibuy.smartdevice.AppEntry;
import com.unibuy.smartdevice.R;
import com.unibuy.smartdevice.MyApp;
import com.unibuy.smartdevice.devices.SlotField;
@ -57,7 +57,7 @@ public class MqttService extends Service {
createNotificationChannel();
// 2. 啟動為前台服務確保不被系統殺掉
Intent notificationIntent = new Intent(this, HomeActivity.class);
Intent notificationIntent = new Intent(this, AppEntry.initialActivity());
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);
@ -118,7 +118,7 @@ public class MqttService extends Service {
.postDelayed(() -> mqttManager.gracefulDisconnect(() -> {
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
Intent restartIntent = new Intent(getApplicationContext(),
com.unibuy.smartdevice.HomeActivity.class);
AppEntry.initialActivity());
restartIntent.addFlags(
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(restartIntent);
@ -160,12 +160,12 @@ public class MqttService extends Service {
mqttManager.publishCommandAck(cmdId, "success", "Machine unlocked, restarting...");
// 🚩 優雅重啟 gracefulDisconnect不觸發 LWT killProcess
// 解鎖後重啟到初始畫面 (HomeActivity)
// 解鎖後重啟到目前版本的初始畫面
new android.os.Handler(android.os.Looper.getMainLooper())
.postDelayed(() -> mqttManager.gracefulDisconnect(() -> {
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
Intent restartIntent = new Intent(getApplicationContext(),
com.unibuy.smartdevice.HomeActivity.class);
AppEntry.initialActivity());
restartIntent.addFlags(
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(restartIntent);

View File

@ -33,8 +33,8 @@ import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.unibuy.smartdevice.AppCompatActivityAbstract;
import com.unibuy.smartdevice.AppEntry;
import com.unibuy.smartdevice.FragmentAbstract;
import com.unibuy.smartdevice.HomeActivity;
import com.unibuy.smartdevice.MainActivity;
import com.unibuy.smartdevice.MyApp;
@ -436,7 +436,7 @@ public class FontendActivity extends AppCompatActivityAbstract implements SaleFl
}
public void ReSetAPP() {
Intent intent = new Intent(getApplicationContext(), HomeActivity.class);
Intent intent = new Intent(getApplicationContext(), AppEntry.initialActivity());
// 清空所有 Task重新啟動
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
@ -449,7 +449,7 @@ public class FontendActivity extends AppCompatActivityAbstract implements SaleFl
}
public void ReSetAPP2() {
Intent intent = new Intent(getApplicationContext(), HomeActivity.class);
Intent intent = new Intent(getApplicationContext(), AppEntry.initialActivity());
// 清空所有 Task重新啟動
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
@ -522,9 +522,9 @@ public class FontendActivity extends AppCompatActivityAbstract implements SaleFl
resetIdleTimer();
return;
}
getLogs().info("⚠️ 無操作 3 分鐘,自動返回首頁(清空購物車)");
getLogs().info("⚠️ 無操作 3 分鐘,自動返回初始畫面(清空購物車)");
MyApp.getInstance().getBuyList().clear(); // 🚩 逾時返回首頁時務必清空購物車避免機台進入永久忙碌狀態
Intent intent = new Intent(FontendActivity.this, HomeActivity.class);
Intent intent = new Intent(FontendActivity.this, AppEntry.initialActivity());
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finish();
@ -840,7 +840,7 @@ public class FontendActivity extends AppCompatActivityAbstract implements SaleFl
/**
* 現代化重啟不再使用 sleep 等待直接確認閒置秒數後執行真重啟
* - 只要閒置 >= 90 立刻啟動 HomeActivity killProcess
* - 只要閒置 >= 90 立刻啟動目前版本的初始畫面 killProcess
* - 若有人正在使用閒置 < 90 則等待 5 秒後再重新判斷最多等待 10 分鐘
*/
private class RestartAPP2 extends HandlerMainScheduler {
@ -864,7 +864,7 @@ public class FontendActivity extends AppCompatActivityAbstract implements SaleFl
getLogs().info("RestartAPP2執行真重啟 (MQTT 優雅斷線模式)");
com.unibuy.smartdevice.external.mqtt.MqttManager.getInstance().gracefulDisconnect(() -> {
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
Intent intent = new Intent(getApplicationContext(), com.unibuy.smartdevice.HomeActivity.class);
Intent intent = new Intent(getApplicationContext(), AppEntry.initialActivity());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
@ -1235,4 +1235,4 @@ public class FontendActivity extends AppCompatActivityAbstract implements SaleFl
reportOnScheduler = null;
}
}
}
}