feat(pwa): add Android TV native app project for OPD Queue TV display
This commit is contained in:
parent
09adbef59f
commit
1b379bf3d4
35
android_opd_queue_tv/app/build.gradle
Normal file
35
android_opd_queue_tv/app/build.gradle
Normal 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'
|
||||||
|
}
|
||||||
47
android_opd_queue_tv/app/src/main/AndroidManifest.xml
Normal file
47
android_opd_queue_tv/app/src/main/AndroidManifest.xml
Normal 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>
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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>
|
||||||
3
android_opd_queue_tv/app/src/main/res/values/strings.xml
Normal file
3
android_opd_queue_tv/app/src/main/res/values/strings.xml
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">HMS OPD Queue TV</string>
|
||||||
|
</resources>
|
||||||
8
android_opd_queue_tv/app/src/main/res/values/styles.xml
Normal file
8
android_opd_queue_tv/app/src/main/res/values/styles.xml
Normal 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>
|
||||||
20
android_opd_queue_tv/build.gradle
Normal file
20
android_opd_queue_tv/build.gradle
Normal 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
|
||||||
|
}
|
||||||
3
android_opd_queue_tv/gradle.properties
Normal file
3
android_opd_queue_tv/gradle.properties
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
||||||
|
android.useAndroidX=true
|
||||||
|
android.enableJetifier=true
|
||||||
17
android_opd_queue_tv/settings.gradle
Normal file
17
android_opd_queue_tv/settings.gradle
Normal 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'
|
||||||
Loading…
Reference in New Issue
Block a user