killapp/Assets/Scripts/Base/AndroidStatusBarManager.cs

221 lines
6.9 KiB
C#
Raw Normal View History

2026-03-30 16:25:00 +08:00
using System;
using System.Collections.Generic;
using UnityEngine;
class AndroidStatusBar
{
// Enums
public enum States
{
Unknown,
Visible,
VisibleOverContent,
TranslucentOverContent,
Hidden,
}
// Constants
private const uint DEFAULT_BACKGROUND_COLOR = 0xff000000;
#if UNITY_ANDROID
// Android flags for API 21+ (Android 5.0+) and newer
private const int VIEW_SYSTEM_UI_FLAG_LOW_PROFILE = 1; // Added in API 14 (Android 4.0.x)
private const int VIEW_SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 1024; // Added in API 16 (Android 4.1.x)
private static int WINDOW_FLAG_FULLSCREEN = 0x00000400;
private static int WINDOW_FLAG_FORCE_NOT_FULLSCREEN = 0x00000800;
private static int WINDOW_FLAG_LAYOUT_IN_SCREEN = 0x00000100;
private static int WINDOW_FLAG_TRANSLUCENT_STATUS = 0x04000000;
private static int WINDOW_FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = -2147483648; // Added in API 21 (Android 5.0)
// Current values
private static int systemUiVisibilityValue;
private static int flagsValue;
#endif
// Properties
private static States _statusBarState;
private static uint _statusBarColor = DEFAULT_BACKGROUND_COLOR;
private static bool _isStatusBarTranslucent;
private static bool _dimmed;
// ================================================================================================================
// INTERNAL INTERFACE ---------------------------------------------------------------------------------------------
static AndroidStatusBar()
{
ApplyUIStates();
ApplyUIColors();
}
private static void ApplyUIStates()
{
#if UNITY_ANDROID && !UNITY_EDITOR
int newFlagsValue = 0;
int newSystemUiVisibilityValue = 0;
// Apply dim values
if (_dimmed) newSystemUiVisibilityValue |= VIEW_SYSTEM_UI_FLAG_LOW_PROFILE;
// Apply color values
if (_statusBarColor != DEFAULT_BACKGROUND_COLOR) newFlagsValue |= WINDOW_FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
// Apply status bar values
switch (_statusBarState) {
case States.Visible:
_isStatusBarTranslucent = false;
newFlagsValue |= WINDOW_FLAG_FORCE_NOT_FULLSCREEN;
break;
case States.VisibleOverContent:
_isStatusBarTranslucent = false;
newFlagsValue |= WINDOW_FLAG_FORCE_NOT_FULLSCREEN | WINDOW_FLAG_LAYOUT_IN_SCREEN;
newSystemUiVisibilityValue |= VIEW_SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
break;
case States.TranslucentOverContent:
_isStatusBarTranslucent = true;
newFlagsValue |= WINDOW_FLAG_FORCE_NOT_FULLSCREEN | WINDOW_FLAG_LAYOUT_IN_SCREEN | WINDOW_FLAG_TRANSLUCENT_STATUS;
newSystemUiVisibilityValue |= VIEW_SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
break;
case States.Hidden:
newFlagsValue |= WINDOW_FLAG_FULLSCREEN | WINDOW_FLAG_LAYOUT_IN_SCREEN;
if (_isStatusBarTranslucent) newFlagsValue |= WINDOW_FLAG_TRANSLUCENT_STATUS;
break;
}
if (Screen.fullScreen) Screen.fullScreen = false;
// Applies everything natively
SetFlags(newFlagsValue);
SetSystemUiVisibility(newSystemUiVisibilityValue);
#endif
}
private static void ApplyUIColors()
{
#if UNITY_ANDROID && !UNITY_EDITOR
RunOnAndroidUiThread(ApplyUIColorsAndroidInThread);
#endif
}
#if UNITY_ANDROID
private static void RunOnAndroidUiThread(Action target)
{
using (var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
{
using (var activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
{
activity.Call("runOnUiThread", new AndroidJavaRunnable(target));
}
}
}
private static void SetSystemUiVisibility(int value)
{
if (systemUiVisibilityValue != value)
{
systemUiVisibilityValue = value;
RunOnAndroidUiThread(SetSystemUiVisibilityInThread);
}
}
private static void SetSystemUiVisibilityInThread()
{
using (var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
{
using (var activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
{
using (var window = activity.Call<AndroidJavaObject>("getWindow"))
{
using (var view = window.Call<AndroidJavaObject>("getDecorView"))
{
view.Call("setSystemUiVisibility", systemUiVisibilityValue);
}
}
}
}
}
private static void SetFlags(int value)
{
if (flagsValue != value)
{
flagsValue = value;
RunOnAndroidUiThread(SetFlagsInThread);
}
}
private static void SetFlagsInThread()
{
using (var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
{
using (var activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
{
using (var window = activity.Call<AndroidJavaObject>("getWindow"))
{
window.Call("setFlags", flagsValue, -1); // (int)0x7FFFFFFF
}
}
}
}
private static void ApplyUIColorsAndroidInThread()
{
using (var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
{
using (var activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
{
using (var window = activity.Call<AndroidJavaObject>("getWindow"))
{
window.Call("setStatusBarColor", unchecked((int)_statusBarColor));
}
}
}
}
#endif
// ================================================================================================================
// ACCESSOR INTERFACE ---------------------------------------------------------------------------------------------
public static States statusBarState
{
get { return _statusBarState; }
set
{
if (_statusBarState != value)
{
_statusBarState = value;
ApplyUIStates();
}
}
}
public static bool dimmed
{
get { return _dimmed; }
set
{
if (_dimmed != value)
{
_dimmed = value;
ApplyUIStates();
}
}
}
public static uint statusBarColor
{
get { return _statusBarColor; }
set
{
if (_statusBarColor != value)
{
_statusBarColor = value;
ApplyUIColors();
ApplyUIStates();
}
}
}
}