feat(pwa): add Android TV native app project for OPD Queue TV display

This commit is contained in:
DevSoftTech Server 2026-08-30 01:29:15 +05:30
parent 09adbef59f
commit 1b379bf3d4
9 changed files with 272 additions and 0 deletions

View File

@ -0,0 +1,35 @@
plugins {
id 'com.android.application'
}
android {
namespace 'com.eatria.hms.opdqueue'
compileSdk 34
defaultConfig {
applicationId "com.eatria.hms.opdqueue"
minSdk 21
targetSdk 34
versionCode 1
versionName "1.0.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.11.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
}

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Internet & Network Permissions -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- Declare Android TV Leanback Hardware Compatibility -->
<uses-feature android:name="android.hardware.type.television" android:required="false" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
<uses-feature android:name="android.hardware.leanback" android:required="false" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:banner="@mipmap/ic_launcher"
android:logo="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher"
android:supportsRtl="true"
android:theme="@style/Theme.HMSOPDQueueTV"
android:usesCleartextTraffic="true">
<activity
android:name=".MainActivity"
android:exported="true"
android:configChanges="orientation|keyboardHidden|screenSize|screenLayout"
android:screenOrientation="landscape"
android:hardwareAccelerated="true">
<!-- Standard Phone & Tablet Launcher -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- Android TV Leanback Launcher (Displays app icon in Android TV Apps Grid) -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -0,0 +1,120 @@
package com.eatria.hms.opdqueue;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private WebView webView;
private ProgressBar progressBar;
private static final String PREFS_NAME = "HMSQueuePrefs";
private static final String KEY_SERVER_URL = "server_url";
private static final String DEFAULT_URL = "http://192.168.1.100:8080/app/queue";
@Override
@SuppressLint("SetJavaScriptEnabled")
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Keep screen turned on continuous (TV Monitor Display)
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// Hide Android status bar for immersive full TV screen
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
webView = findViewById(R.id.webView);
progressBar = findViewById(R.id.progressBar);
// Configure High-Performance WebView Settings
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setDomStorageEnabled(true);
webSettings.setDatabaseEnabled(true);
webSettings.setAllowFileAccess(true);
webSettings.setAllowContentAccess(true);
webSettings.setMediaPlaybackRequiresUserGesture(false); // Enable auto audio callouts on TV
webSettings.setUseWideViewPort(true);
webSettings.setLoadWithOverviewMode(true);
webSettings.setBuiltInZoomControls(false);
webSettings.setSupportZoom(false);
webView.setWebViewClient(new WebViewClient() {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
if (progressBar != null) progressBar.setVisibility(View.VISIBLE);
}
@Override
public void onPageFinished(WebView view, String url) {
if (progressBar != null) progressBar.setVisibility(View.GONE);
}
});
webView.setWebChromeClient(new WebChromeClient());
// Load configured URL
loadConfiguredUrl();
}
private void loadConfiguredUrl() {
SharedPreferences prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
String url = prefs.getString(KEY_SERVER_URL, DEFAULT_URL);
webView.loadUrl(url);
}
private void showServerUrlDialog() {
SharedPreferences prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
String currentUrl = prefs.getString(KEY_SERVER_URL, DEFAULT_URL);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Configure HMS Server URL");
final EditText input = new EditText(this);
input.setText(currentUrl);
builder.setView(input);
builder.setPositiveButton("Save & Reload", (dialog, which) -> {
String newUrl = input.getText().toString().trim();
if (!newUrl.isEmpty()) {
prefs.edit().putString(KEY_SERVER_URL, newUrl).apply();
webView.loadUrl(newUrl);
Toast.makeText(MainActivity.this, "URL Saved: " + newUrl, Toast.LENGTH_SHORT).show();
}
});
builder.setNegativeButton("Cancel", (dialog, which) -> dialog.cancel());
builder.show();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// TV Remote Long-Press Menu Button or Back Button to edit URL
if (keyCode == KeyEvent.KEYCODE_MENU || keyCode == KeyEvent.KEYCODE_SETTINGS) {
showServerUrlDialog();
return true;
}
if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {
webView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
}

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#0b1329">
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="gone" />
</RelativeLayout>

View File

@ -0,0 +1,3 @@
<resources>
<string name="app_name">HMS OPD Queue TV</string>
</resources>

View File

@ -0,0 +1,8 @@
<resources>
<style name="Theme.HMSOPDQueueTV" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowNoTitle">true</item>
<item name="android:windowActionBar">false</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowBackground">@android:color/black</item>
</style>
</resources>

View File

@ -0,0 +1,20 @@
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.2.2'
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View File

@ -0,0 +1,3 @@
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
android.useAndroidX=true
android.enableJetifier=true

View File

@ -0,0 +1,17 @@
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "HMS OPD Queue TV"
include ':app'