wake lock for all connection type

Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
21pages 2023-11-24 16:40:18 +08:00
parent bd81e4d0fb
commit 2de1c62daf
9 changed files with 102 additions and 87 deletions

3
Cargo.lock generated
View File

@ -124,8 +124,7 @@ checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android-wakelock"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "296e5b7c23adb32743194b1810604b772f2be10f0b0387365cb3ba09cd5c1851"
source = "git+https://github.com/21pages/android-wakelock#d0292e5a367e627c4fa6f1ca6bdfad005dca7d90"
dependencies = [
"jni 0.21.1",
"log",

View File

@ -81,6 +81,7 @@ cidr-utils = "0.5"
libloading = "0.8"
fon = "0.6"
zip = "0.6"
shutdown_hooks = "0.1"
[target.'cfg(not(any(target_os = "android", target_os = "linux")))'.dependencies]
cpal = "0.15"
@ -95,7 +96,6 @@ clipboard = { path = "libs/clipboard" }
ctrlc = "3.2"
arboard = "3.2"
system_shutdown = "4.0"
shutdown_hooks = "0.1"
[target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3", features = ["winuser", "wincrypt", "shellscalingapi", "pdh", "synchapi", "memoryapi"] }
@ -147,7 +147,7 @@ once_cell = {version = "1.18", optional = true}
[target.'cfg(target_os = "android")'.dependencies]
android_logger = "0.13"
jni = "0.21"
android-wakelock = "0.1"
android-wakelock = { git = "https://github.com/21pages/android-wakelock" }
[workspace]
members = ["libs/scrap", "libs/hbb_common", "libs/enigo", "libs/clipboard", "libs/virtual_display", "libs/virtual_display/dylib", "libs/portable"]

View File

@ -76,10 +76,10 @@ class _PeerTabPageState extends State<PeerTabPage>
final uiType = bind.getLocalFlutterOption(k: 'peer-card-ui-type');
if (uiType != '') {
peerCardUiType.value = int.parse(uiType) == 0
? PeerUiType.grid
: int.parse(uiType) == 1
? PeerUiType.tile
: PeerUiType.list;
? PeerUiType.grid
: int.parse(uiType) == 1
? PeerUiType.tile
: PeerUiType.list;
}
hideAbTagsPanel.value =
bind.mainGetLocalOption(key: "hideAbTagsPanel").isNotEmpty;
@ -624,8 +624,6 @@ class _PeerTabPageState extends State<PeerTabPage>
searchWidth -
(actions.length == 2 ? otherActionWidth : 0);
final availablePositions = rightWidth ~/ otherActionWidth;
debugPrint(
"dynamic action count:${dynamicActions.length}, available positions: $availablePositions");
if (availablePositions < dynamicActions.length &&
dynamicActions.length > 1) {
@ -767,7 +765,11 @@ class PeerViewDropdown extends StatefulWidget {
class _PeerViewDropdownState extends State<PeerViewDropdown> {
@override
Widget build(BuildContext context) {
final List<PeerUiType> types = [PeerUiType.grid, PeerUiType.tile, PeerUiType.list];
final List<PeerUiType> types = [
PeerUiType.grid,
PeerUiType.tile,
PeerUiType.list
];
final style = TextStyle(
color: Theme.of(context).textTheme.titleLarge?.color,
fontSize: MenuConfig.fontSize,
@ -777,20 +779,23 @@ class _PeerViewDropdownState extends State<PeerViewDropdown> {
height: 36,
enabled: false,
child: Text(translate("Change view"), style: style)));
for (var e in PeerUiType.values) {
for (var e in PeerUiType.values) {
items.add(PopupMenuItem(
height: 36,
child: Obx(() => Center(
child: SizedBox(
height: 36,
child: getRadio<PeerUiType>(
Text(translate(
types.indexOf(e) == 0 ? 'Big tiles' : types.indexOf(e) == 1 ? 'Small tiles' : 'List'
), style: style),
e,
Text(
translate(types.indexOf(e) == 0
? 'Big tiles'
: types.indexOf(e) == 1
? 'Small tiles'
: 'List'),
style: style),
e,
peerCardUiType.value,
dense: true,
(PeerUiType? v) async {
dense: true, (PeerUiType? v) async {
if (v != null) {
peerCardUiType.value = v;
setState(() {});
@ -798,18 +803,18 @@ class _PeerViewDropdownState extends State<PeerViewDropdown> {
k: "peer-card-ui-type",
v: peerCardUiType.value.index.toString(),
);
}}
),
}
}),
),
))));
}
var menuPos = RelativeRect.fromLTRB(0, 0, 0, 0);
return _hoverAction(
context: context,
child: Tooltip(
message: translate('Change view'),
child: Icon(
context: context,
child: Tooltip(
message: translate('Change view'),
child: Icon(
peerCardUiType.value == PeerUiType.grid
? Icons.grid_view_rounded
: peerCardUiType.value == PeerUiType.tile
@ -817,22 +822,20 @@ class _PeerViewDropdownState extends State<PeerViewDropdown> {
: Icons.view_agenda_rounded,
size: 18,
)),
onTapDown: (details) {
final x = details.globalPosition.dx;
final y = details.globalPosition.dy;
menuPos = RelativeRect.fromLTRB(x, y, x, y);
},
onTap: () => showMenu(
context: context,
position: menuPos,
items: items,
elevation: 8,
)
);
onTapDown: (details) {
final x = details.globalPosition.dx;
final y = details.globalPosition.dy;
menuPos = RelativeRect.fromLTRB(x, y, x, y);
},
onTap: () => showMenu(
context: context,
position: menuPos,
items: items,
elevation: 8,
));
}
}
class PeerSortDropdown extends StatefulWidget {
const PeerSortDropdown({super.key});

View File

@ -260,6 +260,7 @@ fn init_ndk_context() -> JniResult<()> {
unsafe {
ndk_context::release_android_context();
}
*lock = false;
}
if let (Some(jvm), Some(ctx)) = (
JVM.read().unwrap().as_ref(),

View File

@ -310,7 +310,7 @@ impl RecorderApi for WebmRecorder {
impl Drop for WebmRecorder {
fn drop(&mut self) {
std::mem::replace(&mut self.webm, None).map_or(false, |webm| webm.finalize(None));
let _ = std::mem::replace(&mut self.webm, None).map_or(false, |webm| webm.finalize(None));
let mut state = RecordState::WriteTail;
if !self.written || self.start.elapsed().as_secs() < MIN_SECS {
std::fs::remove_file(&self.ctx.filename).ok();

View File

@ -82,35 +82,28 @@ pub const PA_SAMPLE_RATE: u32 = 48000;
#[cfg(target_os = "android")]
#[derive(Default)]
pub struct WakeLock {
lock: Option<android_wakelock::WakeLock>,
}
pub struct WakeLock(Option<android_wakelock::WakeLock>);
#[cfg(target_os = "android")]
impl WakeLock {
pub fn new(tag: &str) -> Self {
let tag = format!("{}:{tag}", crate::get_app_name());
match android_wakelock::partial(tag) {
Ok(lock) => Self { lock: Some(lock) },
Ok(lock) => Self(Some(lock)),
Err(e) => {
hbb_common::log::error!("Failed to get wakelock: {e:?}");
Self::default()
}
}
}
}
pub fn acquire(&self) -> Option<android_wakelock::Guard> {
match self.lock.as_ref() {
Some(lock) => match lock.acquire() {
Ok(guard) => Some(guard),
Err(e) => {
hbb_common::log::error!("Failed to acquire wakelock guard: {e:?}");
None
}
},
None => None,
}
}
pub fn get_wake_lock(_display: bool) -> WakeLock {
hbb_common::log::info!("new wakelock, require display on: {_display}");
#[cfg(target_os = "android")]
return crate::platform::WakeLock::new("server");
#[cfg(not(target_os = "android"))]
return crate::platform::WakeLock::new(_display, true, true);
}
pub(crate) struct InstallingService; // please use new

View File

@ -70,6 +70,7 @@ lazy_static::lazy_static! {
static ref ALIVE_CONNS: Arc::<Mutex<Vec<i32>>> = Default::default();
static ref AUTHED_CONNS: Arc::<Mutex<Vec<(i32, AuthConnType)>>> = Default::default();
static ref SWITCH_SIDES_UUID: Arc::<Mutex<HashMap<String, (Instant, uuid::Uuid)>>> = Default::default();
static ref WAKE_LOCK: Arc::<Mutex<Option<(crate::platform::WakeLock, bool)>>> = Default::default();
}
#[cfg(any(target_os = "windows", target_os = "linux"))]
@ -1248,8 +1249,6 @@ impl Connection {
}
fn on_remote_authorized(&self) {
use std::sync::Once;
static _ONCE: Once = Once::new();
self.update_codec_on_login();
#[cfg(any(target_os = "windows", target_os = "linux"))]
if !Config::get_option("allow-remove-wallpaper").is_empty() {
@ -1259,9 +1258,6 @@ impl Connection {
match crate::platform::WallPaperRemover::new() {
Ok(remover) => {
*wallpaper = Some(remover);
_ONCE.call_once(|| {
shutdown_hooks::add_shutdown_hook(shutdown_hook);
});
}
Err(e) => {
log::info!("create wallpaper remover failed: {:?}", e);
@ -2372,7 +2368,8 @@ impl Connection {
if t.on {
if !virtual_display_manager::is_virtual_display_supported() {
self.send(make_msg("idd_not_support_under_win10_2004_tip".to_string())).await;
self.send(make_msg("idd_not_support_under_win10_2004_tip".to_string()))
.await;
} else {
if let Err(e) =
virtual_display_manager::plug_in_index_modes(t.display as _, Vec::new())
@ -3230,9 +3227,14 @@ impl LinuxHeadlessHandle {
}
}
#[cfg(any(target_os = "windows", target_os = "linux"))]
extern "C" fn shutdown_hook() {
*WALLPAPER_REMOVER.lock().unwrap() = None;
extern "C" fn connection_shutdown_hook() {
// https://stackoverflow.com/questions/35980148/why-does-an-atexit-handler-panic-when-it-accesses-stdout
// Please make sure there is no print in the call stack
*WAKE_LOCK.lock().unwrap() = None;
#[cfg(any(target_os = "windows", target_os = "linux"))]
{
*WALLPAPER_REMOVER.lock().unwrap() = None;
}
}
mod raii {
@ -3262,8 +3264,38 @@ mod raii {
impl AuthedConnID {
pub fn new(id: i32, conn_type: AuthConnType) -> Self {
AUTHED_CONNS.lock().unwrap().push((id, conn_type));
Self::check_wake_lock();
use std::sync::Once;
static _ONCE: Once = Once::new();
_ONCE.call_once(|| {
shutdown_hooks::add_shutdown_hook(connection_shutdown_hook);
});
Self(id, conn_type)
}
fn check_wake_lock() {
let mut wake_lock = WAKE_LOCK.lock().unwrap();
let remote_count = AUTHED_CONNS
.lock()
.unwrap()
.iter()
.filter(|c| c.1 == AuthConnType::Remote)
.count();
let display = remote_count > 0;
if let Some((_, last_display)) = *wake_lock {
if last_display != display {
*wake_lock = None;
}
}
let empty = AUTHED_CONNS.lock().unwrap().is_empty();
if empty {
*wake_lock = None;
} else {
if wake_lock.is_none() {
*wake_lock = Some((crate::platform::get_wake_lock(display), display));
}
}
}
}
impl Drop for AuthedConnID {
@ -3271,9 +3303,14 @@ mod raii {
if self.1 == AuthConnType::Remote {
scrap::codec::Encoder::update(self.0, scrap::codec::EncodingUpdate::Remove);
}
let mut lock = AUTHED_CONNS.lock().unwrap();
lock.retain(|&c| c.0 != self.0);
if lock.iter().filter(|c| c.1 == AuthConnType::Remote).count() == 0 {
AUTHED_CONNS.lock().unwrap().retain(|&c| c.0 != self.0);
let remote_count = AUTHED_CONNS
.lock()
.unwrap()
.iter()
.filter(|c| c.1 == AuthConnType::Remote)
.count();
if remote_count == 0 {
#[cfg(any(target_os = "windows", target_os = "linux"))]
{
*WALLPAPER_REMOVER.lock().unwrap() = None;
@ -3283,6 +3320,7 @@ mod raii {
#[cfg(all(windows, feature = "virtual_display_driver"))]
let _ = virtual_display_manager::reset_all();
}
Self::check_wake_lock();
}
}
}

View File

@ -618,10 +618,11 @@ pub mod client {
}
pub extern "C" fn drop_portable_service_shared_memory() {
// https://stackoverflow.com/questions/35980148/why-does-an-atexit-handler-panic-when-it-accesses-stdout
// Please make sure there is no print in the call stack
let mut lock = SHMEM.lock().unwrap();
if lock.is_some() {
*lock = None;
log::info!("drop shared memory");
}
}

View File

@ -363,13 +363,6 @@ fn get_capturer(current: usize, portable_service_running: bool) -> ResultType<Ca
}
fn run(vs: VideoService) -> ResultType<()> {
#[cfg(not(target_os = "android"))]
let _wake_lock = get_wake_lock();
#[cfg(target_os = "android")]
let wake_lock = crate::platform::WakeLock::new("video service");
#[cfg(target_os = "android")]
let _lock_guard = wake_lock.acquire();
// Wayland only support one video capturer for now. It is ok to call ensure_inited() here.
//
// ensure_inited() is needed because clear() may be called.
@ -735,19 +728,6 @@ fn start_uac_elevation_check() {
});
}
#[cfg(not(target_os = "android"))]
fn get_wake_lock() -> crate::platform::WakeLock {
let (display, idle, sleep) = if cfg!(windows) {
(true, false, false)
} else if cfg!(linux) {
(false, false, true)
} else {
//macos
(true, false, false)
};
crate::platform::WakeLock::new(display, idle, sleep)
}
#[inline]
fn try_broadcast_display_changed(
sp: &GenericService,